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 { 21 if (client_type == HNAE3_CLIENT_KNIC || 22 client_type == HNAE3_CLIENT_ROCE) 23 return true; 24 25 return false; 26 } 27 28 void hnae3_set_client_init_flag(struct hnae3_client *client, 29 struct hnae3_ae_dev *ae_dev, 30 unsigned int inited) 31 { 32 if (!client || !ae_dev) 33 return; 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_ROCE: 40 hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited); 41 break; 42 default: 43 break; 44 } 45 } 46 EXPORT_SYMBOL(hnae3_set_client_init_flag); 47 48 static int hnae3_get_client_init_flag(struct hnae3_client *client, 49 struct hnae3_ae_dev *ae_dev) 50 { 51 int inited = 0; 52 53 switch (client->type) { 54 case HNAE3_CLIENT_KNIC: 55 inited = hnae3_get_bit(ae_dev->flag, 56 HNAE3_KNIC_CLIENT_INITED_B); 57 break; 58 case HNAE3_CLIENT_ROCE: 59 inited = hnae3_get_bit(ae_dev->flag, 60 HNAE3_ROCE_CLIENT_INITED_B); 61 break; 62 default: 63 break; 64 } 65 66 return inited; 67 } 68 69 static int hnae3_init_client_instance(struct hnae3_client *client, 70 struct hnae3_ae_dev *ae_dev) 71 { 72 int ret; 73 74 /* check if this client matches the type of ae_dev */ 75 if (!(hnae3_client_match(client->type) && 76 hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) { 77 return 0; 78 } 79 80 ret = ae_dev->ops->init_client_instance(client, ae_dev); 81 if (ret) 82 dev_err(&ae_dev->pdev->dev, 83 "fail to instantiate client, ret = %d\n", ret); 84 85 return ret; 86 } 87 88 static void hnae3_uninit_client_instance(struct hnae3_client *client, 89 struct hnae3_ae_dev *ae_dev) 90 { 91 /* check if this client matches the type of ae_dev */ 92 if (!(hnae3_client_match(client->type) && 93 hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) 94 return; 95 96 if (hnae3_get_client_init_flag(client, ae_dev)) { 97 ae_dev->ops->uninit_client_instance(client, ae_dev); 98 99 hnae3_set_client_init_flag(client, ae_dev, 0); 100 } 101 } 102 103 int hnae3_register_client(struct hnae3_client *client) 104 { 105 struct hnae3_client *client_tmp; 106 struct hnae3_ae_dev *ae_dev; 107 108 if (!client) 109 return -ENODEV; 110 111 mutex_lock(&hnae3_common_lock); 112 /* one system should only have one client for every type */ 113 list_for_each_entry(client_tmp, &hnae3_client_list, node) { 114 if (client_tmp->type == client->type) 115 goto exit; 116 } 117 118 list_add_tail(&client->node, &hnae3_client_list); 119 120 /* initialize the client on every matched port */ 121 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 122 /* if the client could not be initialized on current port, for 123 * any error reasons, move on to next available port 124 */ 125 int ret = hnae3_init_client_instance(client, ae_dev); 126 if (ret) 127 dev_err(&ae_dev->pdev->dev, 128 "match and instantiation failed for port, ret = %d\n", 129 ret); 130 } 131 132 exit: 133 mutex_unlock(&hnae3_common_lock); 134 135 return 0; 136 } 137 EXPORT_SYMBOL(hnae3_register_client); 138 139 void hnae3_unregister_client(struct hnae3_client *client) 140 { 141 struct hnae3_client *client_tmp; 142 struct hnae3_ae_dev *ae_dev; 143 bool existed = false; 144 145 if (!client) 146 return; 147 148 mutex_lock(&hnae3_common_lock); 149 /* one system should only have one client for every type */ 150 list_for_each_entry(client_tmp, &hnae3_client_list, node) { 151 if (client_tmp->type == client->type) { 152 existed = true; 153 break; 154 } 155 } 156 157 if (!existed) { 158 mutex_unlock(&hnae3_common_lock); 159 pr_err("client %s does not exist!\n", client->name); 160 return; 161 } 162 163 /* un-initialize the client on every matched port */ 164 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 165 hnae3_uninit_client_instance(client, ae_dev); 166 } 167 168 list_del(&client->node); 169 mutex_unlock(&hnae3_common_lock); 170 } 171 EXPORT_SYMBOL(hnae3_unregister_client); 172 173 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework 174 * @ae_algo: AE algorithm 175 * NOTE: the duplicated name will not be checked 176 */ 177 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo) 178 { 179 const struct pci_device_id *id; 180 struct hnae3_ae_dev *ae_dev; 181 struct hnae3_client *client; 182 int ret; 183 184 if (!ae_algo) 185 return; 186 187 mutex_lock(&hnae3_common_lock); 188 189 list_add_tail(&ae_algo->node, &hnae3_ae_algo_list); 190 191 /* Check if this algo/ops matches the list of ae_devs */ 192 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 193 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 194 if (!id) 195 continue; 196 197 if (!ae_algo->ops) { 198 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); 199 continue; 200 } 201 ae_dev->ops = ae_algo->ops; 202 203 ret = ae_algo->ops->init_ae_dev(ae_dev); 204 if (ret) { 205 dev_err(&ae_dev->pdev->dev, 206 "init ae_dev error, ret = %d\n", ret); 207 continue; 208 } 209 210 /* ae_dev init should set flag */ 211 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 212 213 /* check the client list for the match with this ae_dev type and 214 * initialize the figure out client instance 215 */ 216 list_for_each_entry(client, &hnae3_client_list, node) { 217 ret = hnae3_init_client_instance(client, ae_dev); 218 if (ret) 219 dev_err(&ae_dev->pdev->dev, 220 "match and instantiation failed, ret = %d\n", 221 ret); 222 } 223 } 224 225 mutex_unlock(&hnae3_common_lock); 226 } 227 EXPORT_SYMBOL(hnae3_register_ae_algo); 228 229 /* hnae3_unregister_ae_algo - unregisters a AE algorithm 230 * @ae_algo: the AE algorithm to unregister 231 */ 232 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo) 233 { 234 const struct pci_device_id *id; 235 struct hnae3_ae_dev *ae_dev; 236 struct hnae3_client *client; 237 238 if (!ae_algo) 239 return; 240 241 mutex_lock(&hnae3_common_lock); 242 /* Check if there are matched ae_dev */ 243 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 244 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 245 continue; 246 247 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 248 if (!id) 249 continue; 250 251 /* check the client list for the match with this ae_dev type and 252 * un-initialize the figure out client instance 253 */ 254 list_for_each_entry(client, &hnae3_client_list, node) 255 hnae3_uninit_client_instance(client, ae_dev); 256 257 ae_algo->ops->uninit_ae_dev(ae_dev); 258 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 259 ae_dev->ops = NULL; 260 } 261 262 list_del(&ae_algo->node); 263 mutex_unlock(&hnae3_common_lock); 264 } 265 EXPORT_SYMBOL(hnae3_unregister_ae_algo); 266 267 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework 268 * @ae_dev: the AE device 269 * NOTE: the duplicated name will not be checked 270 */ 271 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev) 272 { 273 const struct pci_device_id *id; 274 struct hnae3_ae_algo *ae_algo; 275 struct hnae3_client *client; 276 int ret; 277 278 if (!ae_dev) 279 return -ENODEV; 280 281 mutex_lock(&hnae3_common_lock); 282 283 list_add_tail(&ae_dev->node, &hnae3_ae_dev_list); 284 285 /* Check if there are matched ae_algo */ 286 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 287 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 288 if (!id) 289 continue; 290 291 if (!ae_algo->ops) { 292 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); 293 ret = -EOPNOTSUPP; 294 goto out_err; 295 } 296 ae_dev->ops = ae_algo->ops; 297 298 ret = ae_dev->ops->init_ae_dev(ae_dev); 299 if (ret) { 300 dev_err(&ae_dev->pdev->dev, 301 "init ae_dev error, ret = %d\n", ret); 302 goto out_err; 303 } 304 305 /* ae_dev init should set flag */ 306 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 307 break; 308 } 309 310 /* check the client list for the match with this ae_dev type and 311 * initialize the figure out client instance 312 */ 313 list_for_each_entry(client, &hnae3_client_list, node) { 314 ret = hnae3_init_client_instance(client, ae_dev); 315 if (ret) 316 dev_err(&ae_dev->pdev->dev, 317 "match and instantiation failed, ret = %d\n", 318 ret); 319 } 320 321 mutex_unlock(&hnae3_common_lock); 322 323 return 0; 324 325 out_err: 326 list_del(&ae_dev->node); 327 mutex_unlock(&hnae3_common_lock); 328 329 return ret; 330 } 331 EXPORT_SYMBOL(hnae3_register_ae_dev); 332 333 /* hnae3_unregister_ae_dev - unregisters a AE device 334 * @ae_dev: the AE device to unregister 335 */ 336 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev) 337 { 338 const struct pci_device_id *id; 339 struct hnae3_ae_algo *ae_algo; 340 struct hnae3_client *client; 341 342 if (!ae_dev) 343 return; 344 345 mutex_lock(&hnae3_common_lock); 346 /* Check if there are matched ae_algo */ 347 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 348 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 349 continue; 350 351 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 352 if (!id) 353 continue; 354 355 list_for_each_entry(client, &hnae3_client_list, node) 356 hnae3_uninit_client_instance(client, ae_dev); 357 358 ae_algo->ops->uninit_ae_dev(ae_dev); 359 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 360 ae_dev->ops = NULL; 361 } 362 363 list_del(&ae_dev->node); 364 mutex_unlock(&hnae3_common_lock); 365 } 366 EXPORT_SYMBOL(hnae3_unregister_ae_dev); 367 368 MODULE_AUTHOR("Huawei Tech. Co., Ltd."); 369 MODULE_LICENSE("GPL"); 370 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework"); 371 MODULE_VERSION(HNAE3_MOD_VERSION); 372