]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/i386/pci/mmconfig.c
97dcaaa0de0fa7fbb5e558585c13bc4afed02fd2
[linux-2.6-omap-h63xx.git] / arch / i386 / pci / mmconfig.c
1 /*
2  * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
3  * Copyright (C) 2004 Intel Corp.
4  *
5  * This code is released under the GNU General Public License version 2.
6  */
7
8 /*
9  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
10  */
11
12 #include <linux/pci.h>
13 #include <linux/init.h>
14 #include <linux/acpi.h>
15 #include <asm/e820.h>
16 #include "pci.h"
17
18 /* Assume systems with more busses have correct MCFG */
19 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
20
21 /* The base address of the last MMCONFIG device accessed */
22 static u32 mmcfg_last_accessed_device;
23 static int mmcfg_last_accessed_cpu;
24
25 /*
26  * Functions for accessing PCI configuration space with MMCONFIG accesses
27  */
28 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
29 {
30         int cfg_num = -1;
31         struct acpi_mcfg_allocation *cfg;
32
33         if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
34             test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots))
35                 return 0;
36
37         while (1) {
38                 ++cfg_num;
39                 if (cfg_num >= pci_mmcfg_config_num) {
40                         break;
41                 }
42                 cfg = &pci_mmcfg_config[cfg_num];
43                 if (cfg->pci_segment != seg)
44                         continue;
45                 if ((cfg->start_bus_number <= bus) &&
46                     (cfg->end_bus_number >= bus))
47                         return cfg->address;
48         }
49
50         /* Handle more broken MCFG tables on Asus etc.
51            They only contain a single entry for bus 0-0. Assume
52            this applies to all busses. */
53         cfg = &pci_mmcfg_config[0];
54         if (pci_mmcfg_config_num == 1 &&
55                 cfg->pci_segment == 0 &&
56                 (cfg->start_bus_number | cfg->end_bus_number) == 0)
57                 return cfg->address;
58
59         /* Fall back to type 0 */
60         return 0;
61 }
62
63 /*
64  * This is always called under pci_config_lock
65  */
66 static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
67 {
68         u32 dev_base = base | (bus << 20) | (devfn << 12);
69         int cpu = smp_processor_id();
70         if (dev_base != mmcfg_last_accessed_device ||
71             cpu != mmcfg_last_accessed_cpu) {
72                 mmcfg_last_accessed_device = dev_base;
73                 mmcfg_last_accessed_cpu = cpu;
74                 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
75         }
76 }
77
78 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
79                           unsigned int devfn, int reg, int len, u32 *value)
80 {
81         unsigned long flags;
82         u32 base;
83
84         if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
85                 *value = -1;
86                 return -EINVAL;
87         }
88
89         base = get_base_addr(seg, bus, devfn);
90         if (!base)
91                 return pci_conf1_read(seg,bus,devfn,reg,len,value);
92
93         spin_lock_irqsave(&pci_config_lock, flags);
94
95         pci_exp_set_dev_base(base, bus, devfn);
96
97         switch (len) {
98         case 1:
99                 *value = readb(mmcfg_virt_addr + reg);
100                 break;
101         case 2:
102                 *value = readw(mmcfg_virt_addr + reg);
103                 break;
104         case 4:
105                 *value = readl(mmcfg_virt_addr + reg);
106                 break;
107         }
108
109         spin_unlock_irqrestore(&pci_config_lock, flags);
110
111         return 0;
112 }
113
114 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
115                            unsigned int devfn, int reg, int len, u32 value)
116 {
117         unsigned long flags;
118         u32 base;
119
120         if ((bus > 255) || (devfn > 255) || (reg > 4095))
121                 return -EINVAL;
122
123         base = get_base_addr(seg, bus, devfn);
124         if (!base)
125                 return pci_conf1_write(seg,bus,devfn,reg,len,value);
126
127         spin_lock_irqsave(&pci_config_lock, flags);
128
129         pci_exp_set_dev_base(base, bus, devfn);
130
131         switch (len) {
132         case 1:
133                 writeb(value, mmcfg_virt_addr + reg);
134                 break;
135         case 2:
136                 writew(value, mmcfg_virt_addr + reg);
137                 break;
138         case 4:
139                 writel(value, mmcfg_virt_addr + reg);
140                 break;
141         }
142
143         spin_unlock_irqrestore(&pci_config_lock, flags);
144
145         return 0;
146 }
147
148 static struct pci_raw_ops pci_mmcfg = {
149         .read =         pci_mmcfg_read,
150         .write =        pci_mmcfg_write,
151 };
152
153 int __init pci_mmcfg_arch_init(void)
154 {
155         printk(KERN_INFO "PCI: Using MMCONFIG\n");
156         raw_pci_ops = &pci_mmcfg;
157         return 1;
158 }