diff options
Diffstat (limited to 'arch/powerpc/platforms/celleb/pci.c')
-rw-r--r-- | arch/powerpc/platforms/celleb/pci.c | 98 |
1 files changed, 56 insertions, 42 deletions
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index e9ac19c4bba4..6bc32fda7a6b 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/bootmem.h> | 32 | #include <linux/bootmem.h> |
33 | #include <linux/pci_regs.h> | 33 | #include <linux/pci_regs.h> |
34 | #include <linux/of_device.h> | ||
34 | 35 | ||
35 | #include <asm/io.h> | 36 | #include <asm/io.h> |
36 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
@@ -242,8 +243,8 @@ static int celleb_fake_pci_write_config(struct pci_bus *bus, | |||
242 | } | 243 | } |
243 | 244 | ||
244 | static struct pci_ops celleb_fake_pci_ops = { | 245 | static struct pci_ops celleb_fake_pci_ops = { |
245 | celleb_fake_pci_read_config, | 246 | .read = celleb_fake_pci_read_config, |
246 | celleb_fake_pci_write_config | 247 | .write = celleb_fake_pci_write_config, |
247 | }; | 248 | }; |
248 | 249 | ||
249 | static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, | 250 | static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, |
@@ -288,8 +289,8 @@ static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, | |||
288 | celleb_config_write_fake(config, PCI_COMMAND, 2, val); | 289 | celleb_config_write_fake(config, PCI_COMMAND, 2, val); |
289 | } | 290 | } |
290 | 291 | ||
291 | static int __devinit celleb_setup_fake_pci_device(struct device_node *node, | 292 | static int __init celleb_setup_fake_pci_device(struct device_node *node, |
292 | struct pci_controller *hose) | 293 | struct pci_controller *hose) |
293 | { | 294 | { |
294 | unsigned int rlen; | 295 | unsigned int rlen; |
295 | int num_base_addr = 0; | 296 | int num_base_addr = 0; |
@@ -327,10 +328,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, | |||
327 | 328 | ||
328 | size = 256; | 329 | size = 256; |
329 | config = &private->fake_config[devno][fn]; | 330 | config = &private->fake_config[devno][fn]; |
330 | if (mem_init_done) | 331 | *config = alloc_maybe_bootmem(size, GFP_KERNEL); |
331 | *config = kzalloc(size, GFP_KERNEL); | ||
332 | else | ||
333 | *config = alloc_bootmem(size); | ||
334 | if (*config == NULL) { | 332 | if (*config == NULL) { |
335 | printk(KERN_ERR "PCI: " | 333 | printk(KERN_ERR "PCI: " |
336 | "not enough memory for fake configuration space\n"); | 334 | "not enough memory for fake configuration space\n"); |
@@ -341,10 +339,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, | |||
341 | 339 | ||
342 | size = sizeof(struct celleb_pci_resource); | 340 | size = sizeof(struct celleb_pci_resource); |
343 | res = &private->res[devno][fn]; | 341 | res = &private->res[devno][fn]; |
344 | if (mem_init_done) | 342 | *res = alloc_maybe_bootmem(size, GFP_KERNEL); |
345 | *res = kzalloc(size, GFP_KERNEL); | ||
346 | else | ||
347 | *res = alloc_bootmem(size); | ||
348 | if (*res == NULL) { | 343 | if (*res == NULL) { |
349 | printk(KERN_ERR | 344 | printk(KERN_ERR |
350 | "PCI: not enough memory for resource data space\n"); | 345 | "PCI: not enough memory for resource data space\n"); |
@@ -418,8 +413,8 @@ error: | |||
418 | return 1; | 413 | return 1; |
419 | } | 414 | } |
420 | 415 | ||
421 | static int __devinit phb_set_bus_ranges(struct device_node *dev, | 416 | static int __init phb_set_bus_ranges(struct device_node *dev, |
422 | struct pci_controller *phb) | 417 | struct pci_controller *phb) |
423 | { | 418 | { |
424 | const int *bus_range; | 419 | const int *bus_range; |
425 | unsigned int len; | 420 | unsigned int len; |
@@ -434,46 +429,65 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev, | |||
434 | return 0; | 429 | return 0; |
435 | } | 430 | } |
436 | 431 | ||
437 | static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) | 432 | static void __init celleb_alloc_private_mem(struct pci_controller *hose) |
438 | { | 433 | { |
439 | if (mem_init_done) | 434 | hose->private_data = |
440 | hose->private_data = | 435 | alloc_maybe_bootmem(sizeof(struct celleb_pci_private), |
441 | kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL); | 436 | GFP_KERNEL); |
442 | else | ||
443 | hose->private_data = | ||
444 | alloc_bootmem(sizeof(struct celleb_pci_private)); | ||
445 | } | 437 | } |
446 | 438 | ||
447 | int __devinit celleb_setup_phb(struct pci_controller *phb) | 439 | static int __init celleb_setup_fake_pci(struct device_node *dev, |
440 | struct pci_controller *phb) | ||
448 | { | 441 | { |
449 | const char *name; | ||
450 | struct device_node *dev = phb->arch_data; | ||
451 | struct device_node *node; | 442 | struct device_node *node; |
452 | unsigned int rlen; | ||
453 | 443 | ||
454 | name = of_get_property(dev, "name", &rlen); | 444 | phb->ops = &celleb_fake_pci_ops; |
455 | if (!name) | 445 | celleb_alloc_private_mem(phb); |
456 | return 1; | ||
457 | 446 | ||
458 | pr_debug("PCI: celleb_setup_phb() %s\n", name); | 447 | for (node = of_get_next_child(dev, NULL); |
459 | phb_set_bus_ranges(dev, phb); | 448 | node != NULL; node = of_get_next_child(dev, node)) |
460 | phb->buid = 1; | 449 | celleb_setup_fake_pci_device(node, phb); |
450 | |||
451 | return 0; | ||
452 | } | ||
461 | 453 | ||
462 | if (strcmp(name, "epci") == 0) { | 454 | void __init fake_pci_workaround_init(struct pci_controller *phb) |
463 | phb->ops = &celleb_epci_ops; | 455 | { |
464 | return celleb_setup_epci(dev, phb); | 456 | /** |
457 | * We will add fake pci bus to scc_pci_bus for the purpose to improve | ||
458 | * I/O Macro performance. But device-tree and device drivers | ||
459 | * are not ready to use address with a token. | ||
460 | */ | ||
461 | |||
462 | /* celleb_pci_add_one(phb, NULL); */ | ||
463 | } | ||
465 | 464 | ||
466 | } else if (strcmp(name, "pci-pseudo") == 0) { | 465 | static struct of_device_id celleb_phb_match[] __initdata = { |
467 | phb->ops = &celleb_fake_pci_ops; | 466 | { |
468 | celleb_alloc_private_mem(phb); | 467 | .name = "pci-pseudo", |
469 | for (node = of_get_next_child(dev, NULL); | 468 | .data = celleb_setup_fake_pci, |
470 | node != NULL; node = of_get_next_child(dev, node)) | 469 | }, { |
471 | celleb_setup_fake_pci_device(node, phb); | 470 | .name = "epci", |
471 | .data = celleb_setup_epci, | ||
472 | }, { | ||
473 | }, | ||
474 | }; | ||
472 | 475 | ||
473 | } else | 476 | int __init celleb_setup_phb(struct pci_controller *phb) |
477 | { | ||
478 | struct device_node *dev = phb->arch_data; | ||
479 | const struct of_device_id *match; | ||
480 | int (*setup_func)(struct device_node *, struct pci_controller *); | ||
481 | |||
482 | match = of_match_node(celleb_phb_match, dev); | ||
483 | if (!match) | ||
474 | return 1; | 484 | return 1; |
475 | 485 | ||
476 | return 0; | 486 | phb_set_bus_ranges(dev, phb); |
487 | phb->buid = 1; | ||
488 | |||
489 | setup_func = match->data; | ||
490 | return (*setup_func)(dev, phb); | ||
477 | } | 491 | } |
478 | 492 | ||
479 | int celleb_pci_probe_mode(struct pci_bus *bus) | 493 | int celleb_pci_probe_mode(struct pci_bus *bus) |