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