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