]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/net/ethernet/hisilicon/hns3/hnae3.c
net: hns3: Add a check for client instance init state
[mirror_ubuntu-bionic-kernel.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 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 ret;
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 int 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 return ret;
165 }
166 EXPORT_SYMBOL(hnae3_register_ae_algo);
167
168 /* hnae3_unregister_ae_algo - unregisters a AE algorithm
169 * @ae_algo: the AE algorithm to unregister
170 */
171 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
172 {
173 const struct pci_device_id *id;
174 struct hnae3_ae_dev *ae_dev;
175 struct hnae3_client *client;
176
177 mutex_lock(&hnae3_common_lock);
178 /* Check if there are matched ae_dev */
179 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
180 if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
181 continue;
182
183 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
184 if (!id)
185 continue;
186
187 /* check the client list for the match with this ae_dev type and
188 * un-initialize the figure out client instance
189 */
190 list_for_each_entry(client, &hnae3_client_list, node)
191 hnae3_match_n_instantiate(client, ae_dev, false);
192
193 ae_algo->ops->uninit_ae_dev(ae_dev);
194 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
195 }
196
197 list_del(&ae_algo->node);
198 mutex_unlock(&hnae3_common_lock);
199 }
200 EXPORT_SYMBOL(hnae3_unregister_ae_algo);
201
202 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework
203 * @ae_dev: the AE device
204 * NOTE: the duplicated name will not be checked
205 */
206 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
207 {
208 const struct pci_device_id *id;
209 struct hnae3_ae_algo *ae_algo;
210 struct hnae3_client *client;
211 int ret = 0;
212
213 mutex_lock(&hnae3_common_lock);
214
215 list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
216
217 /* Check if there are matched ae_algo */
218 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
219 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
220 if (!id)
221 continue;
222
223 ae_dev->ops = ae_algo->ops;
224
225 if (!ae_dev->ops) {
226 dev_err(&ae_dev->pdev->dev, "ae_dev ops are null\n");
227 ret = -EOPNOTSUPP;
228 goto out_err;
229 }
230
231 /* ae_dev init should set flag */
232 ret = ae_dev->ops->init_ae_dev(ae_dev);
233 if (ret) {
234 dev_err(&ae_dev->pdev->dev, "init ae_dev error\n");
235 goto out_err;
236 }
237
238 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
239 break;
240 }
241
242 /* check the client list for the match with this ae_dev type and
243 * initialize the figure out client instance
244 */
245 list_for_each_entry(client, &hnae3_client_list, node) {
246 ret = hnae3_match_n_instantiate(client, ae_dev, true);
247 if (ret)
248 dev_err(&ae_dev->pdev->dev,
249 "match and instantiation failed\n");
250 }
251
252 out_err:
253 mutex_unlock(&hnae3_common_lock);
254
255 return ret;
256 }
257 EXPORT_SYMBOL(hnae3_register_ae_dev);
258
259 /* hnae3_unregister_ae_dev - unregisters a AE device
260 * @ae_dev: the AE device to unregister
261 */
262 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
263 {
264 const struct pci_device_id *id;
265 struct hnae3_ae_algo *ae_algo;
266 struct hnae3_client *client;
267
268 mutex_lock(&hnae3_common_lock);
269 /* Check if there are matched ae_algo */
270 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
271 if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
272 continue;
273
274 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
275 if (!id)
276 continue;
277
278 list_for_each_entry(client, &hnae3_client_list, node)
279 hnae3_match_n_instantiate(client, ae_dev, false);
280
281 ae_algo->ops->uninit_ae_dev(ae_dev);
282 hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
283 }
284
285 list_del(&ae_dev->node);
286 mutex_unlock(&hnae3_common_lock);
287 }
288 EXPORT_SYMBOL(hnae3_unregister_ae_dev);
289
290 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
291 MODULE_LICENSE("GPL");
292 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");