x86/pci: AMD one chain system to use pci read out res
[linux-flexiantxendom0.git] / arch / x86 / pci / amd_bus.c
1 #include <linux/init.h>
2 #include <linux/pci.h>
3 #include <linux/topology.h>
4 #include <linux/cpu.h>
5 #include <linux/range.h>
6
7 #include <asm/pci_x86.h>
8
9 #ifdef CONFIG_X86_64
10 #include <asm/pci-direct.h>
11 #endif
12
13 #include "bus_numa.h"
14
15 /*
16  * This discovers the pcibus <-> node mapping on AMD K8.
17  * also get peer root bus resource for io,mmio
18  */
19
20 #ifdef CONFIG_X86_64
21
22 struct pci_hostbridge_probe {
23         u32 bus;
24         u32 slot;
25         u32 vendor;
26         u32 device;
27 };
28
29 static struct pci_hostbridge_probe pci_probes[] __initdata = {
30         { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 },
31         { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
32         { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
33         { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
34 };
35
36 static u64 __initdata fam10h_mmconf_start;
37 static u64 __initdata fam10h_mmconf_end;
38 static void __init get_pci_mmcfg_amd_fam10h_range(void)
39 {
40         u32 address;
41         u64 base, msr;
42         unsigned segn_busn_bits;
43
44         /* assume all cpus from fam10h have mmconf */
45         if (boot_cpu_data.x86 < 0x10)
46                 return;
47
48         address = MSR_FAM10H_MMIO_CONF_BASE;
49         rdmsrl(address, msr);
50
51         /* mmconfig is not enable */
52         if (!(msr & FAM10H_MMIO_CONF_ENABLE))
53                 return;
54
55         base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
56
57         segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
58                          FAM10H_MMIO_CONF_BUSRANGE_MASK;
59
60         fam10h_mmconf_start = base;
61         fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
62 }
63
64 #define RANGE_NUM 16
65
66 /**
67  * early_fill_mp_bus_to_node()
68  * called before pcibios_scan_root and pci_scan_bus
69  * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
70  * Registers found in the K8 northbridge
71  */
72 static int __init early_fill_mp_bus_info(void)
73 {
74         int i;
75         int j;
76         unsigned bus;
77         unsigned slot;
78         int node;
79         int link;
80         int def_node;
81         int def_link;
82         struct pci_root_info *info;
83         u32 reg;
84         struct resource *res;
85         size_t start;
86         size_t end;
87         struct range range[RANGE_NUM];
88         u64 val;
89         u32 address;
90         bool found;
91
92         if (!early_pci_allowed())
93                 return -1;
94
95         found = false;
96         for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
97                 u32 id;
98                 u16 device;
99                 u16 vendor;
100
101                 bus = pci_probes[i].bus;
102                 slot = pci_probes[i].slot;
103                 id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
104
105                 vendor = id & 0xffff;
106                 device = (id>>16) & 0xffff;
107                 if (pci_probes[i].vendor == vendor &&
108                     pci_probes[i].device == device) {
109                         found = true;
110                         break;
111                 }
112         }
113
114         if (!found)
115                 return 0;
116
117         pci_root_num = 0;
118         for (i = 0; i < 4; i++) {
119                 int min_bus;
120                 int max_bus;
121                 reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2));
122
123                 /* Check if that register is enabled for bus range */
124                 if ((reg & 7) != 3)
125                         continue;
126
127                 min_bus = (reg >> 16) & 0xff;
128                 max_bus = (reg >> 24) & 0xff;
129                 node = (reg >> 4) & 0x07;
130 #ifdef CONFIG_NUMA
131                 for (j = min_bus; j <= max_bus; j++)
132                         set_mp_bus_to_node(j, node);
133 #endif
134                 link = (reg >> 8) & 0x03;
135
136                 info = &pci_root_info[pci_root_num];
137                 info->bus_min = min_bus;
138                 info->bus_max = max_bus;
139                 info->node = node;
140                 info->link = link;
141                 sprintf(info->name, "PCI Bus #%02x", min_bus);
142                 pci_root_num++;
143         }
144
145         /* get the default node and link for left over res */
146         reg = read_pci_config(bus, slot, 0, 0x60);
147         def_node = (reg >> 8) & 0x07;
148         reg = read_pci_config(bus, slot, 0, 0x64);
149         def_link = (reg >> 8) & 0x03;
150
151         memset(range, 0, sizeof(range));
152         range[0].end = 0xffff;
153         /* io port resource */
154         for (i = 0; i < 4; i++) {
155                 reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
156                 if (!(reg & 3))
157                         continue;
158
159                 start = reg & 0xfff000;
160                 reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
161                 node = reg & 0x07;
162                 link = (reg >> 4) & 0x03;
163                 end = (reg & 0xfff000) | 0xfff;
164
165                 /* find the position */
166                 for (j = 0; j < pci_root_num; j++) {
167                         info = &pci_root_info[j];
168                         if (info->node == node && info->link == link)
169                                 break;
170                 }
171                 if (j == pci_root_num)
172                         continue; /* not found */
173
174                 info = &pci_root_info[j];
175                 printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
176                        node, link, (u64)start, (u64)end);
177
178                 /* kernel only handle 16 bit only */
179                 if (end > 0xffff)
180                         end = 0xffff;
181                 update_res(info, start, end, IORESOURCE_IO, 1);
182                 subtract_range(range, RANGE_NUM, start, end);
183         }
184         /* add left over io port range to def node/link, [0, 0xffff] */
185         /* find the position */
186         for (j = 0; j < pci_root_num; j++) {
187                 info = &pci_root_info[j];
188                 if (info->node == def_node && info->link == def_link)
189                         break;
190         }
191         if (j < pci_root_num) {
192                 info = &pci_root_info[j];
193                 for (i = 0; i < RANGE_NUM; i++) {
194                         if (!range[i].end)
195                                 continue;
196
197                         update_res(info, range[i].start, range[i].end,
198                                    IORESOURCE_IO, 1);
199                 }
200         }
201
202         memset(range, 0, sizeof(range));
203         /* 0xfd00000000-0xffffffffff for HT */
204         range[0].end = (0xfdULL<<32) - 1;
205
206         /* need to take out [0, TOM) for RAM*/
207         address = MSR_K8_TOP_MEM1;
208         rdmsrl(address, val);
209         end = (val & 0xffffff800000ULL);
210         printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20);
211         if (end < (1ULL<<32))
212                 subtract_range(range, RANGE_NUM, 0, end - 1);
213
214         /* get mmconfig */
215         get_pci_mmcfg_amd_fam10h_range();
216         /* need to take out mmconf range */
217         if (fam10h_mmconf_end) {
218                 printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end);
219                 subtract_range(range, RANGE_NUM, fam10h_mmconf_start, fam10h_mmconf_end);
220         }
221
222         /* mmio resource */
223         for (i = 0; i < 8; i++) {
224                 reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
225                 if (!(reg & 3))
226                         continue;
227
228                 start = reg & 0xffffff00; /* 39:16 on 31:8*/
229                 start <<= 8;
230                 reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
231                 node = reg & 0x07;
232                 link = (reg >> 4) & 0x03;
233                 end = (reg & 0xffffff00);
234                 end <<= 8;
235                 end |= 0xffff;
236
237                 /* find the position */
238                 for (j = 0; j < pci_root_num; j++) {
239                         info = &pci_root_info[j];
240                         if (info->node == node && info->link == link)
241                                 break;
242                 }
243                 if (j == pci_root_num)
244                         continue; /* not found */
245
246                 info = &pci_root_info[j];
247
248                 printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
249                        node, link, (u64)start, (u64)end);
250                 /*
251                  * some sick allocation would have range overlap with fam10h
252                  * mmconf range, so need to update start and end.
253                  */
254                 if (fam10h_mmconf_end) {
255                         int changed = 0;
256                         u64 endx = 0;
257                         if (start >= fam10h_mmconf_start &&
258                             start <= fam10h_mmconf_end) {
259                                 start = fam10h_mmconf_end + 1;
260                                 changed = 1;
261                         }
262
263                         if (end >= fam10h_mmconf_start &&
264                             end <= fam10h_mmconf_end) {
265                                 end = fam10h_mmconf_start - 1;
266                                 changed = 1;
267                         }
268
269                         if (start < fam10h_mmconf_start &&
270                             end > fam10h_mmconf_end) {
271                                 /* we got a hole */
272                                 endx = fam10h_mmconf_start - 1;
273                                 update_res(info, start, endx, IORESOURCE_MEM, 0);
274                                 subtract_range(range, RANGE_NUM, start, endx);
275                                 printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx);
276                                 start = fam10h_mmconf_end + 1;
277                                 changed = 1;
278                         }
279                         if (changed) {
280                                 if (start <= end) {
281                                         printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end);
282                                 } else {
283                                         printk(KERN_CONT "%s\n", endx?"":" ==> none");
284                                         continue;
285                                 }
286                         }
287                 }
288
289                 update_res(info, start, end, IORESOURCE_MEM, 1);
290                 subtract_range(range, RANGE_NUM, start, end);
291                 printk(KERN_CONT "\n");
292         }
293
294         /* need to take out [4G, TOM2) for RAM*/
295         /* SYS_CFG */
296         address = MSR_K8_SYSCFG;
297         rdmsrl(address, val);
298         /* TOP_MEM2 is enabled? */
299         if (val & (1<<21)) {
300                 /* TOP_MEM2 */
301                 address = MSR_K8_TOP_MEM2;
302                 rdmsrl(address, val);
303                 end = (val & 0xffffff800000ULL);
304                 printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20);
305                 subtract_range(range, RANGE_NUM, 1ULL<<32, end - 1);
306         }
307
308         /*
309          * add left over mmio range to def node/link ?
310          * that is tricky, just record range in from start_min to 4G
311          */
312         for (j = 0; j < pci_root_num; j++) {
313                 info = &pci_root_info[j];
314                 if (info->node == def_node && info->link == def_link)
315                         break;
316         }
317         if (j < pci_root_num) {
318                 info = &pci_root_info[j];
319
320                 for (i = 0; i < RANGE_NUM; i++) {
321                         if (!range[i].end)
322                                 continue;
323
324                         update_res(info, range[i].start, range[i].end,
325                                    IORESOURCE_MEM, 1);
326                 }
327         }
328
329         for (i = 0; i < pci_root_num; i++) {
330                 int res_num;
331                 int busnum;
332
333                 info = &pci_root_info[i];
334                 res_num = info->res_num;
335                 busnum = info->bus_min;
336                 printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n",
337                        info->bus_min, info->bus_max, info->node, info->link);
338                 for (j = 0; j < res_num; j++) {
339                         res = &info->res[j];
340                         printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n",
341                                busnum, j,
342                                (res->flags & IORESOURCE_IO)?"io port":"mmio",
343                                res->start, res->end);
344                 }
345         }
346
347         return 0;
348 }
349
350 #else  /* !CONFIG_X86_64 */
351
352 static int __init early_fill_mp_bus_info(void) { return 0; }
353
354 #endif /* !CONFIG_X86_64 */
355
356 /* common 32/64 bit code */
357
358 #define ENABLE_CF8_EXT_CFG      (1ULL << 46)
359
360 static void enable_pci_io_ecs(void *unused)
361 {
362         u64 reg;
363         rdmsrl(MSR_AMD64_NB_CFG, reg);
364         if (!(reg & ENABLE_CF8_EXT_CFG)) {
365                 reg |= ENABLE_CF8_EXT_CFG;
366                 wrmsrl(MSR_AMD64_NB_CFG, reg);
367         }
368 }
369
370 static int __cpuinit amd_cpu_notify(struct notifier_block *self,
371                                     unsigned long action, void *hcpu)
372 {
373         int cpu = (long)hcpu;
374         switch (action) {
375         case CPU_ONLINE:
376         case CPU_ONLINE_FROZEN:
377                 smp_call_function_single(cpu, enable_pci_io_ecs, NULL, 0);
378                 break;
379         default:
380                 break;
381         }
382         return NOTIFY_OK;
383 }
384
385 static struct notifier_block __cpuinitdata amd_cpu_notifier = {
386         .notifier_call  = amd_cpu_notify,
387 };
388
389 static int __init pci_io_ecs_init(void)
390 {
391         int cpu;
392
393         /* assume all cpus from fam10h have IO ECS */
394         if (boot_cpu_data.x86 < 0x10)
395                 return 0;
396
397         register_cpu_notifier(&amd_cpu_notifier);
398         for_each_online_cpu(cpu)
399                 amd_cpu_notify(&amd_cpu_notifier, (unsigned long)CPU_ONLINE,
400                                (void *)(long)cpu);
401         pci_probe |= PCI_HAS_IO_ECS;
402
403         return 0;
404 }
405
406 static int __init amd_postcore_init(void)
407 {
408         if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
409                 return 0;
410
411         early_fill_mp_bus_info();
412         pci_io_ecs_init();
413
414         return 0;
415 }
416
417 postcore_initcall(amd_postcore_init);