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