]> Git Repo - linux.git/blob - drivers/misc/mic/host/mic_intr.c
net: dsa: sja1105: Implement state machine for TAS with PTP clock source
[linux.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 }
This page took 0.104002 seconds and 4 git commands to generate.