This patch series aims at fixing some of the AER error handling issues
we have.
Currently we have the following issues:
- Confusing message in aer_print_error()
- aer_err_info not being initialized completely in DPC path before
we print the AER logs
- A bug [1] in clearing of AER registers in the native AER path
[1] https://lore.kernel.org/linux-pci/20151229155822.GA17321@localhost/
The primary aim of this patch series is to converge the APEI path and the
native AER error handling paths. In our current code, we find that we
have two different behaviours (especially when it comes to clearing of
the AER registers) for the same functionality.
This patch series, tries to bring the same semantics and hence more
commonanlity between the APEI part of code and the native OS
handling of AER errors.
PATCH 1:
- Fixes the first issue
PATCH 2 - 4:
- Fixes the second issue
- "Patch 3/8" is dependent on "Patch 2/8" in the series
PATCH 5 - 7
- Deals with converging the various paths and brings more
commonality between them
- "Patch 6/8" depends on "Patch 1/8"
PATCH 8:
- Adds extra information in AER error logs.
Thanks,
Naveen Naidu
Changelog
=========
v4:
- Implement review comments
- Make "Patch 1/8" commit message more meaningful
- Fix the code comment error detected by kernel test robot
in "Patch 6/8"
v2 and v3:
- Fix up mail formatting and include the appropriate receipients for
the patch.
Naveen Naidu (8):
[PATCH v4 1/8] PCI/AER: Remove ID from aer_agent_string[]
[PATCH v4 2/8] PCI: Cleanup struct aer_err_info
[PATCH v4 3/8] PCI/DPC: Initialize info->id in dpc_process_error()
[PATCH v4 4/8] PCI/DPC: Use pci_aer_clear_status() in dpc_process_error()
[PATCH v4 5/8] PCI/DPC: Converge EDR and DPC Path of clearing AER registers
[PATCH v4 6/8] PCI/AER: Clear error device AER registers in aer_irq()
[PATCH v4 7/8] PCI/ERR: Remove redundant clearing of AER register in pcie_do_recovery()
[PATCH v4 8/8] PCI/AER: Include DEVCTL in aer_print_error()
drivers/pci/pci.h | 23 +++-
drivers/pci/pcie/aer.c | 269 ++++++++++++++++++++++++++++-------------
drivers/pci/pcie/dpc.c | 9 +-
drivers/pci/pcie/err.c | 9 +-
4 files changed, 209 insertions(+), 101 deletions(-)
--
2.25.1
Currently, we do not print the "id" field in the AER error logs. Yet the
aer_agent_string[] has the word "id" in it. The AER error log looks
like:
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID)
Without the "id" field in the error log, The aer_agent_string[]
(eg: "Receiver ID") does not make sense. A user reading the
aer_agent_string[] in the log, might inadvertently look for an "id"
field and not finding it might lead to confusion.
Remove the "ID" from the aer_agent_string[].
The following are sample dummy errors inject via aer-inject.
Before
=======
In 010caed4ccb6 ("PCI/AER: Decode Error Source Requester ID"),
the "id" field was removed from the AER error logs, so currently AER
logs look like:
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03:0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID) <--- no id field
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
After
======
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03.0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver)
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/aer.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
The id, status and the mask fields of the struct aer_err_info comes
directly from the registers, hence their sizes should be explicit.
The length of these registers are:
- id: 16 bits - Represents the Error Source Requester ID
- status: 32 bits - COR/UNCOR Error Status
- mask: 32 bits - COR/UNCOR Error Mask
Since the length of the above registers are even, use u16 and u32
to represent their values.
Also remove the __pad fields.
"pahole" was run on the modified struct aer_err_info and the size
remains unchanged.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pci.h | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
In the dpc_process_error() path, info->id isn't initialized before being
passed to aer_print_error(). In the corresponding AER path, it is
initialized in aer_isr_one_error().
The error message shown during Coverity Scan is:
Coverity #1461602
CID 1461602 (#1 of 1): Uninitialized scalar variable (UNINIT)
8. uninit_use_in_call: Using uninitialized value info.id when calling aer_print_error.
Initialize the "info->id" before passing it to aer_print_error()
Fixes: 8aefa9b0d910 ("PCI/DPC: Print AER status in DPC event handling")
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
dpc_process_error() clears both AER fatal and non fatal status
registers. Instead of clearing each status registers via a different
function call use pci_aer_clear_status().
This helps clean up the code a bit.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
In the EDR path, AER registers are cleared *after* DPC error event is
processed. The process stack in EDR is:
edr_handle_event()
dpc_process_error()
pci_aer_raw_clear_status()
pcie_do_recovery()
But in DPC path, AER status registers are cleared *while* processing
the error. The process stack in DPC is:
dpc_handler()
dpc_process_error()
pci_aer_clear_status()
pcie_do_recovery()
In EDR path, AER status registers are cleared irrespective of whether
the error was an RP PIO or unmasked uncorrectable error. But in DPC, the
AER status registers are cleared only when it's an unmasked uncorrectable
error.
This leads to two different behaviours for the same task (handling of
DPC errors) in FFS systems and when native OS has control.
Bring the same semantics for clearing the AER status register in EDR
path and DPC path.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -297,6 +296,7 @@ static irqreturn_t dpc_handler(int irq, void *context)structpci_dev*pdev=context;dpc_process_error(pdev);+pci_aer_clear_status(pdev);/* We configure DPC so it only triggers on ERR_FATAL */pcie_do_recovery(pdev,pci_channel_io_frozen,dpc_reset_link);
Converge the APEI path and native AER path of clearing the AER registers
of the error device.
In APEI path, the system firmware clears the AER registers before
handing off the record to OS. But in "native AER" path, the execution
path of clearing the AER register is as follows:
aer_isr_one_error
aer_print_port_info
if (find_source_device())
aer_process_err_devices
handle_error_source
pci_write_config_dword(dev, PCI_ERR_COR_STATUS, ...)
The above path has a bug, if the find_source_device() fails, AER
registers are not cleared from the error device. This means, the error
device will keep reporting the error again and again and would lead
to message spew.
Related Bug Report:
https://lore.kernel.org/linux-pci/20151229155822.GA17321@localhost/https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1521173
The above bug could be avoided, if the AER registers are cleared during
the AER IRQ handler aer_irq(), which would provide guarantee that the AER
error registers are always cleared. This is similar to how APEI handles
these errors.
The main aim is that:
When an interrupt handler deals with a interrupt, it must *always*
clear the source of the interrupt.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pci.h | 13 ++-
drivers/pci/pcie/aer.c | 249 ++++++++++++++++++++++++++++-------------
2 files changed, 184 insertions(+), 78 deletions(-)
@@ -424,7 +424,6 @@ static inline bool pci_dev_is_added(const struct pci_dev *dev)#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */structaer_err_info{-structpci_dev*dev[AER_MAX_MULTI_ERR_DEVICES];interror_dev_num;u16id;
@@ -440,6 +439,18 @@ struct aer_err_info {structaer_header_log_regstlp;/* TLP Header */};+/* Preliminary AER error information processed from Root port */+structaer_devices_err_info{+structpci_dev*dev[AER_MAX_MULTI_ERR_DEVICES];+structaer_err_infoerr_info;+};++/* AER information associated with each error device */+structaer_dev_err_info{+structpci_dev*dev;+structaer_err_infoerr_info;+};+intaer_get_device_error_info(structpci_dev*dev,structaer_err_info*info);voidaer_print_error(structpci_dev*dev,structaer_err_info*info);#endif /* CONFIG_PCIEAER */
@@ -36,6 +36,18 @@#define AER_ERROR_SOURCES_MAX 128+/*+*Therecanbe128maximumerrorsources(AER_ERROR_SOURCES_MAX)andeach+*errorsourcecanhavemaximumof5errordevices(AER_MAX_MULTI_ERR_DEVICES)+*sothemaximumerrordeviceswecanreportis:+*+*AER_ERROR_DEVICES_MAX=AER_ERROR_SOURCES_MAX*AER_MAX_MULTI_ERR_DEVICES==(128*5)==640+*+*Butsince,thesizeinKFIFOshouldbeapoweroftwo,theclosestvalue+*to640is1024+*/+# define AER_ERROR_DEVICES_MAX 1024+#define AER_MAX_TYPEOF_COR_ERRS 16 /* as per PCI_ERR_COR_STATUS */#define AER_MAX_TYPEOF_UNCOR_ERRS 27 /* as per PCI_ERR_UNCOR_STATUS*/
@@ -46,7 +58,7 @@ struct aer_err_source {structaer_rpc{structpci_dev*rpd;/* Root Port device */-DECLARE_KFIFO(aer_fifo,structaer_err_source,AER_ERROR_SOURCES_MAX);+DECLARE_KFIFO(aer_fifo,structaer_dev_err_info,AER_ERROR_DEVICES_MAX);};/* AER stats for the device */
@@ -803,14 +815,14 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,/***add_error_device-listdevicetobehandled-*@e_info:pointertoerrorinfo+*@e_dev:pointertoerrorinfo*@dev:pointertopci_devtobeadded*/-staticintadd_error_device(structaer_err_info*e_info,structpci_dev*dev)+staticintadd_error_device(structaer_devices_err_info*e_dev,structpci_dev*dev){-if(e_info->error_dev_num<AER_MAX_MULTI_ERR_DEVICES){-e_info->dev[e_info->error_dev_num]=pci_dev_get(dev);-e_info->error_dev_num++;+if(e_dev->err_info.error_dev_num<AER_MAX_MULTI_ERR_DEVICES){+e_dev->dev[e_dev->err_info.error_dev_num]=pci_dev_get(dev);+e_dev->err_info.error_dev_num++;return0;}return-ENOSPC;
@@ -877,18 +889,18 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)staticintfind_device_iter(structpci_dev*dev,void*data){-structaer_err_info*e_info=(structaer_err_info*)data;+structaer_devices_err_info*e_dev=(structaer_devices_err_info*)data;-if(is_error_source(dev,e_info)){+if(is_error_source(dev,&e_dev->err_info)){/* List this device */-if(add_error_device(e_info,dev)){+if(add_error_device(e_dev,dev)){/* We cannot handle more... Stop iteration *//* TODO: Should print error message here? */return1;}/* If there is only a single error, stop iteration */-if(!e_info->multi_error_valid)+if(!e_dev->err_info.multi_error_valid)return1;}return0;
@@ -907,26 +919,26 @@ static int find_device_iter(struct pci_dev *dev, void *data)*e_info->error_dev_numande_info->dev[],basedonthegiveninformation.*/staticboolfind_source_device(structpci_dev*parent,-structaer_err_info*e_info)+structaer_devices_err_info*e_dev){structpci_dev*dev=parent;intresult;/* Must reset in this function */-e_info->error_dev_num=0;+e_dev->err_info.error_dev_num=0;/* Is Root Port an agent that sends error message? */-result=find_device_iter(dev,e_info);+result=find_device_iter(dev,e_dev);if(result)returntrue;if(pci_pcie_type(parent)==PCI_EXP_TYPE_RC_EC)-pcie_walk_rcec(parent,find_device_iter,e_info);+pcie_walk_rcec(parent,find_device_iter,e_dev);else-pci_walk_bus(parent->subordinate,find_device_iter,e_info);+pci_walk_bus(parent->subordinate,find_device_iter,e_dev);-if(!e_info->error_dev_num){-pci_info(parent,"can't find device of ID%04x\n",e_info->id);+if(!e_dev->err_info.error_dev_num){+pci_info(parent,"can't find device of ID%04x\n",e_dev->err_info.id);returnfalse;}returntrue;
@@ -1093,70 +1123,112 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)return1;}-staticinlinevoidaer_process_err_devices(structaer_err_info*e_info)-{-inti;--/* Report all before handle them, not to lost records by reset etc. */-for(i=0;i<e_info->error_dev_num&&e_info->dev[i];i++){-if(aer_get_device_error_info(e_info->dev[i],e_info))-aer_print_error(e_info->dev[i],e_info);-}-for(i=0;i<e_info->error_dev_num&&e_info->dev[i];i++){-if(aer_get_device_error_info(e_info->dev[i],e_info))-handle_error_source(e_info->dev[i],e_info);-}-}-/**-*aer_isr_one_error-consumeanerrordetectedbyrootport-*@rpc:pointertotherootportwhichholdsanerror+*aer_find_corr_error_source_device-findtheerrorsourcewhichdetectedthecorrectederror+*@rp:pointertoRootPortpci_devdatastructure*@e_src:pointertoanerrorsource+*@e_info:includingdetailederrorinformationsuchlikeid+*+*Returntrueiffound.+*+*ProcesstheerrorinformationreceivedattheRootPort,setthesevalues+*intheaer_devices_err_infoandfindallthedevicesthatarerelatedto+*theerror.*/-staticvoidaer_isr_one_error(structaer_rpc*rpc,-structaer_err_source*e_src)+staticboolaer_find_corr_error_source_device(structpci_dev*rp,+structaer_err_source*e_src,+structaer_devices_err_info*e_info){-structpci_dev*pdev=rpc->rpd;-structaer_err_infoe_info;--pci_rootport_aer_stats_incr(pdev,e_src);--/*-*Thereisapossibilitythatbothcorrectableerrorand-*uncorrectableerrorbeinglogged.Reportcorrectableerrorfirst.-*/if(e_src->status&PCI_ERR_ROOT_COR_RCV){-e_info.id=ERR_COR_ID(e_src->id);-e_info.severity=AER_CORRECTABLE;+e_info->err_info.id=ERR_COR_ID(e_src->id);+e_info->err_info.severity=AER_CORRECTABLE;if(e_src->status&PCI_ERR_ROOT_MULTI_COR_RCV)-e_info.multi_error_valid=1;+e_info->err_info.multi_error_valid=1;else-e_info.multi_error_valid=0;-aer_print_port_info(pdev,&e_info);+e_info->err_info.multi_error_valid=0;-if(find_source_device(pdev,&e_info))-aer_process_err_devices(&e_info);+if(!find_source_device(rp,e_info))+returnfalse;}+returntrue;+}+/**+*aer_find_uncorr_error_source_device-findtheerrorsourcewhichdetectedtheuncorrectederror+*@rp:pointertoRootPortpci_devdatastructure+*@e_src:pointertoanerrorsource+*@e_info:includingdetailederrorinformationsuchlikeid+*+*Returntrueiffound.+*+*ProcesstheerrorinformationreceivedattheRootPort,setthesevalues+*intheaer_devices_err_infoandfindallthedevicesthatarerelatedto+*theerror.+*/+staticboolaer_find_uncorr_error_source_device(structpci_dev*rp,+structaer_err_source*e_src,+structaer_devices_err_info*e_info)+{if(e_src->status&PCI_ERR_ROOT_UNCOR_RCV){-e_info.id=ERR_UNCOR_ID(e_src->id);+e_info->err_info.id=ERR_UNCOR_ID(e_src->id);if(e_src->status&PCI_ERR_ROOT_FATAL_RCV)-e_info.severity=AER_FATAL;+e_info->err_info.severity=AER_FATAL;else-e_info.severity=AER_NONFATAL;+e_info->err_info.severity=AER_NONFATAL;if(e_src->status&PCI_ERR_ROOT_MULTI_UNCOR_RCV)-e_info.multi_error_valid=1;+e_info->err_info.multi_error_valid=1;else-e_info.multi_error_valid=0;+e_info->err_info.multi_error_valid=0;++if(!find_source_device(rp,e_info))+returnfalse;+}-aer_print_port_info(pdev,&e_info);+returntrue;+}-if(find_source_device(pdev,&e_info))-aer_process_err_devices(&e_info);+/**+*aer_isr_one_error-consumeanerrordetectedbyrootport+*@rp:pointertoRootPortpci_devdatastructure+*@e_dev:pointertoanerrordevice+*/+staticvoidaer_isr_one_error(structpci_dev*rp,structaer_dev_err_info*e_dev)+{+aer_print_port_info(rp,&e_dev->err_info);+aer_print_error(e_dev->dev,&e_dev->err_info);+handle_error_source(e_dev->dev,&e_dev->err_info);+}++staticboolaer_add_err_devices_to_queue(structaer_rpc*rpc,+structaer_devices_err_info*e_info)+{+inti;+structaer_dev_err_info*e_dev;++e_dev=kzalloc(sizeof(*e_dev),GFP_ATOMIC);+if(!e_dev)+returnfalse;++for(i=0;i<e_info->err_info.error_dev_num&&e_info->dev[i];i++){+e_dev->err_info=e_info->err_info;+e_dev->dev=e_info->dev[i];++/*+*StoretheAERregisterinformationforeacherrordeviceon+*thequeue+*/+if(aer_get_device_error_info(e_dev->dev,&e_dev->err_info)){+if(!kfifo_put(&rpc->aer_fifo,*e_dev))+returnfalse;++clear_error_source_aer_registers(e_dev->dev,e_dev->err_info);+}}++returntrue;}/**
pcie_do_recovery() is shared across the following paths:
- ACPI APEI
- Native AER path
- EDR
- DPC
ACPI APEI
==========
ghes_handle_aer()
aer_recover_queue()
kfifo_in_spinlocked(aer_recover_ring)
aer_recover_work_func()
while (kfifo_get(aer_recover_ring))
pcie_do_recovery()
In this path the system firmware clears the AER registers before
handing off the record to the OS in ghes_handle_aer()
Native AER
==========
aer_irq()
aer_add_err_devices_to_queue()
kfifo_put(&rpc->aer_fifo, *e_dev)
clear_error_source_aer_registers() <---- AER registers are cleard
aer_isr()
aer_isr_one_error()
handle_error_source()
pcie_do_recovery()
The AER registers are cleared during the handling of IRQ, i.e before we
the recovery starts.
DPC
=====
dpc_handler()
dpc_process_error()
pci_aer_clear_status() <---- AER registers are cleared
pcie_do_recovery()
EDR
====
edr_handle_event()
dpc_process_error()
pci_aer_raw_clear_status() <---- AER registers are cleared
pcie_do_recovery()
In all the above paths, the AER registers are cleared before
pcie_do_recovery(). The non fatal status AER registers are again cleared
in pcie_do_recovery(). This is redundant.
Remove redundant clearing of AER register in pcie_do_recovery()
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/err.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
On Tue, Oct 05, 2021 at 10:48:10PM +0530, Naveen Naidu wrote:
quoted hunk
In the dpc_process_error() path, info->id isn't initialized before being
passed to aer_print_error(). In the corresponding AER path, it is
initialized in aer_isr_one_error().
The error message shown during Coverity Scan is:
Coverity #1461602
CID 1461602 (#1 of 1): Uninitialized scalar variable (UNINIT)
8. uninit_use_in_call: Using uninitialized value info.id when calling aer_print_error.
Initialize the "info->id" before passing it to aer_print_error()
Fixes: 8aefa9b0d910 ("PCI/DPC: Print AER status in DPC event handling")
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
Per PCIe r5.0, sec 7.9.15.5, the Source ID is defined only when the
Trigger Reason indicates ERR_NONFATAL or ERR_FATAL. So I think we
need to extract this reason before reading PCI_EXP_DPC_SOURCE_ID,
e.g.,
reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
if (reason == 1 || reason == 2)
pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &info.id);
else
info.id = 0;
On Tue, Oct 05, 2021 at 10:48:08PM +0530, Naveen Naidu wrote:
Currently, we do not print the "id" field in the AER error logs. Yet the
aer_agent_string[] has the word "id" in it. The AER error log looks
like:
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID)
Without the "id" field in the error log, The aer_agent_string[]
(eg: "Receiver ID") does not make sense. A user reading the
aer_agent_string[] in the log, might inadvertently look for an "id"
field and not finding it might lead to confusion.
Remove the "ID" from the aer_agent_string[].
The following are sample dummy errors inject via aer-inject.
I like this, and the problem it fixes was my fault because
these "ID" strings should have been removed by 010caed4ccb6.
If it's straightforward enough, it would be nice to have the
aer-inject command line here in the commit log to make it easier
for people to play with this.
quoted hunk
Before
=======
In 010caed4ccb6 ("PCI/AER: Decode Error Source Requester ID"),
the "id" field was removed from the AER error logs, so currently AER
logs look like:
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03:0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID) <--- no id field
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
After
======
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03.0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver)
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/aer.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
On Tue, Oct 05, 2021 at 10:48:11PM +0530, Naveen Naidu wrote:
quoted hunk
dpc_process_error() clears both AER fatal and non fatal status
registers. Instead of clearing each status registers via a different
function call use pci_aer_clear_status().
This helps clean up the code a bit.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
The commit log suggests that this is a simple cleanup that doesn't
change any behavior, but that's not quite true:
- The new code would clear PCI_ERR_ROOT_STATUS, but the old code
does not.
- The old code masks the status bits with the severity bits before
clearing, but the new code does not.
The commit log needs to show why these changes are what we want.
[+cc Keith, Sinan, Oza]
On Tue, Oct 05, 2021 at 10:48:12PM +0530, Naveen Naidu wrote:
In the EDR path, AER registers are cleared *after* DPC error event is
processed. The process stack in EDR is:
edr_handle_event()
dpc_process_error()
pci_aer_raw_clear_status()
pcie_do_recovery()
But in DPC path, AER status registers are cleared *while* processing
the error. The process stack in DPC is:
dpc_handler()
dpc_process_error()
pci_aer_clear_status()
pcie_do_recovery()
These are accurate but they both include dpc_process_error(), so we
need a hint to show why the one here is different from the one in the
EDR path, e.g.,
dpc_handler
dpc_process_error
if (reason == 0)
pci_aer_clear_status # uncorrectable errors only
pcie_do_recovery
In EDR path, AER status registers are cleared irrespective of whether
the error was an RP PIO or unmasked uncorrectable error. But in DPC, the
AER status registers are cleared only when it's an unmasked uncorrectable
error.
This leads to two different behaviours for the same task (handling of
DPC errors) in FFS systems and when native OS has control.
FFS?
I'd really like to have a specific example of how a user would observe
this difference. I know you probably don't have two systems to
compare like that, but maybe we can work it out manually.
I guess you're saying the problem is in the native DPC handling, and
we don't clear the AER status registers for ERR_NONFATAL,
ERR_NONFATAL, etc., right?
I think the current behavior is from 8aefa9b0d910 ("PCI/DPC: Print AER
status in DPC event handling"), where Keith explicitly mentions those
cases. The commit log here should connect back to that and explain
whether something has changed.
I cc'd Keith and the reviewers of that change in case any of them have
time to dig into this again.
quoted hunk
Bring the same semantics for clearing the AER status register in EDR
path and DPC path.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -297,6 +296,7 @@ static irqreturn_t dpc_handler(int irq, void *context)structpci_dev*pdev=context;dpc_process_error(pdev);+pci_aer_clear_status(pdev);/* We configure DPC so it only triggers on ERR_FATAL */pcie_do_recovery(pdev,pci_channel_io_frozen,dpc_reset_link);
--
2.25.1
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees
On Tue, Oct 05, 2021 at 10:48:08PM +0530, Naveen Naidu wrote:
quoted
Currently, we do not print the "id" field in the AER error logs. Yet the
aer_agent_string[] has the word "id" in it. The AER error log looks
like:
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID)
Without the "id" field in the error log, The aer_agent_string[]
(eg: "Receiver ID") does not make sense. A user reading the
aer_agent_string[] in the log, might inadvertently look for an "id"
field and not finding it might lead to confusion.
Remove the "ID" from the aer_agent_string[].
The following are sample dummy errors inject via aer-inject.
I like this, and the problem it fixes was my fault because
these "ID" strings should have been removed by 010caed4ccb6.
If it's straightforward enough, it would be nice to have the
aer-inject command line here in the commit log to make it easier
for people to play with this.
Thank you for the review. Do you mean something like:
The following sample dummy errors are injected via aer-inject via the
following steps:
1. The steps to compile the aer-inject tool is mentioned in (Section
4. Software error inject) of the document [1]
[1]: https://www.kernel.org/doc/Documentation/PCI/pcieaer-howto.txt
Make sure to place the aer-inject executable at the home directory
of the qemu system or at any other place.
2. Emulate a PCIE architecture using qemu, A sample looks like
following:
qemu-system-x86_64 -kernel ../linux/arch/x86_64/boot/bzImage \
-initrd buildroot-build/images/rootfs.cpio.gz \
-append "console=ttyS0" \
-enable-kvm -nographic \
-M q35 \
-device pcie-root-port,bus=pcie.0,id=rp1,slot=1 \
-device pcie-pci-bridge,id=br1,bus=rp1 \
-device e1000,bus=br1,addr=8
Note that the PCIe features are available only when using the
'q35' Machine [2]
[2]: https://github.com/qemu/qemu/blob/master/docs/pcie.txt
3. Once the qemu system starts up, create a sample aer-file or use any
example aer file from [3]
[3]:
https://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/aer-inject.git/tree/examples
4. Inject any aer-error using
./aer-inject aer-file
This does look a tad bit longer for a commit log so I am unsure if you
would like to have it there. If you are okay with it, I would be happy
to add it to that :)
quoted
Before
=======
In 010caed4ccb6 ("PCI/AER: Decode Error Source Requester ID"),
the "id" field was removed from the AER error logs, so currently AER
logs look like:
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03:0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID) <--- no id field
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
After
======
pcieport 0000:00:03.0: AER: Corrected error received: 0000:00:03.0
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver)
pcieport 0000:00:03.0: device [1b36:000c] error status/mask=00000040/0000e000
pcieport 0000:00:03.0: [ 6] BadTLP
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/aer.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
On Tue, Oct 05, 2021 at 10:48:10PM +0530, Naveen Naidu wrote:
quoted
In the dpc_process_error() path, info->id isn't initialized before being
passed to aer_print_error(). In the corresponding AER path, it is
initialized in aer_isr_one_error().
The error message shown during Coverity Scan is:
Coverity #1461602
CID 1461602 (#1 of 1): Uninitialized scalar variable (UNINIT)
8. uninit_use_in_call: Using uninitialized value info.id when calling aer_print_error.
Initialize the "info->id" before passing it to aer_print_error()
Fixes: 8aefa9b0d910 ("PCI/DPC: Print AER status in DPC event handling")
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
Per PCIe r5.0, sec 7.9.15.5, the Source ID is defined only when the
Trigger Reason indicates ERR_NONFATAL or ERR_FATAL. So I think we
need to extract this reason before reading PCI_EXP_DPC_SOURCE_ID,
e.g.,
reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
if (reason == 1 || reason == 2)
pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &info.id);
else
info.id = 0;
Thank you for the review, I'll make this change when I send a v5 for the
patch series.
On Tue, Oct 05, 2021 at 10:48:11PM +0530, Naveen Naidu wrote:
quoted
dpc_process_error() clears both AER fatal and non fatal status
registers. Instead of clearing each status registers via a different
function call use pci_aer_clear_status().
This helps clean up the code a bit.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
The commit log suggests that this is a simple cleanup that doesn't
change any behavior, but that's not quite true:
- The new code would clear PCI_ERR_ROOT_STATUS, but the old code
does not.
- The old code masks the status bits with the severity bits before
clearing, but the new code does not.
The commit log needs to show why these changes are what we want.
Reading through the code again, I realize how wrong(stupid) I was when
making this patch. I was thinking that:
pci_aer_clear_status() = pci_aer_clear_fatal_status() + pci_aer_clear_nonfatal_status()
Now I understand, that it is not at all the case. I apologize for the
mistake. I'll make sure to be meticulous while reading functions and not
just assume their behaviour just from their function names.
I'll drop this patch in the next version of the patch series I make.
Apologies again ^^'
[+cc Keith, Sinan, Oza]
On Tue, Oct 05, 2021 at 10:48:12PM +0530, Naveen Naidu wrote:
quoted
In the EDR path, AER registers are cleared *after* DPC error event is
processed. The process stack in EDR is:
edr_handle_event()
dpc_process_error()
pci_aer_raw_clear_status()
pcie_do_recovery()
But in DPC path, AER status registers are cleared *while* processing
the error. The process stack in DPC is:
dpc_handler()
dpc_process_error()
pci_aer_clear_status()
pcie_do_recovery()
These are accurate but they both include dpc_process_error(), so we
need a hint to show why the one here is different from the one in the
EDR path, e.g.,
dpc_handler
dpc_process_error
if (reason == 0)
pci_aer_clear_status # uncorrectable errors only
pcie_do_recovery
quoted
In EDR path, AER status registers are cleared irrespective of whether
the error was an RP PIO or unmasked uncorrectable error. But in DPC, the
AER status registers are cleared only when it's an unmasked uncorrectable
error.
This leads to two different behaviours for the same task (handling of
DPC errors) in FFS systems and when native OS has control.
FFS?
Firmware First Systems
I'd really like to have a specific example of how a user would observe
this difference. I know you probably don't have two systems to
compare like that, but maybe we can work it out manually.
Apologies again! Reading through the code again and the specification, I
realize that my understanding was very incorrect at the time of making
this patch. I grossly oversimplified EDR and DPC when I was learning
about it.
I'll drop this patch when I send the v5 for the series.
Apologies again ^^'
I guess you're saying the problem is in the native DPC handling, and
we don't clear the AER status registers for ERR_NONFATAL,
ERR_NONFATAL, etc., right?
But yes, I did have this question though (I wasn't able to find the
answers to it when reading the spec). Why do we not clear the entire
ERR_NONFATAL and ERR_FATAL registers in the DPC path just like EDR does
using the pci_aer_raw_clear_status() before going to pcie_do_recovery()
I am sure I might have missed something in the spec. I guess I'll
look/re-read these bits again.
Thanks for the review :)
I think the current behavior is from 8aefa9b0d910 ("PCI/DPC: Print AER
status in DPC event handling"), where Keith explicitly mentions those
cases. The commit log here should connect back to that and explain
whether something has changed.
I cc'd Keith and the reviewers of that change in case any of them have
time to dig into this again.
quoted
Bring the same semantics for clearing the AER status register in EDR
path and DPC path.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -297,6 +296,7 @@ static irqreturn_t dpc_handler(int irq, void *context)structpci_dev*pdev=context;dpc_process_error(pdev);+pci_aer_clear_status(pdev);/* We configure DPC so it only triggers on ERR_FATAL */pcie_do_recovery(pdev,pci_channel_io_frozen,dpc_reset_link);
--
2.25.1
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees
On Thu, Oct 21, 2021 at 10:00:21PM +0530, Naveen Naidu wrote:
On 20/10, Bjorn Helgaas wrote:
quoted
On Tue, Oct 05, 2021 at 10:48:08PM +0530, Naveen Naidu wrote:
quoted
Currently, we do not print the "id" field in the AER error logs. Yet the
aer_agent_string[] has the word "id" in it. The AER error log looks
like:
pcieport 0000:00:03.0: PCIe Bus Error: severity=Corrected, type=Data Link Layer, (Receiver ID)
Without the "id" field in the error log, The aer_agent_string[]
(eg: "Receiver ID") does not make sense. A user reading the
aer_agent_string[] in the log, might inadvertently look for an "id"
field and not finding it might lead to confusion.
Remove the "ID" from the aer_agent_string[].
The following are sample dummy errors inject via aer-inject.
I like this, and the problem it fixes was my fault because
these "ID" strings should have been removed by 010caed4ccb6.
If it's straightforward enough, it would be nice to have the
aer-inject command line here in the commit log to make it easier
for people to play with this.
Thank you for the review. Do you mean something like:
The following sample dummy errors are injected via aer-inject via the
following steps:
1. The steps to compile the aer-inject tool is mentioned in (Section
4. Software error inject) of the document [1]
[1]: https://www.kernel.org/doc/Documentation/PCI/pcieaer-howto.txt
Make sure to place the aer-inject executable at the home directory
of the qemu system or at any other place.
2. Emulate a PCIE architecture using qemu, A sample looks like
following:
qemu-system-x86_64 -kernel ../linux/arch/x86_64/boot/bzImage \
-initrd buildroot-build/images/rootfs.cpio.gz \
-append "console=ttyS0" \
-enable-kvm -nographic \
-M q35 \
-device pcie-root-port,bus=pcie.0,id=rp1,slot=1 \
-device pcie-pci-bridge,id=br1,bus=rp1 \
-device e1000,bus=br1,addr=8
Note that the PCIe features are available only when using the
'q35' Machine [2]
[2]: https://github.com/qemu/qemu/blob/master/docs/pcie.txt
3. Once the qemu system starts up, create a sample aer-file or use any
example aer file from [3]
[3]:
https://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/aer-inject.git/tree/examples
4. Inject any aer-error using
./aer-inject aer-file
This does look a tad bit longer for a commit log so I am unsure if you
would like to have it there. If you are okay with it, I would be happy
to add it to that :)
Yes, that's kind of long. Something like this
https://git.kernel.org/linus/d95f20c4f070 would be enough for the
commit log, especially since you've now provided all the details in
the email thread, where we can find them via the Link: tag.
Bjorn
On Thu, Oct 21, 2021 at 10:06:11PM +0530, Naveen Naidu wrote:
On 20/10, Bjorn Helgaas wrote:
quoted
On Tue, Oct 05, 2021 at 10:48:11PM +0530, Naveen Naidu wrote:
quoted
dpc_process_error() clears both AER fatal and non fatal status
registers. Instead of clearing each status registers via a different
function call use pci_aer_clear_status().
This helps clean up the code a bit.
Signed-off-by: Naveen Naidu <redacted>
---
drivers/pci/pcie/dpc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
The commit log suggests that this is a simple cleanup that doesn't
change any behavior, but that's not quite true:
- The new code would clear PCI_ERR_ROOT_STATUS, but the old code
does not.
- The old code masks the status bits with the severity bits before
clearing, but the new code does not.
The commit log needs to show why these changes are what we want.
Reading through the code again, I realize how wrong(stupid) I was when
making this patch. I was thinking that:
pci_aer_clear_status() = pci_aer_clear_fatal_status() + pci_aer_clear_nonfatal_status()
Now I understand, that it is not at all the case. I apologize for the
mistake. I'll make sure to be meticulous while reading functions and not
just assume their behaviour just from their function names.
No problem, one could argue that the collection of pci_aer_clear_*()
functions that do slightly different things is itself a defect.
On Thu, Oct 21, 2021 at 10:23:30PM +0530, Naveen Naidu wrote:
On 20/10, Bjorn Helgaas wrote:
quoted
On Tue, Oct 05, 2021 at 10:48:12PM +0530, Naveen Naidu wrote:
quoted
quoted
In EDR path, AER status registers are cleared irrespective of whether
the error was an RP PIO or unmasked uncorrectable error. But in DPC, the
AER status registers are cleared only when it's an unmasked uncorrectable
error.
This leads to two different behaviours for the same task (handling of
DPC errors) in FFS systems and when native OS has control.
FFS?
Firmware First Systems
I assumed that's what it was, but it's helpful to use the same terms
used by the specs to make things easier to find. I don't think it's
actually the case that "Firmware First" necessary applies to the
entire system, since the ACPI FIRMWARE_FIRST flag is a per-error
source thing, not a per-system thing.