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