aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/pci-ioda.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/pci-ioda.c')
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c143
1 files changed, 143 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