Address error and recovery for AER and DPC
Subsystems (2)
v12 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 v11:
Bjorn's comments addressed.
> rename pcie-err.c to err.c
> removed EXPORT_SYMBOL
> made generic find_serivce function in port driver.
> removed mutex patch as no need to have mutex in pcie_do_recovery > brough in DPC_FATAL in aer.h
> so now all the error codes (AER and DPC) are unified in aer.h
Changes since v10:
Christoph Hellwig's, David Laight's and Randy Dunlap's
comments addressed.
> renamed pci_do_recovery to pcie_do_recovery
> removed inner braces in conditional statements.
> restrctured the code in pci_wait_for_link
> EXPORT_SYMBOL_GPL
Changes since v9:
Sinan's comments addressed.
> bool active = true; unnecessary variable removed.
Changes since v8:
Fixed Kbuild errors.
Changes since v7:
Rebased the code on pci master
> https://kernel.googlesource.com/pub/scm/linux/kernel/git/helgaas/pci
Changes since v6:
Sinan's and Stefan's comments implemented.
> reordered patch 6 and 7
> cleaned up
Changes since v5:
Sinan's and Keith's comments incorporated.
> made separate patch for mutex
> unified error repotting codes into driver/pci/pci.h
> got rid of wait link active/inactive and
made generic function in driver/pci/pci.c
Changes since v4:
Bjorn's comments incorporated.
> Renamed only do_recovery.
> moved the things more locally to drivers/pci/pci.h
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 (6):
PCI/AER: Rename error recovery to generic PCI naming PCI/AER: Factor out error reporting from AER PCI/PORTDRV: Implement generic find service PCI/DPC: Unify and plumb error handling into DPC
PCI: Unify wait for link active into generic PCI PCI/DPC: Enumerate the devices after DPC trigger event
drivers/pci/hotplug/pciehp_hpc.c | 20 +-- drivers/pci/pci.c | 29 +++ drivers/pci/pci.h | 5 + drivers/pci/pcie/Makefile | 2 +- drivers/pci/pcie/aer/aerdrv.h | 30 ---- drivers/pci/pcie/aer/aerdrv_core.c | 317 +------------------------------- drivers/pci/pcie/err.c | 359 +++++++++++++++++++++++++++++++++++++ drivers/pci/pcie/pcie-dpc.c | 90 ++++++++-- drivers/pci/pcie/portdrv.h | 2 + drivers/pci/pcie/portdrv_core.c | 43 +++++ include/linux/aer.h | 2 + 11 files changed, 521 insertions(+), 378 deletions(-) create mode 100644 drivers/pci/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 v12 1/6 PCI/AER: Rename error recovery to generic PCI naming
This patch renames error recovery to generic name with pcie prefix
drivers/pci/pci.h +3 -0
@@ -342,6 +342,9 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,void pci_enable_acs (struct pci_dev *dev); +/* PCI error reporting and recovery */ +void pcie_do_recovery (struct pci_dev *dev,int severity); +#ifdef CONFIG_PCIEASPM void pcie_aspm_init_link_state (struct pci_dev *pdev);void pcie_aspm_exit_link_state (struct pci_dev *pdev);
drivers/pci/pcie/aer/aerdrv_core.c +4 -4
@@ -478,7 +478,7 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) }/** -* do_recovery - handle nonfatal/fatal error recovery process +* pcie_do_recovery - handle nonfatal/fatal error recovery process * @dev: pointer to a pci_dev data structure of agent detecting an error * @severity: error severity type *
@@ -486,7 +486,7 @@ static pci_ers_result_t reset_link(struct pci_dev *dev)* error detected message to all downstream drivers within a hierarchy in * question and return the returned code. */ -static void do_recovery (struct pci_dev *dev,int severity) +static void pcie_do_recovery (struct pci_dev *dev,int severity) {pci_ers_result_t status, result =PCI_ERS_RESULT_RECOVERED ;enum pci_channel_state state;
@@ -566,7 +566,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); +pcie_do_recovery (dev, info->severity); }#ifdef CONFIG_ACPI_APEI_PCIEAER
@@ -631,7 +631,7 @@ static void aer_recover_work_func(struct work_struct *work) }cper_print_aer (pdev, entry.severity, entry.regs);if (entry.severity !=AER_CORRECTABLE ) -do_recovery (pdev, entry.severity); +pcie_do_recovery (pdev, entry.severity);pci_dev_put (pdev); } }
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 v12 2/6 PCI/AER: Factor out error reporting from AER
In reply to Oza PawandeepThis patch factors out error reporting callbacks, which are currently tightly coupled with AER.
DPC should be able to register callbacks and attempt 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 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 -287
313 lines not on this page · raw message
drivers/pci/pcie/err.c new file +332 -0
332 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 *find_aer_service (struct pci_dev *dev);#endif /* _PORTDRV_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 v12 3/6 PCI/PORTDRV: Implement generic find service
In reply to Oza PawandeepThis patch implements generic pcie_port_find_service() routine.
drivers/pci/pcie/aer/aerdrv_core.c +0 -26
@@ -231,32 +231,6 @@ static bool find_source_device(struct pci_dev *parent,return true; } -static int find_aer_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_AER ) { - *drv = service_driver; -return 1 ; - } - } - -return 0 ; -} - -struct pcie_port_service_driver *find_aer_service (struct pci_dev *dev) -{ -struct pcie_port_service_driver *drv =NULL ; - -device_for_each_child (&dev->dev, &drv, find_aer_service_iter); - -return drv; -} -/** * handle_error_source - handle logging error into an event log * @aerdev: pointer to pcie_device data structure of the root port
drivers/pci/pcie/err.c +1 -1
@@ -194,7 +194,7 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) }/* Use the aer driver of the component firstly */ - driver =find_aer_service (udev); + driver =pcie_port_find_service (udev,PCIE_PORT_SERVICE_AER );if (driver && driver->reset_link) { status = driver->reset_link (udev);
drivers/pci/pcie/portdrv.h +2 -1
@@ -79,5 +79,6 @@ 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 *find_aer_service (struct pci_dev *dev); +struct pcie_port_service_driver *pcie_port_find_service (struct pci_dev *dev, +u32 service);#endif /* _PORTDRV_H_ */
drivers/pci/pcie/portdrv_core.c +44 -0
56 lines not on this page · raw message
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 v12 3/6] PCI/PORTDRV: Implement generic find service
drivers/pci/pcie/portdrv_core.c static int remove_iter(struct device *dev, void *data) · line 451
Quoted 4 lines · Oza Pawandeep
drivers/pci/pcie/portdrv_core.c +4
-0+struct pcie_port_service_driver *pcie_port_find_service (struct pci_dev *dev, +u32 service) +{ +struct pcie_port_service_driver *drv =NULL ;
Remove initialization
drivers/pci/pcie/portdrv_core.c static int remove_iter(struct device *dev, void *data) · line 454
Quoted 3 lines
drivers/pci/pcie/portdrv_core.c +3
-0+struct portdrv_service_data pdrvs; + + pdrvs.service = service;
initialize pdrvs.drv = NULL here.
Quoted 5 lines
drivers/pci/pcie/portdrv_core.c +5
-0+device_for_each_child (&dev->dev, &pdrvs, find_service_iter); + + drv = pdrvs.drv; +return drv; +}
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v12 3/6] PCI/PORTDRV: Implement generic find service
Quoted 9 lines · Sinan Kaya
drivers/pci/pcie/portdrv_core.c static int remove_iter(struct device *dev, void *data) · line 451
Quoted 5 lines · Oza Pawandeep
+struct
pcie_port_service_driver*pcie_port_find_service(structpci_dev*dev,drivers/pci/pcie/portdrv_core.c +3
-0+ u32 service) +{ +struct pcie_port_service_driver *drv =NULL ;Remove initialization
Quoted 6 lines
drivers/pci/pcie/portdrv_core.c static int remove_iter(struct device *dev, void *data) · line 454
Quoted 3 lines
drivers/pci/pcie/portdrv_core.c +3
-0+struct portdrv_service_data pdrvs; + + pdrvs.service = service;initialize pdrvs.drv = NULL here.
good point, will take care of this. [along with other comments if any]
Quoted 5 lines
Quoted 5 lines
drivers/pci/pcie/portdrv_core.c +5
-0+device_for_each_child (&dev->dev, &pdrvs, find_service_iter); + + drv = pdrvs.drv; +return drv; +}
PATCH v12 4/6 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/err.c +17 -6
@@ -19,6 +19,7 @@#include <linux/aer.h> #include <linux/pcieport_if.h> #include "portdrv.h" +#include "./../pci.h" struct aer_broadcast_data {enum pci_channel_state state;
@@ -179,11 +180,12 @@ static pci_ers_result_t default_reset_link(struct pci_dev *dev)return PCI_ERS_RESULT_RECOVERED ; } -static pci_ers_result_t reset_link (struct pci_dev *dev) +static pci_ers_result_t reset_link (struct pci_dev *dev,int severity) {struct pci_dev *udev;pci_ers_result_t status;struct pcie_port_service_driver *driver =NULL ; +u32 service;if (dev->hdr_type ==PCI_HEADER_TYPE_BRIDGE ) {/* Reset this port for all subordinates */
@@ -193,8 +195,12 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) udev = dev->bus->self; } -/* Use the aer driver of the component firstly */ - driver =pcie_port_find_service (udev,PCIE_PORT_SERVICE_AER ); +if (severity ==DPC_FATAL ) + service =PCIE_PORT_SERVICE_DPC ; +else + service =PCIE_PORT_SERVICE_AER ; + + driver =pcie_port_find_service (udev, service);if (driver && driver->reset_link) { status = driver->reset_link (udev);
@@ -281,7 +287,8 @@ void pcie_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 ==AER_FATAL ) || + (severity ==DPC_FATAL )) state = pci_channel_io_frozen;else state = pci_channel_io_normal;
@@ -291,10 +298,13 @@ void pcie_do_recovery(struct pci_dev *dev, int severity)"error_detected" , report_error_detected); -if (severity ==AER_FATAL ) { - result =reset_link (dev); +if ((severity ==AER_FATAL ) || + (severity ==DPC_FATAL )) { + result =reset_link (dev, severity);if (result !=PCI_ERS_RESULT_RECOVERED ) goto failed; +else if (severity ==DPC_FATAL ) + goto resume; }if (status ==PCI_ERS_RESULT_CAN_RECOVER )
@@ -318,6 +328,7 @@ void pcie_do_recovery(struct pci_dev *dev, int severity)if (status !=PCI_ERS_RESULT_RECOVERED ) goto failed; +resume: broadcast_error_message(dev, state, "resume",
drivers/pci/pcie/pcie-dpc.c +58 -6
109 lines not on this page · raw message
include/linux/aer.h +2 -0
@@ -15,6 +15,8 @@#define AER_FATAL 1#define AER_CORRECTABLE 2 +#define DPC_FATAL 4 +struct pci_dev ;struct aer_header_log_regs {
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 v12 5/6 PCI: Unify wait for link active into generic PCI
In reply to Oza PawandeepClients such as HP, DPC are using pcie_wait_link_active(), which waits till the link becomes active or inactive.
Made generic function and moved it to drivers/pci/pci.c
drivers/pci/hotplug/pciehp_hpc.c +3 -17
@@ -231,25 +231,11 @@ bool pciehp_check_link_active(struct controller *ctrl)return ret; } -static void __pcie_wait_link_active (struct controller *ctrl,bool active) -{ -int timeout =1000 ; - -if (pciehp_check_link_active (ctrl) == active) -return ; -while (timeout >0 ) { -msleep (10 ); - timeout -=10 ; -if (pciehp_check_link_active (ctrl) == active) -return ; - } -ctrl_dbg (ctrl,"Data Link Layer Link Active not %s in 1000 msec\n" , - active ?"set" :"cleared" ); -} -static void pcie_wait_link_active (struct controller *ctrl) { -__pcie_wait_link_active (ctrl, true); +struct pci_dev *pdev =ctrl_dev (ctrl); + +pcie_wait_for_link (pdev, true); }static bool pci_bus_check_dev (struct pci_bus *bus,int devfn)
drivers/pci/pci.c +29 -0
@@ -4176,6 +4176,35 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)return 0 ; } +/** +* pcie_wait_for_link - Wait for link till it's active/inactive +* @pdev: Bridge device +* @active: waiting for active or inactive ? +* +* Use this to wait till link becomes active or inactive. +*/ +bool pcie_wait_for_link (struct pci_dev *pdev,bool active) +{ +int timeout =1000 ; +bool ret; +u16 lnk_status; + +for (;;) { +pcie_capability_read_word (pdev,PCI_EXP_LNKSTA , &lnk_status); + ret = !!(lnk_status &PCI_EXP_LNKSTA_DLLLA ); +if (ret == active) +return true; +if (timeout <=0 ) +break ; + timeout -=10 ; + } + +pci_info (pdev,"Data Link Layer Link Active not %s in 1000 msec\n" , + active ?"set" :"cleared" ); + +return false; +} +void pci_reset_secondary_bus (struct pci_dev *dev) {u16 ctrl;
drivers/pci/pci.h +2 -0
@@ -345,6 +345,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,/* PCI error reporting and recovery */ void pcie_do_recovery (struct pci_dev *dev,int severity); +bool pcie_wait_for_link (struct pci_dev *pdev,bool active); +#ifdef CONFIG_PCIEASPM void pcie_aspm_init_link_state (struct pci_dev *pdev);void pcie_aspm_exit_link_state (struct pci_dev *pdev);
drivers/pci/pcie/pcie-dpc.c +1 -11
@@ -95,19 +95,9 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)static void dpc_wait_link_inactive (struct dpc_dev *dpc) { -unsigned long timeout = jiffies +HZ ;struct pci_dev *pdev = dpc->dev->port; -struct device *dev = &dpc->dev->device; -u16 lnk_status; -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 (dev,"Link state not disabled for DPC event\n" ); +pcie_wait_for_link (pdev, false); }/**
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 v12 6/6 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/err.c +21 -5
@@ -237,7 +237,8 @@ static pci_ers_result_t reset_link(struct pci_dev *dev, int severity)static pci_ers_result_t 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 aer_broadcast_data result_data;
@@ -249,6 +250,17 @@ static pci_ers_result_t 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 handler +* because, at this point we can safely assume that +* link recovery has happened, this is only handled if +* callback is resume, as this function can be called +* with multiple callbacks. +*/ +if ((severity ==DPC_FATAL ) && + (cb == 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
@@ -296,7 +308,8 @@ void pcie_do_recovery(struct pci_dev *dev, int severity) status =broadcast_error_message (dev, state,"error_detected" , - report_error_detected); + report_error_detected, + severity);if ((severity ==AER_FATAL ) || (severity ==DPC_FATAL )) {
@@ -311,7 +324,8 @@ void pcie_do_recovery(struct pci_dev *dev, int severity) status =broadcast_error_message (dev, state,"mmio_enabled" , - report_mmio_enabled); + report_mmio_enabled, + severity);if (status ==PCI_ERS_RESULT_NEED_RESET ) {/*
@@ -322,7 +336,8 @@ void pcie_do_recovery(struct pci_dev *dev, int severity) status =broadcast_error_message (dev, state,"slot_reset" , - report_slot_reset); + report_slot_reset, + severity); }if (status !=PCI_ERS_RESULT_RECOVERED )
@@ -332,7 +347,8 @@ void pcie_do_recovery(struct pci_dev *dev, int severity)broadcast_error_message (dev, state,"resume" , - report_resume); + report_resume, + severity);dev_info (&dev->dev,"Device recovery successful\n" );return ;
drivers/pci/pcie/pcie-dpc.c +17 -1
@@ -101,9 +101,24 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc) }/** -* dpc_reset_link - reset link DPC routine +* dpc_error_resume - enumerate the devices beneath * @pdev: pointer to Root Port's pci_dev data structure * +* Invoked by Port Bus driver during fatal recovery. +*/ +static void dpc_error_resume (struct pci_dev *pdev) +{ +if (pcie_wait_for_link (pdev, true)) { +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 +* * Invoked by Port Bus driver when performing link reset at Root Port. */ static pci_ers_result_t dpc_reset_link (struct pci_dev *pdev)
@@ -338,6 +353,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, };
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.
Quoted 10 lines · Oza Pawandeep
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_resumecallback.
The main point of this series is to call the driver error handling callbacks (error_detected(), mmio_enabled(), slot_reset(), etc.) when DPC events occur. We've always called them for AER events, but prior to this series, we didn't call them for DPC events.
That's a good thing -- we should treat DPC events as much like AER events as possible.
This series does make it more obvious that there's still a big difference between AER and DPC handling -- for DPC, we remove and re-enumerate all the devices, but we don't for AER.
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to reset_link() and broadcast_error_message().
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
Bjorn
Quoted 10 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
Was it the absence of error callback? or are we missing something in our assumptions?
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Quoted 8 lines · Sinan Kaya
Quoted 7 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().
Quoted 8 lines
Quoted 3 lines
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed. Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Quoted 25 lines · Keith Busch
Quoted 8 lines · Sinan Kaya
Quoted 7 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().Quoted 8 lines
Quoted 3 lines
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed. Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
Quoted 4 lines
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Now it begs the question, that
after DPC trigger
should we enumerate the devices, ?
or
error handling callbacks, followed by stop devices followed by enumeration ? or
error handling callbacks, followed by enumeration ? (no stop devices)
Regards,
Oza.
Quoted 33 lines · On Mon, Mar 12, 2018 at 08:16:38PM +0530, [email protected] wrote:
Quoted 25 lines · Keith Busch
Quoted 8 lines · Sinan Kaya
Quoted 7 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().Quoted 8 lines
Quoted 3 lines
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed. Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
Quoted 4 lines
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Now it begs the question, that
Quoted 7 lines
after DPC trigger
should we enumerate the devices, ?
or
error handling callbacks, followed by stop devices followed by enumeration ? or
error handling callbacks, followed by enumeration ? (no stop devices)
I'm not sure I understand. The link is disabled while DPC is triggered, so if anything, you'd want to un-enumerate everything below the contained port (that's what it does today).
After releasing a slot from DPC, the link is allowed to retrain. If there is a working device on the other side, a link up event occurs. That event is handled by the pciehp driver, and that schedules enumeration no matter what you do to the DPC driver.
Quoted 42 lines · Keith Busch
Quoted 33 lines · On Mon, Mar 12, 2018 at 08:16:38PM +0530, [email protected] wrote:
Quoted 25 lines · Keith Busch
Quoted 8 lines · Sinan Kaya
Quoted 7 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().Quoted 8 lines
Quoted 3 lines
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed. Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
Quoted 4 lines
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Now it begs the question, that
Quoted 7 lines
after DPC trigger
should we enumerate the devices, ?
or
error handling callbacks, followed by stop devices followed by enumeration ? or
error handling callbacks, followed by enumeration ? (no stop devices)
Quoted 8 lines
I'm not sure I understand. The link is disabled while DPC is triggered, so if anything, you'd want to un-enumerate everything below the contained port (that's what it does today).
After releasing a slot from DPC, the link is allowed to retrain. If there is a working device on the other side, a link up event occurs. That event is handled by the pciehp driver, and that schedules enumeration no matter what you do to the DPC driver.
yes, that is what i current, but this patch-set makes DPC aware of error handling driver callbacks.
besides, in absence of pciehp there is nobody to do enumeration.
And, I was talking about pci_stop_and_remove_bus_device() in dpc. if DPC calls driver's error callbacks, is it required to stop the devices ?
Quoted 6 lines · On Mon, Mar 12, 2018 at 09:04:47PM +0530, [email protected] wrote:
Quoted 5 lines · Keith Busch
I'm not sure I understand. The link is disabled while DPC is triggered, so if anything, you'd want to un-enumerate everything below the contained
port (that's what it does today).
Quoted 8 lines
Quoted 5 lines
After releasing a slot from DPC, the link is allowed to retrain. If there
is a working device on the other side, a link up event occurs. That event is handled by the pciehp driver, and that schedules enumeration no matter what you do to the DPC driver.yes, that is what i current, but this patch-set makes DPC aware of error handling driver callbacks.
I've been questioning the utility of doing that since the very first version of this patch set.
Quoted 1 line
besides, in absence of pciehp there is nobody to do enumeration.
If you configure your kernel to not have a feature, you don't get to expect the feature works.
You can still manually rescan through sysfs, /sys/bus/pci/rescan.
Quoted 2 lines
And, I was talking about
pci_stop_and_remove_bus_device()in dpc. if DPC calls driver's error callbacks, is it required to stop the devices ?
DPC is PCIe's preferred surprise removal mechanism. If you don't want the DPC driver to handle removing devices downstream the containment, how do you want those devices get removed? Just calling driver's error callbacks leaves the kernel's view of the topology in the wrong state.
I was just writing a reply to you. You acted first :)
Quoted 10 lines · Keith Busch
Quoted 7 lines
Quoted 5 lines
After releasing a slot from DPC, the link is allowed to retrain. If there
is a working device on the other side, a link up event occurs. That event is handled by the pciehp driver, and that schedules enumeration no matter what you do to the DPC driver.yes, that is what i current, but this patch-set makes DPC aware of error handling driver callbacks.
I've been questioning the utility of doing that since the very first version of this patch set.
I think we should all agree that shutting down the device drivers with active work is not safe. There could be outstanding work that the endpoint driver needs to take care of.
That was the motivation for this change so that we give endpoint drivers an error callback when something goes wrong.
The rest is implementation detail that we can all figure out.
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Quoted 14 lines · Sinan Kaya
I was just writing a reply to you. You acted first :)
Quoted 10 lines · Keith Busch
Quoted 7 lines
Quoted 5 lines
After releasing a slot from DPC, the link is allowed to retrain. If there
is a working device on the other side, a link up event occurs. That event is handled by the pciehp driver, and that schedules enumeration no matter what you do to the DPC driver.yes, that is what i current, but this patch-set makes DPC aware of error handling driver callbacks.
I've been questioning the utility of doing that since the very first version of this patch set.
Quoted 8 lines
I think we should all agree that shutting down the device drivers with active work is not safe. There could be outstanding work that the endpoint driver needs to take care of.
That was the motivation for this change so that we give endpoint drivers an error callback when something goes wrong.
The rest is implementation detail that we can all figure out.
I'm not sure if I agree here. All Linux device drivers are supposed to cope with sudden/unexpected loss of communication at any time. This includes cleaning up appropriately when requested to unbind from an inaccessible device with active outstanding work.
[+cc Alex]
Quoted 13 lines · Keith Busch
Quoted 12 lines · Sinan Kaya
Quoted 10 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
Quoted 8 lines
Quoted 4 lines
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed.
When DPC is triggered, the port takes the link down. When we handle an uncorrectable (nonfatal or fatal) AER event, software takes the link down.
In both cases, devices on the other side are at least reset. Whenever the link goes down, it's conceivable the device could be replaced with a different one before the link comes back up. Is this why you remove and re-enumerate? (See tangent [1] below.)
The point is that from the device's hardware perspective, these scenarios are the same (it sent a ERR_NONFATAL or ERR_FATAL message and it sees the link go down). I think we should make them the same on the software side, too: the driver should see the same callbacks, in the same order, whether we're doing AER or DPC.
If removing and re-enumerating is the right thing for DPC, I think that means it's also the right thing for AER.
Along this line, we had a question a while back about logging AER information after a DPC trigger. Obviously we can't collect any logged information from the downstream devices while link is down, but I noticed the AER status bits are RW1CS, which means they're sticky and are not modified by hot reset or FLR.
So we may be able to read and log the AER information after the DPC driver brings the link back up. We may want to do the same with AER, i.e., reset the downstream devices first, then collect the AER status bits after the link comes back up.
Quoted 4 lines
Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
I agree with this; I think this is heading toward doing remove/re-enumerate on AER errors as well because it has also reset the device.
Quoted 4 lines
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Thanks for this tip. The only thing I've found so far is the mention of Surprise Down triggering DPC in the last paragraph of sec 6.7.5. Are there other references I should look at? I haven't found the recommendation about not setting 'Surprise' in Slot Capabilities yet.
Bjorn
[1] Tangent: I have similar concerns with the device reset paths. We currently save some config state, reset the device, and restore the config state. It's theoretically possible that the device was replaced or came up with different firmware after the reset, so I would really prefer to remove and re-enumerate there, too. But that would make it hard for things up the stack that want to reset the device but not re-setup the whole stack.
I wonder if DPC is going to cause trouble for that scenario. That's not an argument against DPC, but it might be a stronger reason to figure out how to deal with remove/re-enumerate in those stacks.
Quoted 25 lines · Bjorn Helgaas
[+cc Alex]
Quoted 13 lines · Keith Busch
Quoted 12 lines · Sinan Kaya
Quoted 10 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
Quoted 8 lines
Quoted 4 lines
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed.
Quoted 8 lines
When DPC is triggered, the port takes the link down. When we handle an uncorrectable (nonfatal or fatal) AER event, software takes the link down.
In both cases, devices on the other side are at least reset. Whenever the link goes down, it's conceivable the device could be replaced with a different one before the link comes back up. Is this why you remove and re-enumerate? (See tangent [1] below.)
Yes. Truthfully, DPC events due to changing topologies was the motivating use case when we initially developed this. We were also going for simplicity (at least initially), and remove + re-enumerate seemed safe without concerning this driver with other capability regsiters, or coordinating with/depending on other drivers. For example, a successful reset may depend on any particular driver calling pci_restore_state from a good saved state.
Quoted 15 lines
The point is that from the device's hardware perspective, these scenarios are the same (it sent a
ERR_NONFATALorERR_FATALmessage and it sees the link go down). I think we should make them the same on the software side, too: the driver should see the same callbacks, in the same order, whether we're doing AER or DPC.If removing and re-enumerating is the right thing for DPC, I think that means it's also the right thing for AER.
Along this line, we had a question a while back about logging AER information after a DPC trigger. Obviously we can't collect any logged information from the downstream devices while link is down, but I noticed the AER status bits are RW1CS, which means they're sticky and are not modified by hot reset or FLR.
Quoted 4 lines
So we may be able to read and log the AER information after the DPC driver brings the link back up. We may want to do the same with AER, i.e., reset the downstream devices first, then collect the AER status bits after the link comes back up.
I totally agree. We could consult Slot and AER status to guide a smarter approach.
Quoted 14 lines
Quoted 4 lines
Calling a driver's error handler for the wrong device in an unknown state may have undefined results. Enumerating the slot from scratch should be safe, and will assign resources, tune bus settings, and bind to the matching driver.
I agree with this; I think this is heading toward doing remove/re-enumerate on AER errors as well because it has also reset the device.
Quoted 4 lines
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Quoted 4 lines
Thanks for this tip. The only thing I've found so far is the mention of Surprise Down triggering DPC in the last paragraph of sec 6.7.5. Are there other references I should look at? I haven't found the recommendation about not setting 'Surprise' in Slot Capabilities yet.
No problem, it's in the "IMPLEMENTATION NOTE" at the end of 6.2.10.4, "Avoid Disabled Link and Hot-Plug Surprise Use with DPC".
Outside the spec, Microsemi as one of the PCI-SIG contributors and early adopters of the capability published a white paper "Hot and Surprise Plug Recommendations for Enterprise PCIe" providing guidance for OS drivers using DPC. We originally developed to that guidance. The paper unfortunately appears to be pay-walled now. :(
DPC triggers don't necessarily mean a surprise removal occurred, and I understand those conditions are motivating motivating these current proposals. I've no qualms adding smarter handling as long as we don't break removals: there are installations relying on this.
Quoted 11 lines
[1] Tangent: I have similar concerns with the device reset paths. We currently save some config state, reset the device, and restore the config state. It's theoretically possible that the device was replaced or came up with different firmware after the reset, so I would really prefer to remove and re-enumerate there, too. But that would make it hard for things up the stack that want to reset the device but not re-setup the whole stack.
I wonder if DPC is going to cause trouble for that scenario. That's not an argument against DPC, but it might be a stronger reason to figure out how to deal with remove/re-enumerate in those stacks.
Indeed, that's a great point. From a storage perspective, when a removal tears down the block devices, re-adding the same device initializes as a new block handle. Applications with open file descriptors on old handles are going to have a bad time. You can open through device mappers to avoid those problems, but inflight IO may be aborted.
I assume other classes of devices have similar implications to consider, so I agree expanding remove/re-enumerate may need to be considered carefully.
Quoted 35 lines · Keith Busch
Quoted 25 lines · Bjorn Helgaas
[+cc Alex]
Quoted 13 lines · Keith Busch
Quoted 12 lines · Sinan Kaya
Quoted 10 lines · Bjorn Helgaas
On Wed, Feb 28, 2018 at 10:34:11PM +0530, Oza Pawandeep wrote:
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
Quoted 8 lines
Quoted 4 lines
I agree this should be possible. Code execution path should be almost identical to fatal error case.
Is there any reason why you went to stop driver path, Keith?
The fact is the link is truly down during a DPC event. When the link is enabled again, you don't know at that point if the device(s) on the other side have changed.
Quoted 8 lines
When DPC is triggered, the port takes the link down. When we handle an uncorrectable (nonfatal or fatal) AER event, software takes the link down.
In both cases, devices on the other side are at least reset. Whenever the link goes down, it's conceivable the device could be replaced with a different one before the link comes back up. Is this why you remove and re-enumerate? (See tangent [1] below.)
Quoted 7 lines
Yes. Truthfully, DPC events due to changing topologies was the motivating use case when we initially developed this. We were also going for simplicity (at least initially), and remove + re-enumerate seemed safe without concerning this driver with other capability regsiters, or coordinating with/depending on other drivers. For example, a successful reset may depend on any particular driver calling
pci_restore_statefrom a good saved state.
The spec is recommending code to use "Hotplug Surprise" to differentiate these two cases we are looking for.
The use case Keith is looking for is for hotplug support.
The case I and Oza are more interested is for error handling on platforms with no hotplug support.
According to the spec, if "Hotplug Surprise" is set in slot capabilities, then hotplug driver handles link up and DPC driver doesn't interfere with its operation. Hotplug driver observes link up interrupt like it is doing today. When link up event is observed, hotplug driver will do the enumeration.
If "Hotplug Surprise" bit is not set, it is the job of the DPC driver to bring up the link. I believe this path should follow the AER driver path as there is a very well defined error reporting and recovery framework in the code.
The link comes back up automatically when DPC driver handles its interrupt very similar to what secondary bus reset does for AER. I don't believe there is a hotplug possibility under this condition since it is not supported to begin with.
Should we plumb the "Hotplug Surprise" condition into the code to satisfy both cases and leave the error handling path according to this code series?
Quoted 10 lines
Quoted 10 lines
The point is that from the device's hardware perspective, these scenarios are the same (it sent a
ERR_NONFATALorERR_FATALmessage and it sees the link go down). I think we should make them the same on the software side, too: the driver should see the same callbacks, in the same order, whether we're doing AER or DPC.If removing and re-enumerating is the right thing for DPC, I think that means it's also the right thing for AER.
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Quoted 18 lines · Sinan Kaya
The spec is recommending code to use "Hotplug Surprise" to differentiate these two cases we are looking for.
The use case Keith is looking for is for hotplug support.
The case I and Oza are more interested is for error handling on platforms with no hotplug support.According to the spec, if "Hotplug Surprise" is set in slot capabilities, then hotplug driver handles link up and DPC driver doesn't interfere with its operation. Hotplug driver observes link up interrupt like it is doing today. When link up event is observed, hotplug driver will do the enumeration.
If "Hotplug Surprise" bit is not set, it is the job of the DPC driver to bring up the link. I believe this path should follow the AER driver path as there is a very well defined error reporting and recovery framework in the code.
Quoted 7 lines
The link comes back up automatically when DPC driver handles its interrupt very similar to what secondary bus reset does for AER. I don't believe there is a hotplug possibility under this condition since it is not supported to begin with.
Should we plumb the "Hotplug Surprise" condition into the code to satisfy both cases and leave the error handling path according to this code series?
I'm on board with this, but I think you mean "Hotplug Capable" rather than "Hotplug Surprise". The former may co-exist with DPC and handles the link-ups, leaving DPC responsible for handling the link-down.
The "Hotplug Surprise" capability is recommended to not co-exist with DPC since that capability may suppress the "surprise link down" notification that DPC needs to see in order to trigger.
If the "Hotplug Capable" bit is not set, detecting the link-up after a DPC event would have to fall under a different component's responsibility, so I think I'm finally seeing your point.
Quoted 24 lines · Keith Busch
Quoted 23 lines · Sinan Kaya
The spec is recommending code to use "Hotplug Surprise" to differentiate these two cases we are looking for.
The use case Keith is looking for is for hotplug support.
The case I and Oza are more interested is for error handling on platforms with no hotplug support.According to the spec, if "Hotplug Surprise" is set in slot capabilities, then hotplug driver handles link up and DPC driver doesn't interfere with its operation. Hotplug driver observes link up interrupt like it is doing today. When link up event is observed, hotplug driver will do the enumeration.
If "Hotplug Surprise" bit is not set, it is the job of the DPC driver to bring up the link. I believe this path should follow the AER driver path as there is a very well defined error reporting and recovery framework in the code.
The link comes back up automatically when DPC driver handles its interrupt very similar to what secondary bus reset does for AER. I don't believe there is a hotplug possibility under this condition since it is not supported to begin with.
Quoted 7 lines
Quoted 2 lines
Should we plumb the "Hotplug Surprise" condition into the code to satisfy both cases and leave the error handling path according to this code series?
I'm on board with this, but I think you mean "Hotplug Capable" rather than "Hotplug Surprise". The former may co-exist with DPC and handles the link-ups, leaving DPC responsible for handling the link-down.
Yes, we can go with "Hotplug Capable".
Quoted 8 lines
The "Hotplug Surprise" capability is recommended to not co-exist with DPC since that capability may suppress the "surprise link down" notification that DPC needs to see in order to trigger.
If the "Hotplug Capable" bit is not set, detecting the link-up after a DPC event would have to fall under a different component's responsibility, so I think I'm finally seeing your point.
OK. To simplify our life, we can check if hotplug service is attached to this device or not and follow two different paths.
We can get rid of re-enumeration and stop devices for the non-hotplug case and make it behave exactly like AER.
Bjorn, will that work for you?
Signature · 3 lines
Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Quoted 13 lines · Keith Busch
Quoted 11 lines · Bjorn Helgaas
Quoted 4 lines · Keith Busch
Per spec, DPC is the recommended way for handling surprise removal events and even recommends DPC capable slots *not* set 'Surprise' in Slot Capabilities so that removals are always handled by DPC. This service driver was developed with that use in mind.
Thanks for this tip. The only thing I've found so far is the mention of Surprise Down triggering DPC in the last paragraph of sec 6.7.5. Are there other references I should look at? I haven't found the recommendation about not setting 'Surprise' in Slot Capabilities yet.
Quoted 8 lines
No problem, it's in the "IMPLEMENTATION NOTE" at the end of 6.2.10.4, "Avoid Disabled Link and Hot-Plug Surprise Use with DPC".
Outside the spec, Microsemi as one of the PCI-SIG contributors and early adopters of the capability published a white paper "Hot and Surprise Plug Recommendations for Enterprise PCIe" providing guidance for OS drivers using DPC. We originally developed to that guidance. The paper unfortunately appears to be pay-walled now. :(
Any chance you have a URL or contact info for this pay-walled white paper? Sounds like it might have useful information in it.
Quoted 29 lines · Bjorn Helgaas
Quoted 10 lines · Oza Pawandeep
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_resumecallback.The main point of this series is to call the driver error handling callbacks (
error_detected(),mmio_enabled(),slot_reset(), etc.) when DPC events occur. We've always called them for AER events, but prior to this series, we didn't call them for DPC events.That's a good thing -- we should treat DPC events as much like AER events as possible.
This series does make it more obvious that there's still a big difference between AER and DPC handling -- for DPC, we remove and re-enumerate all the devices, but we don't for AER.
That difference has been there since the beginning of DPC, so it has nothing to do with *this* series EXCEPT for the fact that it really complicates the logic you're adding to
reset_link()andbroadcast_error_message().
Quoted 5 lines
We ought to be able to simplify that somehow because the only real difference between AER and DPC should be that DPC automatically disables the link and AER does it in software.
Bjorn
Ok, so here is slight modification which I will do and will post final looking patches.
1) do not enumerate the devices after link is up (since AER does not do it)
2) remove the call to pci_stop_and_remove_bus_device(dev); because now DPC also makes use of driver's callback. (like AER does)
above 2 changes should make behavior of DPC identical to AER.
Regards,
Oza.