Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
[sfrench/cifs-2.6.git] / drivers / net / ethernet / hisilicon / hns3 / hnae3.c
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         ae_dev->ops->uninit_client_instance(client, ae_dev);
60         return 0;
61 }
62
63 int hnae3_register_client(struct hnae3_client *client)
64 {
65         struct hnae3_client *client_tmp;
66         struct hnae3_ae_dev *ae_dev;
67         int ret = 0;
68
69         mutex_lock(&hnae3_common_lock);
70         /* one system should only have one client for every type */
71         list_for_each_entry(client_tmp, &hnae3_client_list, node) {
72                 if (client_tmp->type == client->type)
73                         goto exit;
74         }
75
76         list_add_tail(&client->node, &hnae3_client_list);
77
78         /* initialize the client on every matched port */
79         list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
80                 /* if the client could not be initialized on current port, for
81                  * any error reasons, move on to next available port
82                  */
83                 ret = hnae3_match_n_instantiate(client, ae_dev, true);
84                 if (ret)
85                         dev_err(&ae_dev->pdev->dev,
86                                 "match and instantiation failed for port\n");
87         }
88
89 exit:
90         mutex_unlock(&hnae3_common_lock);
91
92         return ret;
93 }
94 EXPORT_SYMBOL(hnae3_register_client);
95
96 void hnae3_unregister_client(struct hnae3_client *client)
97 {
98         struct hnae3_ae_dev *ae_dev;
99
100         mutex_lock(&hnae3_common_lock);
101         /* un-initialize the client on every matched port */
102         list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
103                 hnae3_match_n_instantiate(client, ae_dev, false);
104         }
105
106         list_del(&client->node);
107         mutex_unlock(&hnae3_common_lock);
108 }
109 EXPORT_SYMBOL(hnae3_unregister_client);
110
111 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
112  * @ae_algo: AE algorithm
113  * NOTE: the duplicated name will not be checked
114  */
115 int hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
116 {
117         const struct pci_device_id *id;
118         struct hnae3_ae_dev *ae_dev;
119         struct hnae3_client *client;
120         int ret = 0;
121
122         mutex_lock(&hnae3_common_lock);
123
124         list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);
125
126         /* Check if this algo/ops matches the list of ae_devs */
127         list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
128                 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
129                 if (!id)
130                         continue;
131
132                 /* ae_dev init should set flag */
133                 ae_dev->ops = ae_algo->ops;
134                 ret = ae_algo->ops->init_ae_dev(ae_dev);
135                 if (ret) {
136                         dev_err(&ae_dev->pdev->dev, "init ae_dev error.\n");
137                         continue;
138                 }
139
140                 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
141
142                 /* check the client list for the match with this ae_dev type and
143                  * initialize the figure out client instance
144                  */
145                 list_for_each_entry(client, &hnae3_client_list, node) {
146                         ret = hnae3_match_n_instantiate(client, ae_dev, true);
147                         if (ret)
148                                 dev_err(&ae_dev->pdev->dev,
149                                         "match and instantiation failed\n");
150                 }
151         }
152
153         mutex_unlock(&hnae3_common_lock);
154
155         return ret;
156 }
157 EXPORT_SYMBOL(hnae3_register_ae_algo);
158
159 /* hnae3_unregister_ae_algo - unregisters a AE algorithm
160  * @ae_algo: the AE algorithm to unregister
161  */
162 void hnae3_unregister_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
168         mutex_lock(&hnae3_common_lock);
169         /* Check if there are matched ae_dev */
170         list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
171                 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
172                 if (!id)
173                         continue;
174
175                 /* check the client list for the match with this ae_dev type and
176                  * un-initialize the figure out client instance
177                  */
178                 list_for_each_entry(client, &hnae3_client_list, node)
179                         hnae3_match_n_instantiate(client, ae_dev, false);
180
181                 ae_algo->ops->uninit_ae_dev(ae_dev);
182                 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
183         }
184
185         list_del(&ae_algo->node);
186         mutex_unlock(&hnae3_common_lock);
187 }
188 EXPORT_SYMBOL(hnae3_unregister_ae_algo);
189
190 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework
191  * @ae_dev: the AE device
192  * NOTE: the duplicated name will not be checked
193  */
194 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
195 {
196         const struct pci_device_id *id;
197         struct hnae3_ae_algo *ae_algo;
198         struct hnae3_client *client;
199         int ret = 0;
200
201         mutex_lock(&hnae3_common_lock);
202         list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
203
204         /* Check if there are matched ae_algo */
205         list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
206                 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
207                 if (!id)
208                         continue;
209
210                 ae_dev->ops = ae_algo->ops;
211
212                 if (!ae_dev->ops) {
213                         dev_err(&ae_dev->pdev->dev, "ae_dev ops are null\n");
214                         goto out_err;
215                 }
216
217                 /* ae_dev init should set flag */
218                 ret = ae_dev->ops->init_ae_dev(ae_dev);
219                 if (ret) {
220                         dev_err(&ae_dev->pdev->dev, "init ae_dev error\n");
221                         goto out_err;
222                 }
223
224                 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
225                 break;
226         }
227
228         /* check the client list for the match with this ae_dev type and
229          * initialize the figure out client instance
230          */
231         list_for_each_entry(client, &hnae3_client_list, node) {
232                 ret = hnae3_match_n_instantiate(client, ae_dev, true);
233                 if (ret)
234                         dev_err(&ae_dev->pdev->dev,
235                                 "match and instantiation failed\n");
236         }
237
238 out_err:
239         mutex_unlock(&hnae3_common_lock);
240
241         return ret;
242 }
243 EXPORT_SYMBOL(hnae3_register_ae_dev);
244
245 /* hnae3_unregister_ae_dev - unregisters a AE device
246  * @ae_dev: the AE device to unregister
247  */
248 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
249 {
250         const struct pci_device_id *id;
251         struct hnae3_ae_algo *ae_algo;
252         struct hnae3_client *client;
253
254         mutex_lock(&hnae3_common_lock);
255         /* Check if there are matched ae_algo */
256         list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
257                 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
258                 if (!id)
259                         continue;
260
261                 list_for_each_entry(client, &hnae3_client_list, node)
262                         hnae3_match_n_instantiate(client, ae_dev, false);
263
264                 ae_algo->ops->uninit_ae_dev(ae_dev);
265                 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
266         }
267
268         list_del(&ae_dev->node);
269         mutex_unlock(&hnae3_common_lock);
270 }
271 EXPORT_SYMBOL(hnae3_unregister_ae_dev);
272
273 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
274 MODULE_LICENSE("GPL");
275 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");