1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "scif_main.h"
18#include "../bus/scif_bus.h"
19#include "scif_peer_bus.h"
20
21static inline struct scif_peer_dev *
22dev_to_scif_peer(struct device *dev)
23{
24 return container_of(dev, struct scif_peer_dev, dev);
25}
26
27struct bus_type scif_peer_bus = {
28 .name = "scif_peer_bus",
29};
30
31static void scif_peer_release_dev(struct device *d)
32{
33 struct scif_peer_dev *sdev = dev_to_scif_peer(d);
34 struct scif_dev *scifdev = &scif_dev[sdev->dnode];
35
36 scif_cleanup_scifdev(scifdev);
37 kfree(sdev);
38}
39
40static int scif_peer_initialize_device(struct scif_dev *scifdev)
41{
42 struct scif_peer_dev *spdev;
43 int ret;
44
45 spdev = kzalloc(sizeof(*spdev), GFP_KERNEL);
46 if (!spdev) {
47 ret = -ENOMEM;
48 goto err;
49 }
50
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);
56
57 device_initialize(&spdev->dev);
58 get_device(&spdev->dev);
59 rcu_assign_pointer(scifdev->spdev, spdev);
60
61 mutex_lock(&scif_info.conflock);
62 scif_info.total++;
63 scif_info.maxid = max_t(u32, spdev->dnode, scif_info.maxid);
64 mutex_unlock(&scif_info.conflock);
65 return 0;
66err:
67 dev_err(&scifdev->sdev->dev,
68 "dnode %d: initialize_device rc %d\n", scifdev->node, ret);
69 return ret;
70}
71
72static int scif_peer_add_device(struct scif_dev *scifdev)
73{
74 struct scif_peer_dev *spdev = rcu_dereference(scifdev->spdev);
75 char pool_name[16];
76 int ret;
77
78 ret = device_add(&spdev->dev);
79 put_device(&spdev->dev);
80 if (ret) {
81 dev_err(&scifdev->sdev->dev,
82 "dnode %d: peer device_add failed\n", scifdev->node);
83 goto put_spdev;
84 }
85
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,
89 0);
90 if (!scifdev->signal_pool) {
91 dev_err(&scifdev->sdev->dev,
92 "dnode %d: dmam_pool_create failed\n", scifdev->node);
93 ret = -ENOMEM;
94 goto del_spdev;
95 }
96 dev_dbg(&spdev->dev, "Added peer dnode %d\n", spdev->dnode);
97 return 0;
98del_spdev:
99 device_del(&spdev->dev);
100put_spdev:
101 RCU_INIT_POINTER(scifdev->spdev, NULL);
102 synchronize_rcu();
103 put_device(&spdev->dev);
104
105 mutex_lock(&scif_info.conflock);
106 scif_info.total--;
107 mutex_unlock(&scif_info.conflock);
108 return ret;
109}
110
111void scif_add_peer_device(struct work_struct *work)
112{
113 struct scif_dev *scifdev = container_of(work, struct scif_dev,
114 peer_add_work);
115
116 scif_peer_add_device(scifdev);
117}
118
119
120
121
122
123
124
125
126
127
128
129
130
131void scif_peer_register_device(struct scif_dev *scifdev)
132{
133 int ret;
134
135 mutex_lock(&scifdev->lock);
136 ret = scif_peer_initialize_device(scifdev);
137 if (ret)
138 goto exit;
139 schedule_work(&scifdev->peer_add_work);
140exit:
141 mutex_unlock(&scifdev->lock);
142}
143
144int scif_peer_unregister_device(struct scif_dev *scifdev)
145{
146 struct scif_peer_dev *spdev;
147
148 mutex_lock(&scifdev->lock);
149
150 flush_work(&scifdev->peer_add_work);
151
152
153
154
155
156 spdev = rcu_dereference(scifdev->spdev);
157 if (!spdev) {
158 mutex_unlock(&scifdev->lock);
159 return -ENODEV;
160 }
161
162 RCU_INIT_POINTER(scifdev->spdev, NULL);
163 synchronize_rcu();
164 mutex_unlock(&scifdev->lock);
165
166 dev_dbg(&spdev->dev, "Removing peer dnode %d\n", spdev->dnode);
167 device_unregister(&spdev->dev);
168
169 mutex_lock(&scif_info.conflock);
170 scif_info.total--;
171 mutex_unlock(&scif_info.conflock);
172 return 0;
173}
174
175int scif_peer_bus_init(void)
176{
177 return bus_register(&scif_peer_bus);
178}
179
180void scif_peer_bus_exit(void)
181{
182 bus_unregister(&scif_peer_bus);
183}
184