[CPUFREQ] x86_64: Revert earlier powernow-k8 change
[linux-2.6] / 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 "pci.h"
16
17 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
18
19 /* The base address of the last MMCONFIG device accessed */
20 static u32 mmcfg_last_accessed_device;
21
22 static DECLARE_BITMAP(fallback_slots, 32);
23
24 /*
25  * Functions for accessing PCI configuration space with MMCONFIG accesses
26  */
27 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
28 {
29         int cfg_num = -1;
30         struct acpi_table_mcfg_config *cfg;
31
32         if (seg == 0 && bus == 0 &&
33             test_bit(PCI_SLOT(devfn), fallback_slots))
34                 return 0;
35
36         while (1) {
37                 ++cfg_num;
38                 if (cfg_num >= pci_mmcfg_config_num) {
39                         break;
40                 }
41                 cfg = &pci_mmcfg_config[cfg_num];
42                 if (cfg->pci_segment_group_number != seg)
43                         continue;
44                 if ((cfg->start_bus_number <= bus) &&
45                     (cfg->end_bus_number >= bus))
46                         return cfg->base_address;
47         }
48
49         /* Handle more broken MCFG tables on Asus etc.
50            They only contain a single entry for bus 0-0. Assume
51            this applies to all busses. */
52         cfg = &pci_mmcfg_config[0];
53         if (pci_mmcfg_config_num == 1 &&
54                 cfg->pci_segment_group_number == 0 &&
55                 (cfg->start_bus_number | cfg->end_bus_number) == 0)
56                 return cfg->base_address;
57
58         /* Fall back to type 0 */
59         return 0;
60 }
61
62 static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
63 {
64         u32 dev_base = base | (bus << 20) | (devfn << 12);
65         if (dev_base != mmcfg_last_accessed_device) {
66                 mmcfg_last_accessed_device = dev_base;
67                 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
68         }
69 }
70
71 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
72                           unsigned int devfn, int reg, int len, u32 *value)
73 {
74         unsigned long flags;
75         u32 base;
76
77         if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
78                 return -EINVAL;
79
80         base = get_base_addr(seg, bus, devfn);
81         if (!base)
82                 return pci_conf1_read(seg,bus,devfn,reg,len,value);
83
84         spin_lock_irqsave(&pci_config_lock, flags);
85
86         pci_exp_set_dev_base(base, bus, devfn);
87
88         switch (len) {
89         case 1:
90                 *value = readb(mmcfg_virt_addr + reg);
91                 break;
92         case 2:
93                 *value = readw(mmcfg_virt_addr + reg);
94                 break;
95         case 4:
96                 *value = readl(mmcfg_virt_addr + reg);
97                 break;
98         }
99
100         spin_unlock_irqrestore(&pci_config_lock, flags);
101
102         return 0;
103 }
104
105 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
106                            unsigned int devfn, int reg, int len, u32 value)
107 {
108         unsigned long flags;
109         u32 base;
110
111         if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
112                 return -EINVAL;
113
114         base = get_base_addr(seg, bus, devfn);
115         if (!base)
116                 return pci_conf1_write(seg,bus,devfn,reg,len,value);
117
118         spin_lock_irqsave(&pci_config_lock, flags);
119
120         pci_exp_set_dev_base(base, bus, devfn);
121
122         switch (len) {
123         case 1:
124                 writeb(value, mmcfg_virt_addr + reg);
125                 break;
126         case 2:
127                 writew(value, mmcfg_virt_addr + reg);
128                 break;
129         case 4:
130                 writel(value, mmcfg_virt_addr + reg);
131                 break;
132         }
133
134         spin_unlock_irqrestore(&pci_config_lock, flags);
135
136         return 0;
137 }
138
139 static struct pci_raw_ops pci_mmcfg = {
140         .read =         pci_mmcfg_read,
141         .write =        pci_mmcfg_write,
142 };
143
144 /* K8 systems have some devices (typically in the builtin northbridge)
145    that are only accessible using type1
146    Normally this can be expressed in the MCFG by not listing them
147    and assigning suitable _SEGs, but this isn't implemented in some BIOS.
148    Instead try to discover all devices on bus 0 that are unreachable using MM
149    and fallback for them.
150    We only do this for bus 0/seg 0 */
151 static __init void unreachable_devices(void)
152 {
153         int i;
154         unsigned long flags;
155
156         for (i = 0; i < 32; i++) {
157                 u32 val1;
158                 u32 addr;
159
160                 pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
161                 if (val1 == 0xffffffff)
162                         continue;
163
164                 /* Locking probably not needed, but safer */
165                 spin_lock_irqsave(&pci_config_lock, flags);
166                 addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
167                 if (addr != 0)
168                         pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
169                 if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1)
170                         set_bit(i, fallback_slots);
171                 spin_unlock_irqrestore(&pci_config_lock, flags);
172         }
173 }
174
175 void __init pci_mmcfg_init(void)
176 {
177         if ((pci_probe & PCI_PROBE_MMCONF) == 0)
178                 return;
179
180         acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
181         if ((pci_mmcfg_config_num == 0) ||
182             (pci_mmcfg_config == NULL) ||
183             (pci_mmcfg_config[0].base_address == 0))
184                 return;
185
186         printk(KERN_INFO "PCI: Using MMCONFIG\n");
187         raw_pci_ops = &pci_mmcfg;
188         pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
189
190         unreachable_devices();
191 }