ia64/xen-unstable

view xen/arch/x86/x86_64/mmconfig_64.c @ 19697:42fe00c6f8b4

Enable pci mmcfg and ATS for x86_64

This patch enables PCI MMCONFIG in xen and turns on hooks for ATS.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 02 11:49:34 2009 +0100 (2009-06-02)
parents
children eb82fc994ab2
line source
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 */
10 #include <xen/mm.h>
11 #include <xen/acpi.h>
12 #include <xen/xmalloc.h>
13 #include <xen/pci.h>
14 #include <xen/pci_regs.h>
16 #include "mmconfig.h"
18 /* Static virtual mapping of the MMCONFIG aperture */
19 struct mmcfg_virt {
20 struct acpi_mcfg_allocation *cfg;
21 char __iomem *virt;
22 };
23 static struct mmcfg_virt *pci_mmcfg_virt;
25 static char __iomem *get_virt(unsigned int seg, unsigned bus)
26 {
27 struct acpi_mcfg_allocation *cfg;
28 int cfg_num;
30 for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
31 cfg = pci_mmcfg_virt[cfg_num].cfg;
32 if (cfg->pci_segment == seg &&
33 (cfg->start_bus_number <= bus) &&
34 (cfg->end_bus_number >= bus))
35 return pci_mmcfg_virt[cfg_num].virt;
36 }
38 /* Fall back to type 0 */
39 return NULL;
40 }
42 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
43 {
44 char __iomem *addr;
46 addr = get_virt(seg, bus);
47 if (!addr)
48 return NULL;
49 return addr + ((bus << 20) | (devfn << 12));
50 }
52 int pci_mmcfg_read(unsigned int seg, unsigned int bus,
53 unsigned int devfn, int reg, int len, u32 *value)
54 {
55 char __iomem *addr;
57 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
58 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
59 err: *value = -1;
60 return -EINVAL;
61 }
63 addr = pci_dev_base(seg, bus, devfn);
64 if (!addr)
65 goto err;
67 switch (len) {
68 case 1:
69 *value = mmio_config_readb(addr + reg);
70 break;
71 case 2:
72 *value = mmio_config_readw(addr + reg);
73 break;
74 case 4:
75 *value = mmio_config_readl(addr + reg);
76 break;
77 }
79 return 0;
80 }
82 int pci_mmcfg_write(unsigned int seg, unsigned int bus,
83 unsigned int devfn, int reg, int len, u32 value)
84 {
85 char __iomem *addr;
87 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
88 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
89 return -EINVAL;
91 addr = pci_dev_base(seg, bus, devfn);
92 if (!addr)
93 return -EINVAL;
95 switch (len) {
96 case 1:
97 mmio_config_writeb(addr + reg, value);
98 break;
99 case 2:
100 mmio_config_writew(addr + reg, value);
101 break;
102 case 4:
103 mmio_config_writel(addr + reg, value);
104 break;
105 }
107 return 0;
108 }
110 static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
111 {
112 void __iomem *addr;
113 unsigned long virt;
114 unsigned long mfn;
115 unsigned long size, nr_mfn;
117 printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n", (u64)PCI_MCFG_VIRT_START);
118 printk("amk_mcfg_ioremap: start_bus %x end_bus %x\n",
119 cfg->start_bus_number, cfg->end_bus_number);
121 virt = PCI_MCFG_VIRT_START + (cfg->pci_segment * (1 << 22)) +
122 (cfg->start_bus_number * (1 << 20));
123 mfn = cfg->address >> PAGE_SHIFT;
124 size = (cfg->end_bus_number - cfg->start_bus_number) << 20;
125 nr_mfn = size >> PAGE_SHIFT;
127 printk("amk_mcfg_ioremap: virt %lx mfn = %lx size %lx\n", virt, mfn, size);
129 map_pages_to_xen(virt, mfn, nr_mfn, PAGE_HYPERVISOR_NOCACHE);
130 addr = (void __iomem *) virt;
132 printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n",
133 (u64)PCI_MCFG_VIRT_START);
134 printk("amk_mcfg_ioremap: virt %lx size %lx\n", virt, size);
136 return addr;
137 }
139 int __init pci_mmcfg_arch_init(void)
140 {
141 int i;
142 pci_mmcfg_virt = xmalloc_bytes(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
143 if (pci_mmcfg_virt == NULL) {
144 printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
145 return 0;
146 }
147 memset(pci_mmcfg_virt, 0, sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
149 for (i = 0; i < pci_mmcfg_config_num; ++i) {
150 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
151 pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]);
152 if (!pci_mmcfg_virt[i].virt) {
153 printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
154 "segment %d\n",
155 pci_mmcfg_config[i].pci_segment);
156 pci_mmcfg_arch_free();
157 return 0;
158 }
159 }
160 return 1;
161 }
163 void __init pci_mmcfg_arch_free(void)
164 {
165 int i;
167 if (pci_mmcfg_virt == NULL)
168 return;
170 for (i = 0; i < pci_mmcfg_config_num; ++i) {
171 if (pci_mmcfg_virt[i].virt) {
172 iounmap(pci_mmcfg_virt[i].virt);
173 pci_mmcfg_virt[i].virt = NULL;
174 pci_mmcfg_virt[i].cfg = NULL;
175 }
176 }
178 xfree(pci_mmcfg_virt);
179 pci_mmcfg_virt = NULL;
180 }