1515
1616#include <linux/auxiliary_bus.h>
1717#include <linux/bits.h>
18+ #include <linux/delay.h>
1819#include <linux/kernel.h>
1920#include <linux/idr.h>
2021#include <linux/module.h>
3031#define INTEL_DVSEC_TABLE_BAR (x ) ((x) & GENMASK(2, 0))
3132#define INTEL_DVSEC_TABLE_OFFSET (x ) ((x) & GENMASK(31, 3))
3233#define TABLE_OFFSET_SHIFT 3
34+ #define PMT_XA_START 0
35+ #define PMT_XA_MAX INT_MAX
36+ #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
3337
3438static DEFINE_IDA (intel_vsec_ida );
3539static DEFINE_IDA (intel_vsec_sdsi_ida );
40+ static DEFINE_XARRAY_ALLOC (auxdev_array );
3641
3742/**
3843 * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers.
@@ -132,7 +137,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
132137 const char * name )
133138{
134139 struct auxiliary_device * auxdev = & intel_vsec_dev -> auxdev ;
135- int ret ;
140+ int ret , id ;
136141
137142 ret = ida_alloc (intel_vsec_dev -> ida , GFP_KERNEL );
138143 if (ret < 0 ) {
@@ -159,7 +164,18 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
159164 return ret ;
160165 }
161166
162- return devm_add_action_or_reset (& pdev -> dev , intel_vsec_remove_aux , auxdev );
167+ ret = devm_add_action_or_reset (& pdev -> dev , intel_vsec_remove_aux ,
168+ auxdev );
169+ if (ret < 0 )
170+ return ret ;
171+
172+ /* Add auxdev to list */
173+ ret = xa_alloc (& auxdev_array , & id , intel_vsec_dev , PMT_XA_LIMIT ,
174+ GFP_KERNEL );
175+ if (ret )
176+ return ret ;
177+
178+ return 0 ;
163179}
164180
165181static int intel_vsec_add_dev (struct pci_dev * pdev , struct intel_vsec_header * header ,
@@ -345,6 +361,7 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id
345361 if (ret )
346362 return ret ;
347363
364+ pci_save_state (pdev );
348365 info = (struct intel_vsec_platform_info * )id -> driver_data ;
349366 if (!info )
350367 return - EINVAL ;
@@ -406,10 +423,71 @@ static const struct pci_device_id intel_vsec_pci_ids[] = {
406423};
407424MODULE_DEVICE_TABLE (pci , intel_vsec_pci_ids );
408425
426+ static pci_ers_result_t intel_vsec_pci_error_detected (struct pci_dev * pdev ,
427+ pci_channel_state_t state )
428+ {
429+ pci_channel_state_t status = PCI_ERS_RESULT_NEED_RESET ;
430+
431+ dev_info (& pdev -> dev , "PCI error detected, state %d" , state );
432+
433+ if (state == pci_channel_io_perm_failure )
434+ status = PCI_ERS_RESULT_DISCONNECT ;
435+ else
436+ pci_disable_device (pdev );
437+
438+ return status ;
439+ }
440+
441+ static pci_ers_result_t intel_vsec_pci_slot_reset (struct pci_dev * pdev )
442+ {
443+ struct intel_vsec_device * intel_vsec_dev ;
444+ pci_channel_state_t status = PCI_ERS_RESULT_DISCONNECT ;
445+ const struct pci_device_id * pci_dev_id ;
446+ unsigned long index ;
447+
448+ dev_info (& pdev -> dev , "Resetting PCI slot\n" );
449+
450+ msleep (2000 );
451+ if (pci_enable_device (pdev )) {
452+ dev_info (& pdev -> dev ,
453+ "Failed to re-enable PCI device after reset.\n" );
454+ goto out ;
455+ }
456+
457+ status = PCI_ERS_RESULT_RECOVERED ;
458+
459+ xa_for_each (& auxdev_array , index , intel_vsec_dev ) {
460+ /* check if pdev doesn't match */
461+ if (pdev != intel_vsec_dev -> pcidev )
462+ continue ;
463+ devm_release_action (& pdev -> dev , intel_vsec_remove_aux ,
464+ & intel_vsec_dev -> auxdev );
465+ }
466+ pci_disable_device (pdev );
467+ pci_restore_state (pdev );
468+ pci_dev_id = pci_match_id (intel_vsec_pci_ids , pdev );
469+ intel_vsec_pci_probe (pdev , pci_dev_id );
470+
471+ out :
472+ return status ;
473+ }
474+
475+ static void intel_vsec_pci_resume (struct pci_dev * pdev )
476+ {
477+ dev_info (& pdev -> dev , "Done resuming PCI device\n" );
478+ }
479+
480+ const struct pci_error_handlers intel_vsec_pci_err_handlers = {
481+ .error_detected = intel_vsec_pci_error_detected ,
482+ .slot_reset = intel_vsec_pci_slot_reset ,
483+ .resume = intel_vsec_pci_resume ,
484+ };
485+
409486static struct pci_driver intel_vsec_pci_driver = {
410487 .name = "intel_vsec" ,
411488 .id_table = intel_vsec_pci_ids ,
412489 .probe = intel_vsec_pci_probe ,
490+ .err_handler = & intel_vsec_pci_err_handlers ,
413491};
414492module_pci_driver (intel_vsec_pci_driver );
415493
0 commit comments