1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2026 Intel Corporation 4 */ 5 6 #include <linux/pci.h> 7 8 #include "xe_device.h" 9 #include "xe_gt.h" 10 #include "xe_pci.h" 11 #include "xe_pm.h" 12 #include "xe_printk.h" 13 #include "xe_ras.h" 14 #include "xe_survivability_mode.h" 15 16 static void prepare_device_for_reset(struct pci_dev *pdev) 17 { 18 struct xe_device *xe = pdev_to_xe_device(pdev); 19 struct xe_gt *gt; 20 u8 id; 21 22 /* 23 * Wedge the device to prevent userspace access but do not send the uevent. 24 * xe_device_wedged_fini() releases runtime pm if wedged flag is set, so acquire a runtime 25 * pm reference to avoid underflow. 26 */ 27 if (!atomic_xchg(&xe->wedged.flag, 1)) 28 xe_pm_runtime_get_noresume(xe); 29 30 xe_device_set_in_reset(xe); 31 32 for_each_gt(gt, xe, id) 33 xe_gt_declare_wedged(gt); 34 35 pci_disable_device(pdev); 36 } 37 38 static pci_ers_result_t ras_action_to_pci_result(struct pci_dev *pdev, u8 action) 39 { 40 switch (action) { 41 case XE_RAS_RECOVERY_ACTION_RECOVERED: 42 return PCI_ERS_RESULT_RECOVERED; 43 case XE_RAS_RECOVERY_ACTION_RESET: 44 prepare_device_for_reset(pdev); 45 return PCI_ERS_RESULT_NEED_RESET; 46 case XE_RAS_RECOVERY_ACTION_DISCONNECT: 47 return PCI_ERS_RESULT_DISCONNECT; 48 default: 49 return PCI_ERS_RESULT_DISCONNECT; 50 } 51 } 52 53 static pci_ers_result_t xe_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 54 { 55 struct xe_device *xe = pdev_to_xe_device(pdev); 56 57 xe_info(xe, "PCI error: detected state = %d\n", state); 58 59 if (state == pci_channel_io_perm_failure) 60 return PCI_ERS_RESULT_DISCONNECT; 61 62 /* If the device is already wedged or in survivability mode, do not attempt recovery */ 63 if (xe_survivability_mode_is_boot_enabled(xe) || xe_device_wedged(xe)) 64 return PCI_ERS_RESULT_DISCONNECT; 65 66 switch (state) { 67 case pci_channel_io_normal: 68 return PCI_ERS_RESULT_CAN_RECOVER; 69 case pci_channel_io_frozen: 70 prepare_device_for_reset(pdev); 71 return PCI_ERS_RESULT_NEED_RESET; 72 default: 73 xe_info(xe, "PCI error: unknown state %d\n", state); 74 return PCI_ERS_RESULT_DISCONNECT; 75 } 76 } 77 78 static pci_ers_result_t xe_pci_error_mmio_enabled(struct pci_dev *pdev) 79 { 80 struct xe_device *xe = pdev_to_xe_device(pdev); 81 enum xe_ras_recovery_action action; 82 83 xe_info(xe, "PCI error: MMIO enabled\n"); 84 action = xe_ras_process_errors(xe); 85 86 return ras_action_to_pci_result(pdev, action); 87 } 88 89 static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev) 90 { 91 const struct pci_device_id *ent = pci_match_id(pdev->driver->id_table, pdev); 92 struct xe_device *xe = pdev_to_xe_device(pdev); 93 94 xe_info(xe, "PCI error: slot reset\n"); 95 96 pci_restore_state(pdev); 97 98 if (pci_enable_device(pdev)) { 99 xe_err(xe, "Cannot re-enable PCI device after reset\n"); 100 return PCI_ERS_RESULT_DISCONNECT; 101 } 102 103 /* 104 * Secondary Bus Reset causes all VRAM state to be lost along with 105 * hardware state. As an initial step, re-probe the device to 106 * re-initialize the driver and hardware. 107 * TODO: optimize by re-initializing only the hardware state and re-creating 108 * kernel BOs. 109 */ 110 xe_device_clear_in_reset(xe); 111 pdev->driver->remove(pdev); 112 devres_release_group(&pdev->dev, xe->devres_group); 113 114 if (pdev->driver->probe(pdev, ent)) 115 return PCI_ERS_RESULT_DISCONNECT; 116 117 xe = pdev_to_xe_device(pdev); 118 119 /* Wedge the device to prevent I/O operations till the resume callback */ 120 atomic_set(&xe->wedged.flag, 1); 121 122 return PCI_ERS_RESULT_RECOVERED; 123 } 124 125 static void xe_pci_error_resume(struct pci_dev *pdev) 126 { 127 struct xe_device *xe = pdev_to_xe_device(pdev); 128 129 xe_info(xe, "PCI error: resume\n"); 130 131 atomic_set(&xe->wedged.flag, 0); 132 } 133 134 const struct pci_error_handlers xe_pci_error_handlers = { 135 .error_detected = xe_pci_error_detected, 136 .mmio_enabled = xe_pci_error_mmio_enabled, 137 .slot_reset = xe_pci_error_slot_reset, 138 .resume = xe_pci_error_resume, 139 }; 140