1
2
3
4#include "gasket_interrupt.h"
5
6#include "gasket_constants.h"
7#include "gasket_core.h"
8#include "gasket_sysfs.h"
9#include <linux/device.h>
10#include <linux/interrupt.h>
11#include <linux/printk.h>
12#ifdef GASKET_KERNEL_TRACE_SUPPORT
13#define CREATE_TRACE_POINTS
14#include <trace/events/gasket_interrupt.h>
15#else
16#define trace_gasket_interrupt_event(x, ...)
17#endif
18
19#define MSIX_RETRY_COUNT 3
20
21
22struct gasket_interrupt_data {
23
24 const char *name;
25
26
27 int type;
28
29
30 struct pci_dev *pci_dev;
31
32
33 int msix_configured;
34
35
36 int num_interrupts;
37
38
39 const struct gasket_interrupt_desc *interrupts;
40
41
42 int interrupt_bar_index;
43
44
45 int pack_width;
46
47
48
49
50
51
52
53
54 int num_configured;
55
56
57 struct msix_entry *msix_entries;
58
59
60 struct eventfd_ctx **eventfd_ctxs;
61
62
63 ulong *interrupt_counts;
64
65
66 int irq;
67};
68
69
70enum interrupt_sysfs_attribute_type {
71 ATTR_INTERRUPT_COUNTS,
72};
73
74
75static void gasket_interrupt_setup(struct gasket_dev *gasket_dev)
76{
77 int i;
78 int pack_shift;
79 ulong mask;
80 ulong value;
81 struct gasket_interrupt_data *interrupt_data =
82 gasket_dev->interrupt_data;
83
84 if (!interrupt_data) {
85 dev_dbg(gasket_dev->dev, "Interrupt data is not initialized\n");
86 return;
87 }
88
89 dev_dbg(gasket_dev->dev, "Running interrupt setup\n");
90
91
92
93 for (i = 0; i < interrupt_data->num_interrupts; i++) {
94
95
96
97
98
99 dev_dbg(gasket_dev->dev,
100 "Setting up interrupt index %d with index 0x%llx and packing %d\n",
101 interrupt_data->interrupts[i].index,
102 interrupt_data->interrupts[i].reg,
103 interrupt_data->interrupts[i].packing);
104 if (interrupt_data->interrupts[i].packing == UNPACKED) {
105 value = interrupt_data->interrupts[i].index;
106 } else {
107 switch (interrupt_data->interrupts[i].packing) {
108 case PACK_0:
109 pack_shift = 0;
110 break;
111 case PACK_1:
112 pack_shift = interrupt_data->pack_width;
113 break;
114 case PACK_2:
115 pack_shift = 2 * interrupt_data->pack_width;
116 break;
117 case PACK_3:
118 pack_shift = 3 * interrupt_data->pack_width;
119 break;
120 default:
121 dev_dbg(gasket_dev->dev,
122 "Found interrupt description with unknown enum %d\n",
123 interrupt_data->interrupts[i].packing);
124 return;
125 }
126
127 mask = ~(0xFFFF << pack_shift);
128 value = gasket_dev_read_64(gasket_dev,
129 interrupt_data->interrupt_bar_index,
130 interrupt_data->interrupts[i].reg);
131 value &= mask;
132 value |= interrupt_data->interrupts[i].index
133 << pack_shift;
134 }
135 gasket_dev_write_64(gasket_dev, value,
136 interrupt_data->interrupt_bar_index,
137 interrupt_data->interrupts[i].reg);
138 }
139}
140
141static void
142gasket_handle_interrupt(struct gasket_interrupt_data *interrupt_data,
143 int interrupt_index)
144{
145 struct eventfd_ctx *ctx;
146
147 trace_gasket_interrupt_event(interrupt_data->name, interrupt_index);
148 ctx = interrupt_data->eventfd_ctxs[interrupt_index];
149 if (ctx)
150 eventfd_signal(ctx, 1);
151
152 ++(interrupt_data->interrupt_counts[interrupt_index]);
153}
154
155static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
156{
157 struct gasket_interrupt_data *interrupt_data = dev_id;
158 int interrupt = -1;
159 int i;
160
161
162 for (i = 0; i < interrupt_data->num_interrupts; i++) {
163 if (interrupt_data->msix_entries[i].vector == irq) {
164 interrupt = interrupt_data->msix_entries[i].entry;
165 break;
166 }
167 }
168 if (interrupt == -1) {
169 pr_err("Received unknown irq %d\n", irq);
170 return IRQ_HANDLED;
171 }
172 gasket_handle_interrupt(interrupt_data, interrupt);
173 return IRQ_HANDLED;
174}
175
176static int
177gasket_interrupt_msix_init(struct gasket_interrupt_data *interrupt_data)
178{
179 int ret = 1;
180 int i;
181
182 interrupt_data->msix_entries =
183 kcalloc(interrupt_data->num_interrupts,
184 sizeof(*interrupt_data->msix_entries), GFP_KERNEL);
185 if (!interrupt_data->msix_entries)
186 return -ENOMEM;
187
188 for (i = 0; i < interrupt_data->num_interrupts; i++) {
189 interrupt_data->msix_entries[i].entry = i;
190 interrupt_data->msix_entries[i].vector = 0;
191 interrupt_data->eventfd_ctxs[i] = NULL;
192 }
193
194
195 for (i = 0; i < MSIX_RETRY_COUNT && ret > 0; i++)
196 ret = pci_enable_msix_exact(interrupt_data->pci_dev,
197 interrupt_data->msix_entries,
198 interrupt_data->num_interrupts);
199
200 if (ret)
201 return ret > 0 ? -EBUSY : ret;
202 interrupt_data->msix_configured = 1;
203
204 for (i = 0; i < interrupt_data->num_interrupts; i++) {
205 ret = request_irq(interrupt_data->msix_entries[i].vector,
206 gasket_msix_interrupt_handler, 0,
207 interrupt_data->name, interrupt_data);
208
209 if (ret) {
210 dev_err(&interrupt_data->pci_dev->dev,
211 "Cannot get IRQ for interrupt %d, vector %d; "
212 "%d\n",
213 i, interrupt_data->msix_entries[i].vector, ret);
214 return ret;
215 }
216
217 interrupt_data->num_configured++;
218 }
219
220 return 0;
221}
222
223
224
225
226
227
228
229
230
231
232
233static void force_msix_interrupt_unmasking(struct gasket_dev *gasket_dev)
234{
235 int i;
236#define MSIX_VECTOR_SIZE 16
237#define MSIX_MASK_BIT_OFFSET 12
238#define APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE 0x46800
239 for (i = 0; i < gasket_dev->interrupt_data->num_configured; i++) {
240
241 ulong location = APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE +
242 MSIX_MASK_BIT_OFFSET + i * MSIX_VECTOR_SIZE;
243 u32 mask =
244 gasket_dev_read_32(gasket_dev,
245 gasket_dev->interrupt_data->interrupt_bar_index,
246 location);
247 if (!(mask & 1))
248 continue;
249
250 gasket_dev_write_32(gasket_dev, 0,
251 gasket_dev->interrupt_data->interrupt_bar_index,
252 location);
253 }
254#undef MSIX_VECTOR_SIZE
255#undef MSIX_MASK_BIT_OFFSET
256#undef APEX_BAR2_REG_KERNEL_HIB_MSIX_TABLE
257}
258
259static ssize_t interrupt_sysfs_show(struct device *device,
260 struct device_attribute *attr, char *buf)
261{
262 int i, ret;
263 ssize_t written = 0, total_written = 0;
264 struct gasket_interrupt_data *interrupt_data;
265 struct gasket_dev *gasket_dev;
266 struct gasket_sysfs_attribute *gasket_attr;
267 enum interrupt_sysfs_attribute_type sysfs_type;
268
269 gasket_dev = gasket_sysfs_get_device_data(device);
270 if (!gasket_dev) {
271 dev_dbg(device, "No sysfs mapping found for device\n");
272 return 0;
273 }
274
275 gasket_attr = gasket_sysfs_get_attr(device, attr);
276 if (!gasket_attr) {
277 dev_dbg(device, "No sysfs attr data found for device\n");
278 gasket_sysfs_put_device_data(device, gasket_dev);
279 return 0;
280 }
281
282 sysfs_type = (enum interrupt_sysfs_attribute_type)
283 gasket_attr->data.attr_type;
284 interrupt_data = gasket_dev->interrupt_data;
285 switch (sysfs_type) {
286 case ATTR_INTERRUPT_COUNTS:
287 for (i = 0; i < interrupt_data->num_interrupts; ++i) {
288 written =
289 scnprintf(buf, PAGE_SIZE - total_written,
290 "0x%02x: %ld\n", i,
291 interrupt_data->interrupt_counts[i]);
292 total_written += written;
293 buf += written;
294 }
295 ret = total_written;
296 break;
297 default:
298 dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n",
299 attr->attr.name);
300 ret = 0;
301 break;
302 }
303
304 gasket_sysfs_put_attr(device, gasket_attr);
305 gasket_sysfs_put_device_data(device, gasket_dev);
306 return ret;
307}
308
309static struct gasket_sysfs_attribute interrupt_sysfs_attrs[] = {
310 GASKET_SYSFS_RO(interrupt_counts, interrupt_sysfs_show,
311 ATTR_INTERRUPT_COUNTS),
312 GASKET_END_OF_ATTR_ARRAY,
313};
314
315int gasket_interrupt_init(struct gasket_dev *gasket_dev)
316{
317 int ret;
318 struct gasket_interrupt_data *interrupt_data;
319 const struct gasket_driver_desc *driver_desc =
320 gasket_get_driver_desc(gasket_dev);
321
322 interrupt_data = kzalloc(sizeof(*interrupt_data), GFP_KERNEL);
323 if (!interrupt_data)
324 return -ENOMEM;
325 gasket_dev->interrupt_data = interrupt_data;
326 interrupt_data->name = driver_desc->name;
327 interrupt_data->type = driver_desc->interrupt_type;
328 interrupt_data->pci_dev = gasket_dev->pci_dev;
329 interrupt_data->num_interrupts = driver_desc->num_interrupts;
330 interrupt_data->interrupts = driver_desc->interrupts;
331 interrupt_data->interrupt_bar_index = driver_desc->interrupt_bar_index;
332 interrupt_data->pack_width = driver_desc->interrupt_pack_width;
333 interrupt_data->num_configured = 0;
334
335 interrupt_data->eventfd_ctxs =
336 kcalloc(driver_desc->num_interrupts,
337 sizeof(*interrupt_data->eventfd_ctxs), GFP_KERNEL);
338 if (!interrupt_data->eventfd_ctxs) {
339 kfree(interrupt_data);
340 return -ENOMEM;
341 }
342
343 interrupt_data->interrupt_counts =
344 kcalloc(driver_desc->num_interrupts,
345 sizeof(*interrupt_data->interrupt_counts), GFP_KERNEL);
346 if (!interrupt_data->interrupt_counts) {
347 kfree(interrupt_data->eventfd_ctxs);
348 kfree(interrupt_data);
349 return -ENOMEM;
350 }
351
352 switch (interrupt_data->type) {
353 case PCI_MSIX:
354 ret = gasket_interrupt_msix_init(interrupt_data);
355 if (ret)
356 break;
357 force_msix_interrupt_unmasking(gasket_dev);
358 break;
359
360 default:
361 ret = -EINVAL;
362 }
363
364 if (ret) {
365
366
367
368 dev_warn(gasket_dev->dev,
369 "Couldn't initialize interrupts: %d\n", ret);
370 return 0;
371 }
372
373 gasket_interrupt_setup(gasket_dev);
374 gasket_sysfs_create_entries(gasket_dev->dev_info.device,
375 interrupt_sysfs_attrs);
376
377 return 0;
378}
379
380static void
381gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data)
382{
383 int i;
384
385 for (i = 0; i < interrupt_data->num_configured; i++)
386 free_irq(interrupt_data->msix_entries[i].vector,
387 interrupt_data);
388 interrupt_data->num_configured = 0;
389
390 if (interrupt_data->msix_configured)
391 pci_disable_msix(interrupt_data->pci_dev);
392 interrupt_data->msix_configured = 0;
393 kfree(interrupt_data->msix_entries);
394}
395
396int gasket_interrupt_reinit(struct gasket_dev *gasket_dev)
397{
398 int ret;
399
400 if (!gasket_dev->interrupt_data) {
401 dev_dbg(gasket_dev->dev,
402 "Attempted to reinit uninitialized interrupt data\n");
403 return -EINVAL;
404 }
405
406 switch (gasket_dev->interrupt_data->type) {
407 case PCI_MSIX:
408 gasket_interrupt_msix_cleanup(gasket_dev->interrupt_data);
409 ret = gasket_interrupt_msix_init(gasket_dev->interrupt_data);
410 if (ret)
411 break;
412 force_msix_interrupt_unmasking(gasket_dev);
413 break;
414
415 default:
416 ret = -EINVAL;
417 }
418
419 if (ret) {
420
421
422
423 dev_warn(gasket_dev->dev, "Couldn't reinit interrupts: %d\n",
424 ret);
425 return 0;
426 }
427
428 gasket_interrupt_setup(gasket_dev);
429
430 return 0;
431}
432
433
434int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev)
435{
436 dev_dbg(gasket_dev->dev, "Clearing interrupt counts\n");
437 memset(gasket_dev->interrupt_data->interrupt_counts, 0,
438 gasket_dev->interrupt_data->num_interrupts *
439 sizeof(*gasket_dev->interrupt_data->interrupt_counts));
440 return 0;
441}
442
443
444void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev)
445{
446 struct gasket_interrupt_data *interrupt_data =
447 gasket_dev->interrupt_data;
448
449
450
451
452 if (!interrupt_data)
453 return;
454
455 switch (interrupt_data->type) {
456 case PCI_MSIX:
457 gasket_interrupt_msix_cleanup(interrupt_data);
458 break;
459
460 default:
461 break;
462 }
463
464 kfree(interrupt_data->interrupt_counts);
465 kfree(interrupt_data->eventfd_ctxs);
466 kfree(interrupt_data);
467 gasket_dev->interrupt_data = NULL;
468}
469
470int gasket_interrupt_system_status(struct gasket_dev *gasket_dev)
471{
472 if (!gasket_dev->interrupt_data) {
473 dev_dbg(gasket_dev->dev, "Interrupt data is null\n");
474 return GASKET_STATUS_DEAD;
475 }
476
477 if (gasket_dev->interrupt_data->num_configured !=
478 gasket_dev->interrupt_data->num_interrupts) {
479 dev_dbg(gasket_dev->dev,
480 "Not all interrupts were configured\n");
481 return GASKET_STATUS_LAMED;
482 }
483
484 return GASKET_STATUS_ALIVE;
485}
486
487int gasket_interrupt_set_eventfd(struct gasket_interrupt_data *interrupt_data,
488 int interrupt, int event_fd)
489{
490 struct eventfd_ctx *ctx = eventfd_ctx_fdget(event_fd);
491
492 if (IS_ERR(ctx))
493 return PTR_ERR(ctx);
494
495 if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts)
496 return -EINVAL;
497
498 interrupt_data->eventfd_ctxs[interrupt] = ctx;
499 return 0;
500}
501
502int gasket_interrupt_clear_eventfd(struct gasket_interrupt_data *interrupt_data,
503 int interrupt)
504{
505 if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts)
506 return -EINVAL;
507
508 interrupt_data->eventfd_ctxs[interrupt] = NULL;
509 return 0;
510}
511