]>
Commit | Line | Data |
---|---|---|
d71d8381 JS |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // Copyright (c) 2016-2017 Hisilicon Limited. | |
38caee9d S |
3 | |
4 | #include <linux/list.h> | |
38caee9d S |
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 | ||
0dd8a25f PL |
13 | void 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(ae_algo->pdev_id_table, ae_dev->pdev); | |
26 | if (!pci_id) | |
27 | continue; | |
28 | if (IS_ENABLED(CONFIG_PCI_IOV)) | |
29 | pci_disable_sriov(ae_dev->pdev); | |
30 | } | |
31 | } | |
32 | EXPORT_SYMBOL(hnae3_unregister_ae_algo_prepare); | |
33 | ||
38caee9d S |
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 | */ | |
38 | static DEFINE_MUTEX(hnae3_common_lock); | |
39 | ||
b69c9737 | 40 | static bool hnae3_client_match(enum hnae3_client_type client_type) |
38caee9d | 41 | { |
b69c9737 YL |
42 | if (client_type == HNAE3_CLIENT_KNIC || |
43 | client_type == HNAE3_CLIENT_ROCE) | |
38caee9d S |
44 | return true; |
45 | ||
46 | return false; | |
47 | } | |
48 | ||
d9f28fc2 | 49 | void hnae3_set_client_init_flag(struct hnae3_client *client, |
ebaf1908 WL |
50 | struct hnae3_ae_dev *ae_dev, |
51 | unsigned int inited) | |
90b99b09 | 52 | { |
bdd59d66 YL |
53 | if (!client || !ae_dev) |
54 | return; | |
55 | ||
90b99b09 PL |
56 | switch (client->type) { |
57 | case HNAE3_CLIENT_KNIC: | |
e4e87715 | 58 | hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited); |
90b99b09 | 59 | break; |
90b99b09 | 60 | case HNAE3_CLIENT_ROCE: |
e4e87715 | 61 | hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited); |
90b99b09 PL |
62 | break; |
63 | default: | |
64 | break; | |
65 | } | |
66 | } | |
d9f28fc2 | 67 | EXPORT_SYMBOL(hnae3_set_client_init_flag); |
90b99b09 PL |
68 | |
69 | static int hnae3_get_client_init_flag(struct hnae3_client *client, | |
37417c66 | 70 | struct hnae3_ae_dev *ae_dev) |
90b99b09 PL |
71 | { |
72 | int inited = 0; | |
73 | ||
74 | switch (client->type) { | |
75 | case HNAE3_CLIENT_KNIC: | |
e4e87715 | 76 | inited = hnae3_get_bit(ae_dev->flag, |
90b99b09 PL |
77 | HNAE3_KNIC_CLIENT_INITED_B); |
78 | break; | |
90b99b09 | 79 | case HNAE3_CLIENT_ROCE: |
e4e87715 PL |
80 | inited = hnae3_get_bit(ae_dev->flag, |
81 | HNAE3_ROCE_CLIENT_INITED_B); | |
90b99b09 PL |
82 | break; |
83 | default: | |
84 | break; | |
85 | } | |
86 | ||
87 | return inited; | |
88 | } | |
89 | ||
d223dfa4 JS |
90 | static int hnae3_init_client_instance(struct hnae3_client *client, |
91 | struct hnae3_ae_dev *ae_dev) | |
38caee9d S |
92 | { |
93 | int ret; | |
94 | ||
38caee9d | 95 | /* check if this client matches the type of ae_dev */ |
b69c9737 | 96 | if (!(hnae3_client_match(client->type) && |
e4e87715 | 97 | hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) { |
38caee9d S |
98 | return 0; |
99 | } | |
38caee9d | 100 | |
d223dfa4 JS |
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); | |
e3afa963 | 105 | |
d223dfa4 JS |
106 | return ret; |
107 | } | |
108 | ||
109 | static 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 */ | |
b69c9737 | 113 | if (!(hnae3_client_match(client->type) && |
d223dfa4 JS |
114 | hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) |
115 | return; | |
e3afa963 | 116 | |
90b99b09 | 117 | if (hnae3_get_client_init_flag(client, ae_dev)) { |
e3afa963 FL |
118 | ae_dev->ops->uninit_client_instance(client, ae_dev); |
119 | ||
90b99b09 | 120 | hnae3_set_client_init_flag(client, ae_dev, 0); |
38caee9d | 121 | } |
38caee9d S |
122 | } |
123 | ||
124 | int hnae3_register_client(struct hnae3_client *client) | |
125 | { | |
126 | struct hnae3_client *client_tmp; | |
127 | struct hnae3_ae_dev *ae_dev; | |
38caee9d | 128 | |
bdd59d66 YL |
129 | if (!client) |
130 | return -ENODEV; | |
131 | ||
38caee9d S |
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(&client->node, &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 | */ | |
cdd332ac | 146 | int ret = hnae3_init_client_instance(client, ae_dev); |
38caee9d S |
147 | if (ret) |
148 | dev_err(&ae_dev->pdev->dev, | |
ccc2bef8 PL |
149 | "match and instantiation failed for port, ret = %d\n", |
150 | ret); | |
38caee9d S |
151 | } |
152 | ||
153 | exit: | |
154 | mutex_unlock(&hnae3_common_lock); | |
155 | ||
0c698257 | 156 | return 0; |
38caee9d S |
157 | } |
158 | EXPORT_SYMBOL(hnae3_register_client); | |
159 | ||
160 | void hnae3_unregister_client(struct hnae3_client *client) | |
161 | { | |
b7cf22b7 | 162 | struct hnae3_client *client_tmp; |
38caee9d | 163 | struct hnae3_ae_dev *ae_dev; |
b7cf22b7 | 164 | bool existed = false; |
38caee9d | 165 | |
bdd59d66 YL |
166 | if (!client) |
167 | return; | |
168 | ||
38caee9d | 169 | mutex_lock(&hnae3_common_lock); |
9e690456 | 170 | /* one system should only have one client for every type */ |
b7cf22b7 PL |
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(&hnae3_common_lock); | |
180 | pr_err("client %s does not exist!\n", client->name); | |
181 | return; | |
182 | } | |
183 | ||
38caee9d S |
184 | /* un-initialize the client on every matched port */ |
185 | list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { | |
d223dfa4 | 186 | hnae3_uninit_client_instance(client, ae_dev); |
38caee9d S |
187 | } |
188 | ||
189 | list_del(&client->node); | |
190 | mutex_unlock(&hnae3_common_lock); | |
191 | } | |
192 | EXPORT_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 | */ | |
854cf33a | 198 | void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo) |
38caee9d S |
199 | { |
200 | const struct pci_device_id *id; | |
201 | struct hnae3_ae_dev *ae_dev; | |
202 | struct hnae3_client *client; | |
cdd332ac | 203 | int ret; |
38caee9d | 204 | |
bdd59d66 YL |
205 | if (!ae_algo) |
206 | return; | |
207 | ||
38caee9d S |
208 | mutex_lock(&hnae3_common_lock); |
209 | ||
210 | list_add_tail(&ae_algo->node, &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(ae_algo->pdev_id_table, ae_dev->pdev); | |
215 | if (!id) | |
216 | continue; | |
217 | ||
676131f7 YL |
218 | if (!ae_algo->ops) { |
219 | dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); | |
220 | continue; | |
221 | } | |
38caee9d | 222 | ae_dev->ops = ae_algo->ops; |
676131f7 | 223 | |
38caee9d S |
224 | ret = ae_algo->ops->init_ae_dev(ae_dev); |
225 | if (ret) { | |
ccc2bef8 PL |
226 | dev_err(&ae_dev->pdev->dev, |
227 | "init ae_dev error, ret = %d\n", ret); | |
38caee9d S |
228 | continue; |
229 | } | |
230 | ||
676131f7 | 231 | /* ae_dev init should set flag */ |
e4e87715 | 232 | hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); |
38caee9d S |
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) { | |
d223dfa4 | 238 | ret = hnae3_init_client_instance(client, ae_dev); |
38caee9d S |
239 | if (ret) |
240 | dev_err(&ae_dev->pdev->dev, | |
ccc2bef8 PL |
241 | "match and instantiation failed, ret = %d\n", |
242 | ret); | |
38caee9d S |
243 | } |
244 | } | |
245 | ||
246 | mutex_unlock(&hnae3_common_lock); | |
38caee9d S |
247 | } |
248 | EXPORT_SYMBOL(hnae3_register_ae_algo); | |
249 | ||
250 | /* hnae3_unregister_ae_algo - unregisters a AE algorithm | |
251 | * @ae_algo: the AE algorithm to unregister | |
252 | */ | |
253 | void 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; | |
38caee9d | 258 | |
bdd59d66 YL |
259 | if (!ae_algo) |
260 | return; | |
261 | ||
38caee9d S |
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) { | |
e4e87715 | 265 | if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) |
3e249d3b FL |
266 | continue; |
267 | ||
38caee9d S |
268 | id = pci_match_id(ae_algo->pdev_id_table, 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 | */ | |
90f7b11a | 275 | list_for_each_entry(client, &hnae3_client_list, node) |
d223dfa4 | 276 | hnae3_uninit_client_instance(client, ae_dev); |
38caee9d S |
277 | |
278 | ae_algo->ops->uninit_ae_dev(ae_dev); | |
e4e87715 | 279 | hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); |
594a81b3 | 280 | ae_dev->ops = NULL; |
38caee9d S |
281 | } |
282 | ||
283 | list_del(&ae_algo->node); | |
284 | mutex_unlock(&hnae3_common_lock); | |
285 | } | |
286 | EXPORT_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 | */ | |
74354140 | 292 | int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev) |
38caee9d S |
293 | { |
294 | const struct pci_device_id *id; | |
295 | struct hnae3_ae_algo *ae_algo; | |
296 | struct hnae3_client *client; | |
cdd332ac | 297 | int ret; |
424eb834 | 298 | |
bdd59d66 YL |
299 | if (!ae_dev) |
300 | return -ENODEV; | |
301 | ||
2312e050 | 302 | mutex_lock(&hnae3_common_lock); |
38caee9d | 303 | |
38caee9d S |
304 | list_add_tail(&ae_dev->node, &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(ae_algo->pdev_id_table, ae_dev->pdev); | |
309 | if (!id) | |
310 | continue; | |
311 | ||
676131f7 YL |
312 | if (!ae_algo->ops) { |
313 | dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); | |
74354140 | 314 | ret = -EOPNOTSUPP; |
38caee9d S |
315 | goto out_err; |
316 | } | |
676131f7 | 317 | ae_dev->ops = ae_algo->ops; |
38caee9d | 318 | |
38caee9d S |
319 | ret = ae_dev->ops->init_ae_dev(ae_dev); |
320 | if (ret) { | |
ccc2bef8 PL |
321 | dev_err(&ae_dev->pdev->dev, |
322 | "init ae_dev error, ret = %d\n", ret); | |
38caee9d S |
323 | goto out_err; |
324 | } | |
325 | ||
676131f7 | 326 | /* ae_dev init should set flag */ |
e4e87715 | 327 | hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); |
38caee9d S |
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) { | |
d223dfa4 | 335 | ret = hnae3_init_client_instance(client, ae_dev); |
38caee9d S |
336 | if (ret) |
337 | dev_err(&ae_dev->pdev->dev, | |
ccc2bef8 PL |
338 | "match and instantiation failed, ret = %d\n", |
339 | ret); | |
38caee9d S |
340 | } |
341 | ||
74354140 HT |
342 | mutex_unlock(&hnae3_common_lock); |
343 | ||
344 | return 0; | |
345 | ||
38caee9d | 346 | out_err: |
74354140 | 347 | list_del(&ae_dev->node); |
38caee9d | 348 | mutex_unlock(&hnae3_common_lock); |
74354140 HT |
349 | |
350 | return ret; | |
38caee9d S |
351 | } |
352 | EXPORT_SYMBOL(hnae3_register_ae_dev); | |
353 | ||
354 | /* hnae3_unregister_ae_dev - unregisters a AE device | |
355 | * @ae_dev: the AE device to unregister | |
356 | */ | |
357 | void 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; | |
38caee9d | 362 | |
bdd59d66 YL |
363 | if (!ae_dev) |
364 | return; | |
365 | ||
38caee9d S |
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) { | |
e4e87715 | 369 | if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) |
3e249d3b FL |
370 | continue; |
371 | ||
38caee9d S |
372 | id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); |
373 | if (!id) | |
374 | continue; | |
375 | ||
90f7b11a | 376 | list_for_each_entry(client, &hnae3_client_list, node) |
d223dfa4 | 377 | hnae3_uninit_client_instance(client, ae_dev); |
38caee9d S |
378 | |
379 | ae_algo->ops->uninit_ae_dev(ae_dev); | |
e4e87715 | 380 | hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); |
594a81b3 | 381 | ae_dev->ops = NULL; |
38caee9d S |
382 | } |
383 | ||
384 | list_del(&ae_dev->node); | |
385 | mutex_unlock(&hnae3_common_lock); | |
386 | } | |
387 | EXPORT_SYMBOL(hnae3_unregister_ae_dev); | |
388 | ||
389 | MODULE_AUTHOR("Huawei Tech. Co., Ltd."); | |
390 | MODULE_LICENSE("GPL"); | |
391 | MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework"); | |
3c7624d8 | 392 | MODULE_VERSION(HNAE3_MOD_VERSION); |