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/slab.h>
12 #include <linux/spinlock.h>
13 
14 #include "hnae3.h"
15 
16 static LIST_HEAD(hnae3_ae_algo_list);
17 static LIST_HEAD(hnae3_client_list);
18 static LIST_HEAD(hnae3_ae_dev_list);
19 
20 /* we are keeping things simple and using single lock for all the
21  * list. This is a non-critical code so other updations, if happen
22  * in parallel, can wait.
23  */
24 static DEFINE_MUTEX(hnae3_common_lock);
25 
26 static bool hnae3_client_match(enum hnae3_client_type client_type,
27 			       enum hnae3_dev_type dev_type)
28 {
29 	if ((dev_type == HNAE3_DEV_KNIC) && (client_type == HNAE3_CLIENT_KNIC ||
30 					     client_type == HNAE3_CLIENT_ROCE))
31 		return true;
32 
33 	if (dev_type == HNAE3_DEV_UNIC && client_type == HNAE3_CLIENT_UNIC)
34 		return true;
35 
36 	return false;
37 }
38 
39 static int hnae3_match_n_instantiate(struct hnae3_client *client,
40 				     struct hnae3_ae_dev *ae_dev, bool is_reg)
41 {
42 	int ret;
43 
44 	/* check if this client matches the type of ae_dev */
45 	if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
46 	      hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
47 		return 0;
48 	}
49 
50 	/* now, (un-)instantiate client by calling lower layer */
51 	if (is_reg) {
52 		ret = ae_dev->ops->init_client_instance(client, ae_dev);
53 		if (ret) {
54 			dev_err(&ae_dev->pdev->dev,
55 				"fail to instantiate client\n");
56 			return ret;
57 		}
58 
59 		hnae_set_bit(ae_dev->flag, HNAE3_CLIENT_INITED_B, 1);
60 		return 0;
61 	}
62 
63 	if (hnae_get_bit(ae_dev->flag, HNAE3_CLIENT_INITED_B)) {
64 		ae_dev->ops->uninit_client_instance(client, ae_dev);
65 
66 		hnae_set_bit(ae_dev->flag, HNAE3_CLIENT_INITED_B, 0);
67 	}
68 
69 	return 0;
70 }
71 
72 int hnae3_register_client(struct hnae3_client *client)
73 {
74 	struct hnae3_client *client_tmp;
75 	struct hnae3_ae_dev *ae_dev;
76 	int ret = 0;
77 
78 	mutex_lock(&hnae3_common_lock);
79 	/* one system should only have one client for every type */
80 	list_for_each_entry(client_tmp, &hnae3_client_list, node) {
81 		if (client_tmp->type == client->type)
82 			goto exit;
83 	}
84 
85 	list_add_tail(&client->node, &hnae3_client_list);
86 
87 	/* initialize the client on every matched port */
88 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
89 		/* if the client could not be initialized on current port, for
90 		 * any error reasons, move on to next available port
91 		 */
92 		ret = hnae3_match_n_instantiate(client, ae_dev, true);
93 		if (ret)
94 			dev_err(&ae_dev->pdev->dev,
95 				"match and instantiation failed for port\n");
96 	}
97 
98 exit:
99 	mutex_unlock(&hnae3_common_lock);
100 
101 	return 0;
102 }
103 EXPORT_SYMBOL(hnae3_register_client);
104 
105 void hnae3_unregister_client(struct hnae3_client *client)
106 {
107 	struct hnae3_ae_dev *ae_dev;
108 
109 	mutex_lock(&hnae3_common_lock);
110 	/* un-initialize the client on every matched port */
111 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
112 		hnae3_match_n_instantiate(client, ae_dev, false);
113 	}
114 
115 	list_del(&client->node);
116 	mutex_unlock(&hnae3_common_lock);
117 }
118 EXPORT_SYMBOL(hnae3_unregister_client);
119 
120 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
121  * @ae_algo: AE algorithm
122  * NOTE: the duplicated name will not be checked
123  */
124 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
125 {
126 	const struct pci_device_id *id;
127 	struct hnae3_ae_dev *ae_dev;
128 	struct hnae3_client *client;
129 	int ret = 0;
130 
131 	mutex_lock(&hnae3_common_lock);
132 
133 	list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);
134 
135 	/* Check if this algo/ops matches the list of ae_devs */
136 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
137 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
138 		if (!id)
139 			continue;
140 
141 		/* ae_dev init should set flag */
142 		ae_dev->ops = ae_algo->ops;
143 		ret = ae_algo->ops->init_ae_dev(ae_dev);
144 		if (ret) {
145 			dev_err(&ae_dev->pdev->dev, "init ae_dev error.\n");
146 			continue;
147 		}
148 
149 		hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
150 
151 		/* check the client list for the match with this ae_dev type and
152 		 * initialize the figure out client instance
153 		 */
154 		list_for_each_entry(client, &hnae3_client_list, node) {
155 			ret = hnae3_match_n_instantiate(client, ae_dev, true);
156 			if (ret)
157 				dev_err(&ae_dev->pdev->dev,
158 					"match and instantiation failed\n");
159 		}
160 	}
161 
162 	mutex_unlock(&hnae3_common_lock);
163 }
164 EXPORT_SYMBOL(hnae3_register_ae_algo);
165 
166 /* hnae3_unregister_ae_algo - unregisters a AE algorithm
167  * @ae_algo: the AE algorithm to unregister
168  */
169 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
170 {
171 	const struct pci_device_id *id;
172 	struct hnae3_ae_dev *ae_dev;
173 	struct hnae3_client *client;
174 
175 	mutex_lock(&hnae3_common_lock);
176 	/* Check if there are matched ae_dev */
177 	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
178 		if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
179 			continue;
180 
181 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
182 		if (!id)
183 			continue;
184 
185 		/* check the client list for the match with this ae_dev type and
186 		 * un-initialize the figure out client instance
187 		 */
188 		list_for_each_entry(client, &hnae3_client_list, node)
189 			hnae3_match_n_instantiate(client, ae_dev, false);
190 
191 		ae_algo->ops->uninit_ae_dev(ae_dev);
192 		hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
193 	}
194 
195 	list_del(&ae_algo->node);
196 	mutex_unlock(&hnae3_common_lock);
197 }
198 EXPORT_SYMBOL(hnae3_unregister_ae_algo);
199 
200 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework
201  * @ae_dev: the AE device
202  * NOTE: the duplicated name will not be checked
203  */
204 void hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
205 {
206 	const struct pci_device_id *id;
207 	struct hnae3_ae_algo *ae_algo;
208 	struct hnae3_client *client;
209 	int ret = 0;
210 
211 	mutex_lock(&hnae3_common_lock);
212 
213 	list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
214 
215 	/* Check if there are matched ae_algo */
216 	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
217 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
218 		if (!id)
219 			continue;
220 
221 		ae_dev->ops = ae_algo->ops;
222 
223 		if (!ae_dev->ops) {
224 			dev_err(&ae_dev->pdev->dev, "ae_dev ops are null\n");
225 			goto out_err;
226 		}
227 
228 		/* ae_dev init should set flag */
229 		ret = ae_dev->ops->init_ae_dev(ae_dev);
230 		if (ret) {
231 			dev_err(&ae_dev->pdev->dev, "init ae_dev error\n");
232 			goto out_err;
233 		}
234 
235 		hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
236 		break;
237 	}
238 
239 	/* check the client list for the match with this ae_dev type and
240 	 * initialize the figure out client instance
241 	 */
242 	list_for_each_entry(client, &hnae3_client_list, node) {
243 		ret = hnae3_match_n_instantiate(client, ae_dev, true);
244 		if (ret)
245 			dev_err(&ae_dev->pdev->dev,
246 				"match and instantiation failed\n");
247 	}
248 
249 out_err:
250 	mutex_unlock(&hnae3_common_lock);
251 }
252 EXPORT_SYMBOL(hnae3_register_ae_dev);
253 
254 /* hnae3_unregister_ae_dev - unregisters a AE device
255  * @ae_dev: the AE device to unregister
256  */
257 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
258 {
259 	const struct pci_device_id *id;
260 	struct hnae3_ae_algo *ae_algo;
261 	struct hnae3_client *client;
262 
263 	mutex_lock(&hnae3_common_lock);
264 	/* Check if there are matched ae_algo */
265 	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
266 		if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
267 			continue;
268 
269 		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
270 		if (!id)
271 			continue;
272 
273 		list_for_each_entry(client, &hnae3_client_list, node)
274 			hnae3_match_n_instantiate(client, ae_dev, false);
275 
276 		ae_algo->ops->uninit_ae_dev(ae_dev);
277 		hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
278 	}
279 
280 	list_del(&ae_dev->node);
281 	mutex_unlock(&hnae3_common_lock);
282 }
283 EXPORT_SYMBOL(hnae3_unregister_ae_dev);
284 
285 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
286 MODULE_LICENSE("GPL");
287 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
288 MODULE_VERSION(HNAE3_MOD_VERSION);
289