xref: /linux/drivers/net/ethernet/hisilicon/hns3/hnae3.c (revision 02000b55850deeadffe433e4b4930a8831f477de)
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>
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 
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:
43 		hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited);
44 		break;
45 	case HNAE3_CLIENT_UNIC:
46 		hnae3_set_bit(ae_dev->flag, HNAE3_UNIC_CLIENT_INITED_B, inited);
47 		break;
48 	case HNAE3_CLIENT_ROCE:
49 		hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
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:
63 		inited = hnae3_get_bit(ae_dev->flag,
64 				       HNAE3_KNIC_CLIENT_INITED_B);
65 		break;
66 	case HNAE3_CLIENT_UNIC:
67 		inited = hnae3_get_bit(ae_dev->flag,
68 				       HNAE3_UNIC_CLIENT_INITED_B);
69 		break;
70 	case HNAE3_CLIENT_ROCE:
71 		inited = hnae3_get_bit(ae_dev->flag,
72 				       HNAE3_ROCE_CLIENT_INITED_B);
73 		break;
74 	default:
75 		break;
76 	}
77 
78 	return inited;
79 }
80 
81 static int hnae3_match_n_instantiate(struct hnae3_client *client,
82 				     struct hnae3_ae_dev *ae_dev, bool is_reg)
83 {
84 	int ret;
85 
86 	/* check if this client matches the type of ae_dev */
87 	if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
88 	      hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
89 		return 0;
90 	}
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);
95 		if (ret) {
96 			dev_err(&ae_dev->pdev->dev,
97 				"fail to instantiate client, ret = %d\n", ret);
98 			return ret;
99 		}
100 
101 		hnae3_set_client_init_flag(client, ae_dev, 1);
102 		return 0;
103 	}
104 
105 	if (hnae3_get_client_init_flag(client, ae_dev)) {
106 		ae_dev->ops->uninit_client_instance(client, ae_dev);
107 
108 		hnae3_set_client_init_flag(client, ae_dev, 0);
109 	}
110 
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;
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 		 */
134 		ret = hnae3_match_n_instantiate(client, ae_dev, true);
135 		if (ret)
136 			dev_err(&ae_dev->pdev->dev,
137 				"match and instantiation failed for port, ret = %d\n",
138 				ret);
139 	}
140 
141 exit:
142 	mutex_unlock(&hnae3_common_lock);
143 
144 	return 0;
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;
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) {
155 		hnae3_match_n_instantiate(client, ae_dev, false);
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  */
167 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
168 {
169 	const struct pci_device_id *id;
170 	struct hnae3_ae_dev *ae_dev;
171 	struct hnae3_client *client;
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) {
188 			dev_err(&ae_dev->pdev->dev,
189 				"init ae_dev error, ret = %d\n", ret);
190 			continue;
191 		}
192 
193 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
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) {
199 			ret = hnae3_match_n_instantiate(client, ae_dev, true);
200 			if (ret)
201 				dev_err(&ae_dev->pdev->dev,
202 					"match and instantiation failed, ret = %d\n",
203 					ret);
204 		}
205 	}
206 
207 	mutex_unlock(&hnae3_common_lock);
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;
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) {
223 		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
224 			continue;
225 
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 		 */
233 		list_for_each_entry(client, &hnae3_client_list, node)
234 			hnae3_match_n_instantiate(client, ae_dev, false);
235 
236 		ae_algo->ops->uninit_ae_dev(ae_dev);
237 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
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  */
249 void hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
250 {
251 	const struct pci_device_id *id;
252 	struct hnae3_ae_algo *ae_algo;
253 	struct hnae3_client *client;
254 	int ret = 0;
255 
256 	mutex_lock(&hnae3_common_lock);
257 
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) {
276 			dev_err(&ae_dev->pdev->dev,
277 				"init ae_dev error, ret = %d\n", ret);
278 			goto out_err;
279 		}
280 
281 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
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) {
289 		ret = hnae3_match_n_instantiate(client, ae_dev, true);
290 		if (ret)
291 			dev_err(&ae_dev->pdev->dev,
292 				"match and instantiation failed, ret = %d\n",
293 				ret);
294 	}
295 
296 out_err:
297 	mutex_unlock(&hnae3_common_lock);
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;
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) {
313 		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
314 			continue;
315 
316 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
317 		if (!id)
318 			continue;
319 
320 		list_for_each_entry(client, &hnae3_client_list, node)
321 			hnae3_match_n_instantiate(client, ae_dev, false);
322 
323 		ae_algo->ops->uninit_ae_dev(ae_dev);
324 		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
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");
335 MODULE_VERSION(HNAE3_MOD_VERSION);
336