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