8e05449660fe9ffd45d9405a3bc144c256b95539
[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 <linux/bitmap.h>
12 #include <asm/e820.h>
13
14 #include "pci.h"
15
16 /* aperture is up to 256MB but BIOS may reserve less */
17 #define MMCONFIG_APER_MIN       (2 * 1024*1024)
18 #define MMCONFIG_APER_MAX       (256 * 1024*1024)
19
20 /* Verify the first 16 busses. We assume that systems with more busses
21    get MCFG right. */
22 #define PCI_MMCFG_MAX_CHECK_BUS 16
23
24 /* Static virtual mapping of the MMCONFIG aperture */
25 struct mmcfg_virt {
26         struct acpi_mcfg_allocation *cfg;
27         char __iomem *virt;
28 };
29 static struct mmcfg_virt *pci_mmcfg_virt;
30
31 static inline int mcfg_broken(void)
32 {
33         struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[0];
34
35         /* Handle more broken MCFG tables on Asus etc.
36            They only contain a single entry for bus 0-0. Assume
37            this applies to all busses. */
38         if (pci_mmcfg_config_num == 1 &&
39             cfg->pci_segment_group_number == 0 &&
40             (cfg->start_bus_number | cfg->end_bus_number) == 0)
41                 return 1;
42         return 0;
43 }
44
45 static void __iomem *mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
46 {
47         void __iomem *addr;
48         u32 size;
49
50         if (mcfg_broken())
51                 size = 256 << 20;
52         else
53                 size = (cfg->end_bus_number + 1) << 20;
54
55         addr = ioremap_nocache(cfg->base_address, size);
56         if (addr) {
57                 printk(KERN_INFO "PCI: Using MMCONFIG at %x - %x\n",
58                        cfg->base_address,
59                        cfg->base_address + size - 1);
60         }
61         return addr;
62 }
63
64 static char __iomem *get_virt(unsigned int seg, unsigned bus)
65 {
66         int cfg_num = -1;
67         struct acpi_mcfg_allocation *cfg;
68
69         while (1) {
70                 ++cfg_num;
71                 if (cfg_num >= pci_mmcfg_config_num)
72                         break;
73                 cfg = pci_mmcfg_virt[cfg_num].cfg;
74                 if (cfg->pci_segment != seg)
75                         continue;
76                 if ((cfg->start_bus_number <= bus) &&
77                     (cfg->end_bus_number >= bus))
78                         return pci_mmcfg_virt[cfg_num].virt;
79         }
80
81         if (mcfg_broken())
82                 return pci_mmcfg_virt[0].virt;
83
84         /* Fall back to type 0 */
85         return NULL;
86 }
87
88 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
89 {
90         char __iomem *addr;
91         if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
92                 test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
93                 return NULL;
94         addr = get_virt(seg, bus);
95         if (!addr)
96                 return NULL;
97         return addr + ((bus << 20) | (devfn << 12));
98 }
99
100 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
101                           unsigned int devfn, int reg, int len, u32 *value)
102 {
103         char __iomem *addr;
104
105         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
106         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
107                 *value = -1;
108                 return -EINVAL;
109         }
110
111         addr = pci_dev_base(seg, bus, devfn);
112         if (!addr)
113                 return pci_conf1_read(seg,bus,devfn,reg,len,value);
114
115         switch (len) {
116         case 1:
117                 *value = readb(addr + reg);
118                 break;
119         case 2:
120                 *value = readw(addr + reg);
121                 break;
122         case 4:
123                 *value = readl(addr + reg);
124                 break;
125         }
126
127         return 0;
128 }
129
130 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
131                            unsigned int devfn, int reg, int len, u32 value)
132 {
133         char __iomem *addr;
134
135         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
136         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
137                 return -EINVAL;
138
139         addr = pci_dev_base(seg, bus, devfn);
140         if (!addr)
141                 return pci_conf1_write(seg,bus,devfn,reg,len,value);
142
143         switch (len) {
144         case 1:
145                 writeb(value, addr + reg);
146                 break;
147         case 2:
148                 writew(value, addr + reg);
149                 break;
150         case 4:
151                 writel(value, addr + reg);
152                 break;
153         }
154
155         return 0;
156 }
157
158 static struct pci_raw_ops pci_mmcfg = {
159         .read =         pci_mmcfg_read,
160         .write =        pci_mmcfg_write,
161 };
162
163 int __init pci_mmcfg_arch_init(void)
164 {
165         int i;
166         pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) *
167                                  pci_mmcfg_config_num, GFP_KERNEL);
168         if (pci_mmcfg_virt == NULL) {
169                 printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
170                 return 0;
171         }
172
173         for (i = 0; i < pci_mmcfg_config_num; ++i) {
174                 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
175                 pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]);
176                 if (!pci_mmcfg_virt[i].virt) {
177                         printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
178                                         "segment %d\n",
179                                 pci_mmcfg_config[i].pci_segment);
180                         return 0;
181                 }
182         }
183         raw_pci_ops = &pci_mmcfg;
184         return 1;
185 }