blob: 82792b1033d28eec2851a251df9834ac0cc3fe79 [file] [log] [blame]
Sudeep Duttfb4d0e32015-04-29 05:32:33 -07001/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2014 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * Intel SCIF driver.
16 *
17 */
18#include <linux/module.h>
19#include <linux/idr.h>
20
21#include <linux/mic_common.h>
22#include "../common/mic_dev.h"
23#include "../bus/scif_bus.h"
24#include "scif_peer_bus.h"
25#include "scif_main.h"
26#include "scif_map.h"
27
28struct scif_info scif_info = {
29 .mdev = {
30 .minor = MISC_DYNAMIC_MINOR,
31 .name = "scif",
32 .fops = &scif_fops,
33 }
34};
35
36struct scif_dev *scif_dev;
37static atomic_t g_loopb_cnt;
38
39/* Runs in the context of intr_wq */
40static void scif_intr_bh_handler(struct work_struct *work)
41{
42 struct scif_dev *scifdev =
43 container_of(work, struct scif_dev, intr_bh);
44
45 if (scifdev_self(scifdev))
46 scif_loopb_msg_handler(scifdev, scifdev->qpairs);
47 else
48 scif_nodeqp_intrhandler(scifdev, scifdev->qpairs);
49}
50
51int scif_setup_intr_wq(struct scif_dev *scifdev)
52{
53 if (!scifdev->intr_wq) {
54 snprintf(scifdev->intr_wqname, sizeof(scifdev->intr_wqname),
55 "SCIF INTR %d", scifdev->node);
56 scifdev->intr_wq =
57 alloc_ordered_workqueue(scifdev->intr_wqname, 0);
58 if (!scifdev->intr_wq)
59 return -ENOMEM;
60 INIT_WORK(&scifdev->intr_bh, scif_intr_bh_handler);
61 }
62 return 0;
63}
64
65void scif_destroy_intr_wq(struct scif_dev *scifdev)
66{
67 if (scifdev->intr_wq) {
68 destroy_workqueue(scifdev->intr_wq);
69 scifdev->intr_wq = NULL;
70 }
71}
72
73irqreturn_t scif_intr_handler(int irq, void *data)
74{
75 struct scif_dev *scifdev = data;
76 struct scif_hw_dev *sdev = scifdev->sdev;
77
78 sdev->hw_ops->ack_interrupt(sdev, scifdev->db);
79 queue_work(scifdev->intr_wq, &scifdev->intr_bh);
80 return IRQ_HANDLED;
81}
82
83static int scif_peer_probe(struct scif_peer_dev *spdev)
84{
85 struct scif_dev *scifdev = &scif_dev[spdev->dnode];
86
87 mutex_lock(&scif_info.conflock);
88 scif_info.total++;
89 scif_info.maxid = max_t(u32, spdev->dnode, scif_info.maxid);
90 mutex_unlock(&scif_info.conflock);
91 rcu_assign_pointer(scifdev->spdev, spdev);
92
93 /* In the future SCIF kernel client devices will be added here */
94 dev_info(&spdev->dev, "Peer added dnode %d\n",
95 spdev->dnode);
96 return 0;
97}
98
99static void scif_peer_remove(struct scif_peer_dev *spdev)
100{
101 struct scif_dev *scifdev = &scif_dev[spdev->dnode];
102
103 /* In the future SCIF kernel client devices will be removed here */
104 spdev = rcu_dereference(scifdev->spdev);
105 if (spdev)
106 RCU_INIT_POINTER(scifdev->spdev, NULL);
107 synchronize_rcu();
108
109 mutex_lock(&scif_info.conflock);
110 scif_info.total--;
111 mutex_unlock(&scif_info.conflock);
112 dev_info(&spdev->dev, "Peer removed dnode %d\n",
113 spdev->dnode);
114}
115
116static void scif_qp_setup_handler(struct work_struct *work)
117{
118 struct scif_dev *scifdev = container_of(work, struct scif_dev,
119 qp_dwork.work);
120 struct scif_hw_dev *sdev = scifdev->sdev;
121 dma_addr_t da = 0;
122 int err;
123
124 if (scif_is_mgmt_node()) {
125 struct mic_bootparam *bp = sdev->dp;
126
127 da = bp->scif_card_dma_addr;
128 scifdev->rdb = bp->h2c_scif_db;
129 } else {
130 struct mic_bootparam __iomem *bp = sdev->rdp;
131
132 da = readq(&bp->scif_host_dma_addr);
133 scifdev->rdb = ioread8(&bp->c2h_scif_db);
134 }
135 if (da) {
136 err = scif_qp_response(da, scifdev);
137 if (err)
138 dev_err(&scifdev->sdev->dev,
139 "scif_qp_response err %d\n", err);
140 } else {
141 schedule_delayed_work(&scifdev->qp_dwork,
142 msecs_to_jiffies(1000));
143 }
144}
145
146static int scif_setup_scifdev(struct scif_hw_dev *sdev)
147{
148 int i;
149 u8 num_nodes;
150
151 if (sdev->snode) {
152 struct mic_bootparam __iomem *bp = sdev->rdp;
153
154 num_nodes = ioread8(&bp->tot_nodes);
155 } else {
156 struct mic_bootparam *bp = sdev->dp;
157
158 num_nodes = bp->tot_nodes;
159 }
160 scif_dev = kcalloc(num_nodes, sizeof(*scif_dev), GFP_KERNEL);
161 if (!scif_dev)
162 return -ENOMEM;
163 for (i = 0; i < num_nodes; i++) {
164 struct scif_dev *scifdev = &scif_dev[i];
165
166 scifdev->node = i;
167 scifdev->exit = OP_IDLE;
168 init_waitqueue_head(&scifdev->disconn_wq);
169 mutex_init(&scifdev->lock);
170 INIT_WORK(&scifdev->init_msg_work, scif_qp_response_ack);
171 INIT_DELAYED_WORK(&scifdev->p2p_dwork,
172 scif_poll_qp_state);
173 INIT_DELAYED_WORK(&scifdev->qp_dwork,
174 scif_qp_setup_handler);
175 INIT_LIST_HEAD(&scifdev->p2p);
176 RCU_INIT_POINTER(scifdev->spdev, NULL);
177 }
178 return 0;
179}
180
181static void scif_destroy_scifdev(void)
182{
183 kfree(scif_dev);
184}
185
186static int scif_probe(struct scif_hw_dev *sdev)
187{
188 struct scif_dev *scifdev;
189 int rc;
190
191 dev_set_drvdata(&sdev->dev, sdev);
192 if (1 == atomic_add_return(1, &g_loopb_cnt)) {
193 struct scif_dev *loopb_dev;
194
195 rc = scif_setup_scifdev(sdev);
196 if (rc)
197 goto exit;
198 scifdev = &scif_dev[sdev->dnode];
199 scifdev->sdev = sdev;
200 loopb_dev = &scif_dev[sdev->snode];
201 loopb_dev->sdev = sdev;
202 rc = scif_setup_loopback_qp(loopb_dev);
203 if (rc)
204 goto free_sdev;
205 } else {
206 scifdev = &scif_dev[sdev->dnode];
207 scifdev->sdev = sdev;
208 }
209 rc = scif_setup_intr_wq(scifdev);
210 if (rc)
211 goto destroy_loopb;
212 rc = scif_setup_qp(scifdev);
213 if (rc)
214 goto destroy_intr;
215 scifdev->db = sdev->hw_ops->next_db(sdev);
216 scifdev->cookie = sdev->hw_ops->request_irq(sdev, scif_intr_handler,
217 "SCIF_INTR", scifdev,
218 scifdev->db);
219 if (IS_ERR(scifdev->cookie)) {
220 rc = PTR_ERR(scifdev->cookie);
221 goto free_qp;
222 }
223 if (scif_is_mgmt_node()) {
224 struct mic_bootparam *bp = sdev->dp;
225
226 bp->c2h_scif_db = scifdev->db;
227 bp->scif_host_dma_addr = scifdev->qp_dma_addr;
228 } else {
229 struct mic_bootparam __iomem *bp = sdev->rdp;
230
231 iowrite8(scifdev->db, &bp->h2c_scif_db);
232 writeq(scifdev->qp_dma_addr, &bp->scif_card_dma_addr);
233 }
234 schedule_delayed_work(&scifdev->qp_dwork,
235 msecs_to_jiffies(1000));
236 return rc;
237free_qp:
238 scif_free_qp(scifdev);
239destroy_intr:
240 scif_destroy_intr_wq(scifdev);
241destroy_loopb:
242 if (atomic_dec_and_test(&g_loopb_cnt))
243 scif_destroy_loopback_qp(&scif_dev[sdev->snode]);
244free_sdev:
245 scif_destroy_scifdev();
246exit:
247 return rc;
248}
249
250void scif_stop(struct scif_dev *scifdev)
251{
252 struct scif_dev *dev;
253 int i;
254
255 for (i = scif_info.maxid; i >= 0; i--) {
256 dev = &scif_dev[i];
257 if (scifdev_self(dev))
258 continue;
259 scif_handle_remove_node(i);
260 }
261}
262
263static void scif_remove(struct scif_hw_dev *sdev)
264{
265 struct scif_dev *scifdev = &scif_dev[sdev->dnode];
266
267 if (scif_is_mgmt_node()) {
268 struct mic_bootparam *bp = sdev->dp;
269
270 bp->c2h_scif_db = -1;
271 bp->scif_host_dma_addr = 0x0;
272 } else {
273 struct mic_bootparam __iomem *bp = sdev->rdp;
274
275 iowrite8(-1, &bp->h2c_scif_db);
276 writeq(0x0, &bp->scif_card_dma_addr);
277 }
278 if (scif_is_mgmt_node()) {
279 scif_disconnect_node(scifdev->node, true);
280 } else {
281 scif_info.card_initiated_exit = true;
282 scif_stop(scifdev);
283 }
284 if (atomic_dec_and_test(&g_loopb_cnt))
285 scif_destroy_loopback_qp(&scif_dev[sdev->snode]);
286 if (scifdev->cookie) {
287 sdev->hw_ops->free_irq(sdev, scifdev->cookie, scifdev);
288 scifdev->cookie = NULL;
289 }
290 scif_destroy_intr_wq(scifdev);
291 cancel_delayed_work(&scifdev->qp_dwork);
292 scif_free_qp(scifdev);
293 scifdev->rdb = -1;
294 scifdev->sdev = NULL;
295}
296
297static struct scif_peer_driver scif_peer_driver = {
298 .driver.name = KBUILD_MODNAME,
299 .driver.owner = THIS_MODULE,
300 .probe = scif_peer_probe,
301 .remove = scif_peer_remove,
302};
303
304static struct scif_hw_dev_id id_table[] = {
305 { MIC_SCIF_DEV, SCIF_DEV_ANY_ID },
306 { 0 },
307};
308
309static struct scif_driver scif_driver = {
310 .driver.name = KBUILD_MODNAME,
311 .driver.owner = THIS_MODULE,
312 .id_table = id_table,
313 .probe = scif_probe,
314 .remove = scif_remove,
315};
316
317static int _scif_init(void)
318{
319 spin_lock_init(&scif_info.eplock);
320 spin_lock_init(&scif_info.nb_connect_lock);
321 spin_lock_init(&scif_info.port_lock);
322 mutex_init(&scif_info.conflock);
323 mutex_init(&scif_info.connlock);
324 INIT_LIST_HEAD(&scif_info.uaccept);
325 INIT_LIST_HEAD(&scif_info.listen);
326 INIT_LIST_HEAD(&scif_info.zombie);
327 INIT_LIST_HEAD(&scif_info.connected);
328 INIT_LIST_HEAD(&scif_info.disconnected);
329 INIT_LIST_HEAD(&scif_info.nb_connect_list);
330 init_waitqueue_head(&scif_info.exitwq);
331 scif_info.en_msg_log = 0;
332 scif_info.p2p_enable = 1;
333 INIT_WORK(&scif_info.misc_work, scif_misc_handler);
334 idr_init(&scif_ports);
335 return 0;
336}
337
338static void _scif_exit(void)
339{
340 idr_destroy(&scif_ports);
341 scif_destroy_scifdev();
342}
343
344static int __init scif_init(void)
345{
346 struct miscdevice *mdev = &scif_info.mdev;
347 int rc;
348
349 _scif_init();
350 rc = scif_peer_bus_init();
351 if (rc)
352 goto exit;
353 rc = scif_peer_register_driver(&scif_peer_driver);
354 if (rc)
355 goto peer_bus_exit;
356 rc = scif_register_driver(&scif_driver);
357 if (rc)
358 goto unreg_scif_peer;
359 rc = misc_register(mdev);
360 if (rc)
361 goto unreg_scif;
362 scif_init_debugfs();
363 return 0;
364unreg_scif:
365 scif_unregister_driver(&scif_driver);
366unreg_scif_peer:
367 scif_peer_unregister_driver(&scif_peer_driver);
368peer_bus_exit:
369 scif_peer_bus_exit();
370exit:
371 _scif_exit();
372 return rc;
373}
374
375static void __exit scif_exit(void)
376{
377 scif_exit_debugfs();
378 misc_deregister(&scif_info.mdev);
379 scif_unregister_driver(&scif_driver);
380 scif_peer_unregister_driver(&scif_peer_driver);
381 scif_peer_bus_exit();
382 _scif_exit();
383}
384
385module_init(scif_init);
386module_exit(scif_exit);
387
388MODULE_DEVICE_TABLE(scif, id_table);
389MODULE_AUTHOR("Intel Corporation");
390MODULE_DESCRIPTION("Intel(R) SCIF driver");
391MODULE_LICENSE("GPL v2");