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