]>
Commit | Line | Data |
---|---|---|
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 | ||
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, | |
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 | ||
72 | int 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 | ||
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; | |
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 | } | |
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; | |
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 | } | |
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; | |
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 | } | |
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; | |
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 | ||
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; | |
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 | } | |
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"); |