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

source code of linux/drivers/net/ethernet/hisilicon/hns3/hnae3.c