root/drivers/misc/mic/scif/scif_peer_bus.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dev_to_scif_peer
  2. scif_peer_release_dev
  3. scif_peer_initialize_device
  4. scif_peer_add_device
  5. scif_add_peer_device
  6. scif_peer_register_device
  7. scif_peer_unregister_device
  8. scif_peer_bus_init
  9. scif_peer_bus_exit

   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 
  13 static inline struct scif_peer_dev *
  14 dev_to_scif_peer(struct device *dev)
  15 {
  16         return container_of(dev, struct scif_peer_dev, dev);
  17 }
  18 
  19 struct bus_type scif_peer_bus = {
  20         .name  = "scif_peer_bus",
  21 };
  22 
  23 static 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 
  32 static 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;
  58 err:
  59         dev_err(&scifdev->sdev->dev,
  60                 "dnode %d: initialize_device rc %d\n", scifdev->node, ret);
  61         return ret;
  62 }
  63 
  64 static 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;
  90 del_spdev:
  91         device_del(&spdev->dev);
  92 put_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 
 103 void 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  */
 123 void 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);
 132 exit:
 133         mutex_unlock(&scifdev->lock);
 134 }
 135 
 136 int 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 
 167 int scif_peer_bus_init(void)
 168 {
 169         return bus_register(&scif_peer_bus);
 170 }
 171 
 172 void scif_peer_bus_exit(void)
 173 {
 174         bus_unregister(&scif_peer_bus);
 175 }

/* [<][>][^][v][top][bottom][index][help] */