]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/misc/mic/host/mic_intr.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 290
[mirror_ubuntu-jammy-kernel.git] / drivers / misc / mic / host / mic_intr.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Intel MIC Platform Software Stack (MPSS)
4 *
5 * Copyright(c) 2013 Intel Corporation.
6 *
7 * Intel MIC Host driver.
8 */
9 #include <linux/pci.h>
10 #include <linux/interrupt.h>
11
12 #include "../common/mic_dev.h"
13 #include "mic_device.h"
14
15 static irqreturn_t mic_thread_fn(int irq, void *dev)
16 {
17 struct mic_device *mdev = dev;
18 struct mic_intr_info *intr_info = mdev->intr_info;
19 struct mic_irq_info *irq_info = &mdev->irq_info;
20 struct mic_intr_cb *intr_cb;
21 struct pci_dev *pdev = mdev->pdev;
22 int i;
23
24 spin_lock(&irq_info->mic_thread_lock);
25 for (i = intr_info->intr_start_idx[MIC_INTR_DB];
26 i < intr_info->intr_len[MIC_INTR_DB]; i++)
27 if (test_and_clear_bit(i, &irq_info->mask)) {
28 list_for_each_entry(intr_cb, &irq_info->cb_list[i],
29 list)
30 if (intr_cb->thread_fn)
31 intr_cb->thread_fn(pdev->irq,
32 intr_cb->data);
33 }
34 spin_unlock(&irq_info->mic_thread_lock);
35 return IRQ_HANDLED;
36 }
37 /**
38 * mic_interrupt - Generic interrupt handler for
39 * MSI and INTx based interrupts.
40 */
41 static irqreturn_t mic_interrupt(int irq, void *dev)
42 {
43 struct mic_device *mdev = dev;
44 struct mic_intr_info *intr_info = mdev->intr_info;
45 struct mic_irq_info *irq_info = &mdev->irq_info;
46 struct mic_intr_cb *intr_cb;
47 struct pci_dev *pdev = mdev->pdev;
48 u32 mask;
49 int i;
50
51 mask = mdev->ops->ack_interrupt(mdev);
52 if (!mask)
53 return IRQ_NONE;
54
55 spin_lock(&irq_info->mic_intr_lock);
56 for (i = intr_info->intr_start_idx[MIC_INTR_DB];
57 i < intr_info->intr_len[MIC_INTR_DB]; i++)
58 if (mask & BIT(i)) {
59 list_for_each_entry(intr_cb, &irq_info->cb_list[i],
60 list)
61 if (intr_cb->handler)
62 intr_cb->handler(pdev->irq,
63 intr_cb->data);
64 set_bit(i, &irq_info->mask);
65 }
66 spin_unlock(&irq_info->mic_intr_lock);
67 return IRQ_WAKE_THREAD;
68 }
69
70 /* Return the interrupt offset from the index. Index is 0 based. */
71 static u16 mic_map_src_to_offset(struct mic_device *mdev,
72 int intr_src, enum mic_intr_type type)
73 {
74 if (type >= MIC_NUM_INTR_TYPES)
75 return MIC_NUM_OFFSETS;
76 if (intr_src >= mdev->intr_info->intr_len[type])
77 return MIC_NUM_OFFSETS;
78
79 return mdev->intr_info->intr_start_idx[type] + intr_src;
80 }
81
82 /* Return next available msix_entry. */
83 static struct msix_entry *mic_get_available_vector(struct mic_device *mdev)
84 {
85 int i;
86 struct mic_irq_info *info = &mdev->irq_info;
87
88 for (i = 0; i < info->num_vectors; i++)
89 if (!info->mic_msi_map[i])
90 return &info->msix_entries[i];
91 return NULL;
92 }
93
94 /**
95 * mic_register_intr_callback - Register a callback handler for the
96 * given source id.
97 *
98 * @mdev: pointer to the mic_device instance
99 * @idx: The source id to be registered.
100 * @handler: The function to be called when the source id receives
101 * the interrupt.
102 * @thread_fn: thread fn. corresponding to the handler
103 * @data: Private data of the requester.
104 * Return the callback structure that was registered or an
105 * appropriate error on failure.
106 */
107 static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev,
108 u8 idx, irq_handler_t handler, irq_handler_t thread_fn,
109 void *data)
110 {
111 struct mic_intr_cb *intr_cb;
112 unsigned long flags;
113 int rc;
114 intr_cb = kmalloc(sizeof(*intr_cb), GFP_KERNEL);
115
116 if (!intr_cb)
117 return ERR_PTR(-ENOMEM);
118
119 intr_cb->handler = handler;
120 intr_cb->thread_fn = thread_fn;
121 intr_cb->data = data;
122 intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida,
123 0, 0, GFP_KERNEL);
124 if (intr_cb->cb_id < 0) {
125 rc = intr_cb->cb_id;
126 goto ida_fail;
127 }
128
129 spin_lock(&mdev->irq_info.mic_thread_lock);
130 spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags);
131 list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]);
132 spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags);
133 spin_unlock(&mdev->irq_info.mic_thread_lock);
134
135 return intr_cb;
136 ida_fail:
137 kfree(intr_cb);
138 return ERR_PTR(rc);
139 }
140
141 /**
142 * mic_unregister_intr_callback - Unregister the callback handler
143 * identified by its callback id.
144 *
145 * @mdev: pointer to the mic_device instance
146 * @idx: The callback structure id to be unregistered.
147 * Return the source id that was unregistered or MIC_NUM_OFFSETS if no
148 * such callback handler was found.
149 */
150 static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx)
151 {
152 struct list_head *pos, *tmp;
153 struct mic_intr_cb *intr_cb;
154 unsigned long flags;
155 int i;
156
157 spin_lock(&mdev->irq_info.mic_thread_lock);
158 spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags);
159 for (i = 0; i < MIC_NUM_OFFSETS; i++) {
160 list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) {
161 intr_cb = list_entry(pos, struct mic_intr_cb, list);
162 if (intr_cb->cb_id == idx) {
163 list_del(pos);
164 ida_simple_remove(&mdev->irq_info.cb_ida,
165 intr_cb->cb_id);
166 kfree(intr_cb);
167 spin_unlock_irqrestore(
168 &mdev->irq_info.mic_intr_lock, flags);
169 spin_unlock(&mdev->irq_info.mic_thread_lock);
170 return i;
171 }
172 }
173 }
174 spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags);
175 spin_unlock(&mdev->irq_info.mic_thread_lock);
176 return MIC_NUM_OFFSETS;
177 }
178
179 /**
180 * mic_setup_msix - Initializes MSIx interrupts.
181 *
182 * @mdev: pointer to mic_device instance
183 *
184 *
185 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
186 */
187 static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev)
188 {
189 int rc, i;
190 int entry_size = sizeof(*mdev->irq_info.msix_entries);
191
192 mdev->irq_info.msix_entries = kmalloc_array(MIC_MIN_MSIX,
193 entry_size, GFP_KERNEL);
194 if (!mdev->irq_info.msix_entries) {
195 rc = -ENOMEM;
196 goto err_nomem1;
197 }
198
199 for (i = 0; i < MIC_MIN_MSIX; i++)
200 mdev->irq_info.msix_entries[i].entry = i;
201
202 rc = pci_enable_msix_exact(pdev, mdev->irq_info.msix_entries,
203 MIC_MIN_MSIX);
204 if (rc) {
205 dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc);
206 goto err_enable_msix;
207 }
208
209 mdev->irq_info.num_vectors = MIC_MIN_MSIX;
210 mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) *
211 mdev->irq_info.num_vectors), GFP_KERNEL);
212
213 if (!mdev->irq_info.mic_msi_map) {
214 rc = -ENOMEM;
215 goto err_nomem2;
216 }
217
218 dev_dbg(&mdev->pdev->dev,
219 "%d MSIx irqs setup\n", mdev->irq_info.num_vectors);
220 return 0;
221 err_nomem2:
222 pci_disable_msix(pdev);
223 err_enable_msix:
224 kfree(mdev->irq_info.msix_entries);
225 err_nomem1:
226 mdev->irq_info.num_vectors = 0;
227 return rc;
228 }
229
230 /**
231 * mic_setup_callbacks - Initialize data structures needed
232 * to handle callbacks.
233 *
234 * @mdev: pointer to mic_device instance
235 */
236 static int mic_setup_callbacks(struct mic_device *mdev)
237 {
238 int i;
239
240 mdev->irq_info.cb_list = kmalloc_array(MIC_NUM_OFFSETS,
241 sizeof(*mdev->irq_info.cb_list),
242 GFP_KERNEL);
243 if (!mdev->irq_info.cb_list)
244 return -ENOMEM;
245
246 for (i = 0; i < MIC_NUM_OFFSETS; i++)
247 INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]);
248 ida_init(&mdev->irq_info.cb_ida);
249 spin_lock_init(&mdev->irq_info.mic_intr_lock);
250 spin_lock_init(&mdev->irq_info.mic_thread_lock);
251 return 0;
252 }
253
254 /**
255 * mic_release_callbacks - Uninitialize data structures needed
256 * to handle callbacks.
257 *
258 * @mdev: pointer to mic_device instance
259 */
260 static void mic_release_callbacks(struct mic_device *mdev)
261 {
262 unsigned long flags;
263 struct list_head *pos, *tmp;
264 struct mic_intr_cb *intr_cb;
265 int i;
266
267 spin_lock(&mdev->irq_info.mic_thread_lock);
268 spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags);
269 for (i = 0; i < MIC_NUM_OFFSETS; i++) {
270 if (list_empty(&mdev->irq_info.cb_list[i]))
271 break;
272
273 list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) {
274 intr_cb = list_entry(pos, struct mic_intr_cb, list);
275 list_del(pos);
276 ida_simple_remove(&mdev->irq_info.cb_ida,
277 intr_cb->cb_id);
278 kfree(intr_cb);
279 }
280 }
281 spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags);
282 spin_unlock(&mdev->irq_info.mic_thread_lock);
283 ida_destroy(&mdev->irq_info.cb_ida);
284 kfree(mdev->irq_info.cb_list);
285 }
286
287 /**
288 * mic_setup_msi - Initializes MSI interrupts.
289 *
290 * @mdev: pointer to mic_device instance
291 * @pdev: PCI device structure
292 *
293 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
294 */
295 static int mic_setup_msi(struct mic_device *mdev, struct pci_dev *pdev)
296 {
297 int rc;
298
299 rc = pci_enable_msi(pdev);
300 if (rc) {
301 dev_dbg(&pdev->dev, "Error enabling MSI. rc = %d\n", rc);
302 return rc;
303 }
304
305 mdev->irq_info.num_vectors = 1;
306 mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) *
307 mdev->irq_info.num_vectors), GFP_KERNEL);
308
309 if (!mdev->irq_info.mic_msi_map) {
310 rc = -ENOMEM;
311 goto err_nomem1;
312 }
313
314 rc = mic_setup_callbacks(mdev);
315 if (rc) {
316 dev_err(&pdev->dev, "Error setting up callbacks\n");
317 goto err_nomem2;
318 }
319
320 rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn,
321 0, "mic-msi", mdev);
322 if (rc) {
323 dev_err(&pdev->dev, "Error allocating MSI interrupt\n");
324 goto err_irq_req_fail;
325 }
326
327 dev_dbg(&pdev->dev, "%d MSI irqs setup\n", mdev->irq_info.num_vectors);
328 return 0;
329 err_irq_req_fail:
330 mic_release_callbacks(mdev);
331 err_nomem2:
332 kfree(mdev->irq_info.mic_msi_map);
333 err_nomem1:
334 pci_disable_msi(pdev);
335 mdev->irq_info.num_vectors = 0;
336 return rc;
337 }
338
339 /**
340 * mic_setup_intx - Initializes legacy interrupts.
341 *
342 * @mdev: pointer to mic_device instance
343 * @pdev: PCI device structure
344 *
345 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
346 */
347 static int mic_setup_intx(struct mic_device *mdev, struct pci_dev *pdev)
348 {
349 int rc;
350
351 /* Enable intx */
352 pci_intx(pdev, 1);
353 rc = mic_setup_callbacks(mdev);
354 if (rc) {
355 dev_err(&pdev->dev, "Error setting up callbacks\n");
356 goto err_nomem;
357 }
358
359 rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn,
360 IRQF_SHARED, "mic-intx", mdev);
361 if (rc)
362 goto err;
363
364 dev_dbg(&pdev->dev, "intx irq setup\n");
365 return 0;
366 err:
367 mic_release_callbacks(mdev);
368 err_nomem:
369 return rc;
370 }
371
372 /**
373 * mic_next_db - Retrieve the next doorbell interrupt source id.
374 * The id is picked sequentially from the available pool of
375 * doorlbell ids.
376 *
377 * @mdev: pointer to the mic_device instance.
378 *
379 * Returns the next doorbell interrupt source.
380 */
381 int mic_next_db(struct mic_device *mdev)
382 {
383 int next_db;
384
385 next_db = mdev->irq_info.next_avail_src %
386 mdev->intr_info->intr_len[MIC_INTR_DB];
387 mdev->irq_info.next_avail_src++;
388 return next_db;
389 }
390
391 #define COOKIE_ID_SHIFT 16
392 #define GET_ENTRY(cookie) ((cookie) & 0xFFFF)
393 #define GET_OFFSET(cookie) ((cookie) >> COOKIE_ID_SHIFT)
394 #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT)
395
396 /**
397 * mic_request_threaded_irq - request an irq. mic_mutex needs
398 * to be held before calling this function.
399 *
400 * @mdev: pointer to mic_device instance
401 * @handler: The callback function that handles the interrupt.
402 * The function needs to call ack_interrupts
403 * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts.
404 * @thread_fn: thread fn required by request_threaded_irq.
405 * @name: The ASCII name of the callee requesting the irq.
406 * @data: private data that is returned back when calling the
407 * function handler.
408 * @intr_src: The source id of the requester. Its the doorbell id
409 * for Doorbell interrupts and DMA channel id for DMA interrupts.
410 * @type: The type of interrupt. Values defined in mic_intr_type
411 *
412 * returns: The cookie that is transparent to the caller. Passed
413 * back when calling mic_free_irq. An appropriate error code
414 * is returned on failure. Caller needs to use IS_ERR(return_val)
415 * to check for failure and PTR_ERR(return_val) to obtained the
416 * error code.
417 *
418 */
419 struct mic_irq *
420 mic_request_threaded_irq(struct mic_device *mdev,
421 irq_handler_t handler, irq_handler_t thread_fn,
422 const char *name, void *data, int intr_src,
423 enum mic_intr_type type)
424 {
425 u16 offset;
426 int rc = 0;
427 struct msix_entry *msix = NULL;
428 unsigned long cookie = 0;
429 u16 entry;
430 struct mic_intr_cb *intr_cb;
431 struct pci_dev *pdev = mdev->pdev;
432
433 offset = mic_map_src_to_offset(mdev, intr_src, type);
434 if (offset >= MIC_NUM_OFFSETS) {
435 dev_err(&mdev->pdev->dev,
436 "Error mapping index %d to a valid source id.\n",
437 intr_src);
438 rc = -EINVAL;
439 goto err;
440 }
441
442 if (mdev->irq_info.num_vectors > 1) {
443 msix = mic_get_available_vector(mdev);
444 if (!msix) {
445 dev_err(&mdev->pdev->dev,
446 "No MSIx vectors available for use.\n");
447 rc = -ENOSPC;
448 goto err;
449 }
450
451 rc = request_threaded_irq(msix->vector, handler, thread_fn,
452 0, name, data);
453 if (rc) {
454 dev_dbg(&mdev->pdev->dev,
455 "request irq failed rc = %d\n", rc);
456 goto err;
457 }
458 entry = msix->entry;
459 mdev->irq_info.mic_msi_map[entry] |= BIT(offset);
460 mdev->intr_ops->program_msi_to_src_map(mdev,
461 entry, offset, true);
462 cookie = MK_COOKIE(entry, offset);
463 dev_dbg(&mdev->pdev->dev, "irq: %d assigned for src: %d\n",
464 msix->vector, intr_src);
465 } else {
466 intr_cb = mic_register_intr_callback(mdev, offset, handler,
467 thread_fn, data);
468 if (IS_ERR(intr_cb)) {
469 dev_err(&mdev->pdev->dev,
470 "No available callback entries for use\n");
471 rc = PTR_ERR(intr_cb);
472 goto err;
473 }
474
475 entry = 0;
476 if (pci_dev_msi_enabled(pdev)) {
477 mdev->irq_info.mic_msi_map[entry] |= (1 << offset);
478 mdev->intr_ops->program_msi_to_src_map(mdev,
479 entry, offset, true);
480 }
481 cookie = MK_COOKIE(entry, intr_cb->cb_id);
482 dev_dbg(&mdev->pdev->dev, "callback %d registered for src: %d\n",
483 intr_cb->cb_id, intr_src);
484 }
485 return (struct mic_irq *)cookie;
486 err:
487 return ERR_PTR(rc);
488 }
489
490 /**
491 * mic_free_irq - free irq. mic_mutex
492 * needs to be held before calling this function.
493 *
494 * @mdev: pointer to mic_device instance
495 * @cookie: cookie obtained during a successful call to mic_request_threaded_irq
496 * @data: private data specified by the calling function during the
497 * mic_request_threaded_irq
498 *
499 * returns: none.
500 */
501 void mic_free_irq(struct mic_device *mdev,
502 struct mic_irq *cookie, void *data)
503 {
504 u32 offset;
505 u32 entry;
506 u8 src_id;
507 unsigned int irq;
508 struct pci_dev *pdev = mdev->pdev;
509
510 entry = GET_ENTRY((unsigned long)cookie);
511 offset = GET_OFFSET((unsigned long)cookie);
512 if (mdev->irq_info.num_vectors > 1) {
513 if (entry >= mdev->irq_info.num_vectors) {
514 dev_warn(&mdev->pdev->dev,
515 "entry %d should be < num_irq %d\n",
516 entry, mdev->irq_info.num_vectors);
517 return;
518 }
519 irq = mdev->irq_info.msix_entries[entry].vector;
520 free_irq(irq, data);
521 mdev->irq_info.mic_msi_map[entry] &= ~(BIT(offset));
522 mdev->intr_ops->program_msi_to_src_map(mdev,
523 entry, offset, false);
524
525 dev_dbg(&mdev->pdev->dev, "irq: %d freed\n", irq);
526 } else {
527 irq = pdev->irq;
528 src_id = mic_unregister_intr_callback(mdev, offset);
529 if (src_id >= MIC_NUM_OFFSETS) {
530 dev_warn(&mdev->pdev->dev, "Error unregistering callback\n");
531 return;
532 }
533 if (pci_dev_msi_enabled(pdev)) {
534 mdev->irq_info.mic_msi_map[entry] &= ~(BIT(src_id));
535 mdev->intr_ops->program_msi_to_src_map(mdev,
536 entry, src_id, false);
537 }
538 dev_dbg(&mdev->pdev->dev, "callback %d unregistered for src: %d\n",
539 offset, src_id);
540 }
541 }
542
543 /**
544 * mic_setup_interrupts - Initializes interrupts.
545 *
546 * @mdev: pointer to mic_device instance
547 * @pdev: PCI device structure
548 *
549 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
550 */
551 int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev)
552 {
553 int rc;
554
555 rc = mic_setup_msix(mdev, pdev);
556 if (!rc)
557 goto done;
558
559 rc = mic_setup_msi(mdev, pdev);
560 if (!rc)
561 goto done;
562
563 rc = mic_setup_intx(mdev, pdev);
564 if (rc) {
565 dev_err(&mdev->pdev->dev, "no usable interrupts\n");
566 return rc;
567 }
568 done:
569 mdev->intr_ops->enable_interrupts(mdev);
570 return 0;
571 }
572
573 /**
574 * mic_free_interrupts - Frees interrupts setup by mic_setup_interrupts
575 *
576 * @mdev: pointer to mic_device instance
577 * @pdev: PCI device structure
578 *
579 * returns none.
580 */
581 void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev)
582 {
583 int i;
584
585 mdev->intr_ops->disable_interrupts(mdev);
586 if (mdev->irq_info.num_vectors > 1) {
587 for (i = 0; i < mdev->irq_info.num_vectors; i++) {
588 if (mdev->irq_info.mic_msi_map[i])
589 dev_warn(&pdev->dev, "irq %d may still be in use.\n",
590 mdev->irq_info.msix_entries[i].vector);
591 }
592 kfree(mdev->irq_info.mic_msi_map);
593 kfree(mdev->irq_info.msix_entries);
594 pci_disable_msix(pdev);
595 } else {
596 if (pci_dev_msi_enabled(pdev)) {
597 free_irq(pdev->irq, mdev);
598 kfree(mdev->irq_info.mic_msi_map);
599 pci_disable_msi(pdev);
600 } else {
601 free_irq(pdev->irq, mdev);
602 }
603 mic_release_callbacks(mdev);
604 }
605 }
606
607 /**
608 * mic_intr_restore - Restore MIC interrupt registers.
609 *
610 * @mdev: pointer to mic_device instance.
611 *
612 * Restore the interrupt registers to values previously
613 * stored in the SW data structures. mic_mutex needs to
614 * be held before calling this function.
615 *
616 * returns None.
617 */
618 void mic_intr_restore(struct mic_device *mdev)
619 {
620 int entry, offset;
621 struct pci_dev *pdev = mdev->pdev;
622
623 if (!pci_dev_msi_enabled(pdev))
624 return;
625
626 for (entry = 0; entry < mdev->irq_info.num_vectors; entry++) {
627 for (offset = 0; offset < MIC_NUM_OFFSETS; offset++) {
628 if (mdev->irq_info.mic_msi_map[entry] & BIT(offset))
629 mdev->intr_ops->program_msi_to_src_map(mdev,
630 entry, offset, true);
631 }
632 }
633 }