eeh_check_failure() is used to check frozen state of the PE which
owns the indicated I/O address. The argument "val" of the function
isn't used. The patch drops it and return the frozen state of the
PE as expected.
Cc: Vishal Mansur <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/eeh.h | 29 ++++++++++++++---------------
arch/powerpc/kernel/eeh.c | 15 ++++++---------
2 files changed, 20 insertions(+), 24 deletions(-)
The patch adds sysfs entry "eeh_pe_state". Reading on it returns
the PE's state while writing to it clears the frozen state. It's
used to check or clear the PE frozen state from userland for
debugging purpose.
The patch also replaces printk(KERN_WARNING ...) with pr_warn() in
eeh_sysfs.c
Signed-off-by: Gavin Shan <redacted>
---
v2: Not output PE number and return error from the sysfs entry
if necessary
---
arch/powerpc/kernel/eeh_sysfs.c | 60 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
The frozen state on one specific PE is probably caused by error
injection, which is done with help of PAPR error injection registers.
According to the hardware spec, those registers should be cleared
automatically after one-shot frozen PE. However, that's not always
true, at least on P7IOC of Firebird-L. So we have to clear them
before doing PE reset to avoid recursive EEH errors at recovery
stage.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-ioda.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
When passing through device, its PE might have been put into frozen
state. One obvious example would be: the passed PE is forced to be
offline because of hitting maximal allowed EEH errors in userland.
In that case, the frozen state won't be cleared and then the PE is
returned back to host, which might not have chance detecting and
recovering from it.
The patch adds more check when passing through device and clear the
PE frozen state if necessary.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/eeh.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
The patch adds one more option (EEH_OPT_FREEZE_PE) to set_option()
method to proactively freeze PE, which will be issued before resetting
pass-throughed PE to drop MMIO access during reset because it's
always contributing to recursive EEH error.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh.c | 7 +++++
arch/powerpc/platforms/powernv/eeh-ioda.c | 43 +++++++++++++++++++++-------
arch/powerpc/platforms/pseries/eeh_pseries.c | 4 ++-
4 files changed, 44 insertions(+), 11 deletions(-)
@@ -1382,6 +1382,13 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)break;caseEEH_RESET_HOT:caseEEH_RESET_FUNDAMENTAL:+/*+*ProactivelyfreezethePEtodropallMMIOaccess+*duringreset,whichshouldbebannedasit'salways+*causerecursiveEEHerror.+*/+eeh_ops->set_option(pe,EEH_OPT_FREEZE_PE);+ret=eeh_ops->reset(pe,option);break;default:
@@ -349,7 +349,9 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)if(pe->addr)config_addr=pe->addr;break;-+caseEEH_OPT_FREEZE_PE:+/* Not support */+return0;default:pr_err("%s: Invalid option %d\n",__func__,option);
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 <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/pseries/eeh_pseries.c | 35 ++++++++--------------------
1 file changed, 10 insertions(+), 25 deletions(-)
@@ -88,29 +88,14 @@ static int pseries_eeh_init(void)*anditsvariantsincetheoldfirmwareprobablysupportaddress*ofdomain/bus/slot/functionforEEHRTASoperations.*/-if(ibm_set_eeh_option==RTAS_UNKNOWN_SERVICE){-pr_warn("%s: RTAS service <ibm,set-eeh-option> invalid\n",-__func__);-return-EINVAL;-}elseif(ibm_set_slot_reset==RTAS_UNKNOWN_SERVICE){-pr_warn("%s: RTAS service <ibm,set-slot-reset> invalid\n",-__func__);-return-EINVAL;-}elseif(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;-}elseif(ibm_slot_error_detail==RTAS_UNKNOWN_SERVICE){-pr_warn("%s: RTAS service <ibm,slot-error-detail> invalid\n",-__func__);-return-EINVAL;-}elseif(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;}
From: Mike Qiu <redacted>
The patch adds debugfs file (/sys/kernel/debug/powerpc/PCIxxxx/
err_injct), which accepts following formated string, to support
error injection. It will be used to support userland utility
"errinjct" in future.
"pe_no:0:function:address:mask" - 32-bits PCI errors
"pe_no:1:function:address:mask" - 64-bits PCI errors
Signed-off-by: Mike Qiu <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-ioda.c | 52 +++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
The patch synchronizes firmware header file (opal.h) for PCI error
injection.
Signed-off-by: Mike Qiu <redacted>
Signed-off-by: Gavin Shan <redacted>
---
v2: Seperate enum error type and function and adjust the names
according to mpe's suggestion. Also replacing "injct" with
"inject"
---
arch/powerpc/include/asm/opal.h | 32 ++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal-wrappers.S | 1 +
2 files changed, 33 insertions(+)
The problem was reported by Carol: In the scenario of passing mlx4
adapter to guest, EEH error could be recovered successfully. When
returning the device back to host, the driver (mlx4_core.ko)
couldn't be loaded successfully because of error number -5 (-EIO)
returned from mlx4_get_ownership(), which hits offlined PCI device.
The root cause is that we missed to put the affected devices into
normal state on clearing PE isolated state right after PE reset.
The patch fixes above issue by putting the affected devices to
normal state when clearing PE isolated state in eeh_pe_state_clear().
Cc: stable@vger.kernel.org
Reported-by: Carol L. Soto <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/eeh_pe.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
@@ -584,6 +584,8 @@ static void *__eeh_pe_state_clear(void *data, void *flag){structeeh_pe*pe=(structeeh_pe*)data;intstate=*((int*)flag);+structeeh_dev*edev,*tmp;+structpci_dev*pdev;/* Keep the state of permanently removed PE intact */if((pe->freeze_count>EEH_MAX_ALLOWED_FREEZES)&&
@@ -592,9 +594,22 @@ static void *__eeh_pe_state_clear(void *data, void *flag)pe->state&=~state;-/* Clear check count since last isolation */-if(state&EEH_PE_ISOLATED)-pe->check_count=0;+/*+*Specialtreatmentonclearingisolatedstate.Clear+*checkcountsincelastisolationandputallaffected+*devicestonormalstate.+*/+if(!(state&EEH_PE_ISOLATED))+returnNULL;++pe->check_count=0;+eeh_pe_for_each_dev(pe,edev,tmp){+pdev=eeh_dev_to_pci_dev(edev);+if(!pdev)+continue;++pdev->error_state=pci_channel_io_normal;+}returnNULL;}
The PEs can be organized as nested. Current implementation doesn't
dump PCI config space for subordinate devices of child PEs. However,
the frozen PE could be caused by those subordinate devices of its
child PEs.
The patch dumps PCI config space for all subordinate devices of the
problematic PE.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/eeh.c | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)
@@ -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);-returnret;-}--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);-returnret;-}--/* Clear software isolated state */-eeh_pe_state_clear(pe,EEH_PE_ISOLATED);--returnret;+returneeh_unfreeze_pe(pe,true);}/**
@@ -450,21 +450,15 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)staticvoid*__eeh_clear_pe_frozen_state(void*data,void*flag){structeeh_pe*pe=(structeeh_pe*)data;-inti,rc;+inti,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;}
The dma_get_required_mask() function is used by some drivers to
query the platform about what DMA mask is needed to cover all of
memory. This is a bit of a strange semantic when we have to choose
between IOMMU translation or bypass, but essentially what it means
is "what DMA mask will give best performances".
Currently, our IOMMU backend always returns a 32-bit mask here, we
don't do anything special to it when we have bypass available. This
causes some drivers to choose a 32-bit mask, thus losing the ability
to use the bypass window, thinking this is more efficient. The problem
was reported from the driver of following device:
0004:03:00.0 0107: 1000:0087 (rev 05)
0004:03:00.0 Serial Attached SCSI controller: LSI Logic / Symbios \
Logic SAS2308 PCI-Express Fusion-MPT SAS-2 (rev 05)
This patch adds an override of that function in order to, instead,
return a 64-bit mask whenever a bypass window is available in order
for drivers to prefer this configuration.
Reported-by: Murali N. Iyer <redacted>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/dma-mapping.h | 1 +
arch/powerpc/kernel/dma.c | 14 ++++++++++----
arch/powerpc/platforms/powernv/pci-ioda.c | 23 +++++++++++++++++++++++
arch/powerpc/platforms/powernv/pci.c | 11 +++++++++++
arch/powerpc/platforms/powernv/pci.h | 2 ++
arch/powerpc/platforms/powernv/powernv.h | 6 ++++++
arch/powerpc/platforms/powernv/setup.c | 9 +++++++++
7 files changed, 62 insertions(+), 4 deletions(-)
@@ -173,6 +173,14 @@ static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)return__dma_set_mask(dev,dma_mask);}+staticu64pnv_dma_get_required_mask(structdevice*dev)+{+if(dev_is_pci(dev))+returnpnv_pci_dma_get_required_mask(to_pci_dev(dev));++return__dma_get_required_mask(dev);+}+staticvoidpnv_shutdown(void){/* Let the PCI code clear up IODA tables */
It should have been part of commit 1ad7a72c5 ("powerpc/eeh: Report
frozen parent PE prior to child PE"). There are 2 ways to report
EEH errors: proactively polling because of 0xFF's returned from
PCI config or IO read, or interrupt driven event. We missed to
report and handle parent frozen PE prior to child frozen PE for
the later case on PowerNV platform.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-ioda.c | 48 ++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 14 deletions(-)
@@ -886,14 +886,12 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,*themasterPEbecauseslavePEisinvisible*toEEHcore.*/-if(phb->get_pe_state){-pnv_pe=&phb->ioda.pe_array[pe_no];-if(pnv_pe->flags&PNV_IODA_PE_SLAVE){-pnv_pe=pnv_pe->master;-WARN_ON(!pnv_pe||-!(pnv_pe->flags&PNV_IODA_PE_MASTER));-pe_no=pnv_pe->pe_number;-}+pnv_pe=&phb->ioda.pe_array[pe_no];+if(pnv_pe->flags&PNV_IODA_PE_SLAVE){+pnv_pe=pnv_pe->master;+WARN_ON(!pnv_pe||+!(pnv_pe->flags&PNV_IODA_PE_MASTER));+pe_no=pnv_pe->pe_number;}/* Find the PE according to PE# */
@@ -904,15 +902,37 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,if(!dev_pe)return-EEXIST;-/*-*Atthispoint,we'resurethecompoundPEshould-*beputintofrozenstate.-*/+/* Freeze the (compound) PE */*pe=dev_pe;-if(phb->freeze_pe&&-!(dev_pe->state&EEH_PE_ISOLATED))+if(!(dev_pe->state&EEH_PE_ISOLATED))phb->freeze_pe(phb,pe_no);+/*+*Atthispoint,we'resurethe(compound)PEshould+*havebeenfrozen.However,westillneedpokeuntil+*hittingthefrozenPEontoplevel.+*/+dev_pe=dev_pe->parent;+while(dev_pe&&!(dev_pe->type&EEH_PE_PHB)){+intret;+intactive_flags=(EEH_STATE_MMIO_ACTIVE|+EEH_STATE_DMA_ACTIVE);++ret=eeh_ops->get_state(dev_pe,NULL);+if(ret<=0||(ret&active_flags)==active_flags){+dev_pe=dev_pe->parent;+continue;+}++/* Frozen parent PE */+*pe=dev_pe;+if(!(dev_pe->state&EEH_PE_ISOLATED))+phb->freeze_pe(phb,dev_pe->addr);++/* Next one */+dev_pe=dev_pe->parent;+}+return0;}
@@ -514,11 +514,11 @@ int ioda_eeh_phb_reset(struct pci_controller *hose, int option)if(option==EEH_RESET_FUNDAMENTAL||option==EEH_RESET_HOT)rc=opal_pci_reset(phb->opal_id,-OPAL_PHB_COMPLETE,+OPAL_RESET_PHB_COMPLETE,OPAL_ASSERT_RESET);elseif(option==EEH_RESET_DEACTIVATE)rc=opal_pci_reset(phb->opal_id,-OPAL_PHB_COMPLETE,+OPAL_RESET_PHB_COMPLETE,OPAL_DEASSERT_RESET);if(rc<0)gotoout;
@@ -558,15 +558,15 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option)*/if(option==EEH_RESET_FUNDAMENTAL)rc=opal_pci_reset(phb->opal_id,-OPAL_PCI_FUNDAMENTAL_RESET,+OPAL_RESET_PCI_FUNDAMENTAL,OPAL_ASSERT_RESET);elseif(option==EEH_RESET_HOT)rc=opal_pci_reset(phb->opal_id,-OPAL_PCI_HOT_RESET,+OPAL_RESET_PCI_HOT,OPAL_ASSERT_RESET);elseif(option==EEH_RESET_DEACTIVATE)rc=opal_pci_reset(phb->opal_id,-OPAL_PCI_HOT_RESET,+OPAL_RESET_PCI_HOT,OPAL_DEASSERT_RESET);if(rc<0)gotoout;
@@ -697,7 +697,7 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)(option==EEH_RESET_HOT||option==EEH_RESET_FUNDAMENTAL)){rc=opal_pci_reset(phb->opal_id,-OPAL_PHB_ERROR,+OPAL_RESET_PHB_ERROR,OPAL_ASSERT_RESET);if(rc!=OPAL_SUCCESS){pr_warn("%s: Failure %lld clearing "
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 <redacted>
---
arch/powerpc/kernel/eeh.c | 58 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 16 deletions(-)
@@ -579,25 +579,51 @@ EXPORT_SYMBOL(eeh_check_failure);*/inteeh_pci_enable(structeeh_pe*pe,intfunction){-intrc,flags=(EEH_STATE_MMIO_ACTIVE|EEH_STATE_DMA_ACTIVE);+intactive_flag,rc;/**pHypdoesn'tallowtoenableIOorDMAonunfrozenPE.*Also,it'spointlesstoenablethemonunfrozenPE.So-*wehavethecheckhere.+*wehavetocheckbeforeenablingIOorDMA.*/-if(function==EEH_OPT_THAW_MMIO||-function==EEH_OPT_THAW_DMA){+switch(function){+caseEEH_OPT_THAW_MMIO:+active_flag=EEH_STATE_MMIO_ACTIVE;+break;+caseEEH_OPT_THAW_DMA:+active_flag=EEH_STATE_DMA_ACTIVE;+break;+caseEEH_OPT_DISABLE:+caseEEH_OPT_ENABLE:+caseEEH_OPT_FREEZE_PE:+active_flag=0;+break;+default:+pr_warn("%s: Invalid function %d\n",+__func__,function);+return-EINVAL;+}++/*+*CheckifIOorDMAhasbeenenabledbefore+*enablingthem.+*/+if(active_flag){rc=eeh_ops->get_state(pe,NULL);if(rc<0)returnrc;-/* Needn't to enable or already enabled */-if((rc==EEH_STATE_NOT_SUPPORT)||-((rc&flags)==flags))+/* Needn't enable it at all */+if(rc==EEH_STATE_NOT_SUPPORT)+return0;++/* It's already enabled */+if(rc&active_flag)return0;}++/* Issue the request */rc=eeh_ops->set_option(pe,function);if(rc)pr_warn("%s: Unexpected state change %d on "
@@ -605,17 +631,17 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)__func__,function,pe->phb->global_number,pe->addr,rc);-rc=eeh_ops->wait_state(pe,PCI_BUS_RESET_WAIT_MSEC);-if(rc<=0)-returnrc;+/* Check if the request is finished successfully */+if(active_flag){+rc=eeh_ops->wait_state(pe,PCI_BUS_RESET_WAIT_MSEC);+if(rc<=0)+returnrc;-if((function==EEH_OPT_THAW_MMIO)&&-(rc&EEH_STATE_MMIO_ENABLED))-return0;+if(rc&active_flag)+return0;-if((function==EEH_OPT_THAW_DMA)&&-(rc&EEH_STATE_DMA_ENABLED))-return0;+return-EIO;+}returnrc;}
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 <redacted>
---
arch/powerpc/kernel/eeh.c | 4 ++++
1 file changed, 4 insertions(+)
When enabling EEH functionality on passed through devices (PE)
with VFIO, the devices in the PE would be removed permanently
from guest side. In that case, the PE remains frozen state.
When returning PE to host, or restarting the guest again, we
had mechanism unfreezing the PE by clearing PESTA/B frozen
bits. However, that's not enough for some adapters, which are
indicated as following "lspci" shows. Those adapters require
hot reset on the parent bus to bring their firmware back to
workable state. Otherwise, those adaptrs won't be operative
and the host (for returning case) or the guest will fail to
load the drivers for those adapters without exception.
0000:01:00.0 Ethernet controller: Emulex Corporation OneConnect \
10Gb NIC (be3) (rev 02)
0000:01:00.0 0200: 19a2:0710 (rev 02)
0001:03:00.0 Ethernet controller: Emulex Corporation OneConnect \
NIC (Lancer) (rev 10)
0001:03:00.0 0200: 10df:e220 (rev 10)
The patch adds mechanism to emulate EEH recovery (for hot reset
on parent PCI bus) on 3 gates to fix the issue: open/release one
adapter of the PE, enable EEH functionality on one adapter of the
PE.
Reported-by: Murilo Fossa Vicentini <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh.c | 59 +++++++++++++++++++++++++-
arch/powerpc/kernel/eeh_driver.c | 90 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 144 insertions(+), 6 deletions(-)
@@ -1193,6 +1193,60 @@ int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state)returnret;}++staticstructpci_device_ideeh_reset_ids[]={+{PCI_DEVICE(0x19a2,0x0710)},/* Emulex, BE */+{PCI_DEVICE(0x10df,0xe220)},/* Emulex, Lancer */+{0}+};++staticinteeh_pe_change_owner(structeeh_pe*pe)+{+structeeh_dev*edev,*tmp;+structpci_dev*pdev;+structpci_device_id*id;+intflags,ret;++/* Check PE state */+flags=(EEH_STATE_MMIO_ACTIVE|EEH_STATE_DMA_ACTIVE);+ret=eeh_ops->get_state(pe,NULL);+if(ret<0||ret==EEH_STATE_NOT_SUPPORT)+return0;++/* Unfrozen PE, nothing to do */+if((ret&flags)==flags)+return0;++/* Frozen PE, check if it needs PE level reset */+eeh_pe_for_each_dev(pe,edev,tmp){+pdev=eeh_dev_to_pci_dev(edev);+if(!pdev)+continue;++for(id=&eeh_reset_ids[0];id->vendor!=0;id++){+if(id->vendor!=PCI_ANY_ID&&+id->vendor!=pdev->vendor)+continue;+if(id->device!=PCI_ANY_ID&&+id->device!=pdev->device)+continue;+if(id->subvendor!=PCI_ANY_ID&&+id->subvendor!=pdev->subsystem_vendor)+continue;+if(id->subdevice!=PCI_ANY_ID&&+id->subdevice!=pdev->subsystem_device)+continue;++gotoreset;+}+}++returneeh_unfreeze_pe(pe,true);++reset:+returneeh_pe_reset_and_recover(pe);+}+/***eeh_dev_open-IncreasecountofpassthroughdevicesforPE*@pdev:PCIdevice
@@ -1224,7 +1278,7 @@ int eeh_dev_open(struct pci_dev *pdev)*infrozenPEwon'tworkproperly.Clearthefrozenstate*inadvance.*/-ret=eeh_unfreeze_pe(edev->pe,true);+ret=eeh_pe_change_owner(edev->pe);if(ret)gotoout;
@@ -1345,7 +1400,7 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)switch(option){caseEEH_OPT_ENABLE:if(eeh_enabled()){-ret=eeh_unfreeze_pe(pe,true);+ret=eeh_pe_change_owner(pe);break;}ret=-EIO;
@@ -450,10 +482,11 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)staticvoid*__eeh_clear_pe_frozen_state(void*data,void*flag){structeeh_pe*pe=(structeeh_pe*)data;+bool*clear_sw_state=flag;inti,rc=1;for(i=0;rc&&i<3;i++)-rc=eeh_unfreeze_pe(pe,false);+rc=eeh_unfreeze_pe(pe,clear_sw_state);/* Stop immediately on any errors */if(rc){
@@ -465,17 +498,66 @@ static void *__eeh_clear_pe_frozen_state(void *data, void *flag)returnNULL;}-staticinteeh_clear_pe_frozen_state(structeeh_pe*pe)+staticinteeh_clear_pe_frozen_state(structeeh_pe*pe,+boolclear_sw_state){void*rc;-rc=eeh_pe_traverse(pe,__eeh_clear_pe_frozen_state,NULL);+rc=eeh_pe_traverse(pe,__eeh_clear_pe_frozen_state,&clear_sw_state);if(!rc)eeh_pe_state_clear(pe,EEH_PE_ISOLATED);returnrc?-EIO:0;}+inteeh_pe_reset_and_recover(structeeh_pe*pe)+{+intresult,ret;++/* Bail if the PE is being recovered */+if(pe->state&EEH_PE_RECOVERING)+return0;++/* Put the PE into recovery mode */+eeh_pe_state_mark(pe,EEH_PE_RECOVERING);++/* Save states */+eeh_pe_dev_traverse(pe,eeh_dev_save_state,NULL);++/* Report error */+eeh_pe_dev_traverse(pe,eeh_report_error,&result);++/* Issue reset */+eeh_pe_state_mark(pe,EEH_PE_RESET);+ret=eeh_reset_pe(pe);+if(ret){+eeh_pe_state_clear(pe,EEH_PE_RECOVERING|EEH_PE_RESET);+returnret;+}+eeh_pe_state_clear(pe,EEH_PE_RESET);++/* Unfreeze the PE */+ret=eeh_clear_pe_frozen_state(pe,true);+if(ret){+eeh_pe_state_clear(pe,EEH_PE_RECOVERING);+returnret;+}++/* Notify completion of reset */+eeh_pe_dev_traverse(pe,eeh_report_reset,&result);++/* Restore device state */+eeh_pe_dev_traverse(pe,eeh_dev_restore_state,NULL);++/* Resume */+eeh_pe_dev_traverse(pe,eeh_report_resume,NULL);++/* Clear recovery mode */+eeh_pe_state_clear(pe,EEH_PE_RECOVERING);++return0;+}+/***eeh_reset_device-Performactualresetofapcislot*@pe:EEHPE
@@ -534,7 +616,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)eeh_pe_state_clear(pe,EEH_PE_RESET);/* Clear frozen state */-rc=eeh_clear_pe_frozen_state(pe);+rc=eeh_clear_pe_frozen_state(pe,false);if(rc)returnrc;
PE would be owned by userland, which probably request PE reset
done in host side. During the reset, we should drop the PCI
config accesses to the PE with help of flag EEH_PE_RESET.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/eeh.c | 2 ++
1 file changed, 2 insertions(+)
@@ -1463,6 +1463,7 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)switch(option){caseEEH_RESET_DEACTIVATE:ret=eeh_ops->reset(pe,option);+eeh_pe_state_clear(pe,EEH_PE_RESET);if(ret)break;
@@ -1477,6 +1478,7 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)*/eeh_ops->set_option(pe,EEH_OPT_FREEZE_PE);+eeh_pe_state_mark(pe,EEH_PE_RESET);ret=eeh_ops->reset(pe,option);break;default:
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 <redacted>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh.c | 60 ++++++++++++++++++++++--------------------
2 files changed, 33 insertions(+), 28 deletions(-)
@@ -1338,8 +1340,10 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)*/switch(option){caseEEH_OPT_ENABLE:-if(eeh_enabled())+if(eeh_enabled()){+ret=eeh_unfreeze_pe(pe,true);break;+}ret=-EIO;break;caseEEH_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",
The PCI devices that have been passed through are enabled before
reset, we need restore to the enabled state after reset. Otherwise,
MMIO access might be issued to disabled devices after reset and
causes exceptional recursive EEH error.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/eeh.c | 62 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 48 insertions(+), 14 deletions(-)
@@ -1342,6 +1342,53 @@ int eeh_pe_get_state(struct eeh_pe *pe)}EXPORT_SYMBOL_GPL(eeh_pe_get_state);+staticinteeh_pe_reenable_devices(structeeh_pe*pe)+{+structeeh_dev*edev,*tmp;+structpci_dev*pdev;+intret=0;++/* Restore config space */+eeh_pe_restore_bars(pe);++/*+*ReenablePCIdevicesasthedevicespassed+*througharealwaysenabledbeforethereset.+*/+eeh_pe_for_each_dev(pe,edev,tmp){+pdev=eeh_dev_to_pci_dev(edev);+if(!pdev)+continue;++ret=pci_reenable_device(pdev);+if(ret){+pr_warn("%s: Failure %d reenabling %s\n",+__func__,ret,pci_name(pdev));+returnret;+}+}++/* 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);+returnret;+}++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);+returnret;+}++/* Clear software isolated state */+eeh_pe_state_clear(pe,EEH_PE_ISOLATED);++returnret;+}+/***eeh_pe_reset-IssuePEresetaccordingtospecifiedtype*@pe:EEHPE
@@ -1368,17 +1415,7 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)if(ret)break;-/*-*ThePEisstillinfrozenstateandweneedtoclear-*that.It'sgoodtoclearfrozenstateafterdeassert-*toavoidmessyIOaccessduringreset,whichmight-*causerecursivefrozenPE.-*/-ret=eeh_ops->set_option(pe,EEH_OPT_THAW_MMIO);-if(!ret)-ret=eeh_ops->set_option(pe,EEH_OPT_THAW_DMA);-if(!ret)-eeh_pe_state_clear(pe,EEH_PE_ISOLATED);+ret=eeh_pe_reenable_devices(pe);break;caseEEH_RESET_HOT:caseEEH_RESET_FUNDAMENTAL:
@@ -1417,9 +1454,6 @@ int eeh_pe_configure(struct eeh_pe *pe)if(!pe)return-ENODEV;-/* Restore config space for the affected devices */-eeh_pe_restore_bars(pe);-returnret;}EXPORT_SYMBOL_GPL(eeh_pe_configure);
The patch introduces eeh_ops::err_inject(), which allows to inject
specified errors to indicated PE for testing purpose. The functionality
isn't support on pSeries platform. On PowerNV, the functionality
relies on OPAL API opal_pci_err_inject().
Signed-off-by: Mike Qiu <redacted>
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/eeh.h | 2 ++
arch/powerpc/platforms/powernv/eeh-ioda.c | 44 ++++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/eeh-powernv.c | 26 ++++++++++++++++
arch/powerpc/platforms/powernv/pci.h | 2 ++
arch/powerpc/platforms/pseries/eeh_pseries.c | 1 +
5 files changed, 75 insertions(+)
Looking at all the other eeh sysfs files, they all use 0x%x. Which makes it
much clearer when you're looking at the file in userspace that the content is
hex.
Please send an incremental patch to change the format to 0x%08x, unless there's
a good reason not to.
cheers
Looking at all the other eeh sysfs files, they all use 0x%x. Which makes it
much clearer when you're looking at the file in userspace that the content is
hex.
Please send an incremental patch to change the format to 0x%08x, unless there's
a good reason not to.