Address error and recovery for AER and DPC
v4 cover Address error and recovery for AER and DPC
This patch set brings in error handling support for DPC
The current implementation of AER and error message broadcasting to the EP driver is tightly coupled and limited to AER service driver. It is important to factor out broadcasting and other link handling callbacks. So that not only when AER gets triggered, but also when DPC get triggered (for e.g. ERR_FATAL), callbacks are handled appropriately.
DPC should enumerate the devices after recovering the link, which is achieved by implementing error_resume callback.
Changes since v3:
Bjorn's comments incorporated.
> Made separate patch renaming generic pci_err.c
> Introduce pci_err.h to contain all the error types and recovery > removed all the dependencies on pci.h
Changes since v2:
Based on feedback from Keith:
"
When DPC is triggered due to receipt of an uncorrectable error Message, the Requester ID from the Message is recorded in the DPC Error Source ID register and that Message is discarded and not forwarded Upstream. "
Removed the patch where AER checks if DPC service is active
Changes since v1:
Kbuild errors fixed:
> pci_find_dpc_dev made static
> ras_event.h updated
> pci_find_aer_service call with CONFIG check > pci_find_dpc_service call with CONFIG check
Oza Pawandeep (4):
PCI/AER: factor out error reporting from AER PCI/DPC/AER: Address Concurrency between AER and DPC PCI/ERR: Do not do recovery if DPC service is active PCI/DPC: Enumerate the devices after DPC trigger event
drivers/acpi/apei/ghes.c | 2 +- drivers/pci/pcie/Makefile | 2 +- drivers/pci/pcie/aer/aerdrv.h | 30 --- drivers/pci/pcie/aer/aerdrv_core.c | 306 +------------------------ drivers/pci/pcie/aer/aerdrv_errprint.c | 27 ++- drivers/pci/pcie/pcie-dpc.c | 127 ++++++++++- drivers/pci/pcie/pcie-err.c | 399 +++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 2 + include/linux/aer.h | 4 - include/linux/pci.h | 23 ++ include/ras/ras_event.h | 6 +- 11 files changed, 579 insertions(+), 349 deletions(-) create mode 100644 drivers/pci/pcie/pcie-err.c
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v4 1/5 PCI/AER: factor out error reporting from AER
This patch factors out error reporting callbacks, which are currently tightly coupled with AER.
DPC should be able to register callbacks and attmept recovery when DPC trigger event occurs.
drivers/pci/pcie/Makefile +1 -1
@@ -6,7 +6,7 @@ # Build PCI Express ASPM if needed obj-$(CONFIG_PCIEASPM) += aspm.o -pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o +pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o pcie-err.o pcieportdrv-$(CONFIG_ACPI) += portdrv_acpi.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
drivers/pci/pcie/aer/aerdrv.h +0 -30
@@ -76,36 +76,6 @@ struct aer_rpc {*/ }; -struct aer_broadcast_data { -enum pci_channel_state state; -enum pci_ers_result result; -}; - -static inline pci_ers_result_t merge_result (enum pci_ers_result orig, -enum pci_ers_result new) -{ -if (new ==PCI_ERS_RESULT_NO_AER_DRIVER ) -return PCI_ERS_RESULT_NO_AER_DRIVER ; - -if (new ==PCI_ERS_RESULT_NONE ) -return orig; - -switch (orig) { -case PCI_ERS_RESULT_CAN_RECOVER : -case PCI_ERS_RESULT_RECOVERED : - orig = new; -break ; -case PCI_ERS_RESULT_DISCONNECT : -if (new ==PCI_ERS_RESULT_NEED_RESET ) - orig =PCI_ERS_RESULT_NEED_RESET ; -break ; -default : -break ; - } - -return orig; -} -extern struct bus_type pcie_port_bus_type;void aer_isr (struct work_struct *work);void aer_print_error (struct pci_dev *dev,struct aer_err_info *info);
drivers/pci/pcie/aer/aerdrv_core.c +2 -286
306 lines not on this page · raw message
drivers/pci/pcie/pcie-err.c new file +334 -0
334 lines not on this page · raw message
drivers/pci/pcie/portdrv.h +1 -0
@@ -79,4 +79,5 @@ static inline void pcie_port_platform_notify(struct pci_dev *port, int *mask)static inline void pcie_port_platform_notify (struct pci_dev *port,int *mask){}#endif /* !CONFIG_ACPI */ +struct pcie_port_service_driver *pci_find_aer_service (struct pci_dev *dev);#endif /* _PORTDRV_H_ */
include/linux/aer.h +3 -3
@@ -11,9 +11,9 @@#include <linux/errno.h> #include <linux/types.h> -#define AER_NONFATAL 0 -#define AER_FATAL 1 -#define AER_CORRECTABLE 2 +#define AER_NONFATAL 0 +#define AER_FATAL 1 +#define AER_CORRECTABLE 2struct pci_dev ;
include/linux/pci.h +2 -0
@@ -1998,6 +1998,8 @@ static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resvoid pci_hp_remove_module_link (struct pci_slot *pci_slot);#endif +void do_recovery (struct pci_dev *dev,int severity); +/** * pci_pcie_cap - get the saved PCIe capability offset * @dev: PCI device
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v4 2/5 PCI/ERR: Rename error reporting to generic pci naming
In reply to Oza PawandeepThis patch renames error reporting to generic function with pci prefix
drivers/pci/pcie/aer/aerdrv_core.c +2 -2
@@ -285,7 +285,7 @@ static void handle_error_source(struct pcie_device *aerdev,pci_write_config_dword (dev, pos +PCI_ERR_COR_STATUS , info->status); }else -do_recovery (dev, info->severity); +pci_do_recovery (dev, info->severity); }#ifdef CONFIG_ACPI_APEI_PCIEAER
@@ -349,7 +349,7 @@ static void aer_recover_work_func(struct work_struct *work)continue ; }cper_print_aer (pdev, entry.severity, entry.regs); -do_recovery (pdev, entry.severity); +pci_do_recovery (pdev, entry.severity);pci_dev_put (pdev); } }
drivers/pci/pcie/pcie-err.c +36 -36
227 lines not on this page · raw message
include/linux/pci.h +1 -1
@@ -1998,7 +1998,7 @@ static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resvoid pci_hp_remove_module_link (struct pci_slot *pci_slot);#endif -void do_recovery (struct pci_dev *dev,int severity); +void pci_do_recovery (struct pci_dev *dev,int severity);/** * pci_pcie_cap - get the saved PCIe capability offset
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v4 2/5] PCI/ERR: Rename error reporting to generic pci naming
Quoted 32 lines · Oza Pawandeep
This patch renames error reporting to generic function with pci prefix
Signed-off-by Oza Pawandeep <[email protected]>drivers/pci/pcie/aer/aerdrv_core.c +2
-2@@ -285,7 +285,7 @@ static void handle_error_source(struct pcie_device *aerdev,pci_write_config_dword (dev, pos +PCI_ERR_COR_STATUS , info->status); }else -do_recovery (dev, info->severity); +pci_do_recovery (dev, info->severity); }#ifdef CONFIG_ACPI_APEI_PCIEAER @@ -349,7 +349,7 @@ static void aer_recover_work_func(struct work_struct *work)continue ; }cper_print_aer (pdev, entry.severity, entry.regs); -do_recovery (pdev, entry.severity); +pci_do_recovery (pdev, entry.severity);pci_dev_put (pdev); } }drivers/pci/pcie/pcie-err.c +0
-0@@ -20,12 +20,12 @@#include <linux/pcieport_if.h>
drivers/pci/pcie/pcie-err.c line 28
Quoted 10 lines
drivers/pci/pcie/pcie-err.c +2
-2#include "portdrv.h" -struct aer_broadcast_data { +struct pci_err_broadcast_data {enum pci_channel_state state;enum pci_ers_result result; }; -pci_ers_result_t merge_result(enum pci_ers_result orig, +pci_ers_result_t pci_merge_result(enum pci_ers_result orig,
Most of these functions started out static in aerdrv_core.c and should remain static. Therefore, they do not need to be renamed. Same for the struct aer_broadcast_data.
include/linux/pci.h static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int res · line 2001
Quoted 10 lines
include/linux/pci.h +1
-1@@ -1998,7 +1998,7 @@ static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resvoid pci_hp_remove_module_link (struct pci_slot *pci_slot);#endif -void do_recovery (struct pci_dev *dev,int severity); +void pci_do_recovery (struct pci_dev *dev,int severity);
This one started out static and now needs to be non-static so you can call it both from aerdrv_core.c and pcie-dpc.c.
But it should not be exposed outside the PCI core, so the declaration should go in drivers/pci/pcie/aer/aerdrv.h or at most drivers/pci/pci.h.
The rename should happen before the move out of aerdrv_core.c, i.e., reorder patches 1 and 2.
Quoted 6 lines
include/linux/pci.h +0
-1/** * pci_pcie_cap - get the saved PCIe capability offset -- Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.,
a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v4 2/5] PCI/ERR: Rename error reporting to generic pci naming
Quoted 65 lines · Bjorn Helgaas
Quoted 34 lines · Oza Pawandeep
This patch renames error reporting to generic function with pci prefix
Signed-off-by Oza Pawandeep <[email protected]>drivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -285,7 +285,7 @@ static void handle_error_source(struct pcie_device *aerdev,pci_write_config_dword (dev, pos +PCI_ERR_COR_STATUS , info->status); }else -do_recovery (dev, info->severity); +pci_do_recovery (dev, info->severity); }#ifdef
CONFIG_ACPI_APEI_PCIEAERdrivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -349,7 +349,7 @@ static void aer_recover_work_func(struct work_struct *work) continue; }cper_print_aer (pdev, entry.severity, entry.regs); -do_recovery (pdev, entry.severity); +pci_do_recovery (pdev, entry.severity);pci_dev_put (pdev); }}
drivers/pci/pcie/pcie-err.c +0
-0@@ -20,12 +20,12 @@#include <linux/pcieport_if.h> drivers/pci/pcie/pcie-err.c line 28
Quoted 10 lines
drivers/pci/pcie/pcie-err.c +2
-2#include "portdrv.h" -struct aer_broadcast_data { +struct pci_err_broadcast_data {enum pci_channel_state state;enum pci_ers_result result; }; -pci_ers_result_t merge_result(enum pci_ers_result orig, +pci_ers_result_t pci_merge_result(enum pci_ers_result orig,Most of these functions started out static in
aerdrv_core.cand should remain static. Therefore, they do not need to be renamed. Same for the structaer_broadcast_data.include/linux/pci.h static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int res · line 2001
Quoted 11 lines
include/linux/pci.h +0
-0@@ -1998,7 +1998,7 @@ static inline resource_size_tpci_iov_resource_size(struct
pci_dev*dev, int res
voidpci_hp_remove_module_link(struct pci_slot *pci_slot); #endifinclude/linux/pci.h +1
-1-void do_recovery (struct pci_dev *dev,int severity); +void pci_do_recovery (struct pci_dev *dev,int severity);This one started out static and now needs to be non-static so you can call it both from
aerdrv_core.candpcie-dpc.c.
Quoted 6 lines
But it should not be exposed outside the PCI core, so the declaration should go in
drivers/pci/pcie/aer/aerdrv.hor at mostdrivers/pci/pci.h.The rename should happen before the move out of
aerdrv_core.c, i.e., reorder patches 1 and 2.
ok so let me confirm. you would like to see renaming but that should happen right in patch1. and then move all the error reporting to pcie_err.c
is that correct ?
besides, I am thinking to movepci_do_recovery and removing everything from include/linux/pci.h (which you suggested already) but along with that....following defines will move in driver/pci/pci.h
#define PCI_ERR_AER_NONFATAL 0 #define PCI_ERR_AER_FATAL 1 #define PCI_ERR_AER_CORRECTABLE 2 #define PCI_ERR_DPC_NONFATAL 4
because, error codes have to be unified at one place.
will work on this and post the patch-set soon.
Regards,
Oza.
Quoted 7 lines
Quoted 7 lines
/**
*pci_pcie_cap- get the saved PCIe capability offset
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.,
a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v4 2/5] PCI/ERR: Rename error reporting to generic pci naming
Quoted 44 lines · On 2018-01-17 13:54, [email protected] wrote:
Quoted 43 lines · Bjorn Helgaas
Quoted 42 lines · Oza Pawandeep
This patch renames error reporting to generic function with pci prefix
Signed-off-by Oza Pawandeep <[email protected]>drivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -285,7 +285,7 @@ static void handle_error_source(struct pcie_device *aerdev,pci_write_config_dword (dev, pos +PCI_ERR_COR_STATUS , info->status); }else -do_recovery (dev, info->severity); +pci_do_recovery (dev, info->severity); }#ifdef
CONFIG_ACPI_APEI_PCIEAERdrivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -349,7 +349,7 @@ static void aer_recover_work_func(struct work_struct *work) continue; }cper_print_aer (pdev, entry.severity, entry.regs); -do_recovery (pdev, entry.severity); +pci_do_recovery (pdev, entry.severity);pci_dev_put (pdev); }}
drivers/pci/pcie/pcie-err.c +1
-1@@ -20,12 +20,12 @@#include <linux/pcieport_if.h> #include "portdrv.h" -struct aer_broadcast_data { +struct pci_err_broadcast_data {enum pci_channel_state state;enum pci_ers_result result; };
Quoted 6 lines
Quoted 6 lines
drivers/pci/pcie/pcie-err.c line 28
Quoted 2 lines
drivers/pci/pcie/pcie-err.c +1
-1-pci_ers_result_t merge_result(enum pci_ers_result orig, +pci_ers_result_t pci_merge_result(enum pci_ers_result orig,Most of these functions started out static in
aerdrv_core.cand should remain static. Therefore, they do not need to be renamed. Same for the structaer_broadcast_data.
ok so in conclusion I should rename only do_recovery. nothing else to be renamed. and keep the functions static after moving them to pci_err.c.
Regards,
Oza.
Quoted 53 lines
Quoted 16 lines
include/linux/pci.h static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int res · line 2001
Quoted 12 lines
include/linux/pci.h +0
-0@@ -1998,7 +1998,7 @@ static inline resource_size_tpci_iov_resource_size(struct
pci_dev*dev, int res
voidpci_hp_remove_module_link(struct pci_slot *pci_slot); #endifinclude/linux/pci.h +1
-1-void do_recovery (struct pci_dev *dev,int severity); +void pci_do_recovery (struct pci_dev *dev,int severity);This one started out static and now needs to be non-static so you can call it both from
aerdrv_core.candpcie-dpc.c.Quoted 6 lines
But it should not be exposed outside the PCI core, so the declaration should go in
drivers/pci/pcie/aer/aerdrv.hor at mostdrivers/pci/pci.h.The rename should happen before the move out of
aerdrv_core.c, i.e., reorder patches 1 and 2.ok so let me confirm. you would like to see renaming but that should happen right in patch1.
and then move all the error reporting topcie_err.c
is that correct ?besides, I am thinking to move
pci_do_recoveryand removing everything frominclude/linux/pci.h(which you suggested already)
but along with that....following defines will move indriver/pci/pci.h#define PCI_ERR_AER_NONFATAL 0 #define PCI_ERR_AER_FATAL 1 #define PCI_ERR_AER_CORRECTABLE 2 #define PCI_ERR_DPC_NONFATAL 4because, error codes have to be unified at one place.
will work on this and post the patch-set soon.
Regards,
Oza.Quoted 7 lines
Quoted 7 lines
/**
*pci_pcie_cap- get the saved PCIe capability offset
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.,
a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v4 2/5] PCI/ERR: Rename error reporting to generic pci naming
Quoted 55 lines · On Wed, Jan 17, 2018 at 02:00:40PM +0530, [email protected] wrote:
Quoted 47 lines · On 2018-01-17 13:54, [email protected] wrote:
Quoted 46 lines · Bjorn Helgaas
Quoted 45 lines · Oza Pawandeep
This patch renames error reporting to generic function with pci prefix
Signed-off-by Oza Pawandeep <[email protected]>drivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -285,7 +285,7 @@ static void handle_error_source(struct pcie_device *aerdev,pci_write_config_dword (dev, pos +PCI_ERR_COR_STATUS , info->status); }else -do_recovery (dev, info->severity); +pci_do_recovery (dev, info->severity); }#ifdef
CONFIG_ACPI_APEI_PCIEAERdrivers/pci/pcie/aer/aerdrv_core.c +1
-1@@ -349,7 +349,7 @@ static void aer_recover_work_func(struct work_struct *work) continue; }cper_print_aer (pdev, entry.severity, entry.regs); -do_recovery (pdev, entry.severity); +pci_do_recovery (pdev, entry.severity);pci_dev_put (pdev); }}
drivers/pci/pcie/pcie-err.c +1
-1@@ -20,12 +20,12 @@#include <linux/pcieport_if.h> #include "portdrv.h" -struct aer_broadcast_data { +struct pci_err_broadcast_data {enum pci_channel_state state;enum pci_ers_result result; };Quoted 6 lines
Quoted 6 lines
drivers/pci/pcie/pcie-err.c line 28
Quoted 2 lines
drivers/pci/pcie/pcie-err.c +1
-1-pci_ers_result_t merge_result(enum pci_ers_result orig, +pci_ers_result_t pci_merge_result(enum pci_ers_result orig,Most of these functions started out static in
aerdrv_core.cand should remain static. Therefore, they do not need to be renamed. Same for the structaer_broadcast_data.
Quoted 3 lines
ok so in conclusion I should rename only
do_recovery. nothing else to be renamed.
and keep the functions static after moving them topci_err.c.
Functions should always be static whenever possible.
Names of static functions need not contain the subsystem. It's sometimes nice if they do, but in this case I think a rename adds confusion but no real benefit.
PATCH v4 3/5 PCI/ERR: Unify error info/types in pcie_err
In reply to Oza PawandeepThis patch unifies error reporting defines into separate file so that it can be shared by clients, it provisions to add more error types from multiple error handling agents such as aer, dpc etc.
drivers/acpi/apei/ghes.c +2 -1
@@ -42,6 +42,7 @@#include <linux/llist.h> #include <linux/genalloc.h> #include <linux/pci.h> +#include <linux/pci_err.h> #include <linux/aer.h> #include <linux/nmi.h> #include <linux/sched/clock.h>
@@ -462,7 +463,7 @@ static void ghes_do_proc(struct ghes *ghes,* use, so treat it as a fatal AER error. */ if (gdata->flags &CPER_SEC_RESET ) - aer_severity =AER_FATAL ; + aer_severity =PCI_ERR_AER_FATAL ; aer_recover_queue(pcie_err->device_id.segment, pcie_err->device_id.bus,
drivers/pci/pcie/aer/aerdrv_core.c +8 -7
@@ -18,6 +18,7 @@#include <linux/module.h> #include <linux/pci.h> +#include <linux/pci_err.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pm.h>
@@ -165,7 +166,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)return false;/* Check if error is recorded */ -if (e_info->severity ==AER_CORRECTABLE ) { +if (e_info->severity ==PCI_ERR_AER_CORRECTABLE ) {pci_read_config_dword (dev, pos +PCI_ERR_COR_STATUS , &status);pci_read_config_dword (dev, pos +PCI_ERR_COR_MASK , &mask); }else {
@@ -275,7 +276,7 @@ static void handle_error_source(struct pcie_device *aerdev, {int pos; -if (info->severity ==AER_CORRECTABLE ) { +if (info->severity ==PCI_ERR_AER_CORRECTABLE ) {/* * Correctable error does not need software intervention. * No need to go through error recovery process.
@@ -378,7 +379,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)if (!pos)return 1 ; -if (info->severity ==AER_CORRECTABLE ) { +if (info->severity ==PCI_ERR_AER_CORRECTABLE ) {pci_read_config_dword (dev, pos +PCI_ERR_COR_STATUS , &info->status); pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK,
@@ -386,7 +387,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)if (!(info->status & ~info->mask))return 0 ; }else if (dev->hdr_type ==PCI_HEADER_TYPE_BRIDGE || - info->severity ==AER_NONFATAL ) { + info->severity ==PCI_ERR_AER_NONFATAL ) {/* Link is still healthy for IO reads */ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
@@ -449,7 +450,7 @@ static void aer_isr_one_error(struct pcie_device *p_device,*/ 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->severity =PCI_ERR_AER_CORRECTABLE ;if (e_src->status &PCI_ERR_ROOT_MULTI_COR_RCV ) e_info->multi_error_valid =1 ;
@@ -466,9 +467,9 @@ static void aer_isr_one_error(struct pcie_device *p_device, e_info->id =ERR_UNCOR_ID (e_src->id);if (e_src->status &PCI_ERR_ROOT_FATAL_RCV ) - e_info->severity =AER_FATAL ; + e_info->severity =PCI_ERR_AER_FATAL ;else - e_info->severity =AER_NONFATAL ; + e_info->severity =PCI_ERR_AER_NONFATAL ;if (e_src->status &PCI_ERR_ROOT_MULTI_UNCOR_RCV ) e_info->multi_error_valid =1 ;
drivers/pci/pcie/aer/aerdrv_errprint.c +12 -11
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/pci.h> +#include <linux/pci_err.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pm.h>
@@ -29,11 +30,11 @@#define AER_AGENT_COMPLETER 2#define AER_AGENT_TRANSMITTER 3 -#define AER_AGENT_REQUESTER_MASK (t) ((t == AER_CORRECTABLE) ? \ +#define AER_AGENT_REQUESTER_MASK (t) ((t == PCI_ERR_AER_CORRECTABLE) ? \ 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) -#define AER_AGENT_COMPLETER_MASK (t) ((t == AER_CORRECTABLE) ? \ +#define AER_AGENT_COMPLETER_MASK (t) ((t == PCI_ERR_AER_CORRECTABLE) ? \ 0 : PCI_ERR_UNC_COMP_ABORT) -#define AER_AGENT_TRANSMITTER_MASK (t) ((t == AER_CORRECTABLE) ? \ +#define AER_AGENT_TRANSMITTER_MASK (t) ((t == PCI_ERR_AER_CORRECTABLE) ? \ (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0)#define AER_GET_AGENT (t, e) \
@@ -46,9 +47,9 @@#define AER_DATA_LINK_LAYER_ERROR 1#define AER_TRANSACTION_LAYER_ERROR 2 -#define AER_PHYSICAL_LAYER_ERROR_MASK (t) ((t == AER_CORRECTABLE) ? \ +#define AER_PHYSICAL_LAYER_ERROR_MASK (t) ((t == PCI_ERR_AER_CORRECTABLE) ? \ PCI_ERR_COR_RCVR : 0) -#define AER_DATA_LINK_LAYER_ERROR_MASK (t) ((t == AER_CORRECTABLE) ? \ +#define AER_DATA_LINK_LAYER_ERROR_MASK (t) ((t == PCI_ERR_AER_CORRECTABLE) ? \ (PCI_ERR_COR_BAD_TLP| \ PCI_ERR_COR_BAD_DLLP| \ PCI_ERR_COR_REP_ROLL| \
@@ -147,7 +148,7 @@ static void __aer_print_error(struct pci_dev *dev,if (!(status & (1 << i)))continue ; -if (info->severity ==AER_CORRECTABLE ) +if (info->severity ==PCI_ERR_AER_CORRECTABLE ) errmsg = i <ARRAY_SIZE (aer_correctable_error_string) ? aer_correctable_error_string[i] :NULL ;else
@@ -210,11 +211,11 @@ int cper_severity_to_aer(int cper_severity) {switch (cper_severity) {case CPER_SEV_RECOVERABLE : -return AER_NONFATAL ; +return PCI_ERR_AER_NONFATAL ;case CPER_SEV_FATAL : -return AER_FATAL ; +return PCI_ERR_AER_FATAL ;default : -return AER_CORRECTABLE ; +return PCI_ERR_AER_CORRECTABLE ; } }EXPORT_SYMBOL_GPL (cper_severity_to_aer);
@@ -226,7 +227,7 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,u32 status, mask;const char **status_strs; -if (aer_severity ==AER_CORRECTABLE ) { +if (aer_severity ==PCI_ERR_AER_CORRECTABLE ) { status = aer->cor_status; mask = aer->cor_mask; status_strs = aer_correctable_error_string;
@@ -247,7 +248,7 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,dev_err (&dev->dev,"aer_layer=%s, aer_agent=%s\n" , aer_error_layer[layer], aer_agent_string[agent]); -if (aer_severity !=AER_CORRECTABLE ) +if (aer_severity !=PCI_ERR_AER_CORRECTABLE )dev_err (&dev->dev,"aer_uncor_severity: 0x%08x\n" , aer->uncor_severity);
drivers/pci/pcie/pcie-err.c +3 -2
@@ -16,6 +16,7 @@#include <linux/pci.h> #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/pci_err.h> #include <linux/aer.h> #include <linux/pcieport_if.h> #include "portdrv.h"
@@ -283,7 +284,7 @@ void pci_do_recovery(struct pci_dev *dev, int severity)pci_ers_result_t status, result =PCI_ERS_RESULT_RECOVERED ;enum pci_channel_state state; -if (severity ==AER_FATAL ) +if (severity ==PCI_ERR_AER_FATAL ) state = pci_channel_io_frozen;else state = pci_channel_io_normal;
@@ -293,7 +294,7 @@ void pci_do_recovery(struct pci_dev *dev, int severity)"error_detected" , pci_report_error_detected); -if (severity ==AER_FATAL ) { +if (severity ==PCI_ERR_AER_FATAL ) { result =pci_reset_link (dev);if (result !=PCI_ERS_RESULT_RECOVERED ) goto failed;
include/linux/aer.h +0 -4
@@ -11,10 +11,6 @@#include <linux/errno.h> #include <linux/types.h> -#define AER_NONFATAL 0 -#define AER_FATAL 1 -#define AER_CORRECTABLE 2 -struct pci_dev ;struct aer_header_log_regs {
include/linux/pci.h +0 -2
@@ -1998,8 +1998,6 @@ static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resvoid pci_hp_remove_module_link (struct pci_slot *pci_slot);#endif -void pci_do_recovery (struct pci_dev *dev,int severity); -/** * pci_pcie_cap - get the saved PCIe capability offset * @dev: PCI device
include/linux/pci_err.h new file +11 -0
@@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _PCI_ERR_H_ +#define _PCI_ERR_H_ + +#define PCI_ERR_AER_NONFATAL 0 +#define PCI_ERR_AER_FATAL 1 +#define PCI_ERR_AER_CORRECTABLE 2 + +void pci_do_recovery (struct pci_dev *dev,int severity); +#endif /* _PCI_ERR_H_ */
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v4 4/5 PCI/DPC: Unify and plumb error handling into DPC
In reply to Oza PawandeepCurrent DPC driver does not do recovery, e.g. calling end-point's driver's callbacks, which sanitize the sw.
DPC driver implements link_reset callback, and calls pci_do_recovery.
drivers/pci/pcie/pcie-dpc.c +86 -4
@@ -13,8 +13,12 @@#include <linux/interrupt.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/pci_err.h> #include <linux/pcieport_if.h> #include "../pci.h" +#include "portdrv.h" + +static pci_ers_result_t dpc_reset_link (struct pci_dev *pdev);struct rp_pio_header_log_regs {u32 dw0;
@@ -67,6 +71,60 @@ struct dpc_dev { "Memory Request Completion Timeout", /* Bit Position 18 */ }; +static int find_dpc_dev_iter (struct device *device,void *data) +{ +struct pcie_port_service_driver *service_driver; +struct device **dev; + + dev = (struct device **) data; + +if (device->bus == &pcie_port_bus_type && device->driver) { + service_driver =to_service_driver (device->driver); +if (service_driver->service ==PCIE_PORT_SERVICE_DPC ) { + *dev = device; +return 1 ; + } + } + +return 0 ; +} + +static struct device *pci_find_dpc_dev (struct pci_dev *pdev) +{ +struct device *dev =NULL ; + +device_for_each_child (&pdev->dev, &dev, find_dpc_dev_iter); + +return dev; +} + +static int find_dpc_service_iter (struct device *device,void *data) +{ +struct pcie_port_service_driver *service_driver, **drv; + + drv = (struct pcie_port_service_driver **) data; + +if (device->bus == &pcie_port_bus_type && device->driver) { + service_driver =to_service_driver (device->driver); +if (service_driver->service ==PCIE_PORT_SERVICE_DPC ) { + *drv = service_driver; +return 1 ; + } + } + +return 0 ; +} + +struct pcie_port_service_driver *pci_find_dpc_service (struct pci_dev *dev) +{ +struct pcie_port_service_driver *drv =NULL ; + +device_for_each_child (&dev->dev, &drv, find_dpc_service_iter); + +return drv; +} +EXPORT_SYMBOL (pci_find_dpc_service); +static int dpc_wait_rp_inactive (struct dpc_dev *dpc) {unsigned long timeout = jiffies +HZ ;
@@ -104,11 +162,23 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc)dev_warn (dev,"Link state not disabled for DPC event\n" ); } -static void interrupt_event_handler (struct work_struct *work) +/** +* dpc_reset_link - reset link DPC routine +* @dev: pointer to Root Port's pci_dev data structure +* +* Invoked by Port Bus driver when performing link reset at Root Port. +*/ +static pci_ers_result_t dpc_reset_link (struct pci_dev *pdev) { - struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); -struct pci_dev *dev, *temp, *pdev = dpc->dev->port;struct pci_bus *parent = pdev->subordinate; +struct pci_dev *dev, *temp; +struct dpc_dev *dpc; +struct pcie_device *pciedev; +struct device *devdpc; + + devdpc =pci_find_dpc_dev (pdev); + pciedev =to_pcie_device (devdpc); + dpc =get_service_data (pciedev);pci_lock_rescan_remove (); list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
@@ -125,7 +195,7 @@ static void interrupt_event_handler(struct work_struct *work)dpc_wait_link_inactive (dpc);if (dpc->rp &&dpc_wait_rp_inactive (dpc)) -return ; +return PCI_ERS_RESULT_DISCONNECT ;if (dpc->rp && dpc->rp_pio_status) { pci_write_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS,
@@ -135,6 +205,17 @@ static void interrupt_event_handler(struct work_struct *work)pci_write_config_word (pdev, dpc->cap_pos +PCI_EXP_DPC_STATUS ,PCI_EXP_DPC_STATUS_TRIGGER |PCI_EXP_DPC_STATUS_INTERRUPT ); + +return PCI_ERS_RESULT_RECOVERED ; +} + +static void interrupt_event_handler (struct work_struct *work) +{ + struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); +struct pci_dev *pdev = dpc->dev->port; + +/* From DPC point of view error is always FATAL. */ +pci_do_recovery (pdev,PCI_ERR_DPC_FATAL ); } static void dpc_rp_pio_print_tlp_header(struct device *dev,
@@ -339,6 +420,7 @@ static void dpc_remove(struct pcie_device *dev) .service = PCIE_PORT_SERVICE_DPC, .probe = dpc_probe, .remove = dpc_remove, + .reset_link = dpc_reset_link, };static int __init dpc_service_init (void )
drivers/pci/pcie/pcie-err.c +22 -6
@@ -21,6 +21,8 @@#include <linux/pcieport_if.h> #include "portdrv.h" +static DEFINE_MUTEX (pci_err_recovery_lock); +struct pci_err_broadcast_data {enum pci_channel_state state;enum pci_ers_result result;
@@ -180,7 +182,7 @@ static pci_ers_result_t pci_default_reset_link(struct pci_dev *dev)return PCI_ERS_RESULT_RECOVERED ; } -pci_ers_result_t pci_reset_link (struct pci_dev *dev) +pci_ers_result_t pci_reset_link (struct pci_dev *dev,int severity) {struct pci_dev *udev;pci_ers_result_t status;
@@ -194,9 +196,17 @@ pci_ers_result_t pci_reset_link(struct pci_dev *dev) udev = dev->bus->self; } + +/* Use the service driver of the component firstly */ +#if IS_ENABLED (CONFIG_PCIE_DPC ) +if (severity ==PCI_ERR_DPC_FATAL ) + driver =pci_find_dpc_service (udev); +#endif #if IS_ENABLED (CONFIG_PCIEAER ) -/* Use the aer driver of the component firstly */ - driver =pci_find_aer_service (udev); +if ((severity ==PCI_ERR_AER_FATAL ) || + (severity ==PCI_ERR_AER_NONFATAL ) || + (severity ==PCI_ERR_AER_CORRECTABLE )) + driver =pci_find_aer_service (udev);#endif if (driver && driver->reset_link) {
@@ -284,7 +294,10 @@ void pci_do_recovery(struct pci_dev *dev, int severity)pci_ers_result_t status, result =PCI_ERS_RESULT_RECOVERED ;enum pci_channel_state state; -if (severity ==PCI_ERR_AER_FATAL ) +mutex_lock (&pci_err_recovery_lock); + +if ((severity ==PCI_ERR_AER_FATAL ) || + (severity ==PCI_ERR_DPC_FATAL )) state = pci_channel_io_frozen;else state = pci_channel_io_normal;
@@ -294,8 +307,9 @@ void pci_do_recovery(struct pci_dev *dev, int severity)"error_detected" , pci_report_error_detected); -if (severity ==PCI_ERR_AER_FATAL ) { - result =pci_reset_link (dev); +if ((severity ==PCI_ERR_AER_FATAL ) || + (severity ==PCI_ERR_DPC_FATAL )) { + result =pci_reset_link (dev, severity);if (result !=PCI_ERS_RESULT_RECOVERED ) goto failed; }
@@ -327,9 +341,11 @@ void pci_do_recovery(struct pci_dev *dev, int severity) pci_report_resume);dev_info (&dev->dev,"Device recovery successful\n" ); +mutex_unlock (&pci_err_recovery_lock);return ; failed:/* TODO: Should kernel panic here? */ +mutex_unlock (&pci_err_recovery_lock);dev_info (&dev->dev,"Device recovery failed\n" ); }
drivers/pci/pcie/portdrv.h +1 -0
@@ -80,4 +80,5 @@ static inline void pcie_port_platform_notify(struct pci_dev *port, int *mask){}#endif /* !CONFIG_ACPI */ struct pcie_port_service_driver *pci_find_aer_service (struct pci_dev *dev); +struct pcie_port_service_driver *pci_find_dpc_service (struct pci_dev *dev);#endif /* _PORTDRV_H_ */
include/linux/pci_err.h +2 -0
@@ -7,5 +7,7 @@#define PCI_ERR_AER_FATAL 1#define PCI_ERR_AER_CORRECTABLE 2 +#define PCI_ERR_DPC_FATAL 4 +void pci_do_recovery (struct pci_dev *dev,int severity);#endif /* _PCI_ERR_H_ */
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v4 5/5 PCI/DPC: Enumerate the devices after DPC trigger event
In reply to Oza PawandeepImplement error_resume callback in DPC so, after DPC trigger event enumerates the devices beneath.
drivers/pci/pcie/pcie-dpc.c +38 -0
@@ -162,6 +162,43 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc)dev_warn (dev,"Link state not disabled for DPC event\n" ); } +static bool dpc_wait_link_active (struct pci_dev *pdev) +{ +unsigned long timeout = jiffies +HZ ; +u16 lnk_status; +bool ret = true; + +pcie_capability_read_word (pdev,PCI_EXP_LNKSTA , &lnk_status); + +while (!(lnk_status &PCI_EXP_LNKSTA_DLLLA ) && + !time_after (jiffies, timeout)) { +msleep (10 ); +pcie_capability_read_word (pdev,PCI_EXP_LNKSTA , &lnk_status); + } + +if (!(lnk_status &PCI_EXP_LNKSTA_DLLLA )) { +dev_warn (&pdev->dev,"Link state not enabled after DPC event\n" ); + ret = false; + } + +return ret; +} + +/** +* dpc_error_resume - enumerate the devices beneath +* @dev: pointer to Root Port's pci_dev data structure +* +* Invoked by Port Bus driver during nonfatal recovery. +*/ +static void dpc_error_resume (struct pci_dev *pdev) +{ +if (dpc_wait_link_active (pdev)) { +pci_lock_rescan_remove (); +pci_rescan_bus (pdev->bus); +pci_unlock_rescan_remove (); + } +} +/** * dpc_reset_link - reset link DPC routine * @dev: pointer to Root Port's pci_dev data structure
@@ -420,6 +457,7 @@ static void dpc_remove(struct pcie_device *dev) .service = PCIE_PORT_SERVICE_DPC, .probe = dpc_probe, .remove = dpc_remove, + .error_resume = dpc_error_resume, .reset_link = dpc_reset_link, };
drivers/pci/pcie/pcie-err.c +25 -6
@@ -236,6 +236,7 @@ pci_ers_result_t pci_reset_link(struct pci_dev *dev, int severity)* @state: error state * @error_mesg: message to print * @cb: callback to be broadcasted +* @severity: error severity * * Invoked during error recovery process. Once being invoked, the content * of error severity will be broadcasted to all downstream drivers in a
@@ -244,7 +245,8 @@ pci_ers_result_t pci_reset_link(struct pci_dev *dev, int severity)pci_ers_result_t pci_broadcast_error_message (struct pci_dev *dev,enum pci_channel_state state,char *error_mesg, -int (*cb)(struct pci_dev *,void *)) +int (*cb)(struct pci_dev *,void *), +int severity) {struct pci_err_broadcast_data result_data;
@@ -256,6 +258,15 @@ pci_ers_result_t pci_broadcast_error_message(struct pci_dev *dev, result_data.result =PCI_ERS_RESULT_RECOVERED ;if (dev->hdr_type ==PCI_HEADER_TYPE_BRIDGE ) { +/* If DPC is triggered, call resume error hanlder +* because, at this point we can safely assume that +* link recovery has happened. +*/ +if ((severity ==PCI_ERR_DPC_FATAL ) && + (cb == pci_report_resume)) { +cb (dev,NULL ); +return PCI_ERS_RESULT_RECOVERED ; + }/* * If the error is reported by a bridge, we think this error * is related to the downstream link of the bridge, so we
@@ -305,7 +316,8 @@ void pci_do_recovery(struct pci_dev *dev, int severity) status =pci_broadcast_error_message (dev, state,"error_detected" , - pci_report_error_detected); + pci_report_error_detected, + severity);if ((severity ==PCI_ERR_AER_FATAL ) || (severity ==PCI_ERR_DPC_FATAL )) {
@@ -314,11 +326,15 @@ void pci_do_recovery(struct pci_dev *dev, int severity) goto failed; } +if (severity ==PCI_ERR_DPC_FATAL ) + goto resume; +if (status ==PCI_ERS_RESULT_CAN_RECOVER ) status =pci_broadcast_error_message (dev, state,"mmio_enabled" , - pci_report_mmio_enabled); + pci_report_mmio_enabled, + severity);if (status ==PCI_ERS_RESULT_NEED_RESET ) {/*
@@ -329,19 +345,22 @@ void pci_do_recovery(struct pci_dev *dev, int severity) status =pci_broadcast_error_message (dev, state,"slot_reset" , - pci_report_slot_reset); + pci_report_slot_reset, + severity); }if (status !=PCI_ERS_RESULT_RECOVERED ) goto failed; +resume:pci_broadcast_error_message (dev, state,"resume" , - pci_report_resume); + pci_report_resume, + severity); -dev_info (&dev->dev,"Device recovery successful\n" );mutex_unlock (&pci_err_recovery_lock); +dev_info (&dev->dev,"Device recovery successful\n" );return ; failed:
Signature · 2 lines
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc., a Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.