aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-07-21 00:42:33 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-08-05 02:33:30 -0400
commit49dec9222f14a01b2de7b11e3de5adc204a74302 (patch)
treebbb7ea6205868a7bad65d32f64f42c6ccccf93c2 /arch/powerpc
parentc979c70ed176518dfb32eaf8a7ac58f41ae21de1 (diff)
powerpc/powernv: Handle compound PE
The patch introduces 3 PHB callbacks: compound PE state retrieval, force freezing and unfreezing compound PE. The PCI config accessors and PowerNV EEH backend can use them in subsequent patches. We don't export the capability of compound PE to EEH core, which helps avoiding more complexity to EEH core. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c143
-rw-r--r--arch/powerpc/platforms/powernv/pci.h3
2 files changed, 146 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 899fe4049b44..b136108ddc99 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -347,6 +347,146 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
347 phb->pick_m64_pe = pnv_ioda2_pick_m64_pe; 347 phb->pick_m64_pe = pnv_ioda2_pick_m64_pe;
348} 348}
349 349
350static void pnv_ioda_freeze_pe(struct pnv_phb *phb, int pe_no)
351{
352 struct pnv_ioda_pe *pe = &phb->ioda.pe_array[pe_no];
353 struct pnv_ioda_pe *slave;
354 s64 rc;
355
356 /* Fetch master PE */
357 if (pe->flags & PNV_IODA_PE_SLAVE) {
358 pe = pe->master;
359 WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
360 pe_no = pe->pe_number;
361 }
362
363 /* Freeze master PE */
364 rc = opal_pci_eeh_freeze_set(phb->opal_id,
365 pe_no,
366 OPAL_EEH_ACTION_SET_FREEZE_ALL);
367 if (rc != OPAL_SUCCESS) {
368 pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
369 __func__, rc, phb->hose->global_number, pe_no);
370 return;
371 }
372
373 /* Freeze slave PEs */
374 if (!(pe->flags & PNV_IODA_PE_MASTER))
375 return;
376
377 list_for_each_entry(slave, &pe->slaves, list) {
378 rc = opal_pci_eeh_freeze_set(phb->opal_id,
379 slave->pe_number,
380 OPAL_EEH_ACTION_SET_FREEZE_ALL);
381 if (rc != OPAL_SUCCESS)
382 pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
383 __func__, rc, phb->hose->global_number,
384 slave->pe_number);
385 }
386}
387
388int pnv_ioda_unfreeze_pe(struct pnv_phb *phb, int pe_no, int opt)
389{
390 struct pnv_ioda_pe *pe, *slave;
391 s64 rc;
392
393 /* Find master PE */
394 pe = &phb->ioda.pe_array[pe_no];
395 if (pe->flags & PNV_IODA_PE_SLAVE) {
396 pe = pe->master;
397 WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
398 pe_no = pe->pe_number;
399 }
400
401 /* Clear frozen state for master PE */
402 rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, opt);
403 if (rc != OPAL_SUCCESS) {
404 pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
405 __func__, rc, opt, phb->hose->global_number, pe_no);
406 return -EIO;
407 }
408
409 if (!(pe->flags & PNV_IODA_PE_MASTER))
410 return 0;
411
412 /* Clear frozen state for slave PEs */
413 list_for_each_entry(slave, &pe->slaves, list) {
414 rc = opal_pci_eeh_freeze_clear(phb->opal_id,
415 slave->pe_number,
416 opt);
417 if (rc != OPAL_SUCCESS) {
418 pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
419 __func__, rc, opt, phb->hose->global_number,
420 slave->pe_number);
421 return -EIO;
422 }
423 }
424
425 return 0;
426}
427
428static int pnv_ioda_get_pe_state(struct pnv_phb *phb, int pe_no)
429{
430 struct pnv_ioda_pe *slave, *pe;
431 u8 fstate, state;
432 __be16 pcierr;
433 s64 rc;
434
435 /* Sanity check on PE number */
436 if (pe_no < 0 || pe_no >= phb->ioda.total_pe)
437 return OPAL_EEH_STOPPED_PERM_UNAVAIL;
438
439 /*
440 * Fetch the master PE and the PE instance might be
441 * not initialized yet.
442 */
443 pe = &phb->ioda.pe_array[pe_no];
444 if (pe->flags & PNV_IODA_PE_SLAVE) {
445 pe = pe->master;
446 WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
447 pe_no = pe->pe_number;
448 }
449
450 /* Check the master PE */
451 rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
452 &state, &pcierr, NULL);
453 if (rc != OPAL_SUCCESS) {
454 pr_warn("%s: Failure %lld getting "
455 "PHB#%x-PE#%x state\n",
456 __func__, rc,
457 phb->hose->global_number, pe_no);
458 return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
459 }
460
461 /* Check the slave PE */
462 if (!(pe->flags & PNV_IODA_PE_MASTER))
463 return state;
464
465 list_for_each_entry(slave, &pe->slaves, list) {
466 rc = opal_pci_eeh_freeze_status(phb->opal_id,
467 slave->pe_number,
468 &fstate,
469 &pcierr,
470 NULL);
471 if (rc != OPAL_SUCCESS) {
472 pr_warn("%s: Failure %lld getting "
473 "PHB#%x-PE#%x state\n",
474 __func__, rc,
475 phb->hose->global_number, slave->pe_number);
476 return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
477 }
478
479 /*
480 * Override the result based on the ascending
481 * priority.
482 */
483 if (fstate > state)
484 state = fstate;
485 }
486
487 return state;
488}
489
350/* Currently those 2 are only used when MSIs are enabled, this will change 490/* Currently those 2 are only used when MSIs are enabled, this will change
351 * but in the meantime, we need to protect them to avoid warnings 491 * but in the meantime, we need to protect them to avoid warnings
352 */ 492 */
@@ -1629,6 +1769,9 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
1629 1769
1630 1770
1631 phb->hose->ops = &pnv_pci_ops; 1771 phb->hose->ops = &pnv_pci_ops;
1772 phb->get_pe_state = pnv_ioda_get_pe_state;
1773 phb->freeze_pe = pnv_ioda_freeze_pe;
1774 phb->unfreeze_pe = pnv_ioda_unfreeze_pe;
1632#ifdef CONFIG_EEH 1775#ifdef CONFIG_EEH
1633 phb->eeh_ops = &ioda_eeh_ops; 1776 phb->eeh_ops = &ioda_eeh_ops;
1634#endif 1777#endif
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 49da9f154950..48494d4b6058 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -128,6 +128,9 @@ struct pnv_phb {
128 int (*init_m64)(struct pnv_phb *phb); 128 int (*init_m64)(struct pnv_phb *phb);
129 void (*alloc_m64_pe)(struct pnv_phb *phb); 129 void (*alloc_m64_pe)(struct pnv_phb *phb);
130 int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all); 130 int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all);
131 int (*get_pe_state)(struct pnv_phb *phb, int pe_no);
132 void (*freeze_pe)(struct pnv_phb *phb, int pe_no);
133 int (*unfreeze_pe)(struct pnv_phb *phb, int pe_no, int opt);
131 134
132 union { 135 union {
133 struct { 136 struct {