xref: /linux/drivers/gpu/drm/xe/xe_pci_error.c (revision 13b9555ffb0304d736fcad01e7a75d329b81ae9a)
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