* [PATCH 2/5] powerpc/eeh: Unfreeze PE on enabling EEH functionality
2014-09-19 5:48 [PATCH 1/5] powerpc/eeh: Fix improper condition in eeh_pci_enable() Gavin Shan
@ 2014-09-19 5:48 ` Gavin Shan
2014-09-19 5:48 ` [PATCH 3/5] powerpc/eeh: Use eeh_unfreeze_pe() Gavin Shan
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Gavin Shan @ 2014-09-19 5:48 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
When passing through PE to guest, that's possibly in frozen
state. The driver for the pass-through devices on guest side
can't be loaded successfully as reported. We already had one
gate in eeh_dev_open() to clear PE frozen state accordingly,
but that's not enough because the function is only called at
QEMU startup for once.
The patch adds another gate in eeh_pe_set_option() so that the
PE frozen state can be cleared at QEMU restart time.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh.c | 60 ++++++++++++++++++++++--------------------
2 files changed, 33 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 1951d07..9bf4a5e 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -281,6 +281,7 @@ void eeh_add_device_late(struct pci_dev *);
void eeh_add_device_tree_late(struct pci_bus *);
void eeh_add_sysfs_files(struct pci_bus *);
void eeh_remove_device(struct pci_dev *);
+int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state);
int eeh_dev_open(struct pci_dev *pdev);
void eeh_dev_release(struct pci_dev *pdev);
struct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group);
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 09bcf95..9678e16 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -1164,6 +1164,31 @@ void eeh_remove_device(struct pci_dev *dev)
edev->mode &= ~EEH_DEV_SYSFS;
}
+int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state)
+{
+ int ret;
+
+ ret = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+ if (ret) {
+ pr_warn("%s: Failure %d enabling IO on PHB#%x-PE#%x\n",
+ __func__, ret, pe->phb->global_number, pe->addr);
+ return ret;
+ }
+
+ ret = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
+ if (ret) {
+ pr_warn("%s: Failure %d enabling DMA on PHB#%x-PE#%x\n",
+ __func__, ret, pe->phb->global_number, pe->addr);
+ return ret;
+ }
+
+ /* Clear software isolated state */
+ if (sw_state && (pe->state & EEH_PE_ISOLATED))
+ eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
+
+ return ret;
+}
+
/**
* eeh_dev_open - Increase count of pass through devices for PE
* @pdev: PCI device
@@ -1176,7 +1201,6 @@ void eeh_remove_device(struct pci_dev *dev)
int eeh_dev_open(struct pci_dev *pdev)
{
struct eeh_dev *edev;
- int flag = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
int ret = -ENODEV;
mutex_lock(&eeh_dev_mutex);
@@ -1196,31 +1220,9 @@ int eeh_dev_open(struct pci_dev *pdev)
* in frozen PE won't work properly. Clear the frozen state
* in advance.
*/
- ret = eeh_ops->get_state(edev->pe, NULL);
- if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT &&
- (ret & flag) != flag) {
- ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_MMIO);
- if (ret) {
- pr_warn("%s: Failure %d enabling MMIO "
- "for PHB#%x-PE#%x\n",
- __func__, ret, edev->phb->global_number,
- edev->pe->addr);
- goto out;
- }
-
- ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_DMA);
- if (ret) {
- pr_warn("%s: Failure %d enabling DMA "
- "for PHB#%x-PE#%x\n",
- __func__, ret, edev->phb->global_number,
- edev->pe->addr);
- goto out;
- }
- }
-
- /* Clear software isolated state */
- if (edev->pe->state & EEH_PE_ISOLATED)
- eeh_pe_state_clear(edev->pe, EEH_PE_ISOLATED);
+ ret = eeh_unfreeze_pe(edev->pe, true);
+ if (ret)
+ goto out;
/* Increase PE's pass through count */
atomic_inc(&edev->pe->pass_dev_cnt);
@@ -1338,8 +1340,10 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)
*/
switch (option) {
case EEH_OPT_ENABLE:
- if (eeh_enabled())
+ if (eeh_enabled()) {
+ ret = eeh_unfreeze_pe(pe, true);
break;
+ }
ret = -EIO;
break;
case EEH_OPT_DISABLE:
@@ -1351,7 +1355,7 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)
break;
}
- ret = eeh_ops->set_option(pe, option);
+ ret = eeh_pci_enable(pe, option);
break;
default:
pr_debug("%s: Option %d out of range (%d, %d)\n",
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/5] powerpc/eeh: Use eeh_unfreeze_pe()
2014-09-19 5:48 [PATCH 1/5] powerpc/eeh: Fix improper condition in eeh_pci_enable() Gavin Shan
2014-09-19 5:48 ` [PATCH 2/5] powerpc/eeh: Unfreeze PE on enabling EEH functionality Gavin Shan
@ 2014-09-19 5:48 ` Gavin Shan
2014-09-19 5:48 ` [PATCH 4/5] powerpc/eeh: Block PCI config access during reset Gavin Shan
2014-09-19 5:48 ` [PATCH 5/5] powerpc/pseries: Decrease message level on EEH initialization Gavin Shan
3 siblings, 0 replies; 5+ messages in thread
From: Gavin Shan @ 2014-09-19 5:48 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
The patch uses eeh_unfreeze_pe() to replace the code clearing
frozen IO and DMA, in order to simplify the things.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 19 +------------------
arch/powerpc/kernel/eeh_driver.c | 18 ++++++------------
arch/powerpc/kernel/eeh_sysfs.c | 21 ++-------------------
3 files changed, 9 insertions(+), 49 deletions(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 9678e16..7004673 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -1433,24 +1433,7 @@ static int eeh_pe_reenable_devices(struct eeh_pe *pe)
}
/* The PE is still in frozen state */
- ret = eeh_ops->set_option(pe, EEH_OPT_THAW_MMIO);
- if (ret) {
- pr_warn("%s: Failure %d enabling MMIO for PHB#%x-PE#%x\n",
- __func__, ret, pe->phb->global_number, pe->addr);
- return ret;
- }
-
- ret = eeh_ops->set_option(pe, EEH_OPT_THAW_DMA);
- if (ret) {
- pr_warn("%s: Failure %d enabling DMA for PHB#%x-PE#%x\n",
- __func__, ret, pe->phb->global_number, pe->addr);
- return ret;
- }
-
- /* Clear software isolated state */
- eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
-
- return ret;
+ return eeh_unfreeze_pe(pe, true);
}
/**
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 6a0dcee..948e6f9 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -450,21 +450,15 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)
static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
- int i, rc;
+ int i, rc = 1;
- for (i = 0; i < 3; i++) {
- rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
- if (rc)
- continue;
- rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
- if (!rc)
- break;
- }
+ for (i = 0; rc && i < 3; i++)
+ rc = eeh_unfreeze_pe(pe, false);
- /* The PE has been isolated, clear it */
+ /* Stop immediately on any errors */
if (rc) {
- pr_warn("%s: Can't clear frozen PHB#%x-PE#%x (%d)\n",
- __func__, pe->phb->global_number, pe->addr, rc);
+ pr_warn("%s: Failure %d unfreezing PHB#%x-PE#%x\n",
+ __func__, rc, pe->phb->global_number, pe->addr);
return (void *)pe;
}
diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c
index e69bcbb..ad21b78 100644
--- a/arch/powerpc/kernel/eeh_sysfs.c
+++ b/arch/powerpc/kernel/eeh_sysfs.c
@@ -85,26 +85,9 @@ static ssize_t eeh_pe_state_store(struct device *dev,
if (!(edev->pe->state & EEH_PE_ISOLATED))
return 0;
- /* Enable MMIO */
- ret = eeh_pci_enable(edev->pe, EEH_OPT_THAW_MMIO);
- if (ret) {
- pr_warn("%s: Failure %d enabling MMIO for PHB#%d-PE#%d\n",
- __func__, ret, edev->pe->phb->global_number,
- edev->pe->addr);
+ ret = eeh_unfreeze_pe(edev->pe, true);
+ if (ret)
return 0;
- }
-
- /* Enable DMA */
- ret = eeh_pci_enable(edev->pe, EEH_OPT_THAW_DMA);
- if (ret) {
- pr_warn("%s: Failure %d enabling DMA for PHB#%d-PE#%d\n",
- __func__, ret, edev->pe->phb->global_number,
- edev->pe->addr);
- return 0;
- }
-
- /* Clear software state */
- eeh_pe_state_clear(edev->pe, EEH_PE_ISOLATED);
return count;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/5] powerpc/eeh: Block PCI config access during reset
2014-09-19 5:48 [PATCH 1/5] powerpc/eeh: Fix improper condition in eeh_pci_enable() Gavin Shan
2014-09-19 5:48 ` [PATCH 2/5] powerpc/eeh: Unfreeze PE on enabling EEH functionality Gavin Shan
2014-09-19 5:48 ` [PATCH 3/5] powerpc/eeh: Use eeh_unfreeze_pe() Gavin Shan
@ 2014-09-19 5:48 ` Gavin Shan
2014-09-19 5:48 ` [PATCH 5/5] powerpc/pseries: Decrease message level on EEH initialization Gavin Shan
3 siblings, 0 replies; 5+ messages in thread
From: Gavin Shan @ 2014-09-19 5:48 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
Function pcibios_set_pcie_reset_state() can be used to do PCI
reset. PCI config access during the reset usually causes EEH
errors unexpectedly. In order to avoid the EEH error, the patch
blocks PCI config access during reset with the help of flag
EEH_PE_RESET, which is similar to what we did in EEH PE reset
path.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 7004673..545860f 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -668,14 +668,18 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
switch (state) {
case pcie_deassert_reset:
eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
+ eeh_pe_state_clear(pe, EEH_PE_RESET);
break;
case pcie_hot_reset:
+ eeh_pe_state_mark(pe, EEH_PE_RESET);
eeh_ops->reset(pe, EEH_RESET_HOT);
break;
case pcie_warm_reset:
+ eeh_pe_state_mark(pe, EEH_PE_RESET);
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
break;
default:
+ eeh_pe_state_clear(pe, EEH_PE_RESET);
return -EINVAL;
};
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 5/5] powerpc/pseries: Decrease message level on EEH initialization
2014-09-19 5:48 [PATCH 1/5] powerpc/eeh: Fix improper condition in eeh_pci_enable() Gavin Shan
` (2 preceding siblings ...)
2014-09-19 5:48 ` [PATCH 4/5] powerpc/eeh: Block PCI config access during reset Gavin Shan
@ 2014-09-19 5:48 ` Gavin Shan
3 siblings, 0 replies; 5+ messages in thread
From: Gavin Shan @ 2014-09-19 5:48 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
As Anton suggested, the patch decreases the message level on EEH
initialization to avoid unnecessary messages if required. Also,
we have unified hint if any of needful RTAS calls is missed, and
then we can check /proc/device-tree to figure out the missed RTAS
calls.
Suggested-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/eeh_pseries.c | 35 ++++++++--------------------
1 file changed, 10 insertions(+), 25 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 4fc5ff9..a6c7e19 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -88,29 +88,14 @@ static int pseries_eeh_init(void)
* and its variant since the old firmware probably support address
* of domain/bus/slot/function for EEH RTAS operations.
*/
- if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: RTAS service <ibm,set-eeh-option> invalid\n",
- __func__);
- return -EINVAL;
- } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: RTAS service <ibm,set-slot-reset> invalid\n",
- __func__);
- return -EINVAL;
- } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
- ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: RTAS service <ibm,read-slot-reset-state2> and "
- "<ibm,read-slot-reset-state> invalid\n",
- __func__);
- return -EINVAL;
- } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: RTAS service <ibm,slot-error-detail> invalid\n",
- __func__);
- return -EINVAL;
- } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
- ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: RTAS service <ibm,configure-pe> and "
- "<ibm,configure-bridge> invalid\n",
- __func__);
+ if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE ||
+ ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE ||
+ (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
+ ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) ||
+ ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE ||
+ (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
+ ibm_configure_bridge == RTAS_UNKNOWN_SERVICE)) {
+ pr_info("EEH functionality not supported\n");
return -EINVAL;
}
@@ -118,11 +103,11 @@ static int pseries_eeh_init(void)
spin_lock_init(&slot_errbuf_lock);
eeh_error_buf_size = rtas_token("rtas-error-log-max");
if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
- pr_warn("%s: unknown EEH error log size\n",
+ pr_info("%s: unknown EEH error log size\n",
__func__);
eeh_error_buf_size = 1024;
} else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
- pr_warn("%s: EEH error log size %d exceeds the maximal %d\n",
+ pr_info("%s: EEH error log size %d exceeds the maximal %d\n",
__func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 5+ messages in thread