]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - 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
CommitLineData
38caee9d
S
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
16static LIST_HEAD(hnae3_ae_algo_list);
17static LIST_HEAD(hnae3_client_list);
18static 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 */
24static DEFINE_MUTEX(hnae3_common_lock);
25
26static 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
39static int hnae3_match_n_instantiate(struct hnae3_client *client,
90f7b11a 40 struct hnae3_ae_dev *ae_dev, bool is_reg)
38caee9d
S
41{
42 int ret;
43
38caee9d
S
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 }
38caee9d
S
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);
90400e41 53 if (ret) {
38caee9d
S
54 dev_err(&ae_dev->pdev->dev,
55 "fail to instantiate client\n");
90400e41
FL
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);
38caee9d
S
67 }
68
38caee9d
S
69 return 0;
70}
71
72int hnae3_register_client(struct hnae3_client *client)
73{
74 struct hnae3_client *client_tmp;
75 struct hnae3_ae_dev *ae_dev;
38caee9d
S
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 */
90f7b11a 92 ret = hnae3_match_n_instantiate(client, ae_dev, true);
38caee9d
S
93 if (ret)
94 dev_err(&ae_dev->pdev->dev,
95 "match and instantiation failed for port\n");
96 }
97
98exit:
99 mutex_unlock(&hnae3_common_lock);
100
101 return ret;
102}
103EXPORT_SYMBOL(hnae3_register_client);
104
105void hnae3_unregister_client(struct hnae3_client *client)
106{
107 struct hnae3_ae_dev *ae_dev;
38caee9d
S
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) {
90f7b11a 112 hnae3_match_n_instantiate(client, ae_dev, false);
38caee9d
S
113 }
114
115 list_del(&client->node);
116 mutex_unlock(&hnae3_common_lock);
117}
118EXPORT_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 */
124int 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;
38caee9d
S
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) {
90f7b11a 155 ret = hnae3_match_n_instantiate(client, ae_dev, true);
38caee9d
S
156 if (ret)
157 dev_err(&ae_dev->pdev->dev,
158 "match and instantiation failed\n");
38caee9d
S
159 }
160 }
161
162 mutex_unlock(&hnae3_common_lock);
163
164 return ret;
165}
166EXPORT_SYMBOL(hnae3_register_ae_algo);
167
168/* hnae3_unregister_ae_algo - unregisters a AE algorithm
169 * @ae_algo: the AE algorithm to unregister
170 */
171void 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;
38caee9d
S
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) {
6c46284e
FL
180 if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
181 continue;
182
38caee9d
S
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 */
90f7b11a
L
190 list_for_each_entry(client, &hnae3_client_list, node)
191 hnae3_match_n_instantiate(client, ae_dev, false);
38caee9d
S
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}
200EXPORT_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 */
206int 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;
bc59f827 211 int ret = 0;
a9c89a3f 212
bc59f827 213 mutex_lock(&hnae3_common_lock);
38caee9d 214
38caee9d
S
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");
a9c89a3f 227 ret = -EOPNOTSUPP;
38caee9d
S
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) {
90f7b11a 246 ret = hnae3_match_n_instantiate(client, ae_dev, true);
38caee9d
S
247 if (ret)
248 dev_err(&ae_dev->pdev->dev,
249 "match and instantiation failed\n");
38caee9d
S
250 }
251
252out_err:
253 mutex_unlock(&hnae3_common_lock);
254
255 return ret;
256}
257EXPORT_SYMBOL(hnae3_register_ae_dev);
258
259/* hnae3_unregister_ae_dev - unregisters a AE device
260 * @ae_dev: the AE device to unregister
261 */
262void 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;
38caee9d
S
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) {
6c46284e
FL
271 if (!hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
272 continue;
273
38caee9d
S
274 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
275 if (!id)
276 continue;
277
90f7b11a
L
278 list_for_each_entry(client, &hnae3_client_list, node)
279 hnae3_match_n_instantiate(client, ae_dev, false);
38caee9d
S
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}
288EXPORT_SYMBOL(hnae3_unregister_ae_dev);
289
290MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
291MODULE_LICENSE("GPL");
292MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");