Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/passthrough/x86/ats.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This program is free software; you can redistribute it and/or modify it
3
 * under the terms and conditions of the GNU General Public License,
4
 * version 2, as published by the Free Software Foundation.
5
 *
6
 * This program is distributed in the hope it will be useful, but WITHOUT
7
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
9
 * more details.
10
 *
11
 * You should have received a copy of the GNU General Public License along with
12
 * this program; If not, see <http://www.gnu.org/licenses/>.
13
 */
14
15
#include <xen/sched.h>
16
#include <xen/pci.h>
17
#include <xen/pci_regs.h>
18
#include "../ats.h"
19
20
bool_t __read_mostly ats_enabled = 0;
21
boolean_param("ats", ats_enabled);
22
23
int enable_ats_device(struct pci_dev *pdev, struct list_head *ats_list)
24
0
{
25
0
    u32 value;
26
0
    u16 seg = pdev->seg;
27
0
    u8 bus = pdev->bus, devfn = pdev->devfn;
28
0
    int pos;
29
0
30
0
    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
31
0
    BUG_ON(!pos);
32
0
33
0
    if ( iommu_verbose )
34
0
        dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS capability found\n",
35
0
                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
36
0
37
0
    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
38
0
                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
39
0
    if ( value & ATS_ENABLE )
40
0
    {
41
0
        struct pci_dev *other;
42
0
43
0
        list_for_each_entry ( other, ats_list, ats.list )
44
0
            if ( other == pdev )
45
0
            {
46
0
                pos = 0;
47
0
                break;
48
0
            }
49
0
    }
50
0
51
0
    if ( !(value & ATS_ENABLE) )
52
0
    {
53
0
        value |= ATS_ENABLE;
54
0
        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
55
0
                         pos + ATS_REG_CTL, value);
56
0
    }
57
0
58
0
    if ( pos )
59
0
    {
60
0
        pdev->ats.cap_pos = pos;
61
0
        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
62
0
                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
63
0
        pdev->ats.queue_depth = value & ATS_QUEUE_DEPTH_MASK ?:
64
0
                                ATS_QUEUE_DEPTH_MASK + 1;
65
0
        list_add(&pdev->ats.list, ats_list);
66
0
    }
67
0
68
0
    if ( iommu_verbose )
69
0
        dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS %s enabled\n",
70
0
                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
71
0
                pos ? "is" : "was");
72
0
73
0
    return pos;
74
0
}
75
76
void disable_ats_device(struct pci_dev *pdev)
77
0
{
78
0
    u32 value;
79
0
    u16 seg = pdev->seg;
80
0
    u8 bus = pdev->bus, devfn = pdev->devfn;
81
0
82
0
    BUG_ON(!pdev->ats.cap_pos);
83
0
84
0
    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
85
0
                            pdev->ats.cap_pos + ATS_REG_CTL);
86
0
    value &= ~ATS_ENABLE;
87
0
    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
88
0
                     pdev->ats.cap_pos + ATS_REG_CTL, value);
89
0
90
0
    list_del(&pdev->ats.list);
91
0
92
0
    if ( iommu_verbose )
93
0
        dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS is disabled\n",
94
0
                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
95
0
}