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 
19 static bool hnae3_client_match(enum hnae3_client_type client_type)
20 {
21 	if (client_type == HNAE3_CLIENT_KNIC ||
22 	    client_type == HNAE3_CLIENT_ROCE)
23 		return true;
24 
25 	return false;
26 }
27 
28 void hnae3_set_client_init_flag(struct hnae3_client *client,
29 				struct hnae3_ae_dev *ae_dev,
30 				unsigned int inited)
31 {
32 	if (!client || !ae_dev)
33 		return;
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_ROCE:
40 		hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
41 		break;
42 	default:
43 		break;
44 	}
45 }
46 EXPORT_SYMBOL(hnae3_set_client_init_flag);
47 
48 static int hnae3_get_client_init_flag(struct hnae3_client *client,
49 				       struct hnae3_ae_dev *ae_dev)
50 {
51 	int inited = 0;
52 
53 	switch (client->type) {
54 	case HNAE3_CLIENT_KNIC:
55 		inited = hnae3_get_bit(ae_dev->flag,
56 				       HNAE3_KNIC_CLIENT_INITED_B);
57 		break;
58 	case HNAE3_CLIENT_ROCE:
59 		inited = hnae3_get_bit(ae_dev->flag,
60 				       HNAE3_ROCE_CLIENT_INITED_B);
61 		break;
62 	default:
63 		break;
64 	}
65 
66 	return inited;
67 }
68 
69 static int hnae3_init_client_instance(struct hnae3_client *client,
70 				      struct hnae3_ae_dev *ae_dev)
71 {
72 	int ret;
73 
74 	/* check if this client matches the type of ae_dev */
75 	if (!(hnae3_client_match(client->type) &&
76 	      hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
77 		return 0;
78 	}
79 
80 	ret = ae_dev->ops->init_client_instance(client, ae_dev);
81 	if (ret)
82 		dev_err(&ae_dev->pdev->dev,
83 			"fail to instantiate client, ret = %d\n", ret);
84 
85 	return ret;
86 }
87 
88 static void hnae3_uninit_client_instance(struct hnae3_client *client,
89 					 struct hnae3_ae_dev *ae_dev)
90 {
91 	/* check if this client matches the type of ae_dev */
92 	if (!(hnae3_client_match(client->type) &&
93 	      hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)))
94 		return;
95 
96 	if (hnae3_get_client_init_flag(client, ae_dev)) {
97 		ae_dev->ops->uninit_client_instance(client, ae_dev);
98 
99 		hnae3_set_client_init_flag(client, ae_dev, 0);
100 	}
101 }
102 
103 int hnae3_register_client(struct hnae3_client *client)
104 {
105 	struct hnae3_client *client_tmp;
106 	struct hnae3_ae_dev *ae_dev;
107 	int ret = 0;
108 
109 	if (!client)
110 		return -ENODEV;
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_init_client_instance(client, ae_dev);
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 
140 void hnae3_unregister_client(struct hnae3_client *client)
141 {
142 	struct hnae3_ae_dev *ae_dev;
143 
144 	if (!client)
145 		return;
146 
147 	mutex_lock(&hnae3_common_lock);
148 	/* un-initialize the client on every matched port */
149 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
150 		hnae3_uninit_client_instance(client, ae_dev);
151 	}
152 
153 	list_del(&client->node);
154 	mutex_unlock(&hnae3_common_lock);
155 }
156 EXPORT_SYMBOL(hnae3_unregister_client);
157 
158 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
159  * @ae_algo: AE algorithm
160  * NOTE: the duplicated name will not be checked
161  */
162 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
163 {
164 	const struct pci_device_id *id;
165 	struct hnae3_ae_dev *ae_dev;
166 	struct hnae3_client *client;
167 	int ret = 0;
168 
169 	if (!ae_algo)
170 		return;
171 
172 	mutex_lock(&hnae3_common_lock);
173 
174 	list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);
175 
176 	/* Check if this algo/ops matches the list of ae_devs */
177 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
178 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
179 		if (!id)
180 			continue;
181 
182 		if (!ae_algo->ops) {
183 			dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
184 			continue;
185 		}
186 		ae_dev->ops = ae_algo->ops;
187 
188 		ret = ae_algo->ops->init_ae_dev(ae_dev);
189 		if (ret) {
190 			dev_err(&ae_dev->pdev->dev,
191 				"init ae_dev error, ret = %d\n", ret);
192 			continue;
193 		}
194 
195 		/* ae_dev init should set flag */
196 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
197 
198 		/* check the client list for the match with this ae_dev type and
199 		 * initialize the figure out client instance
200 		 */
201 		list_for_each_entry(client, &hnae3_client_list, node) {
202 			ret = hnae3_init_client_instance(client, ae_dev);
203 			if (ret)
204 				dev_err(&ae_dev->pdev->dev,
205 					"match and instantiation failed, ret = %d\n",
206 					ret);
207 		}
208 	}
209 
210 	mutex_unlock(&hnae3_common_lock);
211 }
212 EXPORT_SYMBOL(hnae3_register_ae_algo);
213 
214 /* hnae3_unregister_ae_algo - unregisters a AE algorithm
215  * @ae_algo: the AE algorithm to unregister
216  */
217 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
218 {
219 	const struct pci_device_id *id;
220 	struct hnae3_ae_dev *ae_dev;
221 	struct hnae3_client *client;
222 
223 	if (!ae_algo)
224 		return;
225 
226 	mutex_lock(&hnae3_common_lock);
227 	/* Check if there are matched ae_dev */
228 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
229 		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
230 			continue;
231 
232 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
233 		if (!id)
234 			continue;
235 
236 		/* check the client list for the match with this ae_dev type and
237 		 * un-initialize the figure out client instance
238 		 */
239 		list_for_each_entry(client, &hnae3_client_list, node)
240 			hnae3_uninit_client_instance(client, ae_dev);
241 
242 		ae_algo->ops->uninit_ae_dev(ae_dev);
243 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
244 		ae_dev->ops = NULL;
245 	}
246 
247 	list_del(&ae_algo->node);
248 	mutex_unlock(&hnae3_common_lock);
249 }
250 EXPORT_SYMBOL(hnae3_unregister_ae_algo);
251 
252 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework
253  * @ae_dev: the AE device
254  * NOTE: the duplicated name will not be checked
255  */
256 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
257 {
258 	const struct pci_device_id *id;
259 	struct hnae3_ae_algo *ae_algo;
260 	struct hnae3_client *client;
261 	int ret = 0;
262 
263 	if (!ae_dev)
264 		return -ENODEV;
265 
266 	mutex_lock(&hnae3_common_lock);
267 
268 	list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
269 
270 	/* Check if there are matched ae_algo */
271 	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
272 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
273 		if (!id)
274 			continue;
275 
276 		if (!ae_algo->ops) {
277 			dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
278 			ret = -EOPNOTSUPP;
279 			goto out_err;
280 		}
281 		ae_dev->ops = ae_algo->ops;
282 
283 		ret = ae_dev->ops->init_ae_dev(ae_dev);
284 		if (ret) {
285 			dev_err(&ae_dev->pdev->dev,
286 				"init ae_dev error, ret = %d\n", ret);
287 			goto out_err;
288 		}
289 
290 		/* ae_dev init should set flag */
291 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
292 		break;
293 	}
294 
295 	/* check the client list for the match with this ae_dev type and
296 	 * initialize the figure out client instance
297 	 */
298 	list_for_each_entry(client, &hnae3_client_list, node) {
299 		ret = hnae3_init_client_instance(client, ae_dev);
300 		if (ret)
301 			dev_err(&ae_dev->pdev->dev,
302 				"match and instantiation failed, ret = %d\n",
303 				ret);
304 	}
305 
306 	mutex_unlock(&hnae3_common_lock);
307 
308 	return 0;
309 
310 out_err:
311 	list_del(&ae_dev->node);
312 	mutex_unlock(&hnae3_common_lock);
313 
314 	return ret;
315 }
316 EXPORT_SYMBOL(hnae3_register_ae_dev);
317 
318 /* hnae3_unregister_ae_dev - unregisters a AE device
319  * @ae_dev: the AE device to unregister
320  */
321 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
322 {
323 	const struct pci_device_id *id;
324 	struct hnae3_ae_algo *ae_algo;
325 	struct hnae3_client *client;
326 
327 	if (!ae_dev)
328 		return;
329 
330 	mutex_lock(&hnae3_common_lock);
331 	/* Check if there are matched ae_algo */
332 	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
333 		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
334 			continue;
335 
336 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
337 		if (!id)
338 			continue;
339 
340 		list_for_each_entry(client, &hnae3_client_list, node)
341 			hnae3_uninit_client_instance(client, ae_dev);
342 
343 		ae_algo->ops->uninit_ae_dev(ae_dev);
344 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
345 		ae_dev->ops = NULL;
346 	}
347 
348 	list_del(&ae_dev->node);
349 	mutex_unlock(&hnae3_common_lock);
350 }
351 EXPORT_SYMBOL(hnae3_unregister_ae_dev);
352 
353 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
354 MODULE_LICENSE("GPL");
355 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
356 MODULE_VERSION(HNAE3_MOD_VERSION);
357