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