Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / micscif / micscif_intr.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36#include "mic/micscif.h"
37#include "mic/micscif_intr.h"
38#include "mic/micscif_nodeqp.h"
39#include "mic_common.h"
40
41/* Runs in the context of sd_intr_wq */
42static void micscif_intr_bh_handler(struct work_struct *work)
43{
44 struct micscif_dev *scifdev =
45 container_of(work, struct micscif_dev, sd_intr_bh);
46
47 /* figure out which qp we got a recv on */
48 struct micscif_qp *qp = micscif_nodeqp_nextmsg(scifdev);
49 if (qp != NULL) {
50 if (is_self_scifdev(scifdev))
51 micscif_loopb_msg_handler(scifdev, qp);
52 else
53 micscif_nodeqp_intrhandler(scifdev, qp);
54 }
55}
56
57int micscif_setup_interrupts(struct micscif_dev *scifdev)
58{
59 if (!scifdev->sd_intr_wq) {
60 snprintf(scifdev->sd_intr_wqname, sizeof(scifdev->sd_intr_wqname),
61 "SCIF INTR %d", scifdev->sd_node);
62
63 /* FIXME: Fix windows */
64 if (!(scifdev->sd_intr_wq =
65 __mic_create_singlethread_workqueue(scifdev->sd_intr_wqname)))
66 return -ENOMEM;
67
68 INIT_WORK(&scifdev->sd_intr_bh, micscif_intr_bh_handler);
69 }
70 return 0;
71}
72
73void micscif_destroy_interrupts(struct micscif_dev *scifdev)
74{
75 destroy_workqueue(scifdev->sd_intr_wq);
76}
77
78#ifdef _MIC_SCIF_
79irqreturn_t micscif_intr_handler(int irq, void *dev_id)
80{
81 struct micscif_dev *dev = (struct micscif_dev *)dev_id;
82 queue_work(dev->sd_intr_wq, &dev->sd_intr_bh);
83 return IRQ_HANDLED;
84}
85
86/*
87 * register_scif_intr_handler() - Registers SCIF interrupt handler with
88 * appropriate IRQ
89 * @dev: per node dev structure to store the intr handle
90 *
91 * IRQ 17 - 24 Corresponds to RDMASR registers RDMASR0 - RRDMASR7.
92 * RDMASR registers are chosen based on the lowest ref count.
93 * There are 8 RDMASRS for the host and the nodes. So When the number of
94 * nodes added to the current node's p2p network increases beyond
95 * 7, it starts sharing the interrupt.
96 */
97int
98register_scif_intr_handler(struct micscif_dev *dev)
99{
100 unsigned int handle = 0;
101 unsigned int i;
102 int ret;
103
104 mutex_lock(&ms_info.mi_conflock);
105
106 /* Find the first lowest ref count */
107 for (i = 0; i < MAX_RDMASR; i++)
108 if (ms_info.mi_intr_rcnt[handle] >
109 ms_info.mi_intr_rcnt[i])
110 handle = i;
111
112 if ((ret = request_irq(get_rdmasr_irq(handle), micscif_intr_handler,
113 IRQF_SHARED, dev->sd_intr_wqname, dev))) {
114 printk(KERN_ERR "Cannot request irq number %d, ret = %d\n"
115 , get_rdmasr_irq(handle), ret);
116 goto error;
117 }
118
119 ms_info.mi_intr_rcnt[handle]++;
120 dev->sd_intr_handle = handle;
121
122 printk("Registered interrupt handler for node %d, for IRQ = %d,"
123 "handle = %d\n", dev->sd_node, get_rdmasr_irq(handle), handle);
124
125error:
126 mutex_unlock(&ms_info.mi_conflock);
127 return ret;
128}
129
130/*
131 * deregister_scif_intr_handler() - Deregisters SCIF interrupt
132 * handler from appropriate IRQ
133 * @dev: per node dev structure to retrieve the intr handle
134 *
135 */
136void
137deregister_scif_intr_handler(struct micscif_dev *dev)
138{
139 unsigned int handle = dev->sd_intr_handle;
140
141 if (handle >= MAX_RDMASR)
142 return;
143
144 mutex_lock(&ms_info.mi_conflock);
145 ms_info.mi_intr_rcnt[handle]--;
146
147 if (ms_info.mi_intr_rcnt[handle] < 0) {
148 printk("scif intr deregister negative ref count"
149 " for node %d, handle = %d, IRQ = %d\n", dev->sd_node,
150 handle, get_rdmasr_irq(handle));
151 WARN_ON(1);
152 }
153
154 mutex_unlock(&ms_info.mi_conflock);
155 free_irq(get_rdmasr_irq(handle), dev);
156 printk("Deregistered interrupt handler for node %d, for IRQ = %d,"
157 "handle = %d\n", dev->sd_node, get_rdmasr_irq(handle), handle);
158}
159#endif /* _MIC_SCIF_ */