Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/x86_64/mmconfig_64.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
3
 *
4
 * This is an 64bit optimized version that always keeps the full mmconfig
5
 * space mapped. This allows lockless config space operation.
6
 *
7
 * copied from Linux
8
 */
9
10
#include <xen/init.h>
11
#include <xen/mm.h>
12
#include <xen/acpi.h>
13
#include <xen/xmalloc.h>
14
#include <xen/pci.h>
15
#include <xen/pci_regs.h>
16
#include <xen/iommu.h>
17
#include <xen/rangeset.h>
18
19
#include "mmconfig.h"
20
21
/* Static virtual mapping of the MMCONFIG aperture */
22
struct mmcfg_virt {
23
    struct acpi_mcfg_allocation *cfg;
24
    char __iomem *virt;
25
};
26
static struct mmcfg_virt *pci_mmcfg_virt;
27
static unsigned int mmcfg_pci_segment_shift;
28
29
static char __iomem *get_virt(unsigned int seg, unsigned int *bus)
30
2
{
31
2
    struct acpi_mcfg_allocation *cfg;
32
2
    int cfg_num;
33
2
34
2
    for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
35
2
        cfg = pci_mmcfg_virt[cfg_num].cfg;
36
2
        if (cfg->pci_segment == seg &&
37
2
            (cfg->start_bus_number <= *bus) &&
38
2
            (cfg->end_bus_number >= *bus)) {
39
2
            *bus -= cfg->start_bus_number;
40
2
            return pci_mmcfg_virt[cfg_num].virt;
41
2
        }
42
2
    }
43
2
44
2
    /* Fall back to type 0 */
45
0
    return NULL;
46
2
}
47
48
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
49
2
{
50
2
    char __iomem *addr;
51
2
52
2
    addr = get_virt(seg, &bus);
53
2
    if (!addr)
54
0
        return NULL;
55
2
     return addr + ((bus << 20) | (devfn << 12));
56
2
}
57
58
int pci_mmcfg_read(unsigned int seg, unsigned int bus,
59
              unsigned int devfn, int reg, int len, u32 *value)
60
2
{
61
2
    char __iomem *addr;
62
2
63
2
    /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
64
2
    if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
65
0
err:        *value = -1;
66
0
        return -EINVAL;
67
0
    }
68
2
69
2
    addr = pci_dev_base(seg, bus, devfn);
70
2
    if (!addr)
71
0
        goto err;
72
2
73
2
    switch (len) {
74
0
    case 1:
75
0
        *value = mmio_config_readb(addr + reg);
76
0
        break;
77
0
    case 2:
78
0
        *value = mmio_config_readw(addr + reg);
79
0
        break;
80
2
    case 4:
81
2
        *value = mmio_config_readl(addr + reg);
82
2
        break;
83
2
    }
84
2
85
2
    return 0;
86
2
}
87
88
int pci_mmcfg_write(unsigned int seg, unsigned int bus,
89
               unsigned int devfn, int reg, int len, u32 value)
90
0
{
91
0
    char __iomem *addr;
92
0
93
0
    /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
94
0
    if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
95
0
        return -EINVAL;
96
0
97
0
    addr = pci_dev_base(seg, bus, devfn);
98
0
    if (!addr)
99
0
        return -EINVAL;
100
0
101
0
    switch (len) {
102
0
    case 1:
103
0
        mmio_config_writeb(addr + reg, value);
104
0
        break;
105
0
    case 2:
106
0
        mmio_config_writew(addr + reg, value);
107
0
        break;
108
0
    case 4:
109
0
        mmio_config_writel(addr + reg, value);
110
0
        break;
111
0
    }
112
0
113
0
    return 0;
114
0
}
115
116
static void __iomem *mcfg_ioremap(const struct acpi_mcfg_allocation *cfg,
117
                                  unsigned long idx, unsigned int prot)
