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

Configure Feed

Select the types of activity you want to include in your feed.

at v5.9-rc7 175 lines 4.5 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel MIC Platform Software Stack (MPSS) 4 * 5 * Copyright(c) 2014 Intel Corporation. 6 * 7 * Intel SCIF driver. 8 */ 9#include "scif_main.h" 10#include "../bus/scif_bus.h" 11#include "scif_peer_bus.h" 12 13static inline struct scif_peer_dev * 14dev_to_scif_peer(struct device *dev) 15{ 16 return container_of(dev, struct scif_peer_dev, dev); 17} 18 19struct bus_type scif_peer_bus = { 20 .name = "scif_peer_bus", 21}; 22 23static void scif_peer_release_dev(struct device *d) 24{ 25 struct scif_peer_dev *sdev = dev_to_scif_peer(d); 26 struct scif_dev *scifdev = &scif_dev[sdev->dnode]; 27 28 scif_cleanup_scifdev(scifdev); 29 kfree(sdev); 30} 31 32static int scif_peer_initialize_device(struct scif_dev *scifdev) 33{ 34 struct scif_peer_dev *spdev; 35 int ret; 36 37 spdev = kzalloc(sizeof(*spdev), GFP_KERNEL); 38 if (!spdev) { 39 ret = -ENOMEM; 40 goto err; 41 } 42 43 spdev->dev.parent = scifdev->sdev->dev.parent; 44 spdev->dev.release = scif_peer_release_dev; 45 spdev->dnode = scifdev->node; 46 spdev->dev.bus = &scif_peer_bus; 47 dev_set_name(&spdev->dev, "scif_peer-dev%u", spdev->dnode); 48 49 device_initialize(&spdev->dev); 50 get_device(&spdev->dev); 51 rcu_assign_pointer(scifdev->spdev, spdev); 52 53 mutex_lock(&scif_info.conflock); 54 scif_info.total++; 55 scif_info.maxid = max_t(u32, spdev->dnode, scif_info.maxid); 56 mutex_unlock(&scif_info.conflock); 57 return 0; 58err: 59 dev_err(&scifdev->sdev->dev, 60 "dnode %d: initialize_device rc %d\n", scifdev->node, ret); 61 return ret; 62} 63 64static int scif_peer_add_device(struct scif_dev *scifdev) 65{ 66 struct scif_peer_dev *spdev = rcu_dereference(scifdev->spdev); 67 char pool_name[16]; 68 int ret; 69 70 ret = device_add(&spdev->dev); 71 put_device(&spdev->dev); 72 if (ret) { 73 dev_err(&scifdev->sdev->dev, 74 "dnode %d: peer device_add failed\n", scifdev->node); 75 goto put_spdev; 76 } 77 78 scnprintf(pool_name, sizeof(pool_name), "scif-%d", spdev->dnode); 79 scifdev->signal_pool = dmam_pool_create(pool_name, &scifdev->sdev->dev, 80 sizeof(struct scif_status), 1, 81 0); 82 if (!scifdev->signal_pool) { 83 dev_err(&scifdev->sdev->dev, 84 "dnode %d: dmam_pool_create failed\n", scifdev->node); 85 ret = -ENOMEM; 86 goto del_spdev; 87 } 88 dev_dbg(&spdev->dev, "Added peer dnode %d\n", spdev->dnode); 89 return 0; 90del_spdev: 91 device_del(&spdev->dev); 92put_spdev: 93 RCU_INIT_POINTER(scifdev->spdev, NULL); 94 synchronize_rcu(); 95 put_device(&spdev->dev); 96 97 mutex_lock(&scif_info.conflock); 98 scif_info.total--; 99 mutex_unlock(&scif_info.conflock); 100 return ret; 101} 102 103void scif_add_peer_device(struct work_struct *work) 104{ 105 struct scif_dev *scifdev = container_of(work, struct scif_dev, 106 peer_add_work); 107 108 scif_peer_add_device(scifdev); 109} 110 111/* 112 * Peer device registration is split into a device_initialize and a device_add. 113 * The reason for doing this is as follows: First, peer device registration 114 * itself cannot be done in the message processing thread and must be delegated 115 * to another workqueue, otherwise if SCIF client probe, called during peer 116 * device registration, calls scif_connect(..), it will block the message 117 * processing thread causing a deadlock. Next, device_initialize is done in the 118 * "top-half" message processing thread and device_add in the "bottom-half" 119 * workqueue. If this is not done, SCIF_CNCT_REQ message processing executing 120 * concurrently with SCIF_INIT message processing is unable to get a reference 121 * on the peer device, thereby failing the connect request. 122 */ 123void scif_peer_register_device(struct scif_dev *scifdev) 124{ 125 int ret; 126 127 mutex_lock(&scifdev->lock); 128 ret = scif_peer_initialize_device(scifdev); 129 if (ret) 130 goto exit; 131 schedule_work(&scifdev->peer_add_work); 132exit: 133 mutex_unlock(&scifdev->lock); 134} 135 136int scif_peer_unregister_device(struct scif_dev *scifdev) 137{ 138 struct scif_peer_dev *spdev; 139 140 mutex_lock(&scifdev->lock); 141 /* Flush work to ensure device register is complete */ 142 flush_work(&scifdev->peer_add_work); 143 144 /* 145 * Continue holding scifdev->lock since theoretically unregister_device 146 * can be called simultaneously from multiple threads 147 */ 148 spdev = rcu_dereference(scifdev->spdev); 149 if (!spdev) { 150 mutex_unlock(&scifdev->lock); 151 return -ENODEV; 152 } 153 154 RCU_INIT_POINTER(scifdev->spdev, NULL); 155 synchronize_rcu(); 156 mutex_unlock(&scifdev->lock); 157 158 dev_dbg(&spdev->dev, "Removing peer dnode %d\n", spdev->dnode); 159 device_unregister(&spdev->dev); 160 161 mutex_lock(&scif_info.conflock); 162 scif_info.total--; 163 mutex_unlock(&scif_info.conflock); 164 return 0; 165} 166 167int scif_peer_bus_init(void) 168{ 169 return bus_register(&scif_peer_bus); 170} 171 172void scif_peer_bus_exit(void) 173{ 174 bus_unregister(&scif_peer_bus); 175}