@@ -745,28 +745,11 @@ static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay)
return ret;
}
-static s64 pnv_eeh_poll(uint64_t id)
-{
- s64 rc = OPAL_HARDWARE;
-
- while (1) {
- rc = opal_pci_poll(id, NULL);
- if (rc <= 0)
- break;
-
- if (system_state < SYSTEM_RUNNING)
- udelay(1000 * rc);
- else
- msleep(rc);
- }
-
- return rc;
-}
-
int pnv_eeh_phb_reset(struct pci_controller *hose, int option)
{
struct pnv_phb *phb = hose->private_data;
s64 rc = OPAL_HARDWARE;
+ int ret;
pr_debug("%s: Reset PHB#%x, option=%d\n",
__func__, hose->global_number, option);
@@ -781,8 +764,6 @@ int pnv_eeh_phb_reset(struct pci_controller *hose, int option)
rc = opal_pci_reset(phb->opal_id,
OPAL_RESET_PHB_COMPLETE,
OPAL_DEASSERT_RESET);
- if (rc < 0)
- goto out;
/*
* Poll state of the PHB until the request is done
@@ -790,24 +771,22 @@ int pnv_eeh_phb_reset(struct pci_controller *hose, int option)
* reset followed by hot reset on root bus. So we also
* need the PCI bus settlement delay.
*/
- rc = pnv_eeh_poll(phb->opal_id);
- if (option == EEH_RESET_DEACTIVATE) {
+ ret = pnv_pci_poll(phb->opal_id, rc, NULL);
+ if (option == EEH_RESET_DEACTIVATE && !ret) {
if (system_state < SYSTEM_RUNNING)
udelay(1000 * EEH_PE_RST_SETTLE_TIME);
else
msleep(EEH_PE_RST_SETTLE_TIME);
}
-out:
- if (rc != OPAL_SUCCESS)
- return -EIO;
- return 0;
+ return ret;
}
static int pnv_eeh_root_reset(struct pci_controller *hose, int option)
{
struct pnv_phb *phb = hose->private_data;
s64 rc = OPAL_HARDWARE;
+ int ret;
pr_debug("%s: Reset PHB#%x, option=%d\n",
__func__, hose->global_number, option);
@@ -829,18 +808,13 @@ static int pnv_eeh_root_reset(struct pci_controller *hose, int option)
rc = opal_pci_reset(phb->opal_id,
OPAL_RESET_PCI_HOT,
OPAL_DEASSERT_RESET);
- if (rc < 0)
- goto out;
/* Poll state of the PHB until the request is done */
- rc = pnv_eeh_poll(phb->opal_id);
- if (option == EEH_RESET_DEACTIVATE)
+ ret = pnv_pci_poll(phb->opal_id, rc, NULL);
+ if (option == EEH_RESET_DEACTIVATE && !ret)
msleep(EEH_PE_RST_SETTLE_TIME);
-out:
- if (rc != OPAL_SUCCESS)
- return -EIO;
- return 0;
+ return ret;
}
static int __pnv_eeh_bridge_reset(struct pci_dev *dev, int option)
@@ -930,10 +904,7 @@ static int pnv_eeh_bridge_reset(struct pci_dev *pdev, int option)
phb = hose->private_data;
id |= (pdev->bus->number << 24) | (pdev->devfn << 16) | phb->opal_id;
rc = opal_pci_reset(id, scope, OPAL_ASSERT_RESET);
- if (rc > 0)
- rc = pnv_eeh_poll(id);
-
- return (rc == OPAL_SUCCESS) ? 0 : -EIO;
+ return pnv_pci_poll(id, rc, NULL);
}
static void pnv_eeh_wait_for_pending(struct pci_dn *pdn, int pos,
@@ -44,6 +44,27 @@
#define cfg_dbg(fmt...) do { } while(0)
//#define cfg_dbg(fmt...) printk(fmt)
+int pnv_pci_poll(uint64_t id, int64_t rval, uint8_t *pval)
+{
+ while (rval > 0) {
+ if (system_state < SYSTEM_RUNNING)
+ udelay(1000 * rval);
+ else
+ msleep(rval);
+
+ rval = opal_pci_poll(id, pval);
+ }
+
+ /*
+ * The caller expects to retrieve additional information
+ * if the last argument is valid.
+ */
+ if (rval == OPAL_SUCCESS && pval)
+ rval = opal_pci_poll(id, pval);
+
+ return rval ? -EIO : 0;
+}
+
#ifdef CONFIG_PCI_MSI
int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
@@ -214,6 +214,7 @@ extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
unsigned long *hpa, enum dma_data_direction *direction);
extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index);
+int pnv_pci_poll(uint64_t id, int64_t rval, uint8_t *pval);
void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
unsigned char *log_buff);
int pnv_pci_cfg_read(struct pci_dn *pdn,
This converts pnv_eeh_poll() to pnv_pci_poll() in order to: * Return linux error code other than OPAL error code. * The return value from last OPAL call, requested delay, is passed to pnv_pci_poll() and delay accordingly. Thus one call to opal_pci_poll() is saved. * More information (e.g. PCI slot power status) is returned if the last argument isn't NULL. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> --- arch/powerpc/platforms/powernv/eeh-powernv.c | 47 ++++++---------------------- arch/powerpc/platforms/powernv/pci.c | 21 +++++++++++++ arch/powerpc/platforms/powernv/pci.h | 1 + 3 files changed, 31 insertions(+), 38 deletions(-)