1 // SPDX-License-Identifier: GPL-2.0-only
3 * Intel MIC Platform Software Stack (MPSS)
5 * Copyright(c) 2014 Intel Corporation.
10 #include "../bus/scif_bus.h"
11 #include "scif_peer_bus.h"
13 static inline struct scif_peer_dev
*
14 dev_to_scif_peer(struct device
*dev
)
16 return container_of(dev
, struct scif_peer_dev
, dev
);
19 struct bus_type scif_peer_bus
= {
20 .name
= "scif_peer_bus",
23 static void scif_peer_release_dev(struct device
*d
)
25 struct scif_peer_dev
*sdev
= dev_to_scif_peer(d
);
26 struct scif_dev
*scifdev
= &scif_dev
[sdev
->dnode
];
28 scif_cleanup_scifdev(scifdev
);
32 static int scif_peer_initialize_device(struct scif_dev
*scifdev
)
34 struct scif_peer_dev
*spdev
;
37 spdev
= kzalloc(sizeof(*spdev
), GFP_KERNEL
);
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
);
49 device_initialize(&spdev
->dev
);
50 get_device(&spdev
->dev
);
51 rcu_assign_pointer(scifdev
->spdev
, spdev
);
53 mutex_lock(&scif_info
.conflock
);
55 scif_info
.maxid
= max_t(u32
, spdev
->dnode
, scif_info
.maxid
);
56 mutex_unlock(&scif_info
.conflock
);
59 dev_err(&scifdev
->sdev
->dev
,
60 "dnode %d: initialize_device rc %d\n", scifdev
->node
, ret
);
64 static int scif_peer_add_device(struct scif_dev
*scifdev
)
66 struct scif_peer_dev
*spdev
= rcu_dereference(scifdev
->spdev
);
70 ret
= device_add(&spdev
->dev
);
71 put_device(&spdev
->dev
);
73 dev_err(&scifdev
->sdev
->dev
,
74 "dnode %d: peer device_add failed\n", scifdev
->node
);
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,
82 if (!scifdev
->signal_pool
) {
83 dev_err(&scifdev
->sdev
->dev
,
84 "dnode %d: dmam_pool_create failed\n", scifdev
->node
);
88 dev_dbg(&spdev
->dev
, "Added peer dnode %d\n", spdev
->dnode
);
91 device_del(&spdev
->dev
);
93 RCU_INIT_POINTER(scifdev
->spdev
, NULL
);
95 put_device(&spdev
->dev
);
97 mutex_lock(&scif_info
.conflock
);
99 mutex_unlock(&scif_info
.conflock
);
103 void scif_add_peer_device(struct work_struct
*work
)
105 struct scif_dev
*scifdev
= container_of(work
, struct scif_dev
,
108 scif_peer_add_device(scifdev
);
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.
123 void scif_peer_register_device(struct scif_dev
*scifdev
)
127 mutex_lock(&scifdev
->lock
);
128 ret
= scif_peer_initialize_device(scifdev
);
131 schedule_work(&scifdev
->peer_add_work
);
133 mutex_unlock(&scifdev
->lock
);
136 int scif_peer_unregister_device(struct scif_dev
*scifdev
)
138 struct scif_peer_dev
*spdev
;
140 mutex_lock(&scifdev
->lock
);
141 /* Flush work to ensure device register is complete */
142 flush_work(&scifdev
->peer_add_work
);
145 * Continue holding scifdev->lock since theoretically unregister_device
146 * can be called simultaneously from multiple threads
148 spdev
= rcu_dereference(scifdev
->spdev
);
150 mutex_unlock(&scifdev
->lock
);
154 RCU_INIT_POINTER(scifdev
->spdev
, NULL
);
156 mutex_unlock(&scifdev
->lock
);
158 dev_dbg(&spdev
->dev
, "Removing peer dnode %d\n", spdev
->dnode
);
159 device_unregister(&spdev
->dev
);
161 mutex_lock(&scif_info
.conflock
);
163 mutex_unlock(&scif_info
.conflock
);
167 int scif_peer_bus_init(void)
169 return bus_register(&scif_peer_bus
);
172 void scif_peer_bus_exit(void)
174 bus_unregister(&scif_peer_bus
);