Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: mic: add threaded irq support in host driver

Convert mic_request_irq to mic_request_threaded_irq to support threaded
irq for virtual devices on mic bus.

Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Reviewed-by: Nikhil Rao <nikhil.rao@intel.com>
Reviewed-by: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: Siva Yerramreddy <yshivakrishna@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Siva Yerramreddy and committed by
Greg Kroah-Hartman
b8e439f4 726526c3

+96 -60
+72 -49
drivers/misc/mic/host/mic_intr.c
··· 24 24 #include "../common/mic_dev.h" 25 25 #include "mic_device.h" 26 26 27 - /* 28 - * mic_invoke_callback - Invoke callback functions registered for 29 - * the corresponding source id. 30 - * 31 - * @mdev: pointer to the mic_device instance 32 - * @idx: The interrupt source id. 33 - * 34 - * Returns none. 35 - */ 36 - static inline void mic_invoke_callback(struct mic_device *mdev, int idx) 27 + static irqreturn_t mic_thread_fn(int irq, void *dev) 37 28 { 29 + struct mic_device *mdev = dev; 30 + struct mic_intr_info *intr_info = mdev->intr_info; 31 + struct mic_irq_info *irq_info = &mdev->irq_info; 38 32 struct mic_intr_cb *intr_cb; 39 33 struct pci_dev *pdev = container_of(mdev->sdev->parent, 40 - struct pci_dev, dev); 34 + struct pci_dev, dev); 35 + int i; 41 36 42 - spin_lock(&mdev->irq_info.mic_intr_lock); 43 - list_for_each_entry(intr_cb, &mdev->irq_info.cb_list[idx], list) 44 - if (intr_cb->func) 45 - intr_cb->func(pdev->irq, intr_cb->data); 46 - spin_unlock(&mdev->irq_info.mic_intr_lock); 37 + spin_lock(&irq_info->mic_thread_lock); 38 + for (i = intr_info->intr_start_idx[MIC_INTR_DB]; 39 + i < intr_info->intr_len[MIC_INTR_DB]; i++) 40 + if (test_and_clear_bit(i, &irq_info->mask)) { 41 + list_for_each_entry(intr_cb, &irq_info->cb_list[i], 42 + list) 43 + if (intr_cb->thread_fn) 44 + intr_cb->thread_fn(pdev->irq, 45 + intr_cb->data); 46 + } 47 + spin_unlock(&irq_info->mic_thread_lock); 48 + return IRQ_HANDLED; 47 49 } 48 - 49 50 /** 50 51 * mic_interrupt - Generic interrupt handler for 51 52 * MSI and INTx based interrupts. ··· 54 53 static irqreturn_t mic_interrupt(int irq, void *dev) 55 54 { 56 55 struct mic_device *mdev = dev; 57 - struct mic_intr_info *info = mdev->intr_info; 56 + struct mic_intr_info *intr_info = mdev->intr_info; 57 + struct mic_irq_info *irq_info = &mdev->irq_info; 58 + struct mic_intr_cb *intr_cb; 59 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 60 + struct pci_dev, dev); 58 61 u32 mask; 59 62 int i; 60 63 ··· 66 61 if (!mask) 67 62 return IRQ_NONE; 68 63 69 - for (i = info->intr_start_idx[MIC_INTR_DB]; 70 - i < info->intr_len[MIC_INTR_DB]; i++) 71 - if (mask & BIT(i)) 72 - mic_invoke_callback(mdev, i); 73 - 74 - return IRQ_HANDLED; 64 + spin_lock(&irq_info->mic_intr_lock); 65 + for (i = intr_info->intr_start_idx[MIC_INTR_DB]; 66 + i < intr_info->intr_len[MIC_INTR_DB]; i++) 67 + if (mask & BIT(i)) { 68 + list_for_each_entry(intr_cb, &irq_info->cb_list[i], 69 + list) 70 + if (intr_cb->handler) 71 + intr_cb->handler(pdev->irq, 72 + intr_cb->data); 73 + set_bit(i, &irq_info->mask); 74 + } 75 + spin_unlock(&irq_info->mic_intr_lock); 76 + return IRQ_WAKE_THREAD; 75 77 } 76 78 77 79 /* Return the interrupt offset from the index. Index is 0 based. */ ··· 111 99 * 112 100 * @mdev: pointer to the mic_device instance 113 101 * @idx: The source id to be registered. 114 - * @func: The function to be called when the source id receives 102 + * @handler: The function to be called when the source id receives 115 103 * the interrupt. 104 + * @thread_fn: thread fn. corresponding to the handler 116 105 * @data: Private data of the requester. 117 106 * Return the callback structure that was registered or an 118 107 * appropriate error on failure. 119 108 */ 120 109 static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, 121 - u8 idx, irqreturn_t (*func) (int irq, void *dev), 110 + u8 idx, irq_handler_t handler, irq_handler_t thread_fn, 122 111 void *data) 123 112 { 124 113 struct mic_intr_cb *intr_cb; ··· 130 117 if (!intr_cb) 131 118 return ERR_PTR(-ENOMEM); 132 119 133 - intr_cb->func = func; 120 + intr_cb->handler = handler; 121 + intr_cb->thread_fn = thread_fn; 134 122 intr_cb->data = data; 135 123 intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida, 136 124 0, 0, GFP_KERNEL); ··· 140 126 goto ida_fail; 141 127 } 142 128 129 + spin_lock(&mdev->irq_info.mic_thread_lock); 143 130 spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 144 131 list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]); 145 132 spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 133 + spin_unlock(&mdev->irq_info.mic_thread_lock); 146 134 147 135 return intr_cb; 148 136 ida_fail: ··· 168 152 unsigned long flags; 169 153 int i; 170 154 155 + spin_lock(&mdev->irq_info.mic_thread_lock); 156 + spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 171 157 for (i = 0; i < MIC_NUM_OFFSETS; i++) { 172 - spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 173 158 list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { 174 159 intr_cb = list_entry(pos, struct mic_intr_cb, list); 175 160 if (intr_cb->cb_id == idx) { ··· 180 163 kfree(intr_cb); 181 164 spin_unlock_irqrestore( 182 165 &mdev->irq_info.mic_intr_lock, flags); 166 + spin_unlock(&mdev->irq_info.mic_thread_lock); 183 167 return i; 184 168 } 185 169 } 186 - spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 187 170 } 171 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 172 + spin_unlock(&mdev->irq_info.mic_thread_lock); 188 173 return MIC_NUM_OFFSETS; 189 174 } 190 175 ··· 261 242 INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); 262 243 ida_init(&mdev->irq_info.cb_ida); 263 244 spin_lock_init(&mdev->irq_info.mic_intr_lock); 245 + spin_lock_init(&mdev->irq_info.mic_thread_lock); 264 246 return 0; 265 247 } 266 248 ··· 278 258 struct mic_intr_cb *intr_cb; 279 259 int i; 280 260 261 + spin_lock(&mdev->irq_info.mic_thread_lock); 262 + spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 281 263 for (i = 0; i < MIC_NUM_OFFSETS; i++) { 282 - spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 283 264 284 - if (list_empty(&mdev->irq_info.cb_list[i])) { 285 - spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, 286 - flags); 265 + if (list_empty(&mdev->irq_info.cb_list[i])) 287 266 break; 288 - } 289 267 290 268 list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { 291 269 intr_cb = list_entry(pos, struct mic_intr_cb, list); ··· 292 274 intr_cb->cb_id); 293 275 kfree(intr_cb); 294 276 } 295 - spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 296 277 } 278 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 279 + spin_unlock(&mdev->irq_info.mic_thread_lock); 297 280 ida_destroy(&mdev->irq_info.cb_ida); 298 281 kfree(mdev->irq_info.cb_list); 299 282 } ··· 332 313 goto err_nomem2; 333 314 } 334 315 335 - rc = request_irq(pdev->irq, mic_interrupt, 0 , "mic-msi", mdev); 316 + rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn, 317 + 0, "mic-msi", mdev); 336 318 if (rc) { 337 319 dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); 338 320 goto err_irq_req_fail; ··· 373 353 goto err_nomem; 374 354 } 375 355 376 - rc = request_irq(pdev->irq, mic_interrupt, 377 - IRQF_SHARED, "mic-intx", mdev); 356 + rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn, 357 + IRQF_SHARED, "mic-intx", mdev); 378 358 if (rc) 379 359 goto err; 380 360 ··· 411 391 #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) 412 392 413 393 /** 414 - * mic_request_irq - request an irq. mic_mutex needs 394 + * mic_request_threaded_irq - request an irq. mic_mutex needs 415 395 * to be held before calling this function. 416 396 * 417 397 * @mdev: pointer to mic_device instance 418 - * @func: The callback function that handles the interrupt. 398 + * @handler: The callback function that handles the interrupt. 419 399 * The function needs to call ack_interrupts 420 400 * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. 401 + * @thread_fn: thread fn required by request_threaded_irq. 421 402 * @name: The ASCII name of the callee requesting the irq. 422 403 * @data: private data that is returned back when calling the 423 404 * function handler. ··· 433 412 * error code. 434 413 * 435 414 */ 436 - struct mic_irq *mic_request_irq(struct mic_device *mdev, 437 - irqreturn_t (*func)(int irq, void *dev), 438 - const char *name, void *data, int intr_src, 439 - enum mic_intr_type type) 415 + struct mic_irq * 416 + mic_request_threaded_irq(struct mic_device *mdev, 417 + irq_handler_t handler, irq_handler_t thread_fn, 418 + const char *name, void *data, int intr_src, 419 + enum mic_intr_type type) 440 420 { 441 421 u16 offset; 442 422 int rc = 0; ··· 466 444 goto err; 467 445 } 468 446 469 - rc = request_irq(msix->vector, func, 0, name, data); 447 + rc = request_threaded_irq(msix->vector, handler, thread_fn, 448 + 0, name, data); 470 449 if (rc) { 471 450 dev_dbg(mdev->sdev->parent, 472 451 "request irq failed rc = %d\n", rc); ··· 481 458 dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", 482 459 msix->vector, intr_src); 483 460 } else { 484 - intr_cb = mic_register_intr_callback(mdev, 485 - offset, func, data); 461 + intr_cb = mic_register_intr_callback(mdev, offset, handler, 462 + thread_fn, data); 486 463 if (IS_ERR(intr_cb)) { 487 464 dev_err(mdev->sdev->parent, 488 465 "No available callback entries for use\n"); ··· 510 487 * needs to be held before calling this function. 511 488 * 512 489 * @mdev: pointer to mic_device instance 513 - * @cookie: cookie obtained during a successful call to mic_request_irq 490 + * @cookie: cookie obtained during a successful call to mic_request_threaded_irq 514 491 * @data: private data specified by the calling function during the 515 - * mic_request_irq 492 + * mic_request_threaded_irq 516 493 * 517 494 * returns: none. 518 495 */
+17 -7
drivers/misc/mic/host/mic_intr.h
··· 21 21 #ifndef _MIC_INTR_H_ 22 22 #define _MIC_INTR_H_ 23 23 24 + #include <linux/bitops.h> 25 + #include <linux/interrupt.h> 24 26 /* 25 27 * The minimum number of msix vectors required for normal operation. 26 28 * 3 for virtio network, console and block devices. ··· 70 68 * @num_vectors: The number of MSI/MSI-x vectors that have been allocated. 71 69 * @cb_ida: callback ID allocator to track the callbacks registered. 72 70 * @mic_intr_lock: spinlock to protect the interrupt callback list. 71 + * @mic_thread_lock: spinlock to protect the thread callback list. 72 + * This lock is used to protect against thread_fn while 73 + * mic_intr_lock is used to protect against interrupt handler. 73 74 * @cb_list: Array of callback lists one for each source. 75 + * @mask: Mask used by the main thread fn to call the underlying thread fns. 74 76 */ 75 77 struct mic_irq_info { 76 78 int next_avail_src; ··· 83 77 u16 num_vectors; 84 78 struct ida cb_ida; 85 79 spinlock_t mic_intr_lock; 80 + spinlock_t mic_thread_lock; 86 81 struct list_head *cb_list; 82 + unsigned long mask; 87 83 }; 88 84 89 85 /** 90 86 * struct mic_intr_cb - Interrupt callback structure. 91 87 * 92 - * @func: The callback function 88 + * @handler: The callback function 89 + * @thread_fn: The thread_fn. 93 90 * @data: Private data of the requester. 94 91 * @cb_id: The callback id. Identifies this callback. 95 92 * @list: list head pointing to the next callback structure. 96 93 */ 97 94 struct mic_intr_cb { 98 - irqreturn_t (*func) (int irq, void *data); 95 + irq_handler_t handler; 96 + irq_handler_t thread_fn; 99 97 void *data; 100 98 int cb_id; 101 99 struct list_head list; ··· 134 124 }; 135 125 136 126 int mic_next_db(struct mic_device *mdev); 137 - struct mic_irq *mic_request_irq(struct mic_device *mdev, 138 - irqreturn_t (*func)(int irq, void *data), 139 - const char *name, void *data, int intr_src, 140 - enum mic_intr_type type); 141 - 127 + struct mic_irq * 128 + mic_request_threaded_irq(struct mic_device *mdev, 129 + irq_handler_t handler, irq_handler_t thread_fn, 130 + const char *name, void *data, int intr_src, 131 + enum mic_intr_type type); 142 132 void mic_free_irq(struct mic_device *mdev, 143 133 struct mic_irq *cookie, void *data); 144 134 int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev);
+3 -2
drivers/misc/mic/host/mic_main.c
··· 389 389 mutex_lock(&mdev->mic_mutex); 390 390 391 391 mdev->shutdown_db = mic_next_db(mdev); 392 - mdev->shutdown_cookie = mic_request_irq(mdev, mic_shutdown_db, 393 - "shutdown-interrupt", mdev, mdev->shutdown_db, MIC_INTR_DB); 392 + mdev->shutdown_cookie = mic_request_threaded_irq(mdev, mic_shutdown_db, 393 + NULL, "shutdown-interrupt", mdev, 394 + mdev->shutdown_db, MIC_INTR_DB); 394 395 if (IS_ERR(mdev->shutdown_cookie)) { 395 396 rc = PTR_ERR(mdev->shutdown_cookie); 396 397 mutex_unlock(&mdev->mic_mutex);
+4 -2
drivers/misc/mic/host/mic_virtio.c
··· 594 594 snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, 595 595 mvdev->virtio_id); 596 596 mvdev->virtio_db = mic_next_db(mdev); 597 - mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, 598 - irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); 597 + mvdev->virtio_cookie = mic_request_threaded_irq(mdev, 598 + mic_virtio_intr_handler, 599 + NULL, irqname, mvdev, 600 + mvdev->virtio_db, MIC_INTR_DB); 599 601 if (IS_ERR(mvdev->virtio_cookie)) { 600 602 ret = PTR_ERR(mvdev->virtio_cookie); 601 603 dev_dbg(mdev->sdev->parent, "request irq failed\n");