linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state()
@ 2015-03-11  4:59 Gavin Shan
  2015-03-11  4:59 ` [PATCH v2 2/2] PCI: Apply warm reset to specific devices Gavin Shan
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Gavin Shan @ 2015-03-11  4:59 UTC (permalink / raw)
  To: linux-pci; +Cc: cascardo, bhelgaas, Gavin Shan, Brian King, Frank Haverkamp

The patch adds one more parameter ("probe") to pci_set_pcie_reset_state(),
which allows to check if one particular PCI device can be resetted by the
function. The function will be reused to support PCI device specific methods
maintained in pci_dev_reset_methods[] in subsequent patch.

Cc: Brian King <brking@us.ibm.com>
Cc: Frank Haverkamp <haver@linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/eeh.c       | 14 ++++++++++----
 drivers/misc/genwqe/card_base.c |  9 +++++++--
 drivers/pci/pci.c               | 15 +++++++++------
 drivers/scsi/ipr.c              |  5 +++--
 include/linux/pci.h             |  5 +++--
 5 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 19a897c..60a0f15ce 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -720,11 +720,14 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
  * pcibios_set_pcie_slot_reset - Set PCI-E reset state
  * @dev: pci device struct
  * @state: reset state to enter
+ * @probe: check if the device can take the reset
  *
  * Return value:
  * 	0 if success
  */
-int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+int pcibios_set_pcie_reset_state(struct pci_dev *dev,
+				 enum pcie_reset_state state,
+				 int probe)
 {
 	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
 	struct eeh_pe *pe = eeh_dev_to_pe(edev);
@@ -732,9 +735,12 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
 	if (!pe) {
 		pr_err("%s: No PE found on PCI device %s\n",
 			__func__, pci_name(dev));
-		return -EINVAL;
+		return -ENOTTY;
 	}
 
+	if (probe)
+		return 0;
+
 	switch (state) {
 	case pcie_deassert_reset:
 		eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
@@ -756,8 +762,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
 		break;
 	default:
 		eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
-		return -EINVAL;
-	};
+		return -ENOTTY;
+	}
 
 	return 0;
 }
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index 4cf8f82..4871f69 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -782,17 +782,22 @@ static int genwqe_pci_fundamental_reset(struct pci_dev *pci_dev)
 {
 	int rc;
 
+	/* Probe if the device can take the reset */
+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 1);
+	if (rc)
+		return rc;
+
 	/*
 	 * lock pci config space access from userspace,
 	 * save state and issue PCIe fundamental reset
 	 */
 	pci_cfg_access_lock(pci_dev);
 	pci_save_state(pci_dev);
-	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset);
+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 0);
 	if (!rc) {
 		/* keep PCIe reset asserted for 250ms */
 		msleep(250);
-		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset);
+		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset, 0);
 		/* Wait for 2s to reload flash and train the link */
 		msleep(2000);
 	}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 81f06e8..8581a5f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1558,28 +1558,31 @@ EXPORT_SYMBOL(pci_disable_device);
  * pcibios_set_pcie_reset_state - set reset state for device dev
  * @dev: the PCIe device reset
  * @state: Reset state to enter into
- *
+ * @probe: Check if the device can take the reset
  *
  * Sets the PCIe reset state for the device. This is the default
  * implementation. Architecture implementations can override this.
  */
 int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
-					enum pcie_reset_state state)
+					enum pcie_reset_state state,
+					int probe)
 {
-	return -EINVAL;
+	return -ENOTTY;
 }
 
 /**
  * pci_set_pcie_reset_state - set reset state for device dev
  * @dev: the PCIe device reset
  * @state: Reset state to enter into
- *
+ * @probe: Check if the device can take the reset
  *
  * Sets the PCI reset state for the device.
  */
-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+int pci_set_pcie_reset_state(struct pci_dev *dev,
+			     enum pcie_reset_state state,
+			     int probe)
 {
-	return pcibios_set_pcie_reset_state(dev, state);
+	return pcibios_set_pcie_reset_state(dev, state, probe);
 }
 EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
 
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 9219953..89026f4 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -8317,7 +8317,8 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
 static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
 {
 	ENTER;
-	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
+	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev,
+				 pcie_deassert_reset, 0);
 	ipr_cmd->job_step = ipr_reset_bist_done;
 	ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
 	LEAVE;
@@ -8339,7 +8340,7 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
 	struct pci_dev *pdev = ioa_cfg->pdev;
 
 	ENTER;
-	pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+	pci_set_pcie_reset_state(pdev, pcie_warm_reset, 0);
 	ipr_cmd->job_step = ipr_reset_slot_reset_done;
 	ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
 	LEAVE;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 211e9da..c15ca2f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -960,7 +960,8 @@ extern unsigned int pcibios_max_latency;
 void pci_set_master(struct pci_dev *dev);
 void pci_clear_master(struct pci_dev *dev);
 
-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
+int pci_set_pcie_reset_state(struct pci_dev *dev,
+			     enum pcie_reset_state state, int probe);
 int pci_set_cacheline_size(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
 int __must_check pci_set_mwi(struct pci_dev *dev);
@@ -1647,7 +1648,7 @@ extern unsigned long pci_hotplug_mem_size;
 void pcibios_disable_device(struct pci_dev *dev);
 void pcibios_set_master(struct pci_dev *dev);
 int pcibios_set_pcie_reset_state(struct pci_dev *dev,
-				 enum pcie_reset_state state);
+				 enum pcie_reset_state state, int probe);
 int pcibios_add_device(struct pci_dev *dev);
 void pcibios_release_device(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq, int active);
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] PCI: Apply warm reset to specific devices
  2015-03-11  4:59 [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
@ 2015-03-11  4:59 ` Gavin Shan
  2015-03-11  5:02 ` [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
  2015-03-11  5:38 ` Gavin Shan
  2 siblings, 0 replies; 4+ messages in thread
