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