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/spinlock.h> 12 13 #include "hnae3.h" 14 15 static LIST_HEAD(hnae3_ae_algo_list); 16 static LIST_HEAD(hnae3_client_list); 17 static LIST_HEAD(hnae3_ae_dev_list); 18 19 /* we are keeping things simple and using single lock for all the 20 * list. This is a non-critical code so other updations, if happen 21 * in parallel, can wait. 22 */ 23 static DEFINE_MUTEX(hnae3_common_lock); 24 25 static bool hnae3_client_match(enum hnae3_client_type client_type, 26 enum hnae3_dev_type dev_type) 27 { 28 if ((dev_type == HNAE3_DEV_KNIC) && (client_type == HNAE3_CLIENT_KNIC || 29 client_type == HNAE3_CLIENT_ROCE)) 30 return true; 31 32 if (dev_type == HNAE3_DEV_UNIC && client_type == HNAE3_CLIENT_UNIC) 33 return true; 34 35 return false; 36 } 37 38 static void hnae3_set_client_init_flag(struct hnae3_client *client, 39 struct hnae3_ae_dev *ae_dev, int inited) 40 { 41 switch (client->type) { 42 case HNAE3_CLIENT_KNIC: 43 hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited); 44 break; 45 case HNAE3_CLIENT_UNIC: 46 hnae3_set_bit(ae_dev->flag, HNAE3_UNIC_CLIENT_INITED_B, inited); 47 break; 48 case HNAE3_CLIENT_ROCE: 49 hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited); 50 break; 51 default: 52 break; 53 } 54 } 55 56 static int hnae3_get_client_init_flag(struct hnae3_client *client, 57 struct hnae3_ae_dev *ae_dev) 58 { 59 int inited = 0; 60 61 switch (client->type) { 62 case HNAE3_CLIENT_KNIC: 63 inited = hnae3_get_bit(ae_dev->flag, 64 HNAE3_KNIC_CLIENT_INITED_B); 65 break; 66 case HNAE3_CLIENT_UNIC: 67 inited = hnae3_get_bit(ae_dev->flag, 68 HNAE3_UNIC_CLIENT_INITED_B); 69 break; 70 case HNAE3_CLIENT_ROCE: 71 inited = hnae3_get_bit(ae_dev->flag, 72 HNAE3_ROCE_CLIENT_INITED_B); 73 break; 74 default: 75 break; 76 } 77 78 return inited; 79 } 80 81 static int hnae3_match_n_instantiate(struct hnae3_client *client, 82 struct hnae3_ae_dev *ae_dev, bool is_reg) 83 { 84 int ret; 85 86 /* check if this client matches the type of ae_dev */ 87 if (!(hnae3_client_match(client->type, ae_dev->dev_type) && 88 hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) { 89 return 0; 90 } 91 92 /* now, (un-)instantiate client by calling lower layer */ 93 if (is_reg) { 94 ret = ae_dev->ops->init_client_instance(client, ae_dev); 95 if (ret) { 96 dev_err(&ae_dev->pdev->dev, 97 "fail to instantiate client, ret = %d\n", ret); 98 return ret; 99 } 100 101 hnae3_set_client_init_flag(client, ae_dev, 1); 102 return 0; 103 } 104 105 if (hnae3_get_client_init_flag(client, ae_dev)) { 106 ae_dev->ops->uninit_client_instance(client, ae_dev); 107 108 hnae3_set_client_init_flag(client, ae_dev, 0); 109 } 110 111 return 0; 112 } 113 114 int hnae3_register_client(struct hnae3_client *client) 115 { 116 struct hnae3_client *client_tmp; 117 struct hnae3_ae_dev *ae_dev; 118 int ret = 0; 119 120 mutex_lock(&hnae3_common_lock); 121 /* one system should only have one client for every type */ 122 list_for_each_entry(client_tmp, &hnae3_client_list, node) { 123 if (client_tmp->type == client->type) 124 goto exit; 125 } 126 127 list_add_tail(&client->node, &hnae3_client_list); 128 129 /* initialize the client on every matched port */ 130 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 131 /* if the client could not be initialized on current port, for 132 * any error reasons, move on to next available port 133 */ 134 ret = hnae3_match_n_instantiate(client, ae_dev, true); 135 if (ret) 136 dev_err(&ae_dev->pdev->dev, 137 "match and instantiation failed for port, ret = %d\n", 138 ret); 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, 189 "init ae_dev error, ret = %d\n", ret); 190 continue; 191 } 192 193 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 194 195 /* check the client list for the match with this ae_dev type and 196 * initialize the figure out client instance 197 */ 198 list_for_each_entry(client, &hnae3_client_list, node) { 199 ret = hnae3_match_n_instantiate(client, ae_dev, true); 200 if (ret) 201 dev_err(&ae_dev->pdev->dev, 202 "match and instantiation failed, ret = %d\n", 203 ret); 204 } 205 } 206 207 mutex_unlock(&hnae3_common_lock); 208 } 209 EXPORT_SYMBOL(hnae3_register_ae_algo); 210 211 /* hnae3_unregister_ae_algo - unregisters a AE algorithm 212 * @ae_algo: the AE algorithm to unregister 213 */ 214 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo) 215 { 216 const struct pci_device_id *id; 217 struct hnae3_ae_dev *ae_dev; 218 struct hnae3_client *client; 219 220 mutex_lock(&hnae3_common_lock); 221 /* Check if there are matched ae_dev */ 222 list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) { 223 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 224 continue; 225 226 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 227 if (!id) 228 continue; 229 230 /* check the client list for the match with this ae_dev type and 231 * un-initialize the figure out client instance 232 */ 233 list_for_each_entry(client, &hnae3_client_list, node) 234 hnae3_match_n_instantiate(client, ae_dev, false); 235 236 ae_algo->ops->uninit_ae_dev(ae_dev); 237 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 238 } 239 240 list_del(&ae_algo->node); 241 mutex_unlock(&hnae3_common_lock); 242 } 243 EXPORT_SYMBOL(hnae3_unregister_ae_algo); 244 245 /* hnae3_register_ae_dev - registers a AE device to hnae3 framework 246 * @ae_dev: the AE device 247 * NOTE: the duplicated name will not be checked 248 */ 249 void hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev) 250 { 251 const struct pci_device_id *id; 252 struct hnae3_ae_algo *ae_algo; 253 struct hnae3_client *client; 254 int ret = 0; 255 256 mutex_lock(&hnae3_common_lock); 257 258 list_add_tail(&ae_dev->node, &hnae3_ae_dev_list); 259 260 /* Check if there are matched ae_algo */ 261 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 262 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 263 if (!id) 264 continue; 265 266 ae_dev->ops = ae_algo->ops; 267 268 if (!ae_dev->ops) { 269 dev_err(&ae_dev->pdev->dev, "ae_dev ops are null\n"); 270 goto out_err; 271 } 272 273 /* ae_dev init should set flag */ 274 ret = ae_dev->ops->init_ae_dev(ae_dev); 275 if (ret) { 276 dev_err(&ae_dev->pdev->dev, 277 "init ae_dev error, ret = %d\n", ret); 278 goto out_err; 279 } 280 281 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1); 282 break; 283 } 284 285 /* check the client list for the match with this ae_dev type and 286 * initialize the figure out client instance 287 */ 288 list_for_each_entry(client, &hnae3_client_list, node) { 289 ret = hnae3_match_n_instantiate(client, ae_dev, true); 290 if (ret) 291 dev_err(&ae_dev->pdev->dev, 292 "match and instantiation failed, ret = %d\n", 293 ret); 294 } 295 296 out_err: 297 mutex_unlock(&hnae3_common_lock); 298 } 299 EXPORT_SYMBOL(hnae3_register_ae_dev); 300 301 /* hnae3_unregister_ae_dev - unregisters a AE device 302 * @ae_dev: the AE device to unregister 303 */ 304 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev) 305 { 306 const struct pci_device_id *id; 307 struct hnae3_ae_algo *ae_algo; 308 struct hnae3_client *client; 309 310 mutex_lock(&hnae3_common_lock); 311 /* Check if there are matched ae_algo */ 312 list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) { 313 if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) 314 continue; 315 316 id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev); 317 if (!id) 318 continue; 319 320 list_for_each_entry(client, &hnae3_client_list, node) 321 hnae3_match_n_instantiate(client, ae_dev, false); 322 323 ae_algo->ops->uninit_ae_dev(ae_dev); 324 hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0); 325 } 326 327 list_del(&ae_dev->node); 328 mutex_unlock(&hnae3_common_lock); 329 } 330 EXPORT_SYMBOL(hnae3_unregister_ae_dev); 331 332 MODULE_AUTHOR("Huawei Tech. Co., Ltd."); 333 MODULE_LICENSE("GPL"); 334 MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework"); 335 MODULE_VERSION(HNAE3_MOD_VERSION); 336