diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 35 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 26 | ||||
-rw-r--r-- | arch/powerpc/kernel/udbg.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/maple/setup.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/feature.c | 65 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 210 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 72 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 13 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 319 | ||||
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dart.h | 41 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dart_iommu.c (renamed from arch/powerpc/sysdev/u3_iommu.c) | 173 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 199 |
14 files changed, 791 insertions, 371 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 773b880d5577..5692edb3491e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -300,6 +300,7 @@ config PPC_PMAC64 | |||
300 | bool | 300 | bool |
301 | depends on PPC_PMAC && POWER4 | 301 | depends on PPC_PMAC && POWER4 |
302 | select U3_DART | 302 | select U3_DART |
303 | select MPIC_BROKEN_U3 | ||
303 | select GENERIC_TBSYNC | 304 | select GENERIC_TBSYNC |
304 | default y | 305 | default y |
305 | 306 | ||
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 523f35087e81..f73a16e9867a 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #ifdef DEBUG | 35 | #ifdef DEBUG |
36 | #include <asm/udbg.h> | 36 | #include <asm/udbg.h> |
37 | #define DBG(fmt...) udbg_printf(fmt) | 37 | #define DBG(fmt...) printk(fmt) |
38 | #else | 38 | #else |
39 | #define DBG(fmt...) | 39 | #define DBG(fmt...) |
40 | #endif | 40 | #endif |
@@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | |||
323 | addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); | 323 | addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); |
324 | if (!addrs) | 324 | if (!addrs) |
325 | return; | 325 | return; |
326 | DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs); | ||
326 | for (; proplen >= 20; proplen -= 20, addrs += 5) { | 327 | for (; proplen >= 20; proplen -= 20, addrs += 5) { |
327 | flags = pci_parse_of_flags(addrs[0]); | 328 | flags = pci_parse_of_flags(addrs[0]); |
328 | if (!flags) | 329 | if (!flags) |
@@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | |||
332 | if (!size) | 333 | if (!size) |
333 | continue; | 334 | continue; |
334 | i = addrs[0] & 0xff; | 335 | i = addrs[0] & 0xff; |
336 | DBG(" base: %llx, size: %llx, i: %x\n", | ||
337 | (unsigned long long)base, (unsigned long long)size, i); | ||
338 | |||
335 | if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { | 339 | if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { |
336 | res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; | 340 | res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; |
337 | } else if (i == dev->rom_base_reg) { | 341 | } else if (i == dev->rom_base_reg) { |
@@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
362 | if (type == NULL) | 366 | if (type == NULL) |
363 | type = ""; | 367 | type = ""; |
364 | 368 | ||
369 | DBG(" create device, devfn: %x, type: %s\n", devfn, type); | ||
370 | |||
365 | memset(dev, 0, sizeof(struct pci_dev)); | 371 | memset(dev, 0, sizeof(struct pci_dev)); |
366 | dev->bus = bus; | 372 | dev->bus = bus; |
367 | dev->sysdata = node; | 373 | dev->sysdata = node; |
@@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
381 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); | 387 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); |
382 | dev->class = get_int_prop(node, "class-code", 0); | 388 | dev->class = get_int_prop(node, "class-code", 0); |
383 | 389 | ||
390 | DBG(" class: 0x%x\n", dev->class); | ||
391 | |||
384 | dev->current_state = 4; /* unknown power state */ | 392 | dev->current_state = 4; /* unknown power state */ |
385 | 393 | ||
386 | if (!strcmp(type, "pci")) { | 394 | if (!strcmp(type, "pci")) { |
@@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
402 | 410 | ||
403 | pci_parse_of_addrs(node, dev); | 411 | pci_parse_of_addrs(node, dev); |
404 | 412 | ||
413 | DBG(" adding to system ...\n"); | ||
414 | |||
405 | pci_device_add(dev, bus); | 415 | pci_device_add(dev, bus); |
406 | 416 | ||
407 | /* XXX pci_scan_msi_device(dev); */ | 417 | /* XXX pci_scan_msi_device(dev); */ |
@@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node, | |||
418 | int reglen, devfn; | 428 | int reglen, devfn; |
419 | struct pci_dev *dev; | 429 | struct pci_dev *dev; |
420 | 430 | ||
431 | DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); | ||
432 | |||
421 | while ((child = of_get_next_child(node, child)) != NULL) { | 433 | while ((child = of_get_next_child(node, child)) != NULL) { |
434 | DBG(" * %s\n", child->full_name); | ||
422 | reg = (u32 *) get_property(child, "reg", ®len); | 435 | reg = (u32 *) get_property(child, "reg", ®len); |
423 | if (reg == NULL || reglen < 20) | 436 | if (reg == NULL || reglen < 20) |
424 | continue; | 437 | continue; |
425 | devfn = (reg[0] >> 8) & 0xff; | 438 | devfn = (reg[0] >> 8) & 0xff; |
439 | |||
426 | /* create a new pci_dev for this device */ | 440 | /* create a new pci_dev for this device */ |
427 | dev = of_create_pci_dev(child, bus, devfn); | 441 | dev = of_create_pci_dev(child, bus, devfn); |
428 | if (!dev) | 442 | if (!dev) |
429 | continue; | 443 | continue; |
444 | DBG("dev header type: %x\n", dev->hdr_type); | ||
445 | |||
430 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 446 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
431 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | 447 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) |
432 | of_scan_pci_bridge(child, dev); | 448 | of_scan_pci_bridge(child, dev); |
@@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
446 | unsigned int flags; | 462 | unsigned int flags; |
447 | u64 size; | 463 | u64 size; |
448 | 464 | ||
465 | DBG("of_scan_pci_bridge(%s)\n", node->full_name); | ||
466 | |||
449 | /* parse bus-range property */ | 467 | /* parse bus-range property */ |
450 | busrange = (u32 *) get_property(node, "bus-range", &len); | 468 | busrange = (u32 *) get_property(node, "bus-range", &len); |
451 | if (busrange == NULL || len != 8) { | 469 | if (busrange == NULL || len != 8) { |
452 | printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", | 470 | printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", |
453 | node->full_name); | 471 | node->full_name); |
454 | return; | 472 | return; |
455 | } | 473 | } |
456 | ranges = (u32 *) get_property(node, "ranges", &len); | 474 | ranges = (u32 *) get_property(node, "ranges", &len); |
457 | if (ranges == NULL) { | 475 | if (ranges == NULL) { |
458 | printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", | 476 | printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", |
459 | node->full_name); | 477 | node->full_name); |
460 | return; | 478 | return; |
461 | } | 479 | } |
@@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
509 | } | 527 | } |
510 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), | 528 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), |
511 | bus->number); | 529 | bus->number); |
530 | DBG(" bus name: %s\n", bus->name); | ||
512 | 531 | ||
513 | mode = PCI_PROBE_NORMAL; | 532 | mode = PCI_PROBE_NORMAL; |
514 | if (ppc_md.pci_probe_mode) | 533 | if (ppc_md.pci_probe_mode) |
515 | mode = ppc_md.pci_probe_mode(bus); | 534 | mode = ppc_md.pci_probe_mode(bus); |
535 | DBG(" probe mode: %d\n", mode); | ||
536 | |||
516 | if (mode == PCI_PROBE_DEVTREE) | 537 | if (mode == PCI_PROBE_DEVTREE) |
517 | of_scan_bus(node, bus); | 538 | of_scan_bus(node, bus); |
518 | else if (mode == PCI_PROBE_NORMAL) | 539 | else if (mode == PCI_PROBE_NORMAL) |
@@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
528 | int i, mode; | 549 | int i, mode; |
529 | struct resource *res; | 550 | struct resource *res; |
530 | 551 | ||
552 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); | ||
553 | |||
531 | bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); | 554 | bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); |
532 | if (bus == NULL) { | 555 | if (bus == NULL) { |
533 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", | 556 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", |
@@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
552 | 575 | ||
553 | mode = PCI_PROBE_NORMAL; | 576 | mode = PCI_PROBE_NORMAL; |
554 | #ifdef CONFIG_PPC_MULTIPLATFORM | 577 | #ifdef CONFIG_PPC_MULTIPLATFORM |
555 | if (ppc_md.pci_probe_mode) | 578 | if (node && ppc_md.pci_probe_mode) |
556 | mode = ppc_md.pci_probe_mode(bus); | 579 | mode = ppc_md.pci_probe_mode(bus); |
580 | DBG(" probe mode: %d\n", mode); | ||
557 | if (mode == PCI_PROBE_DEVTREE) { | 581 | if (mode == PCI_PROBE_DEVTREE) { |
558 | bus->subordinate = hose->last_busno; | 582 | bus->subordinate = hose->last_busno; |
559 | of_scan_bus(node, bus); | 583 | of_scan_bus(node, bus); |
@@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
842 | * Returns a negative error code on failure, zero on success. | 866 | * Returns a negative error code on failure, zero on success. |
843 | */ | 867 | */ |
844 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | 868 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, |
845 | enum pci_mmap_state mmap_state, | 869 | enum pci_mmap_state mmap_state, int write_combine) |
846 | int write_combine) | ||
847 | { | 870 | { |
848 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 871 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; |
849 | struct resource *rp; | 872 | struct resource *rp; |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1b97e13657e5..977ee3adaf2d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -298,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
298 | int i, j, n, sense; | 298 | int i, j, n, sense; |
299 | unsigned int *irq, virq; | 299 | unsigned int *irq, virq; |
300 | struct device_node *ic; | 300 | struct device_node *ic; |
301 | int trace = 0; | ||
302 | |||
303 | //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0) | ||
304 | #define TRACE(fmt...) | ||
305 | |||
306 | if (!strcmp(np->name, "smu-doorbell")) | ||
307 | trace = 1; | ||
308 | |||
309 | TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n", | ||
310 | num_interrupt_controllers); | ||
301 | 311 | ||
302 | if (num_interrupt_controllers == 0) { | 312 | if (num_interrupt_controllers == 0) { |
303 | /* | 313 | /* |
@@ -332,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
332 | } | 342 | } |
333 | 343 | ||
334 | ints = (unsigned int *) get_property(np, "interrupts", &intlen); | 344 | ints = (unsigned int *) get_property(np, "interrupts", &intlen); |
345 | TRACE("ints=%p, intlen=%d\n", ints, intlen); | ||
335 | if (ints == NULL) | 346 | if (ints == NULL) |
336 | return 0; | 347 | return 0; |
337 | intrcells = prom_n_intr_cells(np); | 348 | intrcells = prom_n_intr_cells(np); |
338 | intlen /= intrcells * sizeof(unsigned int); | 349 | intlen /= intrcells * sizeof(unsigned int); |
339 | 350 | TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen); | |
340 | np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); | 351 | np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); |
341 | if (!np->intrs) | 352 | if (!np->intrs) |
342 | return -ENOMEM; | 353 | return -ENOMEM; |
@@ -347,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
347 | intrcount = 0; | 358 | intrcount = 0; |
348 | for (i = 0; i < intlen; ++i, ints += intrcells) { | 359 | for (i = 0; i < intlen; ++i, ints += intrcells) { |
349 | n = map_interrupt(&irq, &ic, np, ints, intrcells); | 360 | n = map_interrupt(&irq, &ic, np, ints, intrcells); |
361 | TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n); | ||
350 | if (n <= 0) | 362 | if (n <= 0) |
351 | continue; | 363 | continue; |
352 | 364 | ||
@@ -357,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
357 | np->intrs[intrcount].sense = map_isa_senses[sense]; | 369 | np->intrs[intrcount].sense = map_isa_senses[sense]; |
358 | } else { | 370 | } else { |
359 | virq = virt_irq_create_mapping(irq[0]); | 371 | virq = virt_irq_create_mapping(irq[0]); |
372 | TRACE("virq=%d\n", virq); | ||
360 | #ifdef CONFIG_PPC64 | 373 | #ifdef CONFIG_PPC64 |
361 | if (virq == NO_IRQ) { | 374 | if (virq == NO_IRQ) { |
362 | printk(KERN_CRIT "Could not allocate interrupt" | 375 | printk(KERN_CRIT "Could not allocate interrupt" |
@@ -366,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
366 | #endif | 379 | #endif |
367 | np->intrs[intrcount].line = irq_offset_up(virq); | 380 | np->intrs[intrcount].line = irq_offset_up(virq); |
368 | sense = (n > 1)? (irq[1] & 3): 1; | 381 | sense = (n > 1)? (irq[1] & 3): 1; |
382 | |||
383 | /* Apple uses bits in there in a different way, let's | ||
384 | * only keep the real sense bit on macs | ||
385 | */ | ||
386 | if (_machine == PLATFORM_POWERMAC) | ||
387 | sense &= 0x1; | ||
369 | np->intrs[intrcount].sense = map_mpic_senses[sense]; | 388 | np->intrs[intrcount].sense = map_mpic_senses[sense]; |
370 | } | 389 | } |
371 | 390 | ||
@@ -375,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
375 | char *name = get_property(ic->parent, "name", NULL); | 394 | char *name = get_property(ic->parent, "name", NULL); |
376 | if (name && !strcmp(name, "u3")) | 395 | if (name && !strcmp(name, "u3")) |
377 | np->intrs[intrcount].line += 128; | 396 | np->intrs[intrcount].line += 128; |
378 | else if (!(name && !strcmp(name, "mac-io"))) | 397 | else if (!(name && (!strcmp(name, "mac-io") || |
398 | !strcmp(name, "u4")))) | ||
379 | /* ignore other cascaded controllers, such as | 399 | /* ignore other cascaded controllers, such as |
380 | the k2-sata-root */ | 400 | the k2-sata-root */ |
381 | break; | 401 | break; |
382 | } | 402 | } |
383 | #endif | 403 | #endif /* CONFIG_PPC64 */ |
384 | if (n > 2) { | 404 | if (n > 2) { |
385 | printk("hmmm, got %d intr cells for %s:", n, | 405 | printk("hmmm, got %d intr cells for %s:", n, |
386 | np->full_name); | 406 | np->full_name); |
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index a058285a70e7..9567d9474c80 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c | |||
@@ -110,10 +110,12 @@ static int early_console_initialized; | |||
110 | 110 | ||
111 | void __init disable_early_printk(void) | 111 | void __init disable_early_printk(void) |
112 | { | 112 | { |
113 | #if 1 | ||
113 | if (!early_console_initialized) | 114 | if (!early_console_initialized) |
114 | return; | 115 | return; |
115 | unregister_console(&udbg_console); | 116 | unregister_console(&udbg_console); |
116 | early_console_initialized = 0; | 117 | early_console_initialized = 0; |
118 | #endif | ||
117 | } | 119 | } |
118 | 120 | ||
119 | /* called by setup_system */ | 121 | /* called by setup_system */ |
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 65fe4c166a68..dd73e38bfb7d 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -195,7 +195,7 @@ static void __init maple_init_early(void) | |||
195 | /* Setup interrupt mapping options */ | 195 | /* Setup interrupt mapping options */ |
196 | ppc64_interrupt_controller = IC_OPEN_PIC; | 196 | ppc64_interrupt_controller = IC_OPEN_PIC; |
197 | 197 | ||
198 | iommu_init_early_u3(); | 198 | iommu_init_early_dart(); |
199 | 199 | ||
200 | DBG(" <- maple_init_early\n"); | 200 | DBG(" <- maple_init_early\n"); |
201 | } | 201 | } |
@@ -257,7 +257,7 @@ static int __init maple_probe(int platform) | |||
257 | * occupies having to be broken up so the DART itself is not | 257 | * occupies having to be broken up so the DART itself is not |
258 | * part of the cacheable linar mapping | 258 | * part of the cacheable linar mapping |
259 | */ | 259 | */ |
260 | alloc_u3_dart_table(); | 260 | alloc_dart_table(); |
261 | 261 | ||
262 | return 1; | 262 | return 1; |
263 | } | 263 | } |
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index b1f896952b1b..d2915d64d45e 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c | |||
@@ -101,7 +101,8 @@ static const char *macio_names[] = | |||
101 | "Keylargo", | 101 | "Keylargo", |
102 | "Pangea", | 102 | "Pangea", |
103 | "Intrepid", | 103 | "Intrepid", |
104 | "K2" | 104 | "K2", |
105 | "Shasta", | ||
105 | }; | 106 | }; |
106 | 107 | ||
107 | 108 | ||
@@ -119,7 +120,7 @@ static const char *macio_names[] = | |||
119 | static struct device_node *uninorth_node; | 120 | static struct device_node *uninorth_node; |
120 | static u32 __iomem *uninorth_base; | 121 | static u32 __iomem *uninorth_base; |
121 | static u32 uninorth_rev; | 122 | static u32 uninorth_rev; |
122 | static int uninorth_u3; | 123 | static int uninorth_maj; |
123 | static void __iomem *u3_ht; | 124 | static void __iomem *u3_ht; |
124 | 125 | ||
125 | /* | 126 | /* |
@@ -1399,8 +1400,15 @@ static long g5_fw_enable(struct device_node *node, long param, long value) | |||
1399 | static long g5_mpic_enable(struct device_node *node, long param, long value) | 1400 | static long g5_mpic_enable(struct device_node *node, long param, long value) |
1400 | { | 1401 | { |
1401 | unsigned long flags; | 1402 | unsigned long flags; |
1403 | struct device_node *parent = of_get_parent(node); | ||
1404 | int is_u3; | ||
1402 | 1405 | ||
1403 | if (node->parent == NULL || strcmp(node->parent->name, "u3")) | 1406 | if (parent == NULL) |
1407 | return 0; | ||
1408 | is_u3 = strcmp(parent->name, "u3") == 0 || | ||
1409 | strcmp(parent->name, "u4") == 0; | ||
1410 | of_node_put(parent); | ||
1411 | if (!is_u3) | ||
1404 | return 0; | 1412 | return 0; |
1405 | 1413 | ||
1406 | LOCK(flags); | 1414 | LOCK(flags); |
@@ -1464,7 +1472,7 @@ static long g5_i2s_enable(struct device_node *node, long param, long value) | |||
1464 | }, | 1472 | }, |
1465 | }; | 1473 | }; |
1466 | 1474 | ||
1467 | if (macio->type != macio_keylargo2 /* && macio->type != macio_shasta*/) | 1475 | if (macio->type != macio_keylargo2 && macio->type != macio_shasta) |
1468 | return -ENODEV; | 1476 | return -ENODEV; |
1469 | if (strncmp(node->name, "i2s-", 4)) | 1477 | if (strncmp(node->name, "i2s-", 4)) |
1470 | return -ENODEV; | 1478 | return -ENODEV; |
@@ -1473,11 +1481,9 @@ static long g5_i2s_enable(struct device_node *node, long param, long value) | |||
1473 | case 0: | 1481 | case 0: |
1474 | case 1: | 1482 | case 1: |
1475 | break; | 1483 | break; |
1476 | #if 0 | ||
1477 | case 2: | 1484 | case 2: |
1478 | if (macio->type == macio_shasta) | 1485 | if (macio->type == macio_shasta) |
1479 | break; | 1486 | break; |
1480 | #endif | ||
1481 | default: | 1487 | default: |
1482 | return -ENODEV; | 1488 | return -ENODEV; |
1483 | } | 1489 | } |
@@ -1508,7 +1514,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) | |||
1508 | struct device_node *np; | 1514 | struct device_node *np; |
1509 | 1515 | ||
1510 | macio = &macio_chips[0]; | 1516 | macio = &macio_chips[0]; |
1511 | if (macio->type != macio_keylargo2) | 1517 | if (macio->type != macio_keylargo2 && macio->type != macio_shasta) |
1512 | return -ENODEV; | 1518 | return -ENODEV; |
1513 | 1519 | ||
1514 | np = find_path_device("/cpus"); | 1520 | np = find_path_device("/cpus"); |
@@ -1547,7 +1553,8 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) | |||
1547 | */ | 1553 | */ |
1548 | void g5_phy_disable_cpu1(void) | 1554 | void g5_phy_disable_cpu1(void) |
1549 | { | 1555 | { |
1550 | UN_OUT(U3_API_PHY_CONFIG_1, 0); | 1556 | if (uninorth_maj == 3) |
1557 | UN_OUT(U3_API_PHY_CONFIG_1, 0); | ||
1551 | } | 1558 | } |
1552 | #endif /* CONFIG_POWER4 */ | 1559 | #endif /* CONFIG_POWER4 */ |
1553 | 1560 | ||
@@ -2462,6 +2469,14 @@ static struct pmac_mb_def pmac_mb_defs[] = { | |||
2462 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | 2469 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, |
2463 | 0, | 2470 | 0, |
2464 | }, | 2471 | }, |
2472 | { "PowerMac11,2", "PowerMac G5 Dual Core", | ||
2473 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | ||
2474 | 0, | ||
2475 | }, | ||
2476 | { "PowerMac12,1", "iMac G5 (iSight)", | ||
2477 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | ||
2478 | 0, | ||
2479 | }, | ||
2465 | { "RackMac3,1", "XServe G5", | 2480 | { "RackMac3,1", "XServe G5", |
2466 | PMAC_TYPE_XSERVE_G5, g5_features, | 2481 | PMAC_TYPE_XSERVE_G5, g5_features, |
2467 | 0, | 2482 | 0, |
@@ -2574,6 +2589,11 @@ static int __init probe_motherboard(void) | |||
2574 | pmac_mb.model_name = "Unknown K2-based"; | 2589 | pmac_mb.model_name = "Unknown K2-based"; |
2575 | pmac_mb.features = g5_features; | 2590 | pmac_mb.features = g5_features; |
2576 | break; | 2591 | break; |
2592 | case macio_shasta: | ||
2593 | pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA; | ||
2594 | pmac_mb.model_name = "Unknown Shasta-based"; | ||
2595 | pmac_mb.features = g5_features; | ||
2596 | break; | ||
2577 | #endif /* CONFIG_POWER4 */ | 2597 | #endif /* CONFIG_POWER4 */ |
2578 | default: | 2598 | default: |
2579 | return -ENODEV; | 2599 | return -ENODEV; |
@@ -2651,7 +2671,12 @@ static void __init probe_uninorth(void) | |||
2651 | /* Locate G5 u3 */ | 2671 | /* Locate G5 u3 */ |
2652 | if (uninorth_node == NULL) { | 2672 | if (uninorth_node == NULL) { |
2653 | uninorth_node = of_find_node_by_name(NULL, "u3"); | 2673 | uninorth_node = of_find_node_by_name(NULL, "u3"); |
2654 | uninorth_u3 = 1; | 2674 | uninorth_maj = 3; |
2675 | } | ||
2676 | /* Locate G5 u4 */ | ||
2677 | if (uninorth_node == NULL) { | ||
2678 | uninorth_node = of_find_node_by_name(NULL, "u4"); | ||
2679 | uninorth_maj = 4; | ||
2655 | } | 2680 | } |
2656 | if (uninorth_node == NULL) | 2681 | if (uninorth_node == NULL) |
2657 | return; | 2682 | return; |
@@ -2664,12 +2689,13 @@ static void __init probe_uninorth(void) | |||
2664 | return; | 2689 | return; |
2665 | uninorth_base = ioremap(address, 0x40000); | 2690 | uninorth_base = ioremap(address, 0x40000); |
2666 | uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); | 2691 | uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); |
2667 | if (uninorth_u3) | 2692 | if (uninorth_maj == 3 || uninorth_maj == 4) |
2668 | u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); | 2693 | u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); |
2669 | 2694 | ||
2670 | printk(KERN_INFO "Found %s memory controller & host bridge," | 2695 | printk(KERN_INFO "Found %s memory controller & host bridge" |
2671 | " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth", | 2696 | " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" : |
2672 | uninorth_rev); | 2697 | uninorth_maj == 4 ? "U4" : "UniNorth", |
2698 | (unsigned int)address, uninorth_rev); | ||
2673 | printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); | 2699 | printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); |
2674 | 2700 | ||
2675 | /* Set the arbitrer QAck delay according to what Apple does | 2701 | /* Set the arbitrer QAck delay according to what Apple does |
@@ -2677,7 +2703,8 @@ static void __init probe_uninorth(void) | |||
2677 | if (uninorth_rev < 0x11) { | 2703 | if (uninorth_rev < 0x11) { |
2678 | actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; | 2704 | actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; |
2679 | actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : | 2705 | actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : |
2680 | UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; | 2706 | UNI_N_ARB_CTRL_QACK_DELAY) << |
2707 | UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; | ||
2681 | UN_OUT(UNI_N_ARB_CTRL, actrl); | 2708 | UN_OUT(UNI_N_ARB_CTRL, actrl); |
2682 | } | 2709 | } |
2683 | 2710 | ||
@@ -2685,7 +2712,8 @@ static void __init probe_uninorth(void) | |||
2685 | * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI | 2712 | * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI |
2686 | * memory timeout | 2713 | * memory timeout |
2687 | */ | 2714 | */ |
2688 | if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0) | 2715 | if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || |
2716 | uninorth_rev == 0xc0) | ||
2689 | UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); | 2717 | UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); |
2690 | } | 2718 | } |
2691 | 2719 | ||
@@ -2736,12 +2764,14 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ | |||
2736 | node->full_name); | 2764 | node->full_name); |
2737 | return; | 2765 | return; |
2738 | } | 2766 | } |
2739 | if (type == macio_keylargo) { | 2767 | if (type == macio_keylargo || type == macio_keylargo2) { |
2740 | u32 *did = (u32 *)get_property(node, "device-id", NULL); | 2768 | u32 *did = (u32 *)get_property(node, "device-id", NULL); |
2741 | if (*did == 0x00000025) | 2769 | if (*did == 0x00000025) |
2742 | type = macio_pangea; | 2770 | type = macio_pangea; |
2743 | if (*did == 0x0000003e) | 2771 | if (*did == 0x0000003e) |
2744 | type = macio_intrepid; | 2772 | type = macio_intrepid; |
2773 | if (*did == 0x0000004f) | ||
2774 | type = macio_shasta; | ||
2745 | } | 2775 | } |
2746 | macio_chips[i].of_node = node; | 2776 | macio_chips[i].of_node = node; |
2747 | macio_chips[i].type = type; | 2777 | macio_chips[i].type = type; |
@@ -2840,7 +2870,8 @@ set_initial_features(void) | |||
2840 | } | 2870 | } |
2841 | 2871 | ||
2842 | #ifdef CONFIG_POWER4 | 2872 | #ifdef CONFIG_POWER4 |
2843 | if (macio_chips[0].type == macio_keylargo2) { | 2873 | if (macio_chips[0].type == macio_keylargo2 || |
2874 | macio_chips[0].type == macio_shasta) { | ||
2844 | #ifndef CONFIG_SMP | 2875 | #ifndef CONFIG_SMP |
2845 | /* On SMP machines running UP, we have the second CPU eating | 2876 | /* On SMP machines running UP, we have the second CPU eating |
2846 | * bus cycles. We need to take it off the bus. This is done | 2877 | * bus cycles. We need to take it off the bus. This is done |
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 5aab261075de..f671ed253901 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Support for PCI bridges found on Power Macintoshes. | 2 | * Support for PCI bridges found on Power Macintoshes. |
3 | * | 3 | * |
4 | * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) | 4 | * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org) |
5 | * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) | 5 | * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -25,7 +25,7 @@ | |||
25 | #include <asm/pmac_feature.h> | 25 | #include <asm/pmac_feature.h> |
26 | #include <asm/grackle.h> | 26 | #include <asm/grackle.h> |
27 | #ifdef CONFIG_PPC64 | 27 | #ifdef CONFIG_PPC64 |
28 | #include <asm/iommu.h> | 28 | //#include <asm/iommu.h> |
29 | #include <asm/ppc-pci.h> | 29 | #include <asm/ppc-pci.h> |
30 | #endif | 30 | #endif |
31 | 31 | ||
@@ -44,6 +44,7 @@ static int add_bridge(struct device_node *dev); | |||
44 | static int has_uninorth; | 44 | static int has_uninorth; |
45 | #ifdef CONFIG_PPC64 | 45 | #ifdef CONFIG_PPC64 |
46 | static struct pci_controller *u3_agp; | 46 | static struct pci_controller *u3_agp; |
47 | static struct pci_controller *u4_pcie; | ||
47 | static struct pci_controller *u3_ht; | 48 | static struct pci_controller *u3_ht; |
48 | #endif /* CONFIG_PPC64 */ | 49 | #endif /* CONFIG_PPC64 */ |
49 | 50 | ||
@@ -97,11 +98,8 @@ static void __init fixup_bus_range(struct device_node *bridge) | |||
97 | 98 | ||
98 | /* Lookup the "bus-range" property for the hose */ | 99 | /* Lookup the "bus-range" property for the hose */ |
99 | bus_range = (int *) get_property(bridge, "bus-range", &len); | 100 | bus_range = (int *) get_property(bridge, "bus-range", &len); |
100 | if (bus_range == NULL || len < 2 * sizeof(int)) { | 101 | if (bus_range == NULL || len < 2 * sizeof(int)) |
101 | printk(KERN_WARNING "Can't get bus-range for %s\n", | ||
102 | bridge->full_name); | ||
103 | return; | 102 | return; |
104 | } | ||
105 | bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); | 103 | bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); |
106 | } | 104 | } |
107 | 105 | ||
@@ -128,14 +126,14 @@ static void __init fixup_bus_range(struct device_node *bridge) | |||
128 | */ | 126 | */ |
129 | 127 | ||
130 | #define MACRISC_CFA0(devfn, off) \ | 128 | #define MACRISC_CFA0(devfn, off) \ |
131 | ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ | 129 | ((1 << (unsigned int)PCI_SLOT(dev_fn)) \ |
132 | | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ | 130 | | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \ |
133 | | (((unsigned long)(off)) & 0xFCUL)) | 131 | | (((unsigned int)(off)) & 0xFCUL)) |
134 | 132 | ||
135 | #define MACRISC_CFA1(bus, devfn, off) \ | 133 | #define MACRISC_CFA1(bus, devfn, off) \ |
136 | ((((unsigned long)(bus)) << 16) \ | 134 | ((((unsigned int)(bus)) << 16) \ |
137 | |(((unsigned long)(devfn)) << 8) \ | 135 | |(((unsigned int)(devfn)) << 8) \ |
138 | |(((unsigned long)(off)) & 0xFCUL) \ | 136 | |(((unsigned int)(off)) & 0xFCUL) \ |
139 | |1UL) | 137 | |1UL) |
140 | 138 | ||
141 | static unsigned long macrisc_cfg_access(struct pci_controller* hose, | 139 | static unsigned long macrisc_cfg_access(struct pci_controller* hose, |
@@ -168,7 +166,8 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, | |||
168 | hose = pci_bus_to_host(bus); | 166 | hose = pci_bus_to_host(bus); |
169 | if (hose == NULL) | 167 | if (hose == NULL) |
170 | return PCIBIOS_DEVICE_NOT_FOUND; | 168 | return PCIBIOS_DEVICE_NOT_FOUND; |
171 | 169 | if (offset >= 0x100) | |
170 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
172 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); | 171 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); |
173 | if (!addr) | 172 | if (!addr) |
174 | return PCIBIOS_DEVICE_NOT_FOUND; | 173 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -199,7 +198,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, | |||
199 | hose = pci_bus_to_host(bus); | 198 | hose = pci_bus_to_host(bus); |
200 | if (hose == NULL) | 199 | if (hose == NULL) |
201 | return PCIBIOS_DEVICE_NOT_FOUND; | 200 | return PCIBIOS_DEVICE_NOT_FOUND; |
202 | 201 | if (offset >= 0x100) | |
202 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
203 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); | 203 | addr = macrisc_cfg_access(hose, bus->number, devfn, offset); |
204 | if (!addr) | 204 | if (!addr) |
205 | return PCIBIOS_DEVICE_NOT_FOUND; | 205 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -234,12 +234,13 @@ static struct pci_ops macrisc_pci_ops = | |||
234 | /* | 234 | /* |
235 | * Verify that a specific (bus, dev_fn) exists on chaos | 235 | * Verify that a specific (bus, dev_fn) exists on chaos |
236 | */ | 236 | */ |
237 | static int | 237 | static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) |
238 | chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) | ||
239 | { | 238 | { |
240 | struct device_node *np; | 239 | struct device_node *np; |
241 | u32 *vendor, *device; | 240 | u32 *vendor, *device; |
242 | 241 | ||
242 | if (offset >= 0x100) | ||
243 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
243 | np = pci_busdev_to_OF_node(bus, devfn); | 244 | np = pci_busdev_to_OF_node(bus, devfn); |
244 | if (np == NULL) | 245 | if (np == NULL) |
245 | return PCIBIOS_DEVICE_NOT_FOUND; | 246 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -341,10 +342,10 @@ static int u3_ht_skip_device(struct pci_controller *hose, | |||
341 | } | 342 | } |
342 | 343 | ||
343 | #define U3_HT_CFA0(devfn, off) \ | 344 | #define U3_HT_CFA0(devfn, off) \ |
344 | ((((unsigned long)devfn) << 8) | offset) | 345 | ((((unsigned int)devfn) << 8) | offset) |
345 | #define U3_HT_CFA1(bus, devfn, off) \ | 346 | #define U3_HT_CFA1(bus, devfn, off) \ |
346 | (U3_HT_CFA0(devfn, off) \ | 347 | (U3_HT_CFA0(devfn, off) \ |
347 | + (((unsigned long)bus) << 16) \ | 348 | + (((unsigned int)bus) << 16) \ |
348 | + 0x01000000UL) | 349 | + 0x01000000UL) |
349 | 350 | ||
350 | static unsigned long u3_ht_cfg_access(struct pci_controller* hose, | 351 | static unsigned long u3_ht_cfg_access(struct pci_controller* hose, |
@@ -370,7 +371,8 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | |||
370 | hose = pci_bus_to_host(bus); | 371 | hose = pci_bus_to_host(bus); |
371 | if (hose == NULL) | 372 | if (hose == NULL) |
372 | return PCIBIOS_DEVICE_NOT_FOUND; | 373 | return PCIBIOS_DEVICE_NOT_FOUND; |
373 | 374 | if (offset >= 0x100) | |
375 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
374 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 376 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); |
375 | if (!addr) | 377 | if (!addr) |
376 | return PCIBIOS_DEVICE_NOT_FOUND; | 378 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -419,7 +421,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |||
419 | hose = pci_bus_to_host(bus); | 421 | hose = pci_bus_to_host(bus); |
420 | if (hose == NULL) | 422 | if (hose == NULL) |
421 | return PCIBIOS_DEVICE_NOT_FOUND; | 423 | return PCIBIOS_DEVICE_NOT_FOUND; |
422 | 424 | if (offset >= 0x100) | |
425 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
423 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 426 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); |
424 | if (!addr) | 427 | if (!addr) |
425 | return PCIBIOS_DEVICE_NOT_FOUND; | 428 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -459,6 +462,112 @@ static struct pci_ops u3_ht_pci_ops = | |||
459 | u3_ht_read_config, | 462 | u3_ht_read_config, |
460 | u3_ht_write_config | 463 | u3_ht_write_config |
461 | }; | 464 | }; |
465 | |||
466 | #define U4_PCIE_CFA0(devfn, off) \ | ||
467 | ((1 << ((unsigned int)PCI_SLOT(dev_fn))) \ | ||
468 | | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \ | ||
469 | | ((((unsigned int)(off)) >> 8) << 28) \ | ||
470 | | (((unsigned int)(off)) & 0xfcU)) | ||
471 | |||
472 | #define U4_PCIE_CFA1(bus, devfn, off) \ | ||
473 | ((((unsigned int)(bus)) << 16) \ | ||
474 | |(((unsigned int)(devfn)) << 8) \ | ||
475 | | ((((unsigned int)(off)) >> 8) << 28) \ | ||
476 | |(((unsigned int)(off)) & 0xfcU) \ | ||
477 | |1UL) | ||
478 | |||
479 | static unsigned long u4_pcie_cfg_access(struct pci_controller* hose, | ||
480 | u8 bus, u8 dev_fn, int offset) | ||
481 | { | ||
482 | unsigned int caddr; | ||
483 | |||
484 | if (bus == hose->first_busno) { | ||
485 | caddr = U4_PCIE_CFA0(dev_fn, offset); | ||
486 | } else | ||
487 | caddr = U4_PCIE_CFA1(bus, dev_fn, offset); | ||
488 | |||
489 | /* Uninorth will return garbage if we don't read back the value ! */ | ||
490 | do { | ||
491 | out_le32(hose->cfg_addr, caddr); | ||
492 | } while (in_le32(hose->cfg_addr) != caddr); | ||
493 | |||
494 | offset &= 0x03; | ||
495 | return ((unsigned long)hose->cfg_data) + offset; | ||
496 | } | ||
497 | |||
498 | static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, | ||
499 | int offset, int len, u32 *val) | ||
500 | { | ||
501 | struct pci_controller *hose; | ||
502 | unsigned long addr; | ||
503 | |||
504 | hose = pci_bus_to_host(bus); | ||
505 | if (hose == NULL) | ||
506 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
507 | if (offset >= 0x1000) | ||
508 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
509 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | ||
510 | if (!addr) | ||
511 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
512 | /* | ||
513 | * Note: the caller has already checked that offset is | ||
514 | * suitably aligned and that len is 1, 2 or 4. | ||
515 | */ | ||
516 | switch (len) { | ||
517 | case 1: | ||
518 | *val = in_8((u8 *)addr); | ||
519 | break; | ||
520 | case 2: | ||
521 | *val = in_le16((u16 *)addr); | ||
522 | break; | ||
523 | default: | ||
524 | *val = in_le32((u32 *)addr); | ||
525 | break; | ||
526 | } | ||
527 | return PCIBIOS_SUCCESSFUL; | ||
528 | } | ||
529 | |||
530 | static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, | ||
531 | int offset, int len, u32 val) | ||
532 | { | ||
533 | struct pci_controller *hose; | ||
534 | unsigned long addr; | ||
535 | |||
536 | hose = pci_bus_to_host(bus); | ||
537 | if (hose == NULL) | ||
538 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
539 | if (offset >= 0x1000) | ||
540 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
541 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | ||
542 | if (!addr) | ||
543 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
544 | /* | ||
545 | * Note: the caller has already checked that offset is | ||
546 | * suitably aligned and that len is 1, 2 or 4. | ||
547 | */ | ||
548 | switch (len) { | ||
549 | case 1: | ||
550 | out_8((u8 *)addr, val); | ||
551 | (void) in_8((u8 *)addr); | ||
552 | break; | ||
553 | case 2: | ||
554 | out_le16((u16 *)addr, val); | ||
555 | (void) in_le16((u16 *)addr); | ||
556 | break; | ||
557 | default: | ||
558 | out_le32((u32 *)addr, val); | ||
559 | (void) in_le32((u32 *)addr); | ||
560 | break; | ||
561 | } | ||
562 | return PCIBIOS_SUCCESSFUL; | ||
563 | } | ||
564 | |||
565 | static struct pci_ops u4_pcie_pci_ops = | ||
566 | { | ||
567 | u4_pcie_read_config, | ||
568 | u4_pcie_write_config | ||
569 | }; | ||
570 | |||
462 | #endif /* CONFIG_PPC64 */ | 571 | #endif /* CONFIG_PPC64 */ |
463 | 572 | ||
464 | #ifdef CONFIG_PPC32 | 573 | #ifdef CONFIG_PPC32 |
@@ -628,15 +737,36 @@ static void __init setup_u3_agp(struct pci_controller* hose) | |||
628 | hose->ops = ¯isc_pci_ops; | 737 | hose->ops = ¯isc_pci_ops; |
629 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | 738 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); |
630 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | 739 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); |
631 | |||
632 | u3_agp = hose; | 740 | u3_agp = hose; |
633 | } | 741 | } |
634 | 742 | ||
743 | static void __init setup_u4_pcie(struct pci_controller* hose) | ||
744 | { | ||
745 | /* We currently only implement the "non-atomic" config space, to | ||
746 | * be optimised later. | ||
747 | */ | ||
748 | hose->ops = &u4_pcie_pci_ops; | ||
749 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | ||
750 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | ||
751 | |||
752 | /* The bus contains a bridge from root -> device, we need to | ||
753 | * make it visible on bus 0 so that we pick the right type | ||
754 | * of config cycles. If we didn't, we would have to force all | ||
755 | * config cycles to be type 1. So we override the "bus-range" | ||
756 | * property here | ||
757 | */ | ||
758 | hose->first_busno = 0x00; | ||
759 | hose->last_busno = 0xff; | ||
760 | u4_pcie = hose; | ||
761 | } | ||
762 | |||
635 | static void __init setup_u3_ht(struct pci_controller* hose) | 763 | static void __init setup_u3_ht(struct pci_controller* hose) |
636 | { | 764 | { |
637 | struct device_node *np = (struct device_node *)hose->arch_data; | 765 | struct device_node *np = (struct device_node *)hose->arch_data; |
766 | struct pci_controller *other = NULL; | ||
638 | int i, cur; | 767 | int i, cur; |
639 | 768 | ||
769 | |||
640 | hose->ops = &u3_ht_pci_ops; | 770 | hose->ops = &u3_ht_pci_ops; |
641 | 771 | ||
642 | /* We hard code the address because of the different size of | 772 | /* We hard code the address because of the different size of |
@@ -670,11 +800,20 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
670 | 800 | ||
671 | u3_ht = hose; | 801 | u3_ht = hose; |
672 | 802 | ||
673 | if (u3_agp == NULL) { | 803 | if (u3_agp != NULL) |
674 | DBG("U3 has no AGP, using full resource range\n"); | 804 | other = u3_agp; |
805 | else if (u4_pcie != NULL) | ||
806 | other = u4_pcie; | ||
807 | |||
808 | if (other == NULL) { | ||
809 | DBG("U3/4 has no AGP/PCIE, using full resource range\n"); | ||
675 | return; | 810 | return; |
676 | } | 811 | } |
677 | 812 | ||
813 | /* Fixup bus range vs. PCIE */ | ||
814 | if (u4_pcie) | ||
815 | hose->last_busno = u4_pcie->first_busno - 1; | ||
816 | |||
678 | /* We "remove" the AGP resources from the resources allocated to HT, | 817 | /* We "remove" the AGP resources from the resources allocated to HT, |
679 | * that is we create "holes". However, that code does assumptions | 818 | * that is we create "holes". However, that code does assumptions |
680 | * that so far happen to be true (cross fingers...), typically that | 819 | * that so far happen to be true (cross fingers...), typically that |
@@ -682,7 +821,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
682 | */ | 821 | */ |
683 | cur = 0; | 822 | cur = 0; |
684 | for (i=0; i<3; i++) { | 823 | for (i=0; i<3; i++) { |
685 | struct resource *res = &u3_agp->mem_resources[i]; | 824 | struct resource *res = &other->mem_resources[i]; |
686 | if (res->flags != IORESOURCE_MEM) | 825 | if (res->flags != IORESOURCE_MEM) |
687 | continue; | 826 | continue; |
688 | /* We don't care about "fine" resources */ | 827 | /* We don't care about "fine" resources */ |
@@ -777,9 +916,13 @@ static int __init add_bridge(struct device_node *dev) | |||
777 | setup_u3_ht(hose); | 916 | setup_u3_ht(hose); |
778 | disp_name = "U3-HT"; | 917 | disp_name = "U3-HT"; |
779 | primary = 1; | 918 | primary = 1; |
919 | } else if (device_is_compatible(dev, "u4-pcie")) { | ||
920 | setup_u4_pcie(hose); | ||
921 | disp_name = "U4-PCIE"; | ||
922 | primary = 0; | ||
780 | } | 923 | } |
781 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", | 924 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number:" |
782 | disp_name, hose->first_busno, hose->last_busno); | 925 | " %d->%d\n", disp_name, hose->first_busno, hose->last_busno); |
783 | #endif /* CONFIG_PPC64 */ | 926 | #endif /* CONFIG_PPC64 */ |
784 | 927 | ||
785 | /* 32 bits only bridges */ | 928 | /* 32 bits only bridges */ |
@@ -900,6 +1043,8 @@ void __init pmac_pci_init(void) | |||
900 | pci_setup_phb_io(u3_ht, 1); | 1043 | pci_setup_phb_io(u3_ht, 1); |
901 | if (u3_agp) | 1044 | if (u3_agp) |
902 | pci_setup_phb_io(u3_agp, 0); | 1045 | pci_setup_phb_io(u3_agp, 0); |
1046 | if (u4_pcie) | ||
1047 | pci_setup_phb_io(u4_pcie, 0); | ||
903 | 1048 | ||
904 | /* | 1049 | /* |
905 | * On ppc64, fixup the IO resources on our host bridges as | 1050 | * On ppc64, fixup the IO resources on our host bridges as |
@@ -912,7 +1057,8 @@ void __init pmac_pci_init(void) | |||
912 | 1057 | ||
913 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We | 1058 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We |
914 | * assume there is no P2P bridge on the AGP bus, which should be a | 1059 | * assume there is no P2P bridge on the AGP bus, which should be a |
915 | * safe assumptions hopefully. | 1060 | * safe assumptions for now. We should do something better in the |
1061 | * future though | ||
916 | */ | 1062 | */ |
917 | if (u3_agp) { | 1063 | if (u3_agp) { |
918 | struct device_node *np = u3_agp->arch_data; | 1064 | struct device_node *np = u3_agp->arch_data; |
@@ -920,7 +1066,6 @@ void __init pmac_pci_init(void) | |||
920 | for (np = np->child; np; np = np->sibling) | 1066 | for (np = np->child; np; np = np->sibling) |
921 | PCI_DN(np)->busno = 0xf0; | 1067 | PCI_DN(np)->busno = 0xf0; |
922 | } | 1068 | } |
923 | |||
924 | /* pmac_check_ht_link(); */ | 1069 | /* pmac_check_ht_link(); */ |
925 | 1070 | ||
926 | /* Tell pci.c to not use the common resource allocation mechanism */ | 1071 | /* Tell pci.c to not use the common resource allocation mechanism */ |
@@ -1127,7 +1272,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev) | |||
1127 | good: | 1272 | good: |
1128 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); | 1273 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); |
1129 | if ((progif & 5) != 5) { | 1274 | if ((progif & 5) != 5) { |
1130 | printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev)); | 1275 | printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", |
1276 | pci_name(dev)); | ||
1131 | (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); | 1277 | (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); |
1132 | if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || | 1278 | if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || |
1133 | (progif & 5) != 5) | 1279 | (progif & 5) != 5) |
@@ -1153,7 +1299,8 @@ static void fixup_k2_sata(struct pci_dev* dev) | |||
1153 | for (i = 0; i < 6; i++) { | 1299 | for (i = 0; i < 6; i++) { |
1154 | dev->resource[i].start = dev->resource[i].end = 0; | 1300 | dev->resource[i].start = dev->resource[i].end = 0; |
1155 | dev->resource[i].flags = 0; | 1301 | dev->resource[i].flags = 0; |
1156 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); | 1302 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, |
1303 | 0); | ||
1157 | } | 1304 | } |
1158 | } else { | 1305 | } else { |
1159 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 1306 | pci_read_config_word(dev, PCI_COMMAND, &cmd); |
@@ -1162,7 +1309,8 @@ static void fixup_k2_sata(struct pci_dev* dev) | |||
1162 | for (i = 0; i < 5; i++) { | 1309 | for (i = 0; i < 5; i++) { |
1163 | dev->resource[i].start = dev->resource[i].end = 0; | 1310 | dev->resource[i].start = dev->resource[i].end = 0; |
1164 | dev->resource[i].flags = 0; | 1311 | dev->resource[i].flags = 0; |
1165 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); | 1312 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, |
1313 | 0); | ||
1166 | } | 1314 | } |
1167 | } | 1315 | } |
1168 | } | 1316 | } |
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index dbb524a851aa..18bf3011d1e3 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -524,18 +524,56 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) | |||
524 | #endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ | 524 | #endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ |
525 | } | 525 | } |
526 | 526 | ||
527 | static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, | ||
528 | int master) | ||
529 | { | ||
530 | unsigned char senses[128]; | ||
531 | int offset = master ? 0 : 128; | ||
532 | int count = master ? 128 : 124; | ||
533 | const char *name = master ? " MPIC 1 " : " MPIC 2 "; | ||
534 | struct resource r; | ||
535 | struct mpic *mpic; | ||
536 | unsigned int flags = master ? MPIC_PRIMARY : 0; | ||
537 | int rc; | ||
538 | |||
539 | rc = of_address_to_resource(np, 0, &r); | ||
540 | if (rc) | ||
541 | return NULL; | ||
542 | |||
543 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); | ||
544 | |||
545 | prom_get_irq_senses(senses, offset, offset + count); | ||
546 | |||
547 | flags |= MPIC_WANTS_RESET; | ||
548 | if (get_property(np, "big-endian", NULL)) | ||
549 | flags |= MPIC_BIG_ENDIAN; | ||
550 | |||
551 | /* Primary Big Endian means HT interrupts. This is quite dodgy | ||
552 | * but works until I find a better way | ||
553 | */ | ||
554 | if (master && (flags & MPIC_BIG_ENDIAN)) | ||
555 | flags |= MPIC_BROKEN_U3; | ||
556 | |||
557 | mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0, | ||
558 | senses, count, name); | ||
559 | if (mpic == NULL) | ||
560 | return NULL; | ||
561 | |||
562 | mpic_init(mpic); | ||
563 | |||
564 | return mpic; | ||
565 | } | ||
566 | |||
527 | static int __init pmac_pic_probe_mpic(void) | 567 | static int __init pmac_pic_probe_mpic(void) |
528 | { | 568 | { |
529 | struct mpic *mpic1, *mpic2; | 569 | struct mpic *mpic1, *mpic2; |
530 | struct device_node *np, *master = NULL, *slave = NULL; | 570 | struct device_node *np, *master = NULL, *slave = NULL; |
531 | unsigned char senses[128]; | ||
532 | struct resource r; | ||
533 | 571 | ||
534 | /* We can have up to 2 MPICs cascaded */ | 572 | /* We can have up to 2 MPICs cascaded */ |
535 | for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) | 573 | for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) |
536 | != NULL;) { | 574 | != NULL;) { |
537 | if (master == NULL && | 575 | if (master == NULL && |
538 | get_property(np, "interrupt-parent", NULL) != NULL) | 576 | get_property(np, "interrupts", NULL) == NULL) |
539 | master = of_node_get(np); | 577 | master = of_node_get(np); |
540 | else if (slave == NULL) | 578 | else if (slave == NULL) |
541 | slave = of_node_get(np); | 579 | slave = of_node_get(np); |
@@ -557,13 +595,8 @@ static int __init pmac_pic_probe_mpic(void) | |||
557 | ppc_md.get_irq = mpic_get_irq; | 595 | ppc_md.get_irq = mpic_get_irq; |
558 | 596 | ||
559 | /* Setup master */ | 597 | /* Setup master */ |
560 | BUG_ON(of_address_to_resource(master, 0, &r)); | 598 | mpic1 = pmac_setup_one_mpic(master, 1); |
561 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, master, 0, 0); | ||
562 | prom_get_irq_senses(senses, 0, 128); | ||
563 | mpic1 = mpic_alloc(r.start, MPIC_PRIMARY | MPIC_WANTS_RESET, | ||
564 | 0, 0, 128, 252, senses, 128, " OpenPIC "); | ||
565 | BUG_ON(mpic1 == NULL); | 599 | BUG_ON(mpic1 == NULL); |
566 | mpic_init(mpic1); | ||
567 | 600 | ||
568 | /* Install NMI if any */ | 601 | /* Install NMI if any */ |
569 | pmac_pic_setup_mpic_nmi(mpic1); | 602 | pmac_pic_setup_mpic_nmi(mpic1); |
@@ -574,27 +607,12 @@ static int __init pmac_pic_probe_mpic(void) | |||
574 | if (slave == NULL || slave->n_intrs < 1) | 607 | if (slave == NULL || slave->n_intrs < 1) |
575 | return 0; | 608 | return 0; |
576 | 609 | ||
577 | /* Setup slave, failures are non-fatal */ | 610 | mpic2 = pmac_setup_one_mpic(slave, 0); |
578 | if (of_address_to_resource(slave, 0, &r)) { | ||
579 | printk(KERN_ERR "Can't get address of MPIC %s\n", | ||
580 | slave->full_name); | ||
581 | return 0; | ||
582 | } | ||
583 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, slave, 0, 0); | ||
584 | prom_get_irq_senses(senses, 128, 128 + 124); | ||
585 | |||
586 | /* We don't need to set MPIC_BROKEN_U3 here since we don't have | ||
587 | * hypertransport interrupts routed to it, at least not on currently | ||
588 | * supported machines, that may change. | ||
589 | */ | ||
590 | mpic2 = mpic_alloc(r.start, MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, | ||
591 | 0, 128, 124, 0, senses, 124, " U3-MPIC "); | ||
592 | if (mpic2 == NULL) { | 611 | if (mpic2 == NULL) { |
593 | printk(KERN_ERR "Can't create slave MPIC %s\n", | 612 | printk(KERN_ERR "Failed to setup slave MPIC\n"); |
594 | slave->full_name); | 613 | of_node_put(slave); |
595 | return 0; | 614 | return 0; |
596 | } | 615 | } |
597 | mpic_init(mpic2); | ||
598 | mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); | 616 | mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); |
599 | 617 | ||
600 | of_node_put(slave); | 618 | of_node_put(slave); |
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 18c5620f87fa..1daa5a06e9ea 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -345,7 +345,7 @@ void __init pmac_setup_arch(void) | |||
345 | 345 | ||
346 | #ifdef CONFIG_SMP | 346 | #ifdef CONFIG_SMP |
347 | /* Check for Core99 */ | 347 | /* Check for Core99 */ |
348 | if (find_devices("uni-n") || find_devices("u3")) | 348 | if (find_devices("uni-n") || find_devices("u3") || find_devices("u4")) |
349 | smp_ops = &core99_smp_ops; | 349 | smp_ops = &core99_smp_ops; |
350 | #ifdef CONFIG_PPC32 | 350 | #ifdef CONFIG_PPC32 |
351 | else | 351 | else |
@@ -635,7 +635,7 @@ static void __init pmac_init_early(void) | |||
635 | /* Setup interrupt mapping options */ | 635 | /* Setup interrupt mapping options */ |
636 | ppc64_interrupt_controller = IC_OPEN_PIC; | 636 | ppc64_interrupt_controller = IC_OPEN_PIC; |
637 | 637 | ||
638 | iommu_init_early_u3(); | 638 | iommu_init_early_dart(); |
639 | #endif | 639 | #endif |
640 | } | 640 | } |
641 | 641 | ||
@@ -711,7 +711,7 @@ static int __init pmac_probe(int platform) | |||
711 | * occupies having to be broken up so the DART itself is not | 711 | * occupies having to be broken up so the DART itself is not |
712 | * part of the cacheable linar mapping | 712 | * part of the cacheable linar mapping |
713 | */ | 713 | */ |
714 | alloc_u3_dart_table(); | 714 | alloc_dart_table(); |
715 | #endif | 715 | #endif |
716 | 716 | ||
717 | #ifdef CONFIG_PMAC_SMU | 717 | #ifdef CONFIG_PMAC_SMU |
@@ -733,10 +733,11 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) | |||
733 | struct device_node *node = bus->sysdata; | 733 | struct device_node *node = bus->sysdata; |
734 | 734 | ||
735 | /* We need to use normal PCI probing for the AGP bus, | 735 | /* We need to use normal PCI probing for the AGP bus, |
736 | since the device for the AGP bridge isn't in the tree. */ | 736 | * since the device for the AGP bridge isn't in the tree. |
737 | if (bus->self == NULL && device_is_compatible(node, "u3-agp")) | 737 | */ |
738 | if (bus->self == NULL && (device_is_compatible(node, "u3-agp") || | ||
739 | device_is_compatible(node, "u4-pcie"))) | ||
738 | return PCI_PROBE_NORMAL; | 740 | return PCI_PROBE_NORMAL; |
739 | |||
740 | return PCI_PROBE_DEVTREE; | 741 | return PCI_PROBE_DEVTREE; |
741 | } | 742 | } |
742 | #endif | 743 | #endif |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 862f1e985c19..df01bb8feb16 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -361,7 +361,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr) | |||
361 | set_dec(tb_ticks_per_jiffy); | 361 | set_dec(tb_ticks_per_jiffy); |
362 | /* XXX fixme */ | 362 | /* XXX fixme */ |
363 | set_tb(0, 0); | 363 | set_tb(0, 0); |
364 | last_jiffy_stamp(cpu_nr) = 0; | ||
365 | 364 | ||
366 | if (cpu_nr > 0) { | 365 | if (cpu_nr > 0) { |
367 | mb(); | 366 | mb(); |
@@ -429,15 +428,62 @@ struct smp_ops_t psurge_smp_ops = { | |||
429 | }; | 428 | }; |
430 | #endif /* CONFIG_PPC32 - actually powersurge support */ | 429 | #endif /* CONFIG_PPC32 - actually powersurge support */ |
431 | 430 | ||
431 | /* | ||
432 | * Core 99 and later support | ||
433 | */ | ||
434 | |||
435 | static void (*pmac_tb_freeze)(int freeze); | ||
436 | static unsigned long timebase; | ||
437 | static int tb_req; | ||
438 | |||
439 | static void smp_core99_give_timebase(void) | ||
440 | { | ||
441 | unsigned long flags; | ||
442 | |||
443 | local_irq_save(flags); | ||
444 | |||
445 | while(!tb_req) | ||
446 | barrier(); | ||
447 | tb_req = 0; | ||
448 | (*pmac_tb_freeze)(1); | ||
449 | mb(); | ||
450 | timebase = get_tb(); | ||
451 | mb(); | ||
452 | while (timebase) | ||
453 | barrier(); | ||
454 | mb(); | ||
455 | (*pmac_tb_freeze)(0); | ||
456 | mb(); | ||
457 | |||
458 | local_irq_restore(flags); | ||
459 | } | ||
460 | |||
461 | |||
462 | static void __devinit smp_core99_take_timebase(void) | ||
463 | { | ||
464 | unsigned long flags; | ||
465 | |||
466 | local_irq_save(flags); | ||
467 | |||
468 | tb_req = 1; | ||
469 | mb(); | ||
470 | while (!timebase) | ||
471 | barrier(); | ||
472 | mb(); | ||
473 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
474 | timebase = 0; | ||
475 | mb(); | ||
476 | set_dec(tb_ticks_per_jiffy/2); | ||
477 | |||
478 | local_irq_restore(flags); | ||
479 | } | ||
480 | |||
432 | #ifdef CONFIG_PPC64 | 481 | #ifdef CONFIG_PPC64 |
433 | /* | 482 | /* |
434 | * G5s enable/disable the timebase via an i2c-connected clock chip. | 483 | * G5s enable/disable the timebase via an i2c-connected clock chip. |
435 | */ | 484 | */ |
436 | static struct device_node *pmac_tb_clock_chip_host; | 485 | static struct device_node *pmac_tb_clock_chip_host; |
437 | static u8 pmac_tb_pulsar_addr; | 486 | static u8 pmac_tb_pulsar_addr; |
438 | static void (*pmac_tb_freeze)(int freeze); | ||
439 | static DEFINE_SPINLOCK(timebase_lock); | ||
440 | static unsigned long timebase; | ||
441 | 487 | ||
442 | static void smp_core99_cypress_tb_freeze(int freeze) | 488 | static void smp_core99_cypress_tb_freeze(int freeze) |
443 | { | 489 | { |
@@ -447,7 +493,8 @@ static void smp_core99_cypress_tb_freeze(int freeze) | |||
447 | /* Strangely, the device-tree says address is 0xd2, but darwin | 493 | /* Strangely, the device-tree says address is 0xd2, but darwin |
448 | * accesses 0xd0 ... | 494 | * accesses 0xd0 ... |
449 | */ | 495 | */ |
450 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | 496 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, |
497 | pmac_low_i2c_mode_combined); | ||
451 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 498 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
452 | 0xd0 | pmac_low_i2c_read, | 499 | 0xd0 | pmac_low_i2c_read, |
453 | 0x81, &data, 1); | 500 | 0x81, &data, 1); |
@@ -475,7 +522,8 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
475 | u8 data; | 522 | u8 data; |
476 | int rc; | 523 | int rc; |
477 | 524 | ||
478 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | 525 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, |
526 | pmac_low_i2c_mode_combined); | ||
479 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 527 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
480 | pmac_tb_pulsar_addr | pmac_low_i2c_read, | 528 | pmac_tb_pulsar_addr | pmac_low_i2c_read, |
481 | 0x2e, &data, 1); | 529 | 0x2e, &data, 1); |
@@ -496,54 +544,14 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
496 | } | 544 | } |
497 | } | 545 | } |
498 | 546 | ||
499 | 547 | static void __init smp_core99_setup_i2c_hwsync(int ncpus) | |
500 | static void smp_core99_give_timebase(void) | ||
501 | { | ||
502 | /* Open i2c bus for synchronous access */ | ||
503 | if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) | ||
504 | panic("Can't open i2c for TB sync !\n"); | ||
505 | |||
506 | spin_lock(&timebase_lock); | ||
507 | (*pmac_tb_freeze)(1); | ||
508 | mb(); | ||
509 | timebase = get_tb(); | ||
510 | spin_unlock(&timebase_lock); | ||
511 | |||
512 | while (timebase) | ||
513 | barrier(); | ||
514 | |||
515 | spin_lock(&timebase_lock); | ||
516 | (*pmac_tb_freeze)(0); | ||
517 | spin_unlock(&timebase_lock); | ||
518 | |||
519 | /* Close i2c bus */ | ||
520 | pmac_low_i2c_close(pmac_tb_clock_chip_host); | ||
521 | } | ||
522 | |||
523 | |||
524 | static void __devinit smp_core99_take_timebase(void) | ||
525 | { | ||
526 | while (!timebase) | ||
527 | barrier(); | ||
528 | spin_lock(&timebase_lock); | ||
529 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
530 | timebase = 0; | ||
531 | spin_unlock(&timebase_lock); | ||
532 | } | ||
533 | |||
534 | static void __init smp_core99_setup(int ncpus) | ||
535 | { | 548 | { |
536 | struct device_node *cc = NULL; | 549 | struct device_node *cc = NULL; |
537 | struct device_node *p; | 550 | struct device_node *p; |
551 | const char *name = NULL; | ||
538 | u32 *reg; | 552 | u32 *reg; |
539 | int ok; | 553 | int ok; |
540 | 554 | ||
541 | /* HW sync only on these platforms */ | ||
542 | if (!machine_is_compatible("PowerMac7,2") && | ||
543 | !machine_is_compatible("PowerMac7,3") && | ||
544 | !machine_is_compatible("RackMac3,1")) | ||
545 | return; | ||
546 | |||
547 | /* Look for the clock chip */ | 555 | /* Look for the clock chip */ |
548 | while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { | 556 | while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { |
549 | p = of_get_parent(cc); | 557 | p = of_get_parent(cc); |
@@ -561,114 +569,64 @@ static void __init smp_core99_setup(int ncpus) | |||
561 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { | 569 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { |
562 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | 570 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
563 | pmac_tb_pulsar_addr = 0xd2; | 571 | pmac_tb_pulsar_addr = 0xd2; |
564 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | 572 | name = "Pulsar"; |
565 | } else if (device_is_compatible(cc, "cy28508")) { | 573 | } else if (device_is_compatible(cc, "cy28508")) { |
566 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; | 574 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; |
567 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | 575 | name = "Cypress"; |
568 | } | 576 | } |
569 | break; | 577 | break; |
570 | case 0xd4: | 578 | case 0xd4: |
571 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | 579 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
572 | pmac_tb_pulsar_addr = 0xd4; | 580 | pmac_tb_pulsar_addr = 0xd4; |
573 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | 581 | name = "Pulsar"; |
574 | break; | 582 | break; |
575 | } | 583 | } |
576 | if (pmac_tb_freeze != NULL) { | 584 | if (pmac_tb_freeze != NULL) |
577 | pmac_tb_clock_chip_host = of_get_parent(cc); | ||
578 | of_node_put(cc); | ||
579 | break; | 585 | break; |
580 | } | ||
581 | } | 586 | } |
582 | if (pmac_tb_freeze == NULL) { | 587 | if (pmac_tb_freeze != NULL) { |
583 | smp_ops->give_timebase = smp_generic_give_timebase; | 588 | struct device_node *p = of_get_parent(cc); |
584 | smp_ops->take_timebase = smp_generic_take_timebase; | 589 | of_node_put(cc); |
590 | while(p && strcmp(p->type, "i2c")) { | ||
591 | cc = of_get_parent(p); | ||
592 | of_node_put(p); | ||
593 | p = cc; | ||
594 | } | ||
595 | if (p == NULL) | ||
596 | goto no_i2c_sync; | ||
597 | /* Open i2c bus for synchronous access */ | ||
598 | if (pmac_low_i2c_open(p, 0)) { | ||
599 | printk(KERN_ERR "Failed top open i2c bus %s for clock" | ||
600 | " sync, fallback to software sync !\n", | ||
601 | p->full_name); | ||
602 | of_node_put(p); | ||
603 | goto no_i2c_sync; | ||
604 | } | ||
605 | pmac_tb_clock_chip_host = p; | ||
606 | printk(KERN_INFO "Processor timebase sync using %s i2c clock\n", | ||
607 | name); | ||
608 | return; | ||
585 | } | 609 | } |
610 | no_i2c_sync: | ||
611 | pmac_tb_freeze = NULL; | ||
586 | } | 612 | } |
587 | 613 | ||
588 | /* nothing to do here, caches are already set up by service processor */ | 614 | #endif /* CONFIG_PPC64 */ |
589 | static inline void __devinit core99_init_caches(int cpu) | ||
590 | { | ||
591 | } | ||
592 | 615 | ||
593 | #else /* CONFIG_PPC64 */ | ||
594 | 616 | ||
595 | /* | 617 | /* |
596 | * SMP G4 powermacs use a GPIO to enable/disable the timebase. | 618 | * SMP G4 and newer G5 use a GPIO to enable/disable the timebase. |
597 | */ | 619 | */ |
598 | 620 | ||
599 | static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ | 621 | static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ |
600 | 622 | ||
601 | static unsigned int pri_tb_hi, pri_tb_lo; | 623 | static void smp_core99_gpio_tb_freeze(int freeze) |
602 | static unsigned int pri_tb_stamp; | ||
603 | |||
604 | /* not __init, called in sleep/wakeup code */ | ||
605 | void smp_core99_give_timebase(void) | ||
606 | { | 624 | { |
607 | unsigned long flags; | 625 | if (freeze) |
608 | unsigned int t; | 626 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); |
609 | 627 | else | |
610 | /* wait for the secondary to be in take_timebase */ | 628 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); |
611 | for (t = 100000; t > 0 && !sec_tb_reset; --t) | ||
612 | udelay(10); | ||
613 | if (!sec_tb_reset) { | ||
614 | printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); | ||
615 | return; | ||
616 | } | ||
617 | |||
618 | /* freeze the timebase and read it */ | ||
619 | /* disable interrupts so the timebase is disabled for the | ||
620 | shortest possible time */ | ||
621 | local_irq_save(flags); | ||
622 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); | ||
623 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); | 629 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); |
624 | mb(); | ||
625 | pri_tb_hi = get_tbu(); | ||
626 | pri_tb_lo = get_tbl(); | ||
627 | pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); | ||
628 | mb(); | ||
629 | |||
630 | /* tell the secondary we're ready */ | ||
631 | sec_tb_reset = 2; | ||
632 | mb(); | ||
633 | |||
634 | /* wait for the secondary to have taken it */ | ||
635 | /* note: can't use udelay here, since it needs the timebase running */ | ||
636 | for (t = 10000000; t > 0 && sec_tb_reset; --t) | ||
637 | barrier(); | ||
638 | if (sec_tb_reset) | ||
639 | /* XXX BUG_ON here? */ | ||
640 | printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); | ||
641 | |||
642 | /* Now, restart the timebase by leaving the GPIO to an open collector */ | ||
643 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); | ||
644 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); | ||
645 | local_irq_restore(flags); | ||
646 | } | ||
647 | |||
648 | /* not __init, called in sleep/wakeup code */ | ||
649 | void smp_core99_take_timebase(void) | ||
650 | { | ||
651 | unsigned long flags; | ||
652 | |||
653 | /* tell the primary we're here */ | ||
654 | sec_tb_reset = 1; | ||
655 | mb(); | ||
656 | |||
657 | /* wait for the primary to set pri_tb_hi/lo */ | ||
658 | while (sec_tb_reset < 2) | ||
659 | mb(); | ||
660 | |||
661 | /* set our stuff the same as the primary */ | ||
662 | local_irq_save(flags); | ||
663 | set_dec(1); | ||
664 | set_tb(pri_tb_hi, pri_tb_lo); | ||
665 | last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; | ||
666 | mb(); | ||
667 | |||
668 | /* tell the primary we're done */ | ||
669 | sec_tb_reset = 0; | ||
670 | mb(); | ||
671 | local_irq_restore(flags); | ||
672 | } | 630 | } |
673 | 631 | ||
674 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ | 632 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ |
@@ -677,6 +635,7 @@ volatile static long int core99_l3_cache; | |||
677 | 635 | ||
678 | static void __devinit core99_init_caches(int cpu) | 636 | static void __devinit core99_init_caches(int cpu) |
679 | { | 637 | { |
638 | #ifndef CONFIG_PPC64 | ||
680 | if (!cpu_has_feature(CPU_FTR_L2CR)) | 639 | if (!cpu_has_feature(CPU_FTR_L2CR)) |
681 | return; | 640 | return; |
682 | 641 | ||
@@ -702,30 +661,80 @@ static void __devinit core99_init_caches(int cpu) | |||
702 | _set_L3CR(core99_l3_cache); | 661 | _set_L3CR(core99_l3_cache); |
703 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); | 662 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); |
704 | } | 663 | } |
664 | #endif /* !CONFIG_PPC64 */ | ||
705 | } | 665 | } |
706 | 666 | ||
707 | static void __init smp_core99_setup(int ncpus) | 667 | static void __init smp_core99_setup(int ncpus) |
708 | { | 668 | { |
709 | struct device_node *cpu; | 669 | #ifdef CONFIG_PPC64 |
710 | u32 *tbprop = NULL; | ||
711 | int i; | ||
712 | 670 | ||
713 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | 671 | /* i2c based HW sync on some G5s */ |
714 | cpu = of_find_node_by_type(NULL, "cpu"); | 672 | if (machine_is_compatible("PowerMac7,2") || |
715 | if (cpu != NULL) { | 673 | machine_is_compatible("PowerMac7,3") || |
716 | tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL); | 674 | machine_is_compatible("RackMac3,1")) |
717 | if (tbprop) | 675 | smp_core99_setup_i2c_hwsync(ncpus); |
718 | core99_tb_gpio = *tbprop; | 676 | |
719 | of_node_put(cpu); | 677 | /* GPIO based HW sync on recent G5s */ |
678 | if (pmac_tb_freeze == NULL) { | ||
679 | struct device_node *np = | ||
680 | of_find_node_by_name(NULL, "timebase-enable"); | ||
681 | u32 *reg = (u32 *)get_property(np, "reg", NULL); | ||
682 | |||
683 | if (np && reg && !strcmp(np->type, "gpio")) { | ||
684 | core99_tb_gpio = *reg; | ||
685 | if (core99_tb_gpio < 0x50) | ||
686 | core99_tb_gpio += 0x50; | ||
687 | pmac_tb_freeze = smp_core99_gpio_tb_freeze; | ||
688 | printk(KERN_INFO "Processor timebase sync using" | ||
689 | " GPIO 0x%02x\n", core99_tb_gpio); | ||
690 | } | ||
720 | } | 691 | } |
721 | 692 | ||
722 | /* XXX should get this from reg properties */ | 693 | #else /* CONFIG_PPC64 */ |
723 | for (i = 1; i < ncpus; ++i) | 694 | |
724 | smp_hw_index[i] = i; | 695 | /* GPIO based HW sync on ppc32 Core99 */ |
725 | powersave_nap = 0; | 696 | if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) { |
726 | } | 697 | struct device_node *cpu; |
698 | u32 *tbprop = NULL; | ||
699 | |||
700 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | ||
701 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
702 | if (cpu != NULL) { | ||
703 | tbprop = (u32 *)get_property(cpu, "timebase-enable", | ||
704 | NULL); | ||
705 | if (tbprop) | ||
706 | core99_tb_gpio = *tbprop; | ||
707 | of_node_put(cpu); | ||
708 | } | ||
709 | pmac_tb_freeze = smp_core99_gpio_tb_freeze; | ||
710 | printk(KERN_INFO "Processor timebase sync using" | ||
711 | " GPIO 0x%02x\n", core99_tb_gpio); | ||
712 | } | ||
713 | |||
714 | #endif /* CONFIG_PPC64 */ | ||
715 | |||
716 | /* No timebase sync, fallback to software */ | ||
717 | if (pmac_tb_freeze == NULL) { | ||
718 | smp_ops->give_timebase = smp_generic_give_timebase; | ||
719 | smp_ops->take_timebase = smp_generic_take_timebase; | ||
720 | printk(KERN_INFO "Processor timebase sync using software\n"); | ||
721 | } | ||
722 | |||
723 | #ifndef CONFIG_PPC64 | ||
724 | { | ||
725 | int i; | ||
726 | |||
727 | /* XXX should get this from reg properties */ | ||
728 | for (i = 1; i < ncpus; ++i) | ||
729 | smp_hw_index[i] = i; | ||
730 | } | ||
727 | #endif | 731 | #endif |
728 | 732 | ||
733 | /* 32 bits SMP can't NAP */ | ||
734 | if (!machine_is_compatible("MacRISC4")) | ||
735 | powersave_nap = 0; | ||
736 | } | ||
737 | |||
729 | static int __init smp_core99_probe(void) | 738 | static int __init smp_core99_probe(void) |
730 | { | 739 | { |
731 | struct device_node *cpus; | 740 | struct device_node *cpus; |
@@ -803,17 +812,25 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) | |||
803 | mpic_setup_this_cpu(); | 812 | mpic_setup_this_cpu(); |
804 | 813 | ||
805 | if (cpu_nr == 0) { | 814 | if (cpu_nr == 0) { |
806 | #ifdef CONFIG_POWER4 | 815 | #ifdef CONFIG_PPC64 |
807 | extern void g5_phy_disable_cpu1(void); | 816 | extern void g5_phy_disable_cpu1(void); |
808 | 817 | ||
818 | /* Close i2c bus if it was used for tb sync */ | ||
819 | if (pmac_tb_clock_chip_host) { | ||
820 | pmac_low_i2c_close(pmac_tb_clock_chip_host); | ||
821 | pmac_tb_clock_chip_host = NULL; | ||
822 | } | ||
823 | |||
809 | /* If we didn't start the second CPU, we must take | 824 | /* If we didn't start the second CPU, we must take |
810 | * it off the bus | 825 | * it off the bus |
811 | */ | 826 | */ |
812 | if (machine_is_compatible("MacRISC4") && | 827 | if (machine_is_compatible("MacRISC4") && |
813 | num_online_cpus() < 2) | 828 | num_online_cpus() < 2) |
814 | g5_phy_disable_cpu1(); | 829 | g5_phy_disable_cpu1(); |
815 | #endif /* CONFIG_POWER4 */ | 830 | #endif /* CONFIG_PPC64 */ |
816 | if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); | 831 | |
832 | if (ppc_md.progress) | ||
833 | ppc_md.progress("core99_setup_cpu 0 done", 0x349); | ||
817 | } | 834 | } |
818 | } | 835 | } |
819 | 836 | ||
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index b3e3636a57b0..14b9abde2d27 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -4,6 +4,6 @@ obj-$(CONFIG_PPC_I8259) += i8259.o | |||
4 | obj-$(CONFIG_PPC_MPC106) += grackle.o | 4 | obj-$(CONFIG_PPC_MPC106) += grackle.o |
5 | obj-$(CONFIG_BOOKE) += dcr.o | 5 | obj-$(CONFIG_BOOKE) += dcr.o |
6 | obj-$(CONFIG_40x) += dcr.o | 6 | obj-$(CONFIG_40x) += dcr.o |
7 | obj-$(CONFIG_U3_DART) += u3_iommu.o | 7 | obj-$(CONFIG_U3_DART) += dart_iommu.o |
8 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o | 8 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o |
9 | obj-$(CONFIG_83xx) += ipic.o | 9 | obj-$(CONFIG_83xx) += ipic.o |
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h index 33ed9ed7fc1e..c2d05763ccbe 100644 --- a/arch/powerpc/sysdev/dart.h +++ b/arch/powerpc/sysdev/dart.h | |||
@@ -20,29 +20,44 @@ | |||
20 | #define _POWERPC_SYSDEV_DART_H | 20 | #define _POWERPC_SYSDEV_DART_H |
21 | 21 | ||
22 | 22 | ||
23 | /* physical base of DART registers */ | ||
24 | #define DART_BASE 0xf8033000UL | ||
25 | |||
26 | /* Offset from base to control register */ | 23 | /* Offset from base to control register */ |
27 | #define DARTCNTL 0 | 24 | #define DART_CNTL 0 |
25 | |||
28 | /* Offset from base to exception register */ | 26 | /* Offset from base to exception register */ |
29 | #define DARTEXCP 0x10 | 27 | #define DART_EXCP_U3 0x10 |
30 | /* Offset from base to TLB tag registers */ | 28 | /* Offset from base to TLB tag registers */ |
31 | #define DARTTAG 0x1000 | 29 | #define DART_TAGS_U3 0x1000 |
32 | 30 | ||
31 | /* U4 registers */ | ||
32 | #define DART_BASE_U4 0x10 | ||
33 | #define DART_SIZE_U4 0x20 | ||
34 | #define DART_EXCP_U4 0x30 | ||
35 | #define DART_TAGS_U4 0x1000 | ||
33 | 36 | ||
34 | /* Control Register fields */ | 37 | /* Control Register fields */ |
35 | 38 | ||
36 | /* base address of table (pfn) */ | 39 | /* U3 registers */ |
37 | #define DARTCNTL_BASE_MASK 0xfffff | 40 | #define DART_CNTL_U3_BASE_MASK 0xfffff |
38 | #define DARTCNTL_BASE_SHIFT 12 | 41 | #define DART_CNTL_U3_BASE_SHIFT 12 |
42 | #define DART_CNTL_U3_FLUSHTLB 0x400 | ||
43 | #define DART_CNTL_U3_ENABLE 0x200 | ||
44 | #define DART_CNTL_U3_SIZE_MASK 0x1ff | ||
45 | #define DART_CNTL_U3_SIZE_SHIFT 0 | ||
46 | |||
47 | /* U4 registers */ | ||
48 | #define DART_BASE_U4_BASE_MASK 0xffffff | ||
49 | #define DART_BASE_U4_BASE_SHIFT 0 | ||
50 | #define DART_CNTL_U4_FLUSHTLB 0x20000000 | ||
51 | #define DART_CNTL_U4_ENABLE 0x80000000 | ||
52 | #define DART_SIZE_U4_SIZE_MASK 0x1fff | ||
53 | #define DART_SIZE_U4_SIZE_SHIFT 0 | ||
54 | |||
55 | #define DART_REG(r) (dart + ((r) >> 2)) | ||
56 | #define DART_IN(r) (in_be32(DART_REG(r))) | ||
57 | #define DART_OUT(r,v) (out_be32(DART_REG(r), (v))) | ||
39 | 58 | ||
40 | #define DARTCNTL_FLUSHTLB 0x400 | ||
41 | #define DARTCNTL_ENABLE 0x200 | ||
42 | 59 | ||
43 | /* size of table in pages */ | 60 | /* size of table in pages */ |
44 | #define DARTCNTL_SIZE_MASK 0x1ff | ||
45 | #define DARTCNTL_SIZE_SHIFT 0 | ||
46 | 61 | ||
47 | 62 | ||
48 | /* DART table fields */ | 63 | /* DART table fields */ |
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 5c1a26a6d00c..df0dbdee762a 100644 --- a/arch/powerpc/sysdev/u3_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c | |||
@@ -1,25 +1,27 @@ | |||
1 | /* | 1 | /* |
2 | * arch/powerpc/sysdev/u3_iommu.c | 2 | * arch/powerpc/sysdev/dart_iommu.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation | 4 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation |
5 | * Copyright (C) 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>, | ||
6 | * IBM Corporation | ||
5 | * | 7 | * |
6 | * Based on pSeries_iommu.c: | 8 | * Based on pSeries_iommu.c: |
7 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation | 9 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation |
8 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation | 10 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation |
9 | * | 11 | * |
10 | * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. | 12 | * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu. |
13 | * | ||
11 | * | 14 | * |
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
15 | * the Free Software Foundation; either version 2 of the License, or | 17 | * the Free Software Foundation; either version 2 of the License, or |
16 | * (at your option) any later version. | 18 | * (at your option) any later version. |
17 | * | 19 | * |
18 | * This program is distributed in the hope that it will be useful, | 20 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
22 | * | 24 | * |
23 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
24 | * along with this program; if not, write to the Free Software | 26 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
@@ -57,21 +59,22 @@ static unsigned long dart_tablesize; | |||
57 | static u32 *dart_vbase; | 59 | static u32 *dart_vbase; |
58 | 60 | ||
59 | /* Mapped base address for the dart */ | 61 | /* Mapped base address for the dart */ |
60 | static unsigned int *dart; | 62 | static unsigned int *__iomem dart; |
61 | 63 | ||
62 | /* Dummy val that entries are set to when unused */ | 64 | /* Dummy val that entries are set to when unused */ |
63 | static unsigned int dart_emptyval; | 65 | static unsigned int dart_emptyval; |
64 | 66 | ||
65 | static struct iommu_table iommu_table_u3; | 67 | static struct iommu_table iommu_table_dart; |
66 | static int iommu_table_u3_inited; | 68 | static int iommu_table_dart_inited; |
67 | static int dart_dirty; | 69 | static int dart_dirty; |
70 | static int dart_is_u4; | ||
68 | 71 | ||
69 | #define DBG(...) | 72 | #define DBG(...) |
70 | 73 | ||
71 | static inline void dart_tlb_invalidate_all(void) | 74 | static inline void dart_tlb_invalidate_all(void) |
72 | { | 75 | { |
73 | unsigned long l = 0; | 76 | unsigned long l = 0; |
74 | unsigned int reg; | 77 | unsigned int reg, inv_bit; |
75 | unsigned long limit; | 78 | unsigned long limit; |
76 | 79 | ||
77 | DBG("dart: flush\n"); | 80 | DBG("dart: flush\n"); |
@@ -81,29 +84,28 @@ static inline void dart_tlb_invalidate_all(void) | |||
81 | * | 84 | * |
82 | * Gotcha: Sometimes, the DART won't detect that the bit gets | 85 | * Gotcha: Sometimes, the DART won't detect that the bit gets |
83 | * set. If so, clear it and set it again. | 86 | * set. If so, clear it and set it again. |
84 | */ | 87 | */ |
85 | 88 | ||
86 | limit = 0; | 89 | limit = 0; |
87 | 90 | ||
91 | inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB; | ||
88 | retry: | 92 | retry: |
89 | reg = in_be32((unsigned int *)dart+DARTCNTL); | ||
90 | reg |= DARTCNTL_FLUSHTLB; | ||
91 | out_be32((unsigned int *)dart+DARTCNTL, reg); | ||
92 | |||
93 | l = 0; | 93 | l = 0; |
94 | while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && | 94 | reg = DART_IN(DART_CNTL); |
95 | l < (1L<<limit)) { | 95 | reg |= inv_bit; |
96 | DART_OUT(DART_CNTL, reg); | ||
97 | |||
98 | while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit)) | ||
96 | l++; | 99 | l++; |
97 | } | 100 | if (l == (1L << limit)) { |
98 | if (l == (1L<<limit)) { | ||
99 | if (limit < 4) { | 101 | if (limit < 4) { |
100 | limit++; | 102 | limit++; |
101 | reg = in_be32((unsigned int *)dart+DARTCNTL); | 103 | reg = DART_IN(DART_CNTL); |
102 | reg &= ~DARTCNTL_FLUSHTLB; | 104 | reg &= ~inv_bit; |
103 | out_be32((unsigned int *)dart+DARTCNTL, reg); | 105 | DART_OUT(DART_CNTL, reg); |
104 | goto retry; | 106 | goto retry; |
105 | } else | 107 | } else |
106 | panic("U3-DART: TLB did not flush after waiting a long " | 108 | panic("DART: TLB did not flush after waiting a long " |
107 | "time. Buggy U3 ?"); | 109 | "time. Buggy U3 ?"); |
108 | } | 110 | } |
109 | } | 111 | } |
@@ -115,7 +117,7 @@ static void dart_flush(struct iommu_table *tbl) | |||
115 | dart_dirty = 0; | 117 | dart_dirty = 0; |
116 | } | 118 | } |
117 | 119 | ||
118 | static void dart_build(struct iommu_table *tbl, long index, | 120 | static void dart_build(struct iommu_table *tbl, long index, |
119 | long npages, unsigned long uaddr, | 121 | long npages, unsigned long uaddr, |
120 | enum dma_data_direction direction) | 122 | enum dma_data_direction direction) |
121 | { | 123 | { |
@@ -128,7 +130,7 @@ static void dart_build(struct iommu_table *tbl, long index, | |||
128 | npages <<= DART_PAGE_FACTOR; | 130 | npages <<= DART_PAGE_FACTOR; |
129 | 131 | ||
130 | dp = ((unsigned int*)tbl->it_base) + index; | 132 | dp = ((unsigned int*)tbl->it_base) + index; |
131 | 133 | ||
132 | /* On U3, all memory is contigous, so we can move this | 134 | /* On U3, all memory is contigous, so we can move this |
133 | * out of the loop. | 135 | * out of the loop. |
134 | */ | 136 | */ |
@@ -148,7 +150,7 @@ static void dart_build(struct iommu_table *tbl, long index, | |||
148 | static void dart_free(struct iommu_table *tbl, long index, long npages) | 150 | static void dart_free(struct iommu_table *tbl, long index, long npages) |
149 | { | 151 | { |
150 | unsigned int *dp; | 152 | unsigned int *dp; |
151 | 153 | ||
152 | /* We don't worry about flushing the TLB cache. The only drawback of | 154 | /* We don't worry about flushing the TLB cache. The only drawback of |
153 | * not doing it is that we won't catch buggy device drivers doing | 155 | * not doing it is that we won't catch buggy device drivers doing |
154 | * bad DMAs, but then no 32-bit architecture ever does either. | 156 | * bad DMAs, but then no 32-bit architecture ever does either. |
@@ -160,7 +162,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages) | |||
160 | npages <<= DART_PAGE_FACTOR; | 162 | npages <<= DART_PAGE_FACTOR; |
161 | 163 | ||
162 | dp = ((unsigned int *)tbl->it_base) + index; | 164 | dp = ((unsigned int *)tbl->it_base) + index; |
163 | 165 | ||
164 | while (npages--) | 166 | while (npages--) |
165 | *(dp++) = dart_emptyval; | 167 | *(dp++) = dart_emptyval; |
166 | } | 168 | } |
@@ -168,20 +170,25 @@ static void dart_free(struct iommu_table *tbl, long index, long npages) | |||
168 | 170 | ||
169 | static int dart_init(struct device_node *dart_node) | 171 | static int dart_init(struct device_node *dart_node) |
170 | { | 172 | { |
171 | unsigned int regword; | ||
172 | unsigned int i; | 173 | unsigned int i; |
173 | unsigned long tmp; | 174 | unsigned long tmp, base, size; |
175 | struct resource r; | ||
174 | 176 | ||
175 | if (dart_tablebase == 0 || dart_tablesize == 0) { | 177 | if (dart_tablebase == 0 || dart_tablesize == 0) { |
176 | printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); | 178 | printk(KERN_INFO "DART: table not allocated, using " |
179 | "direct DMA\n"); | ||
177 | return -ENODEV; | 180 | return -ENODEV; |
178 | } | 181 | } |
179 | 182 | ||
183 | if (of_address_to_resource(dart_node, 0, &r)) | ||
184 | panic("DART: can't get register base ! "); | ||
185 | |||
180 | /* Make sure nothing from the DART range remains in the CPU cache | 186 | /* Make sure nothing from the DART range remains in the CPU cache |
181 | * from a previous mapping that existed before the kernel took | 187 | * from a previous mapping that existed before the kernel took |
182 | * over | 188 | * over |
183 | */ | 189 | */ |
184 | flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); | 190 | flush_dcache_phys_range(dart_tablebase, |
191 | dart_tablebase + dart_tablesize); | ||
185 | 192 | ||
186 | /* Allocate a spare page to map all invalid DART pages. We need to do | 193 | /* Allocate a spare page to map all invalid DART pages. We need to do |
187 | * that to work around what looks like a problem with the HT bridge | 194 | * that to work around what looks like a problem with the HT bridge |
@@ -189,21 +196,16 @@ static int dart_init(struct device_node *dart_node) | |||
189 | */ | 196 | */ |
190 | tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); | 197 | tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); |
191 | if (!tmp) | 198 | if (!tmp) |
192 | panic("U3-DART: Cannot allocate spare page!"); | 199 | panic("DART: Cannot allocate spare page!"); |
193 | dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK); | 200 | dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & |
201 | DARTMAP_RPNMASK); | ||
194 | 202 | ||
195 | /* Map in DART registers. FIXME: Use device node to get base address */ | 203 | /* Map in DART registers */ |
196 | dart = ioremap(DART_BASE, 0x7000); | 204 | dart = ioremap(r.start, r.end - r.start + 1); |
197 | if (dart == NULL) | 205 | if (dart == NULL) |
198 | panic("U3-DART: Cannot map registers!"); | 206 | panic("DART: Cannot map registers!"); |
199 | 207 | ||
200 | /* Set initial control register contents: table base, | 208 | /* Map in DART table */ |
201 | * table size and enable bit | ||
202 | */ | ||
203 | regword = DARTCNTL_ENABLE | | ||
204 | ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | | ||
205 | (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK) | ||
206 | << DARTCNTL_SIZE_SHIFT); | ||
207 | dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); | 209 | dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); |
208 | 210 | ||
209 | /* Fill initial table */ | 211 | /* Fill initial table */ |
@@ -211,36 +213,50 @@ static int dart_init(struct device_node *dart_node) | |||
211 | dart_vbase[i] = dart_emptyval; | 213 | dart_vbase[i] = dart_emptyval; |
212 | 214 | ||
213 | /* Initialize DART with table base and enable it. */ | 215 | /* Initialize DART with table base and enable it. */ |
214 | out_be32((unsigned int *)dart, regword); | 216 | base = dart_tablebase >> DART_PAGE_SHIFT; |
217 | size = dart_tablesize >> DART_PAGE_SHIFT; | ||
218 | if (dart_is_u4) { | ||
219 | BUG_ON(size & ~DART_SIZE_U4_SIZE_MASK); | ||
220 | DART_OUT(DART_BASE_U4, base); | ||
221 | DART_OUT(DART_SIZE_U4, size); | ||
222 | DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE); | ||
223 | } else { | ||
224 | BUG_ON(size & ~DART_CNTL_U3_SIZE_MASK); | ||
225 | DART_OUT(DART_CNTL, | ||
226 | DART_CNTL_U3_ENABLE | | ||
227 | (base << DART_CNTL_U3_BASE_SHIFT) | | ||
228 | (size << DART_CNTL_U3_SIZE_SHIFT)); | ||
229 | } | ||
215 | 230 | ||
216 | /* Invalidate DART to get rid of possible stale TLBs */ | 231 | /* Invalidate DART to get rid of possible stale TLBs */ |
217 | dart_tlb_invalidate_all(); | 232 | dart_tlb_invalidate_all(); |
218 | 233 | ||
219 | printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); | 234 | printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n", |
235 | dart_is_u4 ? "U4" : "U3"); | ||
220 | 236 | ||
221 | return 0; | 237 | return 0; |
222 | } | 238 | } |
223 | 239 | ||
224 | static void iommu_table_u3_setup(void) | 240 | static void iommu_table_dart_setup(void) |
225 | { | 241 | { |
226 | iommu_table_u3.it_busno = 0; | 242 | iommu_table_dart.it_busno = 0; |
227 | iommu_table_u3.it_offset = 0; | 243 | iommu_table_dart.it_offset = 0; |
228 | /* it_size is in number of entries */ | 244 | /* it_size is in number of entries */ |
229 | iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; | 245 | iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; |
230 | 246 | ||
231 | /* Initialize the common IOMMU code */ | 247 | /* Initialize the common IOMMU code */ |
232 | iommu_table_u3.it_base = (unsigned long)dart_vbase; | 248 | iommu_table_dart.it_base = (unsigned long)dart_vbase; |
233 | iommu_table_u3.it_index = 0; | 249 | iommu_table_dart.it_index = 0; |
234 | iommu_table_u3.it_blocksize = 1; | 250 | iommu_table_dart.it_blocksize = 1; |
235 | iommu_init_table(&iommu_table_u3); | 251 | iommu_init_table(&iommu_table_dart); |
236 | 252 | ||
237 | /* Reserve the last page of the DART to avoid possible prefetch | 253 | /* Reserve the last page of the DART to avoid possible prefetch |
238 | * past the DART mapped area | 254 | * past the DART mapped area |
239 | */ | 255 | */ |
240 | set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map); | 256 | set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); |
241 | } | 257 | } |
242 | 258 | ||
243 | static void iommu_dev_setup_u3(struct pci_dev *dev) | 259 | static void iommu_dev_setup_dart(struct pci_dev *dev) |
244 | { | 260 | { |
245 | struct device_node *dn; | 261 | struct device_node *dn; |
246 | 262 | ||
@@ -254,35 +270,39 @@ static void iommu_dev_setup_u3(struct pci_dev *dev) | |||
254 | dn = pci_device_to_OF_node(dev); | 270 | dn = pci_device_to_OF_node(dev); |
255 | 271 | ||
256 | if (dn) | 272 | if (dn) |
257 | PCI_DN(dn)->iommu_table = &iommu_table_u3; | 273 | PCI_DN(dn)->iommu_table = &iommu_table_dart; |
258 | } | 274 | } |
259 | 275 | ||
260 | static void iommu_bus_setup_u3(struct pci_bus *bus) | 276 | static void iommu_bus_setup_dart(struct pci_bus *bus) |
261 | { | 277 | { |
262 | struct device_node *dn; | 278 | struct device_node *dn; |
263 | 279 | ||
264 | if (!iommu_table_u3_inited) { | 280 | if (!iommu_table_dart_inited) { |
265 | iommu_table_u3_inited = 1; | 281 | iommu_table_dart_inited = 1; |
266 | iommu_table_u3_setup(); | 282 | iommu_table_dart_setup(); |
267 | } | 283 | } |
268 | 284 | ||
269 | dn = pci_bus_to_OF_node(bus); | 285 | dn = pci_bus_to_OF_node(bus); |
270 | 286 | ||
271 | if (dn) | 287 | if (dn) |
272 | PCI_DN(dn)->iommu_table = &iommu_table_u3; | 288 | PCI_DN(dn)->iommu_table = &iommu_table_dart; |
273 | } | 289 | } |
274 | 290 | ||
275 | static void iommu_dev_setup_null(struct pci_dev *dev) { } | 291 | static void iommu_dev_setup_null(struct pci_dev *dev) { } |
276 | static void iommu_bus_setup_null(struct pci_bus *bus) { } | 292 | static void iommu_bus_setup_null(struct pci_bus *bus) { } |
277 | 293 | ||
278 | void iommu_init_early_u3(void) | 294 | void iommu_init_early_dart(void) |
279 | { | 295 | { |
280 | struct device_node *dn; | 296 | struct device_node *dn; |
281 | 297 | ||
282 | /* Find the DART in the device-tree */ | 298 | /* Find the DART in the device-tree */ |
283 | dn = of_find_compatible_node(NULL, "dart", "u3-dart"); | 299 | dn = of_find_compatible_node(NULL, "dart", "u3-dart"); |
284 | if (dn == NULL) | 300 | if (dn == NULL) { |
285 | return; | 301 | dn = of_find_compatible_node(NULL, "dart", "u4-dart"); |
302 | if (dn == NULL) | ||
303 | goto bail; | ||
304 | dart_is_u4 = 1; | ||
305 | } | ||
286 | 306 | ||
287 | /* Setup low level TCE operations for the core IOMMU code */ | 307 | /* Setup low level TCE operations for the core IOMMU code */ |
288 | ppc_md.tce_build = dart_build; | 308 | ppc_md.tce_build = dart_build; |
@@ -290,24 +310,27 @@ void iommu_init_early_u3(void) | |||
290 | ppc_md.tce_flush = dart_flush; | 310 | ppc_md.tce_flush = dart_flush; |
291 | 311 | ||
292 | /* Initialize the DART HW */ | 312 | /* Initialize the DART HW */ |
293 | if (dart_init(dn)) { | 313 | if (dart_init(dn) == 0) { |
294 | /* If init failed, use direct iommu and null setup functions */ | 314 | ppc_md.iommu_dev_setup = iommu_dev_setup_dart; |
295 | ppc_md.iommu_dev_setup = iommu_dev_setup_null; | 315 | ppc_md.iommu_bus_setup = iommu_bus_setup_dart; |
296 | ppc_md.iommu_bus_setup = iommu_bus_setup_null; | ||
297 | |||
298 | /* Setup pci_dma ops */ | ||
299 | pci_direct_iommu_init(); | ||
300 | } else { | ||
301 | ppc_md.iommu_dev_setup = iommu_dev_setup_u3; | ||
302 | ppc_md.iommu_bus_setup = iommu_bus_setup_u3; | ||
303 | 316 | ||
304 | /* Setup pci_dma ops */ | 317 | /* Setup pci_dma ops */ |
305 | pci_iommu_init(); | 318 | pci_iommu_init(); |
319 | |||
320 | return; | ||
306 | } | 321 | } |
322 | |||
323 | bail: | ||
324 | /* If init failed, use direct iommu and null setup functions */ | ||
325 | ppc_md.iommu_dev_setup = iommu_dev_setup_null; | ||
326 | ppc_md.iommu_bus_setup = iommu_bus_setup_null; | ||
327 | |||
328 | /* Setup pci_dma ops */ | ||
329 | pci_direct_iommu_init(); | ||
307 | } | 330 | } |
308 | 331 | ||
309 | 332 | ||
310 | void __init alloc_u3_dart_table(void) | 333 | void __init alloc_dart_table(void) |
311 | { | 334 | { |
312 | /* Only reserve DART space if machine has more than 2GB of RAM | 335 | /* Only reserve DART space if machine has more than 2GB of RAM |
313 | * or if requested with iommu=on on cmdline. | 336 | * or if requested with iommu=on on cmdline. |
@@ -323,5 +346,5 @@ void __init alloc_u3_dart_table(void) | |||
323 | dart_tablebase = (unsigned long) | 346 | dart_tablebase = (unsigned long) |
324 | abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); | 347 | abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); |
325 | 348 | ||
326 | printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); | 349 | printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase); |
327 | } | 350 | } |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 9513ea78e6c1..4f26304d0263 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -13,6 +13,9 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #undef DEBUG | 15 | #undef DEBUG |
16 | #undef DEBUG_IPI | ||
17 | #undef DEBUG_IRQ | ||
18 | #undef DEBUG_LOW | ||
16 | 19 | ||
17 | #include <linux/config.h> | 20 | #include <linux/config.h> |
18 | #include <linux/types.h> | 21 | #include <linux/types.h> |
@@ -168,35 +171,86 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic) | |||
168 | /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) | 171 | /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) |
169 | * to force the edge setting on the MPIC and do the ack workaround. | 172 | * to force the edge setting on the MPIC and do the ack workaround. |
170 | */ | 173 | */ |
171 | static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) | 174 | static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) |
172 | { | 175 | { |
173 | if (source_no >= 128 || !mpic->fixups) | 176 | if (source >= 128 || !mpic->fixups) |
174 | return 0; | 177 | return 0; |
175 | return mpic->fixups[source_no].base != NULL; | 178 | return mpic->fixups[source].base != NULL; |
176 | } | 179 | } |
177 | 180 | ||
178 | 181 | ||
179 | static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) | 182 | static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) |
180 | { | 183 | { |
181 | struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; | 184 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; |
182 | 185 | ||
183 | spin_lock(&mpic->fixup_lock); | 186 | if (fixup->applebase) { |
184 | writeb(0x11 + 2 * fixup->irq, fixup->base + 2); | 187 | unsigned int soff = (fixup->index >> 3) & ~3; |
185 | writel(fixup->data, fixup->base + 4); | 188 | unsigned int mask = 1U << (fixup->index & 0x1f); |
186 | spin_unlock(&mpic->fixup_lock); | 189 | writel(mask, fixup->applebase + soff); |
190 | } else { | ||
191 | spin_lock(&mpic->fixup_lock); | ||
192 | writeb(0x11 + 2 * fixup->index, fixup->base + 2); | ||
193 | writel(fixup->data, fixup->base + 4); | ||
194 | spin_unlock(&mpic->fixup_lock); | ||
195 | } | ||
187 | } | 196 | } |
188 | 197 | ||
198 | static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | ||
199 | unsigned int irqflags) | ||
200 | { | ||
201 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | ||
202 | unsigned long flags; | ||
203 | u32 tmp; | ||
204 | |||
205 | if (fixup->base == NULL) | ||
206 | return; | ||
207 | |||
208 | DBG("startup_ht_interrupt(%u, %u) index: %d\n", | ||
209 | source, irqflags, fixup->index); | ||
210 | spin_lock_irqsave(&mpic->fixup_lock, flags); | ||
211 | /* Enable and configure */ | ||
212 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | ||
213 | tmp = readl(fixup->base + 4); | ||
214 | tmp &= ~(0x23U); | ||
215 | if (irqflags & IRQ_LEVEL) | ||
216 | tmp |= 0x22; | ||
217 | writel(tmp, fixup->base + 4); | ||
218 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | ||
219 | } | ||
220 | |||
221 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | ||
222 | unsigned int irqflags) | ||
223 | { | ||
224 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | ||
225 | unsigned long flags; | ||
226 | u32 tmp; | ||
227 | |||
228 | if (fixup->base == NULL) | ||
229 | return; | ||
230 | |||
231 | DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags); | ||
232 | |||
233 | /* Disable */ | ||
234 | spin_lock_irqsave(&mpic->fixup_lock, flags); | ||
235 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | ||
236 | tmp = readl(fixup->base + 4); | ||
237 | tmp &= ~1U; | ||
238 | writel(tmp, fixup->base + 4); | ||
239 | spin_unlock_irqrestore(&mpic->fixup_lock, flags); | ||
240 | } | ||
189 | 241 | ||
190 | static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) | 242 | static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, |
243 | unsigned int devfn, u32 vdid) | ||
191 | { | 244 | { |
192 | int i, irq, n; | 245 | int i, irq, n; |
246 | u8 __iomem *base; | ||
193 | u32 tmp; | 247 | u32 tmp; |
194 | u8 pos; | 248 | u8 pos; |
195 | 249 | ||
196 | for (pos = readb(devbase + 0x34); pos; pos = readb(devbase + pos + 1)) { | 250 | for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; |
197 | u8 id = readb(devbase + pos); | 251 | pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { |
198 | 252 | u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); | |
199 | if (id == 0x08) { | 253 | if (id == PCI_CAP_ID_HT_IRQCONF) { |
200 | id = readb(devbase + pos + 3); | 254 | id = readb(devbase + pos + 3); |
201 | if (id == 0x80) | 255 | if (id == 0x80) |
202 | break; | 256 | break; |
@@ -205,33 +259,41 @@ static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) | |||
205 | if (pos == 0) | 259 | if (pos == 0) |
206 | return; | 260 | return; |
207 | 261 | ||
208 | printk(KERN_INFO "mpic: - Workarounds @ %p, pos = 0x%02x\n", devbase, pos); | 262 | base = devbase + pos; |
263 | writeb(0x01, base + 2); | ||
264 | n = (readl(base + 4) >> 16) & 0xff; | ||
209 | 265 | ||
210 | devbase += pos; | 266 | printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" |
211 | 267 | " has %d irqs\n", | |
212 | writeb(0x01, devbase + 2); | 268 | devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); |
213 | n = (readl(devbase + 4) >> 16) & 0xff; | ||
214 | 269 | ||
215 | for (i = 0; i <= n; i++) { | 270 | for (i = 0; i <= n; i++) { |
216 | writeb(0x10 + 2 * i, devbase + 2); | 271 | writeb(0x10 + 2 * i, base + 2); |
217 | tmp = readl(devbase + 4); | 272 | tmp = readl(base + 4); |
218 | if ((tmp & 0x21) != 0x20) | ||
219 | continue; | ||
220 | irq = (tmp >> 16) & 0xff; | 273 | irq = (tmp >> 16) & 0xff; |
221 | mpic->fixups[irq].irq = i; | 274 | DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); |
222 | mpic->fixups[irq].base = devbase; | 275 | /* mask it , will be unmasked later */ |
223 | writeb(0x11 + 2 * i, devbase + 2); | 276 | tmp |= 0x1; |
224 | mpic->fixups[irq].data = readl(devbase + 4) | 0x80000000; | 277 | writel(tmp, base + 4); |
278 | mpic->fixups[irq].index = i; | ||
279 | mpic->fixups[irq].base = base; | ||
280 | /* Apple HT PIC has a non-standard way of doing EOIs */ | ||
281 | if ((vdid & 0xffff) == 0x106b) | ||
282 | mpic->fixups[irq].applebase = devbase + 0x60; | ||
283 | else | ||
284 | mpic->fixups[irq].applebase = NULL; | ||
285 | writeb(0x11 + 2 * i, base + 2); | ||
286 | mpic->fixups[irq].data = readl(base + 4) | 0x80000000; | ||
225 | } | 287 | } |
226 | } | 288 | } |
227 | 289 | ||
228 | 290 | ||
229 | static void __init mpic_scan_ioapics(struct mpic *mpic) | 291 | static void __init mpic_scan_ht_pics(struct mpic *mpic) |
230 | { | 292 | { |
231 | unsigned int devfn; | 293 | unsigned int devfn; |
232 | u8 __iomem *cfgspace; | 294 | u8 __iomem *cfgspace; |
233 | 295 | ||
234 | printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); | 296 | printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); |
235 | 297 | ||
236 | /* Allocate fixups array */ | 298 | /* Allocate fixups array */ |
237 | mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); | 299 | mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); |
@@ -247,13 +309,14 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) | |||
247 | cfgspace = ioremap(0xf2000000, 0x10000); | 309 | cfgspace = ioremap(0xf2000000, 0x10000); |
248 | BUG_ON(cfgspace == NULL); | 310 | BUG_ON(cfgspace == NULL); |
249 | 311 | ||
250 | /* Now we scan all slots. We do a very quick scan, we read the header type, | 312 | /* Now we scan all slots. We do a very quick scan, we read the header |
251 | * vendor ID and device ID only, that's plenty enough | 313 | * type, vendor ID and device ID only, that's plenty enough |
252 | */ | 314 | */ |
253 | for (devfn = 0; devfn < 0x100; devfn++) { | 315 | for (devfn = 0; devfn < 0x100; devfn++) { |
254 | u8 __iomem *devbase = cfgspace + (devfn << 8); | 316 | u8 __iomem *devbase = cfgspace + (devfn << 8); |
255 | u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); | 317 | u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); |
256 | u32 l = readl(devbase + PCI_VENDOR_ID); | 318 | u32 l = readl(devbase + PCI_VENDOR_ID); |
319 | u16 s; | ||
257 | 320 | ||
258 | DBG("devfn %x, l: %x\n", devfn, l); | 321 | DBG("devfn %x, l: %x\n", devfn, l); |
259 | 322 | ||
@@ -261,8 +324,12 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) | |||
261 | if (l == 0xffffffff || l == 0x00000000 || | 324 | if (l == 0xffffffff || l == 0x00000000 || |
262 | l == 0x0000ffff || l == 0xffff0000) | 325 | l == 0x0000ffff || l == 0xffff0000) |
263 | goto next; | 326 | goto next; |
327 | /* Check if is supports capability lists */ | ||
328 | s = readw(devbase + PCI_STATUS); | ||
329 | if (!(s & PCI_STATUS_CAP_LIST)) | ||
330 | goto next; | ||
264 | 331 | ||
265 | mpic_scan_ioapic(mpic, devbase); | 332 | mpic_scan_ht_pic(mpic, devbase, devfn, l); |
266 | 333 | ||
267 | next: | 334 | next: |
268 | /* next device, if function 0 */ | 335 | /* next device, if function 0 */ |
@@ -363,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq) | |||
363 | break; | 430 | break; |
364 | } | 431 | } |
365 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); | 432 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); |
433 | |||
434 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
435 | if (mpic->flags & MPIC_BROKEN_U3) { | ||
436 | unsigned int src = irq - mpic->irq_offset; | ||
437 | if (mpic_is_ht_interrupt(mpic, src) && | ||
438 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
439 | mpic_ht_end_irq(mpic, src); | ||
440 | } | ||
441 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
442 | } | ||
443 | |||
444 | static unsigned int mpic_startup_irq(unsigned int irq) | ||
445 | { | ||
446 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
447 | struct mpic *mpic = mpic_from_irq(irq); | ||
448 | unsigned int src = irq - mpic->irq_offset; | ||
449 | |||
450 | if (mpic_is_ht_interrupt(mpic, src)) | ||
451 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
452 | |||
453 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
454 | |||
455 | mpic_enable_irq(irq); | ||
456 | |||
457 | return 0; | ||
366 | } | 458 | } |
367 | 459 | ||
368 | static void mpic_disable_irq(unsigned int irq) | 460 | static void mpic_disable_irq(unsigned int irq) |
@@ -386,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq) | |||
386 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); | 478 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); |
387 | } | 479 | } |
388 | 480 | ||
481 | static void mpic_shutdown_irq(unsigned int irq) | ||
482 | { | ||
483 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
484 | struct mpic *mpic = mpic_from_irq(irq); | ||
485 | unsigned int src = irq - mpic->irq_offset; | ||
486 | |||
487 | if (mpic_is_ht_interrupt(mpic, src)) | ||
488 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
489 | |||
490 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
491 | |||
492 | mpic_disable_irq(irq); | ||
493 | } | ||
494 | |||
389 | static void mpic_end_irq(unsigned int irq) | 495 | static void mpic_end_irq(unsigned int irq) |
390 | { | 496 | { |
391 | struct mpic *mpic = mpic_from_irq(irq); | 497 | struct mpic *mpic = mpic_from_irq(irq); |
392 | 498 | ||
499 | #ifdef DEBUG_IRQ | ||
393 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 500 | DBG("%s: end_irq: %d\n", mpic->name, irq); |
394 | 501 | #endif | |
395 | /* We always EOI on end_irq() even for edge interrupts since that | 502 | /* We always EOI on end_irq() even for edge interrupts since that |
396 | * should only lower the priority, the MPIC should have properly | 503 | * should only lower the priority, the MPIC should have properly |
397 | * latched another edge interrupt coming in anyway | 504 | * latched another edge interrupt coming in anyway |
@@ -400,8 +507,9 @@ static void mpic_end_irq(unsigned int irq) | |||
400 | #ifdef CONFIG_MPIC_BROKEN_U3 | 507 | #ifdef CONFIG_MPIC_BROKEN_U3 |
401 | if (mpic->flags & MPIC_BROKEN_U3) { | 508 | if (mpic->flags & MPIC_BROKEN_U3) { |
402 | unsigned int src = irq - mpic->irq_offset; | 509 | unsigned int src = irq - mpic->irq_offset; |
403 | if (mpic_is_ht_interrupt(mpic, src)) | 510 | if (mpic_is_ht_interrupt(mpic, src) && |
404 | mpic_apic_end_irq(mpic, src); | 511 | (irq_desc[irq].status & IRQ_LEVEL)) |
512 | mpic_ht_end_irq(mpic, src); | ||
405 | } | 513 | } |
406 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 514 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
407 | 515 | ||
@@ -482,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
482 | mpic->name = name; | 590 | mpic->name = name; |
483 | 591 | ||
484 | mpic->hc_irq.typename = name; | 592 | mpic->hc_irq.typename = name; |
593 | mpic->hc_irq.startup = mpic_startup_irq; | ||
594 | mpic->hc_irq.shutdown = mpic_shutdown_irq; | ||
485 | mpic->hc_irq.enable = mpic_enable_irq; | 595 | mpic->hc_irq.enable = mpic_enable_irq; |
486 | mpic->hc_irq.disable = mpic_disable_irq; | 596 | mpic->hc_irq.disable = mpic_disable_irq; |
487 | mpic->hc_irq.end = mpic_end_irq; | 597 | mpic->hc_irq.end = mpic_end_irq; |
@@ -650,10 +760,10 @@ void __init mpic_init(struct mpic *mpic) | |||
650 | mpic->irq_count = mpic->num_sources; | 760 | mpic->irq_count = mpic->num_sources; |
651 | 761 | ||
652 | #ifdef CONFIG_MPIC_BROKEN_U3 | 762 | #ifdef CONFIG_MPIC_BROKEN_U3 |
653 | /* Do the ioapic fixups on U3 broken mpic */ | 763 | /* Do the HT PIC fixups on U3 broken mpic */ |
654 | DBG("MPIC flags: %x\n", mpic->flags); | 764 | DBG("MPIC flags: %x\n", mpic->flags); |
655 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) | 765 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) |
656 | mpic_scan_ioapics(mpic); | 766 | mpic_scan_ht_pics(mpic); |
657 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 767 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
658 | 768 | ||
659 | for (i = 0; i < mpic->num_sources; i++) { | 769 | for (i = 0; i < mpic->num_sources; i++) { |
@@ -840,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) | |||
840 | 950 | ||
841 | BUG_ON(mpic == NULL); | 951 | BUG_ON(mpic == NULL); |
842 | 952 | ||
953 | #ifdef DEBUG_IPI | ||
843 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); | 954 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); |
955 | #endif | ||
844 | 956 | ||
845 | mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, | 957 | mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, |
846 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); | 958 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); |
@@ -851,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) | |||
851 | u32 irq; | 963 | u32 irq; |
852 | 964 | ||
853 | irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; | 965 | irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; |
966 | #ifdef DEBUG_LOW | ||
854 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); | 967 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); |
855 | 968 | #endif | |
856 | if (mpic->cascade && irq == mpic->cascade_vec) { | 969 | if (mpic->cascade && irq == mpic->cascade_vec) { |
970 | #ifdef DEBUG_LOW | ||
857 | DBG("%s: cascading ...\n", mpic->name); | 971 | DBG("%s: cascading ...\n", mpic->name); |
972 | #endif | ||
858 | irq = mpic->cascade(regs, mpic->cascade_data); | 973 | irq = mpic->cascade(regs, mpic->cascade_data); |
859 | mpic_eoi(mpic); | 974 | mpic_eoi(mpic); |
860 | return irq; | 975 | return irq; |
861 | } | 976 | } |
862 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) | 977 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) |
863 | return -1; | 978 | return -1; |
864 | if (irq < MPIC_VEC_IPI_0) | 979 | if (irq < MPIC_VEC_IPI_0) { |
980 | #ifdef DEBUG_IRQ | ||
981 | DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset); | ||
982 | #endif | ||
865 | return irq + mpic->irq_offset; | 983 | return irq + mpic->irq_offset; |
984 | } | ||
985 | #ifdef DEBUG_IPI | ||
866 | DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); | 986 | DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); |
987 | #endif | ||
867 | return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; | 988 | return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; |
868 | } | 989 | } |
869 | 990 | ||