diff options
-rw-r--r-- | arch/powerpc/include/asm/ppc-pci.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 91 |
2 files changed, 35 insertions, 58 deletions
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 5e34b10aaa12..2a80f080a7ba 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h | |||
@@ -53,7 +53,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev); | |||
53 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr); | 53 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr); |
54 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity); | 54 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity); |
55 | int eeh_pci_enable(struct eeh_pe *pe, int function); | 55 | int eeh_pci_enable(struct eeh_pe *pe, int function); |
56 | int eeh_reset_pe(struct eeh_dev *); | 56 | int eeh_reset_pe(struct eeh_pe *); |
57 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | 57 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); |
58 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); | 58 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); |
59 | void eeh_pe_state_mark(struct eeh_pe *pe, int state); | 59 | void eeh_pe_state_mark(struct eeh_pe *pe, int state); |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 45723618b1df..56a022b03651 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -455,17 +455,24 @@ int eeh_pci_enable(struct eeh_pe *pe, int function) | |||
455 | */ | 455 | */ |
456 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | 456 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) |
457 | { | 457 | { |
458 | struct device_node *dn = pci_device_to_OF_node(dev); | 458 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
459 | struct eeh_pe *pe = edev->pe; | ||
460 | |||
461 | if (!pe) { | ||
462 | pr_err("%s: No PE found on PCI device %s\n", | ||
463 | __func__, pci_name(dev)); | ||
464 | return -EINVAL; | ||
465 | } | ||
459 | 466 | ||
460 | switch (state) { | 467 | switch (state) { |
461 | case pcie_deassert_reset: | 468 | case pcie_deassert_reset: |
462 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); | 469 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); |
463 | break; | 470 | break; |
464 | case pcie_hot_reset: | 471 | case pcie_hot_reset: |
465 | eeh_ops->reset(dn, EEH_RESET_HOT); | 472 | eeh_ops->reset(pe, EEH_RESET_HOT); |
466 | break; | 473 | break; |
467 | case pcie_warm_reset: | 474 | case pcie_warm_reset: |
468 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); | 475 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); |
469 | break; | 476 | break; |
470 | default: | 477 | default: |
471 | return -EINVAL; | 478 | return -EINVAL; |
@@ -475,66 +482,37 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
475 | } | 482 | } |
476 | 483 | ||
477 | /** | 484 | /** |
478 | * __eeh_set_pe_freset - Check the required reset for child devices | 485 | * eeh_set_pe_freset - Check the required reset for the indicated device |
479 | * @parent: parent device | 486 | * @data: EEH device |
480 | * @freset: return value | 487 | * @flag: return value |
481 | * | ||
482 | * Each device might have its preferred reset type: fundamental or | ||
483 | * hot reset. The routine is used to collect the information from | ||
484 | * the child devices so that they could be reset accordingly. | ||
485 | */ | ||
486 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
487 | { | ||
488 | struct device_node *dn; | ||
489 | |||
490 | for_each_child_of_node(parent, dn) { | ||
491 | if (of_node_to_eeh_dev(dn)) { | ||
492 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; | ||
493 | |||
494 | if (dev && dev->driver) | ||
495 | *freset |= dev->needs_freset; | ||
496 | |||
497 | __eeh_set_pe_freset(dn, freset); | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * eeh_set_pe_freset - Check the required reset for the indicated device and its children | ||
504 | * @dn: parent device | ||
505 | * @freset: return value | ||
506 | * | 488 | * |
507 | * Each device might have its preferred reset type: fundamental or | 489 | * Each device might have its preferred reset type: fundamental or |
508 | * hot reset. The routine is used to collected the information for | 490 | * hot reset. The routine is used to collected the information for |
509 | * the indicated device and its children so that the bunch of the | 491 | * the indicated device and its children so that the bunch of the |
510 | * devices could be reset properly. | 492 | * devices could be reset properly. |
511 | */ | 493 | */ |
512 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | 494 | static void *eeh_set_dev_freset(void *data, void *flag) |
513 | { | 495 | { |
514 | struct pci_dev *dev; | 496 | struct pci_dev *dev; |
515 | dn = eeh_find_device_pe(dn); | 497 | unsigned int *freset = (unsigned int *)flag; |
516 | 498 | struct eeh_dev *edev = (struct eeh_dev *)data; | |
517 | /* Back up one, since config addrs might be shared */ | ||
518 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) | ||
519 | dn = dn->parent; | ||
520 | 499 | ||
521 | dev = of_node_to_eeh_dev(dn)->pdev; | 500 | dev = eeh_dev_to_pci_dev(edev); |
522 | if (dev) | 501 | if (dev) |
523 | *freset |= dev->needs_freset; | 502 | *freset |= dev->needs_freset; |
524 | 503 | ||
525 | __eeh_set_pe_freset(dn, freset); | 504 | return NULL; |
526 | } | 505 | } |
527 | 506 | ||
528 | /** | 507 | /** |
529 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second | 508 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second |
530 | * @edev: pci device node to be reset. | 509 | * @pe: EEH PE |
531 | * | 510 | * |
532 | * Assert the PCI #RST line for 1/4 second. | 511 | * Assert the PCI #RST line for 1/4 second. |
533 | */ | 512 | */ |
534 | static void eeh_reset_pe_once(struct eeh_dev *edev) | 513 | static void eeh_reset_pe_once(struct eeh_pe *pe) |
535 | { | 514 | { |
536 | unsigned int freset = 0; | 515 | unsigned int freset = 0; |
537 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
538 | 516 | ||
539 | /* Determine type of EEH reset required for | 517 | /* Determine type of EEH reset required for |
540 | * Partitionable Endpoint, a hot-reset (1) | 518 | * Partitionable Endpoint, a hot-reset (1) |
@@ -542,12 +520,12 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
542 | * A fundamental reset required by any device under | 520 | * A fundamental reset required by any device under |
543 | * Partitionable Endpoint trumps hot-reset. | 521 | * Partitionable Endpoint trumps hot-reset. |
544 | */ | 522 | */ |
545 | eeh_set_pe_freset(dn, &freset); | 523 | eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset); |
546 | 524 | ||
547 | if (freset) | 525 | if (freset) |
548 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); | 526 | eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); |
549 | else | 527 | else |
550 | eeh_ops->reset(dn, EEH_RESET_HOT); | 528 | eeh_ops->reset(pe, EEH_RESET_HOT); |
551 | 529 | ||
552 | /* The PCI bus requires that the reset be held high for at least | 530 | /* The PCI bus requires that the reset be held high for at least |
553 | * a 100 milliseconds. We wait a bit longer 'just in case'. | 531 | * a 100 milliseconds. We wait a bit longer 'just in case'. |
@@ -559,9 +537,9 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
559 | * pci slot reset line is dropped. Make sure we don't miss | 537 | * pci slot reset line is dropped. Make sure we don't miss |
560 | * these, and clear the flag now. | 538 | * these, and clear the flag now. |
561 | */ | 539 | */ |
562 | eeh_clear_slot(dn, EEH_MODE_ISOLATED); | 540 | eeh_pe_state_clear(pe, EEH_MODE_ISOLATED); |
563 | 541 | ||
564 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); | 542 | eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); |
565 | 543 | ||
566 | /* After a PCI slot has been reset, the PCI Express spec requires | 544 | /* After a PCI slot has been reset, the PCI Express spec requires |
567 | * a 1.5 second idle time for the bus to stabilize, before starting | 545 | * a 1.5 second idle time for the bus to stabilize, before starting |
@@ -573,32 +551,31 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) | |||
573 | 551 | ||
574 | /** | 552 | /** |
575 | * eeh_reset_pe - Reset the indicated PE | 553 | * eeh_reset_pe - Reset the indicated PE |
576 | * @edev: PCI device associated EEH device | 554 | * @pe: EEH PE |
577 | * | 555 | * |
578 | * This routine should be called to reset indicated device, including | 556 | * This routine should be called to reset indicated device, including |
579 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges | 557 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges |
580 | * might be involved as well. | 558 | * might be involved as well. |
581 | */ | 559 | */ |
582 | int eeh_reset_pe(struct eeh_dev *edev) | 560 | int eeh_reset_pe(struct eeh_pe *pe) |
583 | { | 561 | { |
584 | int i, rc; | 562 | int i, rc; |
585 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
586 | 563 | ||
587 | /* Take three shots at resetting the bus */ | 564 | /* Take three shots at resetting the bus */ |
588 | for (i=0; i<3; i++) { | 565 | for (i=0; i<3; i++) { |
589 | eeh_reset_pe_once(edev); | 566 | eeh_reset_pe_once(pe); |
590 | 567 | ||
591 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); | 568 | rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); |
592 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) | 569 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) |
593 | return 0; | 570 | return 0; |
594 | 571 | ||
595 | if (rc < 0) { | 572 | if (rc < 0) { |
596 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", | 573 | pr_err("%s: Unrecoverable slot failure on PHB#%d-PE#%x", |
597 | dn->full_name); | 574 | __func__, pe->phb->global_number, pe->addr); |
598 | return -1; | 575 | return -1; |
599 | } | 576 | } |
600 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", | 577 | pr_err("EEH: bus reset %d failed on PHB#%d-PE#%x, rc=%d\n", |
601 | i+1, dn->full_name, rc); | 578 | i+1, pe->phb->global_number, pe->addr, rc); |
602 | } | 579 | } |
603 | 580 | ||
604 | return -1; | 581 | return -1; |