2 * Intel MIC Platform Software Stack (MPSS)
4 * Copyright(c) 2014 Intel Corporation.
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.
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.
17 #include "scif_main.h"
18 #include "../bus/scif_bus.h"
19 #include "scif_peer_bus.h"
21 static inline struct scif_peer_dev
*
22 dev_to_scif_peer(struct device
*dev
)
24 return container_of(dev
, struct scif_peer_dev
, dev
);
27 struct bus_type scif_peer_bus
= {
28 .name
= "scif_peer_bus",
31 static void scif_peer_release_dev(struct device
*d
)
33 struct scif_peer_dev
*sdev
= dev_to_scif_peer(d
);
34 struct scif_dev
*scifdev
= &scif_dev
[sdev
->dnode
];
36 scif_cleanup_scifdev(scifdev
);
40 static int scif_peer_initialize_device(struct scif_dev
*scifdev
)
42 struct scif_peer_dev
*spdev
;
45 spdev
= kzalloc(sizeof(*spdev
), GFP_KERNEL
);
51 spdev
->dev
.parent
= scifdev
->sdev
->dev
.parent
;
52 spdev
->dev
.release
= scif_peer_release_dev
;
53 spdev
->dnode
= scifdev
->node
;
54 spdev
->dev
.bus
= &scif_peer_bus
;
55 dev_set_name(&spdev
->dev
, "scif_peer-dev%u", spdev
->dnode
);
57 device_initialize(&spdev
->dev
);
58 get_device(&spdev
->dev
);
59 rcu_assign_pointer(scifdev
->spdev
, spdev
);
61 mutex_lock(&scif_info
.conflock
);
63 scif_info
.maxid
= max_t(u32
, spdev
->dnode
, scif_info
.maxid
);
64 mutex_unlock(&scif_info
.conflock
);
67 dev_err(&scifdev
->sdev
->dev
,
68 "dnode %d: initialize_device rc %d\n", scifdev
->node
, ret
);
72 static int scif_peer_add_device(struct scif_dev
*scifdev
)
74 struct scif_peer_dev
*spdev
= rcu_dereference(scifdev
->spdev
);
78 ret
= device_add(&spdev
->dev
);
79 put_device(&spdev
->dev
);
81 dev_err(&scifdev
->sdev
->dev
,
82 "dnode %d: peer device_add failed\n", scifdev
->node
);
86 scnprintf(pool_name
, sizeof(pool_name
), "scif-%d", spdev
->dnode
);
87 scifdev
->signal_pool
= dmam_pool_create(pool_name
, &scifdev
->sdev
->dev
,
88 sizeof(struct scif_status
), 1,
90 if (!scifdev
->signal_pool
) {
91 dev_err(&scifdev
->sdev
->dev
,
92 "dnode %d: dmam_pool_create failed\n", scifdev
->node
);
96 dev_dbg(&spdev
->dev
, "Added peer dnode %d\n", spdev
->dnode
);
99 device_del(&spdev
->dev
);
101 RCU_INIT_POINTER(scifdev
->spdev
, NULL
);
103 put_device(&spdev
->dev
);
105 mutex_lock(&scif_info
.conflock
);
107 mutex_unlock(&scif_info
.conflock
);
111 void scif_add_peer_device(struct work_struct
*work
)
113 struct scif_dev
*scifdev
= container_of(work
, struct scif_dev
,
116 scif_peer_add_device(scifdev
);
120 * Peer device registration is split into a device_initialize and a device_add.
121 * The reason for doing this is as follows: First, peer device registration
122 * itself cannot be done in the message processing thread and must be delegated
123 * to another workqueue, otherwise if SCIF client probe, called during peer
124 * device registration, calls scif_connect(..), it will block the message
125 * processing thread causing a deadlock. Next, device_initialize is done in the
126 * "top-half" message processing thread and device_add in the "bottom-half"
127 * workqueue. If this is not done, SCIF_CNCT_REQ message processing executing
128 * concurrently with SCIF_INIT message processing is unable to get a reference
129 * on the peer device, thereby failing the connect request.
131 void scif_peer_register_device(struct scif_dev
*scifdev
)
135 mutex_lock(&scifdev
->lock
);
136 ret
= scif_peer_initialize_device(scifdev
);
139 schedule_work(&scifdev
->peer_add_work
);
141 mutex_unlock(&scifdev
->lock
);
144 int scif_peer_unregister_device(struct scif_dev
*scifdev
)
146 struct scif_peer_dev
*spdev
;
148 mutex_lock(&scifdev
->lock
);
149 /* Flush work to ensure device register is complete */
150 flush_work(&scifdev
->peer_add_work
);
153 * Continue holding scifdev->lock since theoretically unregister_device
154 * can be called simultaneously from multiple threads
156 spdev
= rcu_dereference(scifdev
->spdev
);
158 mutex_unlock(&scifdev
->lock
);
162 RCU_INIT_POINTER(scifdev
->spdev
, NULL
);
164 mutex_unlock(&scifdev
->lock
);
166 dev_dbg(&spdev
->dev
, "Removing peer dnode %d\n", spdev
->dnode
);
167 device_unregister(&spdev
->dev
);
169 mutex_lock(&scif_info
.conflock
);
171 mutex_unlock(&scif_info
.conflock
);
175 int scif_peer_bus_init(void)
177 return bus_register(&scif_peer_bus
);
180 void scif_peer_bus_exit(void)
182 bus_unregister(&scif_peer_bus
);