From: Gavin Shan @ 2015-03-11  4:59 UTC (permalink / raw)
  To: linux-pci; +Cc: cascardo, bhelgaas, Gavin Shan

Currently, VFIO infrastructure depends on pci_reset_function()
to ensure the PCI device in clean state when passing to guest,
or being returned back to host. However, the function doesn't
work (or well) on some PCI devices on PowerPC platforms, which
potentiallybrings pending traffic over the boundary between
host/guest and usually causes memory corruption.

The patch applies warm reset to those PCI devices, which is
implemented based on pci_set_pcie_reset_state() to get clean
state when passing device from host to guest, or returning it
back to host. The reset request is routed to platform specific
pcibios_set_pcie_reset_state() and processed there.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
v2: Reuse pci_set_pcie_reset_state()
---
 drivers/pci/quirks.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 85f247e..9846d5e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3504,6 +3504,22 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
 	return 0;
 }
 
+static int pci_dev_warm_reset(struct pci_dev *pdev, int probe)
+{
+	int ret;
+
+	/* Check the device can take the reset or not */
+	if (probe)
+		return pci_set_pcie_reset_state(pdev, pcie_warm_reset, probe);
+
+	/* Issue warm reset */
+	ret = pci_set_pcie_reset_state(pdev, pcie_warm_reset, 0);
+	if (!ret)
+		ret = pci_set_pcie_reset_state(pdev, pcie_deassert_reset, 0);
+
+	return ret;
+}
+
 #define PCI_DEVICE_ID_INTEL_82599_SFP_VF   0x10ed
 #define PCI_DEVICE_ID_INTEL_IVB_M_VGA      0x0156
 #define PCI_DEVICE_ID_INTEL_IVB_M2_VGA     0x0166
@@ -3519,6 +3535,18 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
 		reset_intel_generic_dev },
 	{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
 		reset_chelsio_generic_dev },
