aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-09-29 22:39:00 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2014-09-30 03:15:13 -0400
commit4d4f577e4b5ee1299096438bbcf743bbe14f33ab (patch)
treeacf1c7ebc480e33d06fbab503c7e78a7f40fa506
parent22fca17924094113fe79c1db5135290e1a84ad4b (diff)
powerpc/eeh: Fix improper condition in eeh_pci_enable()
The function eeh_pci_enable() is called to apply various requests to one particular PE: Enabling EEH, Disabling EEH, Enabling IO, Enabling DMA, Freezing PE. When enabling IO or DMA on one specific PE, we need check that IO or DMA isn't enabled previously. But the condition used to do the check isn't completely correct because one PE would be in DMA frozen state with workable IO path, or vice versa. The patch fixes the improper condition. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/kernel/eeh.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index f5677684429e..b79a8331965f 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -579,25 +579,51 @@ EXPORT_SYMBOL(eeh_check_failure);
579 */ 579 */
580int eeh_pci_enable(struct eeh_pe *pe, int function) 580int eeh_pci_enable(struct eeh_pe *pe, int function)
581{ 581{
582 int rc, flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); 582 int active_flag, rc;
583 583
584 /* 584 /*
585 * pHyp doesn't allow to enable IO or DMA on unfrozen PE. 585 * pHyp doesn't allow to enable IO or DMA on unfrozen PE.
586 * Also, it's pointless to enable them on unfrozen PE. So 586 * Also, it's pointless to enable them on unfrozen PE. So
587 * we have the check here. 587 * we have to check before enabling IO or DMA.
588 */ 588 */
589 if (function == EEH_OPT_THAW_MMIO || 589 switch (function) {
590 function == EEH_OPT_THAW_DMA) { 590 case EEH_OPT_THAW_MMIO:
591 active_flag = EEH_STATE_MMIO_ACTIVE;
592 break;
593 case EEH_OPT_THAW_DMA:
594 active_flag = EEH_STATE_DMA_ACTIVE;
595 break;
596 case EEH_OPT_DISABLE:
597 case EEH_OPT_ENABLE:
598 case EEH_OPT_FREEZE_PE:
599 active_flag = 0;
600 break;
601 default:
602 pr_warn("%s: Invalid function %d\n",
603 __func__, function);
604 return -EINVAL;
605 }
606
607 /*
608 * Check if IO or DMA has been enabled before
609 * enabling them.
610 */
611 if (active_flag) {
591 rc = eeh_ops->get_state(pe, NULL); 612 rc = eeh_ops->get_state(pe, NULL);
592 if (rc < 0) 613 if (rc < 0)
593 return rc; 614 return rc;
594 615
595 /* Needn't to enable or already enabled */ 616 /* Needn't enable it at all */
596 if ((rc == EEH_STATE_NOT_SUPPORT) || 617 if (rc == EEH_STATE_NOT_SUPPORT)
597 ((rc & flags) == flags)) 618 return 0;
619
620 /* It's already enabled */
621 if (rc & active_flag)
598 return 0; 622 return 0;
599 } 623 }
600 624
625
626 /* Issue the request */
601 rc = eeh_ops->set_option(pe, function); 627 rc = eeh_ops->set_option(pe, function);
602 if (rc) 628 if (rc)
603 pr_warn("%s: Unexpected state change %d on " 629 pr_warn("%s: Unexpected state change %d on "
@@ -605,17 +631,17 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
605 __func__, function, pe->phb->global_number, 631 __func__, function, pe->phb->global_number,
606 pe->addr, rc); 632 pe->addr, rc);
607 633
608 rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); 634 /* Check if the request is finished successfully */
609 if (rc <= 0) 635 if (active_flag) {
610 return rc; 636 rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
637 if (rc <= 0)
638 return rc;
611 639
612 if ((function == EEH_OPT_THAW_MMIO) && 640 if (rc & active_flag)
613 (rc & EEH_STATE_MMIO_ENABLED)) 641 return 0;
614 return 0;
615 642
616 if ((function == EEH_OPT_THAW_DMA) && 643 return -EIO;
617 (rc & EEH_STATE_DMA_ENABLED)) 644 }
618 return 0;
619 645
620 return rc; 646 return rc;
621} 647}