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 int ret = 0; 108 109 if (!client) 110 return -ENODEV; 111 112 mutex_lock(&hnae3_common_lock); 113 /* one system should only have one client for every type */ 114 list_for_each_entry(client_tmp, &hnae3_client_list, node) { 115 if (client_tmp->type == client->type) 116 goto exit; 117 } 118 119 list_add_tail(&client->node, &hnae3_client_list); 120 121 /* initialize the client on every matched port */ 122 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 123 /* if the client could not be initialized on current port, for 124 * any error reasons, move on to next available port 125 */ 126 ret = hnae3_init_client_instance(client, ae_dev); 127 if (ret) 128 dev_err(&ae_dev->pdev->dev, 129 "match and instantiation failed for port, ret = %d\n", 130 ret); 131 } 132 133 exit: 134 mutex_unlock(&hnae3_common_lock); 135 136 return 0; 137 } 138 EXPORT_SYMBOL(hnae3_register_client); 139 140 void hnae3_unregister_client(struct hnae3_client *client) 141 { 142 struct hnae3_ae_dev *ae_dev; 143 144 if (!client) 145 return; 146 147 mutex_lock(&hnae3_common_lock); 148 /* un-initialize the client on every matched port */ 149 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 150 hnae3_uninit_client_instance(client, ae_dev); 151 } 152 153 list_del(&client->node); 154 mutex_unlock(&hnae3_common_lock); 155 } 156 EXPORT_SYMBOL(hnae3_unregister_client); 157 158 /* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework 159 * @ae_algo: AE algorithm 160 * NOTE: the duplicated name will not be checked 161 */ 162 void hnae3_register_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 int ret = 0; 168 169 if (!ae_algo) 170 return; 171 172 mutex_lock(&hnae3_common_lock); 173 174 list_add_tail(&ae_algo->node, &hnae3_ae_algo_list); 175 176 /* Check if this algo/ops matches the list of ae_devs */ 177 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 178 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 179 if (!id) 180 continue; 181 182 if (!ae_algo->ops) { 183 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); 184 continue; 185 } 186 ae_dev->ops = ae_algo->ops; 187 188 ret = ae_algo->ops->init_ae_dev(ae_dev); 189 if (ret) { 190 dev_err(&ae_dev->pdev->dev, 191 "init ae_dev error, ret = %d\n", ret); 192 continue; 193 } 194 195 /* ae_dev init should set flag */ 196 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 197 198 /* check the client list for the match with this ae_dev type and 199 * initialize the figure out client instance 200 */ 201 list_for_each_entry(client, &hnae3_client_list, node) { 202 ret = hnae3_init_client_instance(client, ae_dev); 203 if (ret) 204 dev_err(&ae_dev->pdev->dev, 205 "match and instantiation failed, ret = %d\n", 206 ret); 207 } 208 } 209 210 mutex_unlock(&hnae3_common_lock); 211 } 212 EXPORT_SYMBOL(hnae3_register_ae_algo); 213 214 /* hnae3_unregister_ae_algo - unregisters a AE algorithm 215 * @ae_algo: the AE algorithm to unregister 216 */ 217 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo) 218 { 219 const struct pci_device_id *id; 220 struct hnae3_ae_dev *ae_dev; 221 struct hnae3_client *client; 222 223 if (!ae_algo) 224 return; 225 226 mutex_lock(&hnae3_common_lock); 227 /* Check if there are matched ae_dev */ 228 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 229 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 230 continue; 231 232 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 233 if (!id) 234 continue; 235 236 /* check the client list for the match with this ae_dev type and 237 * un-initialize the figure out client instance 238 */ 239 list_for_each_entry(client, &hnae3_client_list, node) 240 hnae3_uninit_client_instance(client, ae_dev); 241 242 ae_algo->ops->uninit_ae_dev(ae_dev); 243 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 244 ae_dev->ops = NULL; 245 } 246 247 list_del(&ae_algo->node); 248 mutex_unlock(&hnae3_common_lock); 249 } 250 EXPORT_SYMBOL(hnae3_unregister_ae_algo); 251 252 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework 253 * @ae_dev: the AE device 254 * NOTE: the duplicated name will not be checked 255 */ 256 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev) 257 { 258 const struct pci_device_id *id; 259 struct hnae3_ae_algo *ae_algo; 260 struct hnae3_client *client; 261 int ret = 0; 262 263 if (!ae_dev) 264 return -ENODEV; 265 266 mutex_lock(&hnae3_common_lock); 267 268 list_add_tail(&ae_dev->node, &hnae3_ae_dev_list); 269 270 /* Check if there are matched ae_algo */ 271 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 272 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 273 if (!id) 274 continue; 275 276 if (!ae_algo->ops) { 277 dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n"); 278 ret = -EOPNOTSUPP; 279 goto out_err; 280 } 281 ae_dev->ops = ae_algo->ops; 282 283 ret = ae_dev->ops->init_ae_dev(ae_dev); 284 if (ret) { 285 dev_err(&ae_dev->pdev->dev, 286 "init ae_dev error, ret = %d\n", ret); 287 goto out_err; 288 } 289 290 /* ae_dev init should set flag */ 291 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 292 break; 293 } 294 295 /* check the client list for the match with this ae_dev type and 296 * initialize the figure out client instance 297 */ 298 list_for_each_entry(client, &hnae3_client_list, node) { 299 ret = hnae3_init_client_instance(client, ae_dev); 300 if (ret) 301 dev_err(&ae_dev->pdev->dev, 302 "match and instantiation failed, ret = %d\n", 303 ret); 304 } 305 306 mutex_unlock(&hnae3_common_lock); 307 308 return 0; 309 310 out_err: 311 list_del(&ae_dev->node); 312 mutex_unlock(&hnae3_common_lock); 313 314 return ret; 315 } 316 EXPORT_SYMBOL(hnae3_register_ae_dev); 317 318 /* hnae3_unregister_ae_dev - unregisters a AE device 319 * @ae_dev: the AE device to unregister 320 */ 321 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev) 322 { 323 const struct pci_device_id *id; 324 struct hnae3_ae_algo *ae_algo; 325 struct hnae3_client *client; 326 327 if (!ae_dev) 328 return; 329 330 mutex_lock(&hnae3_common_lock); 331 /* Check if there are matched ae_algo */ 332 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 333 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 334 continue; 335 336 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 337 if (!id) 338 continue; 339 340 list_for_each_entry(client, &hnae3_client_list, node) 341 hnae3_uninit_client_instance(client, ae_dev); 342 343 ae_algo->ops->uninit_ae_dev(ae_dev); 344 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 345 ae_dev->ops = NULL; 346 } 347 348 list_del(&ae_dev->node); 349 mutex_unlock(&hnae3_common_lock); 350 } 351 EXPORT_SYMBOL(hnae3_unregister_ae_dev); 352 353 MODULE_AUTHOR("Huawei Tech. Co., Ltd."); 354 MODULE_LICENSE("GPL"); 355 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework"); 356 MODULE_VERSION(HNAE3_MOD_VERSION); 357