1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright (c) 2016-2017 Hisilicon Limited.
3
4 #include <linux/list.h>
5 #include <linux/spinlock.h>
6
7 #include "hnae3.h"
8
9 static LIST_HEAD(hnae3_ae_algo_list);
10 static LIST_HEAD(hnae3_client_list);
11 static LIST_HEAD(hnae3_ae_dev_list);
12
13 /* we are keeping things simple and using single lock for all the
14 * list. This is a non-critical code so other updations, if happen
15 * in parallel, can wait.
16 */
17 static DEFINE_MUTEX(hnae3_common_lock);
18
hnae3_client_match(enum hnae3_client_type client_type,enum hnae3_dev_type dev_type)19 static bool hnae3_client_match(enum hnae3_client_type client_type,
20 enum hnae3_dev_type dev_type)
21 {
22 if ((dev_type == HNAE3_DEV_KNIC) && (client_type == HNAE3_CLIENT_KNIC ||
23 client_type == HNAE3_CLIENT_ROCE))
24 return true;
25
26 if (dev_type == HNAE3_DEV_UNIC && client_type == HNAE3_CLIENT_UNIC)
27 return true;
28
29 return false;
30 }
31
hnae3_set_client_init_flag(struct hnae3_client * client,struct hnae3_ae_dev * ae_dev,int inited)32 void hnae3_set_client_init_flag(struct hnae3_client *client,
33 struct hnae3_ae_dev *ae_dev, int inited)
34 {
35 switch (client->type) {
36 case HNAE3_CLIENT_KNIC:
37 hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited);
38 break;
39 case HNAE3_CLIENT_UNIC:
40 hnae3_set_bit(ae_dev->flag, HNAE3_UNIC_CLIENT_INITED_B, inited);
41 break;
42 case HNAE3_CLIENT_ROCE:
43 hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
44 break;
45 default:
46 break;
47 }
48 }
49 EXPORT_SYMBOL(hnae3_set_client_init_flag);
50
hnae3_get_client_init_flag(struct hnae3_client * client,struct hnae3_ae_dev * ae_dev)51 static int hnae3_get_client_init_flag(struct hnae3_client *client,
52 struct hnae3_ae_dev *ae_dev)
53 {
54 int inited = 0;
55
56 switch (client->type) {
57 case HNAE3_CLIENT_KNIC:
58 inited = hnae3_get_bit(ae_dev->flag,
59 HNAE3_KNIC_CLIENT_INITED_B);
60 break;
61 case HNAE3_CLIENT_UNIC:
62 inited = hnae3_get_bit(ae_dev->flag,
63 HNAE3_UNIC_CLIENT_INITED_B);
64 break;
65 case HNAE3_CLIENT_ROCE:
66 inited = hnae3_get_bit(ae_dev->flag,
67 HNAE3_ROCE_CLIENT_INITED_B);
68 break;
69 default:
70 break;
71 }
72
73 return inited;
74 }
75
hnae3_match_n_instantiate(struct hnae3_client * client,struct hnae3_ae_dev * ae_dev,bool is_reg)76 static int hnae3_match_n_instantiate(struct hnae3_client *client,
77 struct hnae3_ae_dev *ae_dev, bool is_reg)
78 {
79 int ret;
80
81 /* check if this client matches the type of ae_dev */
82 if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
83 hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
84 return 0;
85 }
86
87 /* now, (un-)instantiate client by calling lower layer */
88 if (is_reg) {
89 ret = ae_dev->ops->init_client_instance(client, ae_dev);
90 if (ret)
91 dev_err(&ae_dev->pdev->dev,
92 "fail to instantiate client, ret = %d\n", ret);
93
94 return ret;
95 }
96
97 if (hnae3_get_client_init_flag(client, ae_dev)) {
98 ae_dev->ops->uninit_client_instance(client, ae_dev);
99
100 hnae3_set_client_init_flag(client, ae_dev, 0);
101 }
102
103 return 0;
104 }
105
hnae3_register_client(struct hnae3_client * client)106 int hnae3_register_client(struct hnae3_client *client)
107 {
108 struct hnae3_client *client_tmp;
109 struct hnae3_ae_dev *ae_dev;
110 int ret = 0;
111
112 mutex_lock(&hnae3_common_lock);
113 /* one system should only have one client for every type */
114 list_for_each_entry(client_tmp, &hnae3_client_list, node) {
115 if (client_tmp->type == client->type)
116 goto exit;
117 }
118
119 list_add_tail(&client->node, &hnae3_client_list);
120
121 /* initialize the client on every matched port */
122 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
123 /* if the client could not be initialized on current port, for
124 * any error reasons, move on to next available port
125 */
126 ret = hnae3_match_n_instantiate(client, ae_dev, true);
127 if (ret)
128 dev_err(&ae_dev->pdev->dev,
129 "match and instantiation failed for port, ret = %d\n",
130 ret);
131 }
132
133 exit:
134 mutex_unlock(&hnae3_common_lock);
135
136 return 0;
137 }
138 EXPORT_SYMBOL(hnae3_register_client);
139
hnae3_unregister_client(struct hnae3_client * client)140 void hnae3_unregister_client(struct hnae3_client *client)
141 {
142 struct hnae3_ae_dev *ae_dev;
143
144 mutex_lock(&hnae3_common_lock);
145 /* un-initialize the client on every matched port */
146 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
147 hnae3_match_n_instantiate(client, ae_dev, false);
148 }
149
150 list_del(&client->node);
151 mutex_unlock(&hnae3_common_lock);
152 }
153 EXPORT_SYMBOL(hnae3_unregister_client);
154
155 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
156 * @ae_algo: AE algorithm
157 * NOTE: the duplicated name will not be checked
158 */
hnae3_register_ae_algo(struct hnae3_ae_algo * ae_algo)159 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
160 {
161 const struct pci_device_id *id;
162 struct hnae3_ae_dev *ae_dev;
163 struct hnae3_client *client;
164 int ret = 0;
165
166 mutex_lock(&hnae3_common_lock);
167
168 list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);
169
170 /* Check if this algo/ops matches the list of ae_devs */
171 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
172 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
173 if (!id)
174 continue;
175
176 if (!ae_algo->ops) {
177 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
178 continue;
179 }
180 ae_dev->ops = ae_algo->ops;
181
182 ret = ae_algo->ops->init_ae_dev(ae_dev);
183 if (ret) {
184 dev_err(&ae_dev->pdev->dev,
185 "init ae_dev error, ret = %d\n", ret);
186 continue;
187 }
188
189 /* ae_dev init should set flag */
190 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
191
192 /* check the client list for the match with this ae_dev type and
193 * initialize the figure out client instance
194 */
195 list_for_each_entry(client, &hnae3_client_list, node) {
196 ret = hnae3_match_n_instantiate(client, ae_dev, true);
197 if (ret)
198 dev_err(&ae_dev->pdev->dev,
199 "match and instantiation failed, ret = %d\n",
200 ret);
201 }
202 }
203
204 mutex_unlock(&hnae3_common_lock);
205 }
206 EXPORT_SYMBOL(hnae3_register_ae_algo);
207
208 /* hnae3_unregister_ae_algo - unregisters a AE algorithm
209 * @ae_algo: the AE algorithm to unregister
210 */
hnae3_unregister_ae_algo(struct hnae3_ae_algo * ae_algo)211 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
212 {
213 const struct pci_device_id *id;
214 struct hnae3_ae_dev *ae_dev;
215 struct hnae3_client *client;
216
217 mutex_lock(&hnae3_common_lock);
218 /* Check if there are matched ae_dev */
219 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
220 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
221 continue;
222
223 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
224 if (!id)
225 continue;
226
227 /* check the client list for the match with this ae_dev type and
228 * un-initialize the figure out client instance
229 */
230 list_for_each_entry(client, &hnae3_client_list, node)
231 hnae3_match_n_instantiate(client, ae_dev, false);
232
233 ae_algo->ops->uninit_ae_dev(ae_dev);
234 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
235 ae_dev->ops = NULL;
236 }
237
238 list_del(&ae_algo->node);
239 mutex_unlock(&hnae3_common_lock);
240 }
241 EXPORT_SYMBOL(hnae3_unregister_ae_algo);
242
243 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework
244 * @ae_dev: the AE device
245 * NOTE: the duplicated name will not be checked
246 */
hnae3_register_ae_dev(struct hnae3_ae_dev * ae_dev)247 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
248 {
249 const struct pci_device_id *id;
250 struct hnae3_ae_algo *ae_algo;
251 struct hnae3_client *client;
252 int ret = 0;
253
254 mutex_lock(&hnae3_common_lock);
255
256 list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
257
258 /* Check if there are matched ae_algo */
259 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
260 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
261 if (!id)
262 continue;
263
264 if (!ae_algo->ops) {
265 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
266 ret = -EOPNOTSUPP;
267 goto out_err;
268 }
269 ae_dev->ops = ae_algo->ops;
270
271 ret = ae_dev->ops->init_ae_dev(ae_dev);
272 if (ret) {
273 dev_err(&ae_dev->pdev->dev,
274 "init ae_dev error, ret = %d\n", ret);
275 goto out_err;
276 }
277
278 /* ae_dev init should set flag */
279 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
280 break;
281 }
282
283 /* check the client list for the match with this ae_dev type and
284 * initialize the figure out client instance
285 */
286 list_for_each_entry(client, &hnae3_client_list, node) {
287 ret = hnae3_match_n_instantiate(client, ae_dev, true);
288 if (ret)
289 dev_err(&ae_dev->pdev->dev,
290 "match and instantiation failed, ret = %d\n",
291 ret);
292 }
293
294 mutex_unlock(&hnae3_common_lock);
295
296 return 0;
297
298 out_err:
299 list_del(&ae_dev->node);
300 mutex_unlock(&hnae3_common_lock);
301
302 return ret;
303 }
304 EXPORT_SYMBOL(hnae3_register_ae_dev);
305
306 /* hnae3_unregister_ae_dev - unregisters a AE device
307 * @ae_dev: the AE device to unregister
308 */
hnae3_unregister_ae_dev(struct hnae3_ae_dev * ae_dev)309 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
310 {
311 const struct pci_device_id *id;
312 struct hnae3_ae_algo *ae_algo;
313 struct hnae3_client *client;
314
315 mutex_lock(&hnae3_common_lock);
316 /* Check if there are matched ae_algo */
317 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
318 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
319 continue;
320
321 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
322 if (!id)
323 continue;
324
325 list_for_each_entry(client, &hnae3_client_list, node)
326 hnae3_match_n_instantiate(client, ae_dev, false);
327
328 ae_algo->ops->uninit_ae_dev(ae_dev);
329 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
330 ae_dev->ops = NULL;
331 }
332
333 list_del(&ae_dev->node);
334 mutex_unlock(&hnae3_common_lock);
335 }
336 EXPORT_SYMBOL(hnae3_unregister_ae_dev);
337
338 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
339 MODULE_LICENSE("GPL");
340 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
341 MODULE_VERSION(HNAE3_MOD_VERSION);
342