+	{ PCI_VENDOR_ID_IBM, PCI_ANY_ID,
+		pci_dev_warm_reset },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800,
+		pci_dev_warm_reset },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840,
+		pci_dev_warm_reset },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810,
+		pci_dev_warm_reset },
+	{ PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
+		pci_dev_warm_reset },
+	{ PCI_VENDOR_ID_TI, PCI_ANY_ID,
+		pci_dev_warm_reset },
 	{ 0 }
 };
 
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state()
  2015-03-11  4:59 [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
  2015-03-11  4:59 ` [PATCH v2 2/2] PCI: Apply warm reset to specific devices Gavin Shan
@ 2015-03-11  5:02 ` Gavin Shan
  2015-03-11  5:38 ` Gavin Shan
  2 siblings, 0 replies; 4+ messages in thread
From: Gavin Shan @ 2015-03-11  5:02 UTC (permalink / raw)
  To: Gavin Shan; +Cc: linux-pci, cascardo, bhelgaas, Brian King, Frank Haverkamp

On Wed, Mar 11, 2015 at 03:59:00PM +1100, Gavin Shan wrote:
>The patch adds one more parameter ("probe") to pci_set_pcie_reset_state(),
>which allows to check if one particular PCI device can be resetted by the
>function. The function will be reused to support PCI device specific methods
>maintained in pci_dev_reset_methods[] in subsequent patch.
>
>Cc: Brian King <brking@us.ibm.com>
>Cc: Frank Haverkamp <haver@linux.vnet.ibm.com>
>Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
>---

The patch depdends on: https://patchwork.ozlabs.org/patch/438598/ which
should be applied prior this one.

Thanks,
Gavin

> arch/powerpc/kernel/eeh.c       | 14 ++++++++++----
> drivers/misc/genwqe/card_base.c |  9 +++++++--
> drivers/pci/pci.c               | 15 +++++++++------
> drivers/scsi/ipr.c              |  5 +++--
> include/linux/pci.h             |  5 +++--
> 5 files changed, 32 insertions(+), 16 deletions(-)
>
>diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
>index 19a897c..60a0f15ce 100644
>--- a/arch/powerpc/kernel/eeh.c
>+++ b/arch/powerpc/kernel/eeh.c
>@@ -720,11 +720,14 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
>  * pcibios_set_pcie_slot_reset - Set PCI-E reset state
>  * @dev: pci device struct
>  * @state: reset state to enter
>+ * @probe: check if the device can take the reset
>  *
>  * Return value:
>  * 	0 if success
>  */
>-int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
>+int pcibios_set_pcie_reset_state(struct pci_dev *dev,
>+				 enum pcie_reset_state state,
>+				 int probe)
> {
> 	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
> 	struct eeh_pe *pe = eeh_dev_to_pe(edev);
>@@ -732,9 +735,12 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
> 	if (!pe) {
> 		pr_err("%s: No PE found on PCI device %s\n",
> 			__func__, pci_name(dev));
>-		return -EINVAL;
>+		return -ENOTTY;
> 	}
>
>+	if (probe)
>+		return 0;
>+
> 	switch (state) {
> 	case pcie_deassert_reset:
> 		eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
>@@ -756,8 +762,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
> 		break;
> 	default:
> 		eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
>-		return -EINVAL;
>-	};
>+		return -ENOTTY;
>+	}
>
> 	return 0;
> }
>diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
>index 4cf8f82..4871f69 100644
>--- a/drivers/misc/genwqe/card_base.c
>+++ b/drivers/misc/genwqe/card_base.c
>@@ -782,17 +782,22 @@ static int genwqe_pci_fundamental_reset(struct pci_dev *pci_dev)
> {
> 	int rc;
>
>+	/* Probe if the device can take the reset */
>+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 1);
>+	if (rc)
>+		return rc;
>+
> 	/*
> 	 * lock pci config space access from userspace,
> 	 * save state and issue PCIe fundamental reset
> 	 */
> 	pci_cfg_access_lock(pci_dev);
> 	pci_save_state(pci_dev);
>-	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset);
>+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 0);
> 	if (!rc) {
> 		/* keep PCIe reset asserted for 250ms */
> 		msleep(250);
>-		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset);
>+		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset, 0);
> 		/* Wait for 2s to reload flash and train the link */
> 		msleep(2000);
> 	}
>diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>index 81f06e8..8581a5f 100644
>--- a/drivers/pci/pci.c
>+++ b/drivers/pci/pci.c
>@@ -1558,28 +1558,31 @@ EXPORT_SYMBOL(pci_disable_device);
>  * pcibios_set_pcie_reset_state - set reset state for device dev
>  * @dev: the PCIe device reset
>  * @state: Reset state to enter into
>- *
>+ * @probe: Check if the device can take the reset
>  *
>  * Sets the PCIe reset state for the device. This is the default
>  * implementation. Architecture implementations can override this.
>  */
> int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
>-					enum pcie_reset_state state)
>+					enum pcie_reset_state state,
>+					int probe)
> {
>-	return -EINVAL;
>+	return -ENOTTY;
> }
>
> /**
>  * pci_set_pcie_reset_state - set reset state for device dev
>  * @dev: the PCIe device reset
>  * @state: Reset state to enter into
>- *
>+ * @probe: Check if the device can take the reset
>  *
>  * Sets the PCI reset state for the device.
>  */
>-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
>+int pci_set_pcie_reset_state(struct pci_dev *dev,
>+			     enum pcie_reset_state state,
>+			     int probe)
> {
>-	return pcibios_set_pcie_reset_state(dev, state);
>+	return pcibios_set_pcie_reset_state(dev, state, probe);
> }
> EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
>
>diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
>index 9219953..89026f4 100644
>--- a/drivers/scsi/ipr.c
>+++ b/drivers/scsi/ipr.c
>@@ -8317,7 +8317,8 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
> static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
> {
> 	ENTER;
>-	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
>+	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev,
>+				 pcie_deassert_reset, 0);
> 	ipr_cmd->job_step = ipr_reset_bist_done;
> 	ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
> 	LEAVE;
>@@ -8339,7 +8340,7 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
> 	struct pci_dev *pdev = ioa_cfg->pdev;
>
> 	ENTER;
>-	pci_set_pcie_reset_state(pdev, pcie_warm_reset);
>+	pci_set_pcie_reset_state(pdev, pcie_warm_reset, 0);
> 	ipr_cmd->job_step = ipr_reset_slot_reset_done;
> 	ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
> 	LEAVE;
>diff --git a/include/linux/pci.h b/include/linux/pci.h
>index 211e9da..c15ca2f 100644
>--- a/include/linux/pci.h
>+++ b/include/linux/pci.h
>@@ -960,7 +960,8 @@ extern unsigned int pcibios_max_latency;
> void pci_set_master(struct pci_dev *dev);
> void pci_clear_master(struct pci_dev *dev);
>
>-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
>+int pci_set_pcie_reset_state(struct pci_dev *dev,
>+			     enum pcie_reset_state state, int probe);
> int pci_set_cacheline_size(struct pci_dev *dev);
> #define HAVE_PCI_SET_MWI
> int __must_check pci_set_mwi(struct pci_dev *dev);
>@@ -1647,7 +1648,7 @@ extern unsigned long pci_hotplug_mem_size;
> void pcibios_disable_device(struct pci_dev *dev);
> void pcibios_set_master(struct pci_dev *dev);
> int pcibios_set_pcie_reset_state(struct pci_dev *dev,
>-				 enum pcie_reset_state state);
>+				 enum pcie_reset_state state, int probe);
> int pcibios_add_device(struct pci_dev *dev);
> void pcibios_release_device(struct pci_dev *dev);
> void pcibios_penalize_isa_irq(int irq, int active);
>-- 
>1.8.3.2
>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state()
  2015-03-11  4:59 [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
  2015-03-11  4:59 ` [PATCH v2 2/2] PCI: Apply warm reset to specific devices Gavin Shan
  2015-03-11  5:02 ` [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
@ 2015-03-11  5:38 ` Gavin Shan
  2 siblings, 0 replies; 4+ messages in thread
From: Gavin Shan @ 2015-03-11  5:38 UTC (permalink / raw)
  To: Gavin Shan; +Cc: linux-pci, cascardo, bhelgaas, Brian King, Frank Haverkamp

On Wed, Mar 11, 2015 at 03:59:00PM +1100, Gavin Shan wrote:
>The patch adds one more parameter ("probe") to pci_set_pcie_reset_state(),
>which allows to check if one particular PCI device can be resetted by the
>function. The function will be reused to support PCI device specific methods
>maintained in pci_dev_reset_methods[] in subsequent patch.
>
>Cc: Brian King <brking@us.ibm.com>
>Cc: Frank Haverkamp <haver@linux.vnet.ibm.com>
>Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
>---
> arch/powerpc/kernel/eeh.c       | 14 ++++++++++----
> drivers/misc/genwqe/card_base.c |  9 +++++++--
> drivers/pci/pci.c               | 15 +++++++++------
> drivers/scsi/ipr.c              |  5 +++--
> include/linux/pci.h             |  5 +++--
> 5 files changed, 32 insertions(+), 16 deletions(-)
>

Missed to change pci_set_pcie_reset_state() for drivers/misc/cxl/pci.c. I'll
fix it in v3 after getting feedback.

Thanks,
Gavin

>diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
>index 19a897c..60a0f15ce 100644
>--- a/arch/powerpc/kernel/eeh.c
>+++ b/arch/powerpc/kernel/eeh.c
>@@ -720,11 +720,14 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
>  * pcibios_set_pcie_slot_reset - Set PCI-E reset state
>  * @dev: pci device struct
>  * @state: reset state to enter
>+ * @probe: check if the device can take the reset
>  *
>  * Return value:
>  * 	0 if success
>  */
>-int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
>+int pcibios_set_pcie_reset_state(struct pci_dev *dev,
>+				 enum pcie_reset_state state,
>+				 int probe)
> {
> 	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
> 	struct eeh_pe *pe = eeh_dev_to_pe(edev);
>@@ -732,9 +735,12 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
> 	if (!pe) {
> 		pr_err("%s: No PE found on PCI device %s\n",
> 			__func__, pci_name(dev));
>-		return -EINVAL;
>+		return -ENOTTY;
> 	}
>
>+	if (probe)
>+		return 0;
>+
> 	switch (state) {
> 	case pcie_deassert_reset:
> 		eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
>@@ -756,8 +762,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
> 		break;
> 	default:
> 		eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
>-		return -EINVAL;
>-	};
>+		return -ENOTTY;
>+	}
>
> 	return 0;
> }
>diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
>index 4cf8f82..4871f69 100644
>--- a/drivers/misc/genwqe/card_base.c
>+++ b/drivers/misc/genwqe/card_base.c
>@@ -782,17 +782,22 @@ static int genwqe_pci_fundamental_reset(struct pci_dev *pci_dev)
> {
> 	int rc;
>
>+	/* Probe if the device can take the reset */
>+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 1);
>+	if (rc)
>+		return rc;
>+
> 	/*
> 	 * lock pci config space access from userspace,
> 	 * save state and issue PCIe fundamental reset
> 	 */
> 	pci_cfg_access_lock(pci_dev);
> 	pci_save_state(pci_dev);
>-	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset);
>+	rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset, 0);
> 	if (!rc) {
> 		/* keep PCIe reset asserted for 250ms */
> 		msleep(250);
>-		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset);
>+		pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset, 0);
> 		/* Wait for 2s to reload flash and train the link */
> 		msleep(2000);
> 	}
>diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>index 81f06e8..8581a5f 100644
>--- a/drivers/pci/pci.c
>+++ b/drivers/pci/pci.c
>@@ -1558,28 +1558,31 @@ EXPORT_SYMBOL(pci_disable_device);
>  * pcibios_set_pcie_reset_state - set reset state for device dev
>  * @dev: the PCIe device reset
>  * @state: Reset state to enter into
>- *
>+ * @probe: Check if the device can take the reset
>  *
>  * Sets the PCIe reset state for the device. This is the default
>  * implementation. Architecture implementations can override this.
>  */
> int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
>-					enum pcie_reset_state state)
>+					enum pcie_reset_state state,
>+					int probe)
> {
>-	return -EINVAL;
>+	return -ENOTTY;
> }
>
> /**
>  * pci_set_pcie_reset_state - set reset state for device dev
>  * @dev: the PCIe device reset
>  * @state: Reset state to enter into
>- *
>+ * @probe: Check if the device can take the reset
>  *
>  * Sets the PCI reset state for the device.
>  */
>-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
>+int pci_set_pcie_reset_state(struct pci_dev *dev,
>+			     enum pcie_reset_state state,
>+			     int probe)
> {
>-	return pcibios_set_pcie_reset_state(dev, state);
>+	return pcibios_set_pcie_reset_state(dev, state, probe);
> }
> EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
>
>diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
>index 9219953..89026f4 100644
>--- a/drivers/scsi/ipr.c
>+++ b/drivers/scsi/ipr.c
>@@ -8317,7 +8317,8 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
> static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
> {
> 	ENTER;
>-	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
>+	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev,
>+				 pcie_deassert_reset, 0);
> 	ipr_cmd->job_step = ipr_reset_bist_done;
> 	ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
> 	LEAVE;
>@@ -8339,7 +8340,7 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
> 	struct pci_dev *pdev = ioa_cfg->pdev;
>
> 	ENTER;
>-	pci_set_pcie_reset_state(pdev, pcie_warm_reset);
>+	pci_set_pcie_reset_state(pdev, pcie_warm_reset, 0);
> 	ipr_cmd->job_step = ipr_reset_slot_reset_done;
> 	ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
> 	LEAVE;
>diff --git a/include/linux/pci.h b/include/linux/pci.h
>index 211e9da..c15ca2f 100644
>--- a/include/linux/pci.h
>+++ b/include/linux/pci.h
>@@ -960,7 +960,8 @@ extern unsigned int pcibios_max_latency;
> void pci_set_master(struct pci_dev *dev);
> void pci_clear_master(struct pci_dev *dev);
>
>-int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
>+int pci_set_pcie_reset_state(struct pci_dev *dev,
>+			     enum pcie_reset_state state, int probe);
> int pci_set_cacheline_size(struct pci_dev *dev);
> #define HAVE_PCI_SET_MWI
> int __must_check pci_set_mwi(struct pci_dev *dev);
>@@ -1647,7 +1648,7 @@ extern unsigned long pci_hotplug_mem_size;
> void pcibios_disable_device(struct pci_dev *dev);
> void pcibios_set_master(struct pci_dev *dev);
> int pcibios_set_pcie_reset_state(struct pci_dev *dev,
>-				 enum pcie_reset_state state);
>+				 enum pcie_reset_state state, int probe);
> int pcibios_add_device(struct pci_dev *dev);
> void pcibios_release_device(struct pci_dev *dev);
> void pcibios_penalize_isa_irq(int irq, int active);
>-- 
>1.8.3.2
>


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-03-11  5:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-11  4:59 [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
2015-03-11  4:59 ` [PATCH v2 2/2] PCI: Apply warm reset to specific devices Gavin Shan
2015-03-11  5:02 ` [PATCH v2 1/2] PCI: One more parameter to pci_set_pcie_reset_state() Gavin Shan
2015-03-11  5:38 ` Gavin Shan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).