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