xref: /linux/drivers/gpu/drm/xe/xe_heci_gsc.c (revision 220994d61cebfc04f071d69049127657c7e8191b)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright(c) 2023, Intel Corporation. All rights reserved.
4  */
5 
6 #include <linux/irq.h>
7 #include <linux/mei_aux.h>
8 #include <linux/pci.h>
9 #include <linux/sizes.h>
10 
11 #include "xe_device_types.h"
12 #include "xe_drv.h"
13 #include "xe_heci_gsc.h"
14 #include "regs/xe_gsc_regs.h"
15 #include "xe_platform_types.h"
16 #include "xe_survivability_mode.h"
17 
18 #define GSC_BAR_LENGTH  0x00000FFC
19 
heci_gsc_irq_mask(struct irq_data * d)20 static void heci_gsc_irq_mask(struct irq_data *d)
21 {
22 	/* generic irq handling */
23 }
24 
heci_gsc_irq_unmask(struct irq_data * d)25 static void heci_gsc_irq_unmask(struct irq_data *d)
26 {
27 	/* generic irq handling */
28 }
29 
30 static const struct irq_chip heci_gsc_irq_chip = {
31 	.name = "gsc_irq_chip",
32 	.irq_mask = heci_gsc_irq_mask,
33 	.irq_unmask = heci_gsc_irq_unmask,
34 };
35 
heci_gsc_irq_init(int irq)36 static int heci_gsc_irq_init(int irq)
37 {
38 	irq_set_chip_and_handler_name(irq, &heci_gsc_irq_chip,
39 				      handle_simple_irq, "heci_gsc_irq_handler");
40 
41 	return irq_set_chip_data(irq, NULL);
42 }
43 
44 /**
45  * struct heci_gsc_def - graphics security controller heci interface definitions
46  *
47  * @name: name of the heci device
48  * @bar: address of the mmio bar
49  * @bar_size: size of the mmio bar
50  * @use_polling: indication of using polling mode for the device
51  * @slow_firmware: indication of whether the device is slow (needs longer timeouts)
52  */
53 struct heci_gsc_def {
54 	const char *name;
55 	unsigned long bar;
56 	size_t bar_size;
57 	bool use_polling;
58 	bool slow_firmware;
59 };
60 
61 /* gsc resources and definitions */
62 static const struct heci_gsc_def heci_gsc_def_dg1 = {
63 	.name = "mei-gscfi",
64 	.bar = DG1_GSC_HECI2_BASE,
65 	.bar_size = GSC_BAR_LENGTH,
66 };
67 
68 static const struct heci_gsc_def heci_gsc_def_dg2 = {
69 	.name = "mei-gscfi",
70 	.bar = DG2_GSC_HECI2_BASE,
71 	.bar_size = GSC_BAR_LENGTH,
72 };
73 
74 static const struct heci_gsc_def heci_gsc_def_pvc = {
75 	.name = "mei-gscfi",
76 	.bar = PVC_GSC_HECI2_BASE,
77 	.bar_size = GSC_BAR_LENGTH,
78 	.slow_firmware = true,
79 };
80 
heci_gsc_release_dev(struct device * dev)81 static void heci_gsc_release_dev(struct device *dev)
82 {
83 	struct auxiliary_device *aux_dev = to_auxiliary_dev(dev);
84 	struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev);
85 
86 	kfree(adev);
87 }
88 
xe_heci_gsc_fini(void * arg)89 static void xe_heci_gsc_fini(void *arg)
90 {
91 	struct xe_heci_gsc *heci_gsc = arg;
92 
93 	if (heci_gsc->adev) {
94 		struct auxiliary_device *aux_dev = &heci_gsc->adev->aux_dev;
95 
96 		auxiliary_device_delete(aux_dev);
97 		auxiliary_device_uninit(aux_dev);
98 		heci_gsc->adev = NULL;
99 	}
100 
101 	if (heci_gsc->irq >= 0)
102 		irq_free_desc(heci_gsc->irq);
103 
104 	heci_gsc->irq = -1;
105 }
106 
heci_gsc_irq_setup(struct xe_device * xe)107 static int heci_gsc_irq_setup(struct xe_device *xe)
108 {
109 	struct xe_heci_gsc *heci_gsc = &xe->heci_gsc;
110 	int ret;
111 
112 	heci_gsc->irq = irq_alloc_desc(0);
113 	if (heci_gsc->irq < 0) {
114 		drm_err(&xe->drm, "gsc irq error %d\n", heci_gsc->irq);
115 		return heci_gsc->irq;
116 	}
117 
118 	ret = heci_gsc_irq_init(heci_gsc->irq);
119 	if (ret < 0)
120 		drm_err(&xe->drm, "gsc irq init failed %d\n", ret);
121 
122 	return ret;
123 }
124 
heci_gsc_add_device(struct xe_device * xe,const struct heci_gsc_def * def)125 static int heci_gsc_add_device(struct xe_device *xe, const struct heci_gsc_def *def)
126 {
127 	struct xe_heci_gsc *heci_gsc = &xe->heci_gsc;
128 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
129 	struct auxiliary_device *aux_dev;
130 	struct mei_aux_device *adev;
131 	int ret;
132 
133 	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
134 	if (!adev)
135 		return -ENOMEM;
136 	adev->irq = heci_gsc->irq;
137 	adev->bar.parent = &pdev->resource[0];
138 	adev->bar.start = def->bar + pdev->resource[0].start;
139 	adev->bar.end = adev->bar.start + def->bar_size - 1;
140 	adev->bar.flags = IORESOURCE_MEM;
141 	adev->bar.desc = IORES_DESC_NONE;
142 	adev->slow_firmware = def->slow_firmware;
143 
144 	aux_dev = &adev->aux_dev;
145 	aux_dev->name = def->name;
146 	aux_dev->id = (pci_domain_nr(pdev->bus) << 16) |
147 		      PCI_DEVID(pdev->bus->number, pdev->devfn);
148 	aux_dev->dev.parent = &pdev->dev;
149 	aux_dev->dev.release = heci_gsc_release_dev;
150 
151 	ret = auxiliary_device_init(aux_dev);
152 	if (ret < 0) {
153 		drm_err(&xe->drm, "gsc aux init failed %d\n", ret);
154 		kfree(adev);
155 		return ret;
156 	}
157 
158 	heci_gsc->adev = adev; /* needed by the notifier */
159 	ret = auxiliary_device_add(aux_dev);
160 	if (ret < 0) {
161 		drm_err(&xe->drm, "gsc aux add failed %d\n", ret);
162 		heci_gsc->adev = NULL;
163 
164 		/* adev will be freed with the put_device() and .release sequence */
165 		auxiliary_device_uninit(aux_dev);
166 	}
167 	return ret;
168 }
169 
xe_heci_gsc_init(struct xe_device * xe)170 int xe_heci_gsc_init(struct xe_device *xe)
171 {
172 	struct xe_heci_gsc *heci_gsc = &xe->heci_gsc;
173 	const struct heci_gsc_def *def = NULL;
174 	int ret;
175 
176 	if (!xe->info.has_heci_gscfi && !xe->info.has_heci_cscfi)
177 		return 0;
178 
179 	heci_gsc->irq = -1;
180 
181 	if (xe->info.platform == XE_BATTLEMAGE) {
182 		def = &heci_gsc_def_dg2;
183 	} else if (xe->info.platform == XE_PVC) {
184 		def = &heci_gsc_def_pvc;
185 	} else if (xe->info.platform == XE_DG2) {
186 		def = &heci_gsc_def_dg2;
187 	} else if (xe->info.platform == XE_DG1) {
188 		def = &heci_gsc_def_dg1;
189 	}
190 
191 	if (!def || !def->name) {
192 		drm_warn(&xe->drm, "HECI is not implemented!\n");
193 		return 0;
194 	}
195 
196 	ret = devm_add_action_or_reset(xe->drm.dev, xe_heci_gsc_fini, heci_gsc);
197 	if (ret)
198 		return ret;
199 
200 	if (!def->use_polling && !xe_survivability_mode_is_enabled(xe)) {
201 		ret = heci_gsc_irq_setup(xe);
202 		if (ret)
203 			return ret;
204 	}
205 
206 	return heci_gsc_add_device(xe, def);
207 }
208 
xe_heci_gsc_irq_handler(struct xe_device * xe,u32 iir)209 void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir)
210 {
211 	int ret;
212 
213 	if ((iir & GSC_IRQ_INTF(1)) == 0)
214 		return;
215 
216 	if (!xe->info.has_heci_gscfi) {
217 		drm_warn_once(&xe->drm, "GSC irq: not supported");
218 		return;
219 	}
220 
221 	if (xe->heci_gsc.irq < 0)
222 		return;
223 
224 	ret = generic_handle_irq(xe->heci_gsc.irq);
225 	if (ret)
226 		drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret);
227 }
228 
xe_heci_csc_irq_handler(struct xe_device * xe,u32 iir)229 void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir)
230 {
231 	int ret;
232 
233 	if ((iir & CSC_IRQ_INTF(1)) == 0)
234 		return;
235 
236 	if (!xe->info.has_heci_cscfi) {
237 		drm_warn_once(&xe->drm, "CSC irq: not supported");
238 		return;
239 	}
240 
241 	if (xe->heci_gsc.irq < 0)
242 		return;
243 
244 	ret = generic_handle_irq(xe->heci_gsc.irq);
245 	if (ret)
246 		drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret);
247 }
248