diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 87 |
1 files changed, 59 insertions, 28 deletions
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index de376584a96d..b854b57ed5e1 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -337,43 +337,52 @@ void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, | |||
337 | static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) | 337 | static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no) |
338 | { | 338 | { |
339 | unsigned long flags, rc; | 339 | unsigned long flags, rc; |
340 | int has_diag; | 340 | int has_diag, ret = 0; |
341 | 341 | ||
342 | spin_lock_irqsave(&phb->lock, flags); | 342 | spin_lock_irqsave(&phb->lock, flags); |
343 | 343 | ||
344 | /* Fetch PHB diag-data */ | ||
344 | rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, | 345 | rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob, |
345 | PNV_PCI_DIAG_BUF_SIZE); | 346 | PNV_PCI_DIAG_BUF_SIZE); |
346 | has_diag = (rc == OPAL_SUCCESS); | 347 | has_diag = (rc == OPAL_SUCCESS); |
347 | 348 | ||
348 | rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, | 349 | /* If PHB supports compound PE, to handle it */ |
350 | if (phb->unfreeze_pe) { | ||
351 | ret = phb->unfreeze_pe(phb, | ||
352 | pe_no, | ||
349 | OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); | 353 | OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); |
350 | if (rc) { | 354 | } else { |
351 | pr_warning("PCI %d: Failed to clear EEH freeze state" | 355 | rc = opal_pci_eeh_freeze_clear(phb->opal_id, |
352 | " for PE#%d, err %ld\n", | 356 | pe_no, |
353 | phb->hose->global_number, pe_no, rc); | 357 | OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); |
354 | 358 | if (rc) { | |
355 | /* For now, let's only display the diag buffer when we fail to clear | 359 | pr_warn("%s: Failure %ld clearing frozen " |
356 | * the EEH status. We'll do more sensible things later when we have | 360 | "PHB#%x-PE#%x\n", |
357 | * proper EEH support. We need to make sure we don't pollute ourselves | 361 | __func__, rc, phb->hose->global_number, |
358 | * with the normal errors generated when probing empty slots | 362 | pe_no); |
359 | */ | 363 | ret = -EIO; |
360 | if (has_diag) | 364 | } |
361 | pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob); | ||
362 | else | ||
363 | pr_warning("PCI %d: No diag data available\n", | ||
364 | phb->hose->global_number); | ||
365 | } | 365 | } |
366 | 366 | ||
367 | /* | ||
368 | * For now, let's only display the diag buffer when we fail to clear | ||
369 | * the EEH status. We'll do more sensible things later when we have | ||
370 | * proper EEH support. We need to make sure we don't pollute ourselves | ||
371 | * with the normal errors generated when probing empty slots | ||
372 | */ | ||
373 | if (has_diag && ret) | ||
374 | pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob); | ||
375 | |||
367 | spin_unlock_irqrestore(&phb->lock, flags); | 376 | spin_unlock_irqrestore(&phb->lock, flags); |
368 | } | 377 | } |
369 | 378 | ||
370 | static void pnv_pci_config_check_eeh(struct pnv_phb *phb, | 379 | static void pnv_pci_config_check_eeh(struct pnv_phb *phb, |
371 | struct device_node *dn) | 380 | struct device_node *dn) |
372 | { | 381 | { |
373 | s64 rc; | ||
374 | u8 fstate; | 382 | u8 fstate; |
375 | __be16 pcierr; | 383 | __be16 pcierr; |
376 | u32 pe_no; | 384 | int pe_no; |
385 | s64 rc; | ||
377 | 386 | ||
378 | /* | 387 | /* |
379 | * Get the PE#. During the PCI probe stage, we might not | 388 | * Get the PE#. During the PCI probe stage, we might not |
@@ -388,20 +397,42 @@ static void pnv_pci_config_check_eeh(struct pnv_phb *phb, | |||
388 | pe_no = phb->ioda.reserved_pe; | 397 | pe_no = phb->ioda.reserved_pe; |
389 | } | 398 | } |
390 | 399 | ||
391 | /* Read freeze status */ | 400 | /* |
392 | rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr, | 401 | * Fetch frozen state. If the PHB support compound PE, |
393 | NULL); | 402 | * we need handle that case. |
394 | if (rc) { | 403 | */ |
395 | pr_warning("%s: Can't read EEH status (PE#%d) for " | 404 | if (phb->get_pe_state) { |
396 | "%s, err %lld\n", | 405 | fstate = phb->get_pe_state(phb, pe_no); |
397 | __func__, pe_no, dn->full_name, rc); | 406 | } else { |
398 | return; | 407 | rc = opal_pci_eeh_freeze_status(phb->opal_id, |
408 | pe_no, | ||
409 | &fstate, | ||
410 | &pcierr, | ||
411 | NULL); | ||
412 | if (rc) { | ||
413 | pr_warn("%s: Failure %lld getting PHB#%x-PE#%x state\n", | ||
414 | __func__, rc, phb->hose->global_number, pe_no); | ||
415 | return; | ||
416 | } | ||
399 | } | 417 | } |
418 | |||
400 | cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n", | 419 | cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n", |
401 | (PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn), | 420 | (PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn), |
402 | pe_no, fstate); | 421 | pe_no, fstate); |
403 | if (fstate != 0) | 422 | |
423 | /* Clear the frozen state if applicable */ | ||
424 | if (fstate == OPAL_EEH_STOPPED_MMIO_FREEZE || | ||
425 | fstate == OPAL_EEH_STOPPED_DMA_FREEZE || | ||
426 | fstate == OPAL_EEH_STOPPED_MMIO_DMA_FREEZE) { | ||
427 | /* | ||
428 | * If PHB supports compound PE, freeze it for | ||
429 | * consistency. | ||
430 | */ | ||
431 | if (phb->freeze_pe) | ||
432 | phb->freeze_pe(phb, pe_no); | ||
433 | |||
404 | pnv_pci_handle_eeh_config(phb, pe_no); | 434 | pnv_pci_handle_eeh_config(phb, pe_no); |
435 | } | ||
405 | } | 436 | } |
406 | 437 | ||
407 | int pnv_pci_cfg_read(struct device_node *dn, | 438 | int pnv_pci_cfg_read(struct device_node *dn, |