aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/eeh-ioda.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/eeh-ioda.c')
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c128
1 files changed, 49 insertions, 79 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index e1e71618b70c..253fefe3d1a0 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
44 44
45 /* We simply send special EEH event */ 45 /* We simply send special EEH event */
46 if ((changed_evts & OPAL_EVENT_PCI_ERROR) && 46 if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
47 (events & OPAL_EVENT_PCI_ERROR)) 47 (events & OPAL_EVENT_PCI_ERROR) &&
48 eeh_enabled())
48 eeh_send_failure_event(NULL); 49 eeh_send_failure_event(NULL);
49 50
50 return 0; 51 return 0;
@@ -113,6 +114,7 @@ DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
113 ioda_eeh_inbB_dbgfs_set, "0x%llx\n"); 114 ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
114#endif /* CONFIG_DEBUG_FS */ 115#endif /* CONFIG_DEBUG_FS */
115 116
117
116/** 118/**
117 * ioda_eeh_post_init - Chip dependent post initialization 119 * ioda_eeh_post_init - Chip dependent post initialization
118 * @hose: PCI controller 120 * @hose: PCI controller
@@ -220,6 +222,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
220 return ret; 222 return ret;
221} 223}
222 224
225static void ioda_eeh_phb_diag(struct pci_controller *hose)
226{
227 struct pnv_phb *phb = hose->private_data;
228 long rc;
229
230 rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
231 PNV_PCI_DIAG_BUF_SIZE);
232 if (rc != OPAL_SUCCESS) {
233 pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
234 __func__, hose->global_number, rc);
235 return;
236 }
237
238 pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
239}
240
223/** 241/**
224 * ioda_eeh_get_state - Retrieve the state of PE 242 * ioda_eeh_get_state - Retrieve the state of PE
225 * @pe: EEH PE 243 * @pe: EEH PE
@@ -271,6 +289,9 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
271 result |= EEH_STATE_DMA_ACTIVE; 289 result |= EEH_STATE_DMA_ACTIVE;
272 result |= EEH_STATE_MMIO_ENABLED; 290 result |= EEH_STATE_MMIO_ENABLED;
273 result |= EEH_STATE_DMA_ENABLED; 291 result |= EEH_STATE_DMA_ENABLED;
292 } else if (!(pe->state & EEH_PE_ISOLATED)) {
293 eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
294 ioda_eeh_phb_diag(hose);
274 } 295 }
275 296
276 return result; 297 return result;
@@ -314,6 +335,15 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
314 __func__, fstate, hose->global_number, pe_no); 335 __func__, fstate, hose->global_number, pe_no);
315 } 336 }
316 337
338 /* Dump PHB diag-data for frozen PE */
339 if (result != EEH_STATE_NOT_SUPPORT &&
340 (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
341 (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
342 !(pe->state & EEH_PE_ISOLATED)) {
343 eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
344 ioda_eeh_phb_diag(hose);
345 }
346
317 return result; 347 return result;
318} 348}
319 349
@@ -489,8 +519,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose,
489static int ioda_eeh_reset(struct eeh_pe *pe, int option) 519static int ioda_eeh_reset(struct eeh_pe *pe, int option)
490{ 520{
491 struct pci_controller *hose = pe->phb; 521 struct pci_controller *hose = pe->phb;
492 struct eeh_dev *edev; 522 struct pci_bus *bus;
493 struct pci_dev *dev;
494 int ret; 523 int ret;
495 524
496 /* 525 /*
@@ -519,73 +548,17 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
519 if (pe->type & EEH_PE_PHB) { 548 if (pe->type & EEH_PE_PHB) {
520 ret = ioda_eeh_phb_reset(hose, option); 549 ret = ioda_eeh_phb_reset(hose, option);
521 } else { 550 } else {
522 if (pe->type & EEH_PE_DEVICE) { 551 bus = eeh_pe_bus_get(pe);
523 /* 552 if (pci_is_root_bus(bus))
524 * If it's device PE, we didn't refer to the parent
525 * PCI bus yet. So we have to figure it out indirectly.
526 */
527 edev = list_first_entry(&pe->edevs,
528 struct eeh_dev, list);
529 dev = eeh_dev_to_pci_dev(edev);
530 dev = dev->bus->self;
531 } else {
532 /*
533 * If it's bus PE, the parent PCI bus is already there
534 * and just pick it up.
535 */
536 dev = pe->bus->self;
537 }
538
539 /*
540 * Do reset based on the fact that the direct upstream bridge
541 * is root bridge (port) or not.
542 */
543 if (dev->bus->number == 0)
544 ret = ioda_eeh_root_reset(hose, option); 553 ret = ioda_eeh_root_reset(hose, option);
545 else 554 else
546 ret = ioda_eeh_bridge_reset(hose, dev, option); 555 ret = ioda_eeh_bridge_reset(hose, bus->self, option);
547 } 556 }
548 557
549 return ret; 558 return ret;
550} 559}
551 560
552/** 561/**
553 * ioda_eeh_get_log - Retrieve error log
554 * @pe: EEH PE
555 * @severity: Severity level of the log
556 * @drv_log: buffer to store the log
557 * @len: space of the log buffer
558 *
559 * The function is used to retrieve error log from P7IOC.
560 */
561static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
562 char *drv_log, unsigned long len)
563{
564 s64 ret;
565 unsigned long flags;
566 struct pci_controller *hose = pe->phb;
567 struct pnv_phb *phb = hose->private_data;
568
569 spin_lock_irqsave(&phb->lock, flags);
570
571 ret = opal_pci_get_phb_diag_data2(phb->opal_id,
572 phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
573 if (ret) {
574 spin_unlock_irqrestore(&phb->lock, flags);
575 pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n",
576 __func__, hose->global_number, pe->addr, ret);
577 return -EIO;
578 }
579
580 /* The PHB diag-data is always indicative */
581 pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
582
583 spin_unlock_irqrestore(&phb->lock, flags);
584
585 return 0;
586}
587
588/**
589 * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE 562 * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
590 * @pe: EEH PE 563 * @pe: EEH PE
591 * 564 *
@@ -666,22 +639,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
666 } 639 }
667} 640}
668 641
669static void ioda_eeh_phb_diag(struct pci_controller *hose)
670{
671 struct pnv_phb *phb = hose->private_data;
672 long rc;
673
674 rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
675 PNV_PCI_DIAG_BUF_SIZE);
676 if (rc != OPAL_SUCCESS) {
677 pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
678 __func__, hose->global_number, rc);
679 return;
680 }
681
682 pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
683}
684
685static int ioda_eeh_get_phb_pe(struct pci_controller *hose, 642static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
686 struct eeh_pe **pe) 643 struct eeh_pe **pe)
687{ 644{
@@ -855,6 +812,20 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
855 } 812 }
856 813
857 /* 814 /*
815 * EEH core will try recover from fenced PHB or
816 * frozen PE. In the time for frozen PE, EEH core
817 * enable IO path for that before collecting logs,
818 * but it ruins the site. So we have to dump the
819 * log in advance here.
820 */
821 if ((ret == EEH_NEXT_ERR_FROZEN_PE ||
822 ret == EEH_NEXT_ERR_FENCED_PHB) &&
823 !((*pe)->state & EEH_PE_ISOLATED)) {
824 eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
825 ioda_eeh_phb_diag(hose);
826 }
827
828 /*
858 * If we have no errors on the specific PHB or only 829 * If we have no errors on the specific PHB or only
859 * informative error there, we continue poking it. 830 * informative error there, we continue poking it.
860 * Otherwise, we need actions to be taken by upper 831 * Otherwise, we need actions to be taken by upper
@@ -872,7 +843,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
872 .set_option = ioda_eeh_set_option, 843 .set_option = ioda_eeh_set_option,
873 .get_state = ioda_eeh_get_state, 844 .get_state = ioda_eeh_get_state,
874 .reset = ioda_eeh_reset, 845 .reset = ioda_eeh_reset,
875 .get_log = ioda_eeh_get_log,
876 .configure_bridge = ioda_eeh_configure_bridge, 846 .configure_bridge = ioda_eeh_configure_bridge,
877 .next_error = ioda_eeh_next_error 847 .next_error = ioda_eeh_next_error
878}; 848};