118
1
{
119
1
    unsigned long virt, size;
120
1
121
1
    virt = PCI_MCFG_VIRT_START + (idx << mmcfg_pci_segment_shift) +
122
1
           (cfg->start_bus_number << 20);
123
1
    size = (cfg->end_bus_number - cfg->start_bus_number + 1) << 20;
124
1
    if (virt + size < virt || virt + size > PCI_MCFG_VIRT_END)
125
0
        return NULL;
126
1
127
1
    if (map_pages_to_xen(virt,
128
1
                         (cfg->address >> PAGE_SHIFT) +
129
1
                         (cfg->start_bus_number << (20 - PAGE_SHIFT)),
130
1
                         size >> PAGE_SHIFT, prot))
131
0
        return NULL;
132
1
133
1
    return (void __iomem *) virt;
134
1
}
135
136
int pci_mmcfg_arch_enable(unsigned int idx)
137
1
{
138
1
    const typeof(pci_mmcfg_config[0]) *cfg = pci_mmcfg_virt[idx].cfg;
139
1
    unsigned long start_mfn, end_mfn;
140
1
141
1
    if (pci_mmcfg_virt[idx].virt)
142
0
        return 0;
143
1
    pci_mmcfg_virt[idx].virt = mcfg_ioremap(cfg, idx, PAGE_HYPERVISOR_UC);
144
1
    if (!pci_mmcfg_virt[idx].virt) {
145
0
        printk(KERN_ERR "PCI: Cannot map MCFG aperture for segment %04x\n",
146
0
               cfg->pci_segment);
147
0
        return -ENOMEM;
148
0
    }
149
1
    printk(KERN_INFO "PCI: Using MCFG for segment %04x bus %02x-%02x\n",
150
1
           cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number);
151
1
152
1
    start_mfn = PFN_DOWN(cfg->address) + PCI_BDF(cfg->start_bus_number, 0, 0);
153
1
    end_mfn = PFN_DOWN(cfg->address) + PCI_BDF(cfg->end_bus_number, ~0, ~0);
154
1
    if ( rangeset_add_range(mmio_ro_ranges, start_mfn, end_mfn) )
155
0
        printk(XENLOG_ERR
156
0
               "%04x:%02x-%02x: could not mark MCFG (mfns %lx-%lx) read-only\n",
157
0
               cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number,
158
0
               start_mfn, end_mfn);
159
1
160
1
    return 0;
161
1
}
162
163
void pci_mmcfg_arch_disable(unsigned int idx)
164
0
{
165
0
    const typeof(pci_mmcfg_config[0]) *cfg = pci_mmcfg_virt[idx].cfg;
166
0
167
0
    pci_mmcfg_virt[idx].virt = NULL;
168
0
    /*
169
0
     * Don't use destroy_xen_mappings() here, or make sure that at least
170
0
     * the necessary L4 entries get populated (so that they get properly
171
0
     * propagated to guest domains' page tables).
172
0
     */
173
0
    mcfg_ioremap(cfg, idx, 0);
174
0
    printk(KERN_WARNING "PCI: Not using MCFG for segment %04x bus %02x-%02x\n",
175
0
           cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number);
176
0
}
177
178
bool_t pci_mmcfg_decode(unsigned long mfn, unsigned int *seg,
179
                        unsigned int *bdf)
180
0
{
181
0
    unsigned int idx;
182
0
183
0
    for (idx = 0; idx < pci_mmcfg_config_num; ++idx) {
184
0
        const struct acpi_mcfg_allocation *cfg = pci_mmcfg_virt[idx].cfg;
185
0
186
0
        if (pci_mmcfg_virt[idx].virt &&
187
0
            mfn >= PFN_DOWN(cfg->address) + PCI_BDF(cfg->start_bus_number,
188
0
                                                    0, 0) &&
189
0
            mfn <= PFN_DOWN(cfg->address) + PCI_BDF(cfg->end_bus_number,
190
0
                                                    ~0, ~0)) {
191
0
            *seg = cfg->pci_segment;
192
0
            *bdf = mfn - PFN_DOWN(cfg->address);
193
0
            return 1;
194
0
        }
195
0
    }
196
0
197
0
    return 0;
198
0
}
199
200
bool_t pci_ro_mmcfg_decode(unsigned long mfn, unsigned int *seg,
201
                           unsigned int *bdf)
202
0
{
203
0
    const unsigned long *ro_map;
204
0
205
0
    return pci_mmcfg_decode(mfn, seg, bdf) &&
206
0
           ((ro_map = pci_get_ro_map(*seg)) == NULL ||
207
0
             !test_bit(*bdf, ro_map));
208
0
}
209
210
int __init pci_mmcfg_arch_init(void)
211
1
{
212
1
    int i;
213
1
214
1
    if (pci_mmcfg_virt)
215
0
        return 0;
216
1
217
1
    pci_mmcfg_virt = xzalloc_array(struct mmcfg_virt, pci_mmcfg_config_num);
218
1
    if (pci_mmcfg_virt == NULL) {
219
0
        printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
220
0
        pci_mmcfg_config_num = 0;
221
0
        return 0;
222
0
    }
223
1
224
2
    for (i = 0; i < pci_mmcfg_config_num; ++i) {
225
1
        pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
226
9
        while (pci_mmcfg_config[i].end_bus_number >> mmcfg_pci_segment_shift)
227
8
            ++mmcfg_pci_segment_shift;
228
1
    }
229
1
    mmcfg_pci_segment_shift += 20;
230
1
    return 1;
231
1
}