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

misc: mic: SCIF module initialization

SCIF module initialization, DMA mapping, ioremap wrapper APIs
and debugfs hooks. SCIF gets probed by the SCIF hardware bus
if SCIF devices were registered by base drivers. A MISC device
is registered to provide the SCIF character device interface.

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

authored by

Sudeep Dutt and committed by
Greg Kroah-Hartman
fb4d0e3d c9d5c53d

+841
+85
drivers/misc/mic/scif/scif_debugfs.c
··· 1 + /* 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/debugfs.h> 19 + #include <linux/seq_file.h> 20 + 21 + #include "../common/mic_dev.h" 22 + #include "scif_main.h" 23 + 24 + /* Debugfs parent dir */ 25 + static struct dentry *scif_dbg; 26 + 27 + static int scif_dev_test(struct seq_file *s, void *unused) 28 + { 29 + int node; 30 + 31 + seq_printf(s, "Total Nodes %d Self Node Id %d Maxid %d\n", 32 + scif_info.total, scif_info.nodeid, 33 + scif_info.maxid); 34 + 35 + if (!scif_dev) 36 + return 0; 37 + 38 + seq_printf(s, "%-16s\t%-16s\n", "node_id", "state"); 39 + 40 + for (node = 0; node <= scif_info.maxid; node++) 41 + seq_printf(s, "%-16d\t%-16s\n", scif_dev[node].node, 42 + _scifdev_alive(&scif_dev[node]) ? 43 + "Running" : "Offline"); 44 + return 0; 45 + } 46 + 47 + static int scif_dev_test_open(struct inode *inode, struct file *file) 48 + { 49 + return single_open(file, scif_dev_test, inode->i_private); 50 + } 51 + 52 + static int scif_dev_test_release(struct inode *inode, struct file *file) 53 + { 54 + return single_release(inode, file); 55 + } 56 + 57 + static const struct file_operations scif_dev_ops = { 58 + .owner = THIS_MODULE, 59 + .open = scif_dev_test_open, 60 + .read = seq_read, 61 + .llseek = seq_lseek, 62 + .release = scif_dev_test_release 63 + }; 64 + 65 + void __init scif_init_debugfs(void) 66 + { 67 + struct dentry *d; 68 + 69 + scif_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); 70 + if (!scif_dbg) { 71 + dev_err(scif_info.mdev.this_device, 72 + "can't create debugfs dir scif\n"); 73 + return; 74 + } 75 + 76 + d = debugfs_create_file("scif_dev", 0444, scif_dbg, 77 + NULL, &scif_dev_ops); 78 + debugfs_create_u8("en_msg_log", 0666, scif_dbg, &scif_info.en_msg_log); 79 + debugfs_create_u8("p2p_enable", 0666, scif_dbg, &scif_info.p2p_enable); 80 + } 81 + 82 + void scif_exit_debugfs(void) 83 + { 84 + debugfs_remove_recursive(scif_dbg); 85 + }
+391
drivers/misc/mic/scif/scif_main.c
··· 1 + /* 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 + 28 + struct scif_info scif_info = { 29 + .mdev = { 30 + .minor = MISC_DYNAMIC_MINOR, 31 + .name = "scif", 32 + .fops = &scif_fops, 33 + } 34 + }; 35 + 36 + struct scif_dev *scif_dev; 37 + static atomic_t g_loopb_cnt; 38 + 39 + /* Runs in the context of intr_wq */ 40 + static 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 + 51 + int 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 + 65 + void 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 + 73 + irqreturn_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 + 83 + static 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 + 99 + static 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 + 116 + static 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 + 146 + static 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 + 181 + static void scif_destroy_scifdev(void) 182 + { 183 + kfree(scif_dev); 184 + } 185 + 186 + static 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; 237 + free_qp: 238 + scif_free_qp(scifdev); 239 + destroy_intr: 240 + scif_destroy_intr_wq(scifdev); 241 + destroy_loopb: 242 + if (atomic_dec_and_test(&g_loopb_cnt)) 243 + scif_destroy_loopback_qp(&scif_dev[sdev->snode]); 244 + free_sdev: 245 + scif_destroy_scifdev(); 246 + exit: 247 + return rc; 248 + } 249 + 250 + void 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 + 263 + static 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 + 297 + static 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 + 304 + static struct scif_hw_dev_id id_table[] = { 305 + { MIC_SCIF_DEV, SCIF_DEV_ANY_ID }, 306 + { 0 }, 307 + }; 308 + 309 + static 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 + 317 + static 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 + 338 + static void _scif_exit(void) 339 + { 340 + idr_destroy(&scif_ports); 341 + scif_destroy_scifdev(); 342 + } 343 + 344 + static 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; 364 + unreg_scif: 365 + scif_unregister_driver(&scif_driver); 366 + unreg_scif_peer: 367 + scif_peer_unregister_driver(&scif_peer_driver); 368 + peer_bus_exit: 369 + scif_peer_bus_exit(); 370 + exit: 371 + _scif_exit(); 372 + return rc; 373 + } 374 + 375 + static 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 + 385 + module_init(scif_init); 386 + module_exit(scif_exit); 387 + 388 + MODULE_DEVICE_TABLE(scif, id_table); 389 + MODULE_AUTHOR("Intel Corporation"); 390 + MODULE_DESCRIPTION("Intel(R) SCIF driver"); 391 + MODULE_LICENSE("GPL v2");
+252
drivers/misc/mic/scif/scif_main.h
··· 1 + /* 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 + #ifndef SCIF_MAIN_H 19 + #define SCIF_MAIN_H 20 + 21 + #include <linux/sched.h> 22 + #include <linux/pci.h> 23 + #include <linux/miscdevice.h> 24 + #include <linux/dmaengine.h> 25 + #include <linux/file.h> 26 + #include <linux/scif.h> 27 + 28 + #include "../common/mic_dev.h" 29 + 30 + #define SCIF_MGMT_NODE 0 31 + #define SCIF_DEFAULT_WATCHDOG_TO 30 32 + #define SCIF_NODE_ACCEPT_TIMEOUT (3 * HZ) 33 + #define SCIF_NODE_ALIVE_TIMEOUT (SCIF_DEFAULT_WATCHDOG_TO * HZ) 34 + 35 + /* 36 + * Generic state used for certain node QP message exchanges 37 + * like Unregister, Alloc etc. 38 + */ 39 + enum scif_msg_state { 40 + OP_IDLE = 1, 41 + OP_IN_PROGRESS, 42 + OP_COMPLETED, 43 + OP_FAILED 44 + }; 45 + 46 + /* 47 + * struct scif_info - Global SCIF information 48 + * 49 + * @nodeid: Node ID this node is to others 50 + * @maxid: Max known node ID 51 + * @total: Total number of SCIF nodes 52 + * @nr_zombies: number of zombie endpoints 53 + * @eplock: Lock to synchronize listening, zombie endpoint lists 54 + * @connlock: Lock to synchronize connected and disconnected lists 55 + * @nb_connect_lock: Synchronize non blocking connect operations 56 + * @port_lock: Synchronize access to SCIF ports 57 + * @uaccept: List of user acceptreq waiting for acceptreg 58 + * @listen: List of listening end points 59 + * @zombie: List of zombie end points with pending RMA's 60 + * @connected: List of end points in connected state 61 + * @disconnected: List of end points in disconnected state 62 + * @nb_connect_list: List for non blocking connections 63 + * @misc_work: miscellaneous SCIF tasks 64 + * @conflock: Lock to synchronize SCIF node configuration changes 65 + * @en_msg_log: Enable debug message logging 66 + * @p2p_enable: Enable P2P SCIF network 67 + * @mdev: The MISC device 68 + * @conn_work: Work for workqueue handling all connections 69 + * @exitwq: Wait queue for waiting for an EXIT node QP message response 70 + * @loopb_dev: Dummy SCIF device used for loopback 71 + * @loopb_wq: Workqueue used for handling loopback messages 72 + * @loopb_wqname[16]: Name of loopback workqueue 73 + * @loopb_work: Used for submitting work to loopb_wq 74 + * @loopb_recv_q: List of messages received on the loopb_wq 75 + * @card_initiated_exit: set when the card has initiated the exit 76 + */ 77 + struct scif_info { 78 + u8 nodeid; 79 + u8 maxid; 80 + u8 total; 81 + u32 nr_zombies; 82 + spinlock_t eplock; 83 + struct mutex connlock; 84 + spinlock_t nb_connect_lock; 85 + spinlock_t port_lock; 86 + struct list_head uaccept; 87 + struct list_head listen; 88 + struct list_head zombie; 89 + struct list_head connected; 90 + struct list_head disconnected; 91 + struct list_head nb_connect_list; 92 + struct work_struct misc_work; 93 + struct mutex conflock; 94 + u8 en_msg_log; 95 + u8 p2p_enable; 96 + struct miscdevice mdev; 97 + struct work_struct conn_work; 98 + wait_queue_head_t exitwq; 99 + struct scif_dev *loopb_dev; 100 + struct workqueue_struct *loopb_wq; 101 + char loopb_wqname[16]; 102 + struct work_struct loopb_work; 103 + struct list_head loopb_recv_q; 104 + bool card_initiated_exit; 105 + }; 106 + 107 + /* 108 + * struct scif_p2p_info - SCIF mapping information used for P2P 109 + * 110 + * @ppi_peer_id - SCIF peer node id 111 + * @ppi_sg - Scatter list for bar information (One for mmio and one for aper) 112 + * @sg_nentries - Number of entries in the scatterlist 113 + * @ppi_da: DMA address for MMIO and APER bars 114 + * @ppi_len: Length of MMIO and APER bars 115 + * @ppi_list: Link in list of mapping information 116 + */ 117 + struct scif_p2p_info { 118 + u8 ppi_peer_id; 119 + struct scatterlist *ppi_sg[2]; 120 + u64 sg_nentries[2]; 121 + dma_addr_t ppi_da[2]; 122 + u64 ppi_len[2]; 123 + #define SCIF_PPI_MMIO 0 124 + #define SCIF_PPI_APER 1 125 + struct list_head ppi_list; 126 + }; 127 + 128 + /* 129 + * struct scif_dev - SCIF remote device specific fields 130 + * 131 + * @node: Node id 132 + * @p2p: List of P2P mapping information 133 + * @qpairs: The node queue pair for exchanging control messages 134 + * @intr_wq: Workqueue for handling Node QP messages 135 + * @intr_wqname: Name of node QP workqueue for handling interrupts 136 + * @intr_bh: Used for submitting work to intr_wq 137 + * @lock: Lock used for synchronizing access to the scif device 138 + * @sdev: SCIF hardware device on the SCIF hardware bus 139 + * @db: doorbell the peer will trigger to generate an interrupt on self 140 + * @rdb: Doorbell to trigger on the peer to generate an interrupt on the peer 141 + * @cookie: Cookie received while registering the interrupt handler 142 + * init_msg_work: work scheduled for SCIF_INIT message processing 143 + * @p2p_dwork: Delayed work to enable polling for P2P state 144 + * @qp_dwork: Delayed work for enabling polling for remote QP information 145 + * @p2p_retry: Number of times to retry polling of P2P state 146 + * @base_addr: P2P aperture bar base address 147 + * @mic_mw mmio: The peer MMIO information used for P2P 148 + * @spdev: SCIF peer device on the SCIF peer bus 149 + * @node_remove_ack_pending: True if a node_remove_ack is pending 150 + * @exit_ack_pending: true if an exit_ack is pending 151 + * @disconn_wq: Used while waiting for a node remove response 152 + * @disconn_rescnt: Keeps track of number of node remove requests sent 153 + * @exit: Status of exit message 154 + * @qp_dma_addr: Queue pair DMA address passed to the peer 155 + */ 156 + struct scif_dev { 157 + u8 node; 158 + struct list_head p2p; 159 + struct scif_qp *qpairs; 160 + struct workqueue_struct *intr_wq; 161 + char intr_wqname[16]; 162 + struct work_struct intr_bh; 163 + struct mutex lock; 164 + struct scif_hw_dev *sdev; 165 + int db; 166 + int rdb; 167 + struct mic_irq *cookie; 168 + struct work_struct init_msg_work; 169 + struct delayed_work p2p_dwork; 170 + struct delayed_work qp_dwork; 171 + int p2p_retry; 172 + dma_addr_t base_addr; 173 + struct mic_mw mmio; 174 + struct scif_peer_dev __rcu *spdev; 175 + bool node_remove_ack_pending; 176 + bool exit_ack_pending; 177 + wait_queue_head_t disconn_wq; 178 + atomic_t disconn_rescnt; 179 + enum scif_msg_state exit; 180 + dma_addr_t qp_dma_addr; 181 + }; 182 + 183 + extern struct scif_info scif_info; 184 + extern struct idr scif_ports; 185 + extern struct scif_dev *scif_dev; 186 + extern const struct file_operations scif_fops; 187 + 188 + /* Size of the RB for the Node QP */ 189 + #define SCIF_NODE_QP_SIZE 0x10000 190 + 191 + #include "scif_nodeqp.h" 192 + 193 + /* 194 + * scifdev_self: 195 + * @dev: The remote SCIF Device 196 + * 197 + * Returns true if the SCIF Device passed is the self aka Loopback SCIF device. 198 + */ 199 + static inline int scifdev_self(struct scif_dev *dev) 200 + { 201 + return dev->node == scif_info.nodeid; 202 + } 203 + 204 + static inline bool scif_is_mgmt_node(void) 205 + { 206 + return !scif_info.nodeid; 207 + } 208 + 209 + /* 210 + * scifdev_is_p2p: 211 + * @dev: The remote SCIF Device 212 + * 213 + * Returns true if the SCIF Device is a MIC Peer to Peer SCIF device. 214 + */ 215 + static inline bool scifdev_is_p2p(struct scif_dev *dev) 216 + { 217 + if (scif_is_mgmt_node()) 218 + return false; 219 + else 220 + return dev != &scif_dev[SCIF_MGMT_NODE] && 221 + !scifdev_self(dev); 222 + } 223 + 224 + /* 225 + * scifdev_alive: 226 + * @scifdev: The remote SCIF Device 227 + * 228 + * Returns true if the remote SCIF Device is running or sleeping for 229 + * this endpoint. 230 + */ 231 + static inline int _scifdev_alive(struct scif_dev *scifdev) 232 + { 233 + struct scif_peer_dev *spdev; 234 + 235 + rcu_read_lock(); 236 + spdev = rcu_dereference(scifdev->spdev); 237 + rcu_read_unlock(); 238 + return !!spdev; 239 + } 240 + 241 + void __init scif_init_debugfs(void); 242 + void scif_exit_debugfs(void); 243 + int scif_setup_intr_wq(struct scif_dev *scifdev); 244 + void scif_destroy_intr_wq(struct scif_dev *scifdev); 245 + void scif_cleanup_scifdev(struct scif_dev *dev); 246 + void scif_handle_remove_node(int node); 247 + void scif_disconnect_node(u32 node_id, bool mgmt_initiated); 248 + void scif_free_qp(struct scif_dev *dev); 249 + void scif_misc_handler(struct work_struct *work); 250 + void scif_stop(struct scif_dev *scifdev); 251 + irqreturn_t scif_intr_handler(int irq, void *data); 252 + #endif /* SCIF_MAIN_H */
+113
drivers/misc/mic/scif/scif_map.h
··· 1 + /* 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 + #ifndef SCIF_MAP_H 19 + #define SCIF_MAP_H 20 + 21 + #include "../bus/scif_bus.h" 22 + 23 + static __always_inline void * 24 + scif_alloc_coherent(dma_addr_t *dma_handle, 25 + struct scif_dev *scifdev, size_t size, 26 + gfp_t gfp) 27 + { 28 + void *va; 29 + 30 + if (scifdev_self(scifdev)) { 31 + va = kmalloc(size, gfp); 32 + if (va) 33 + *dma_handle = virt_to_phys(va); 34 + } else { 35 + va = dma_alloc_coherent(&scifdev->sdev->dev, 36 + size, dma_handle, gfp); 37 + if (va && scifdev_is_p2p(scifdev)) 38 + *dma_handle = *dma_handle + scifdev->base_addr; 39 + } 40 + return va; 41 + } 42 + 43 + static __always_inline void 44 + scif_free_coherent(void *va, dma_addr_t local, 45 + struct scif_dev *scifdev, size_t size) 46 + { 47 + if (scifdev_self(scifdev)) { 48 + kfree(va); 49 + } else { 50 + if (scifdev_is_p2p(scifdev) && local > scifdev->base_addr) 51 + local = local - scifdev->base_addr; 52 + dma_free_coherent(&scifdev->sdev->dev, 53 + size, va, local); 54 + } 55 + } 56 + 57 + static __always_inline int 58 + scif_map_single(dma_addr_t *dma_handle, 59 + void *local, struct scif_dev *scifdev, size_t size) 60 + { 61 + int err = 0; 62 + 63 + if (scifdev_self(scifdev)) { 64 + *dma_handle = virt_to_phys((local)); 65 + } else { 66 + *dma_handle = dma_map_single(&scifdev->sdev->dev, 67 + local, size, DMA_BIDIRECTIONAL); 68 + if (dma_mapping_error(&scifdev->sdev->dev, *dma_handle)) 69 + err = -ENOMEM; 70 + else if (scifdev_is_p2p(scifdev)) 71 + *dma_handle = *dma_handle + scifdev->base_addr; 72 + } 73 + if (err) 74 + *dma_handle = 0; 75 + return err; 76 + } 77 + 78 + static __always_inline void 79 + scif_unmap_single(dma_addr_t local, struct scif_dev *scifdev, 80 + size_t size) 81 + { 82 + if (!scifdev_self(scifdev)) { 83 + if (scifdev_is_p2p(scifdev) && local > scifdev->base_addr) 84 + local = local - scifdev->base_addr; 85 + dma_unmap_single(&scifdev->sdev->dev, local, 86 + size, DMA_BIDIRECTIONAL); 87 + } 88 + } 89 + 90 + static __always_inline void * 91 + scif_ioremap(dma_addr_t phys, size_t size, struct scif_dev *scifdev) 92 + { 93 + void *out_virt; 94 + struct scif_hw_dev *sdev = scifdev->sdev; 95 + 96 + if (scifdev_self(scifdev)) 97 + out_virt = phys_to_virt(phys); 98 + else 99 + out_virt = (void __force *) 100 + sdev->hw_ops->ioremap(sdev, phys, size); 101 + return out_virt; 102 + } 103 + 104 + static __always_inline void 105 + scif_iounmap(void *virt, size_t len, struct scif_dev *scifdev) 106 + { 107 + if (!scifdev_self(scifdev)) { 108 + struct scif_hw_dev *sdev = scifdev->sdev; 109 + 110 + sdev->hw_ops->iounmap(sdev, (void __force __iomem *)virt); 111 + } 112 + } 113 + #endif /* SCIF_MAP_H */