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