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