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