[PATCH] x86{-64}: Remove old hack that disabled mmconfig support on AMD systems.
[pandora-kernel.git] / arch / x86_64 / pci / mmconfig.c
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
8 #include <linux/pci.h>
9 #include <linux/init.h>
10 #include <linux/acpi.h>
11 #include "pci.h"
12
13 #define MMCONFIG_APER_SIZE (256*1024*1024)
14
15 /* Static virtual mapping of the MMCONFIG aperture */
16 struct mmcfg_virt {
17         struct acpi_table_mcfg_config *cfg;
18         char *virt;
19 };
20 static struct mmcfg_virt *pci_mmcfg_virt;
21
22 static char *get_virt(unsigned int seg, int bus)
23 {
24         int cfg_num = -1;
25         struct acpi_table_mcfg_config *cfg;
26
27         while (1) {
28                 ++cfg_num;
29                 if (cfg_num >= pci_mmcfg_config_num) {
30                         /* something bad is going on, no cfg table is found. */
31                         /* so we fall back to the old way we used to do this */
32                         /* and just rely on the first entry to be correct. */
33                         return pci_mmcfg_virt[0].virt;
34                 }
35                 cfg = pci_mmcfg_virt[cfg_num].cfg;
36                 if (cfg->pci_segment_group_number != seg)
37                         continue;
38                 if ((cfg->start_bus_number <= bus) &&
39                     (cfg->end_bus_number >= bus))
40                         return pci_mmcfg_virt[cfg_num].virt;
41         }
42 }
43
44 static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
45 {
46
47         return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
48 }
49
50 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
51                           unsigned int devfn, int reg, int len, u32 *value)
52 {
53         char *addr = pci_dev_base(seg, bus, devfn);
54
55         if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
56                 return -EINVAL;
57
58         switch (len) {
59         case 1:
60                 *value = readb(addr + reg);
61                 break;
62         case 2:
63                 *value = readw(addr + reg);
64                 break;
65         case 4:
66                 *value = readl(addr + reg);
67                 break;
68         }
69
70         return 0;
71 }
72
73 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
74                            unsigned int devfn, int reg, int len, u32 value)
75 {
76         char *addr = pci_dev_base(seg, bus, devfn);
77
78         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
79                 return -EINVAL;
80
81         switch (len) {
82         case 1:
83                 writeb(value, addr + reg);
84                 break;
85         case 2:
86                 writew(value, addr + reg);
87                 break;
88         case 4:
89                 writel(value, addr + reg);
90                 break;
91         }
92
93         return 0;
94 }
95
96 static struct pci_raw_ops pci_mmcfg = {
97         .read =         pci_mmcfg_read,
98         .write =        pci_mmcfg_write,
99 };
100
101 static int __init pci_mmcfg_init(void)
102 {
103         int i;
104
105         if ((pci_probe & PCI_PROBE_MMCONF) == 0)
106                 return 0;
107
108         acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
109         if ((pci_mmcfg_config_num == 0) ||
110             (pci_mmcfg_config == NULL) ||
111             (pci_mmcfg_config[0].base_address == 0))
112                 return 0;
113
114         /* RED-PEN i386 doesn't do _nocache right now */
115         pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
116         if (pci_mmcfg_virt == NULL) {
117                 printk("PCI: Can not allocate memory for mmconfig structures\n");
118                 return 0;
119         }
120         for (i = 0; i < pci_mmcfg_config_num; ++i) {
121                 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
122                 pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
123                 if (!pci_mmcfg_virt[i].virt) {
124                         printk("PCI: Cannot map mmconfig aperture for segment %d\n",
125                                pci_mmcfg_config[i].pci_segment_group_number);
126                         return 0;
127                 }
128                 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
129         }
130
131         raw_pci_ops = &pci_mmcfg;
132         pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
133
134         return 0;
135 }
136
137 arch_initcall(pci_mmcfg_init);