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