linux/drivers/net/ethernet/intel/i40evf/i40evf_client.c
<<
>>
Prefs
   1#include <linux/list.h>
   2#include <linux/errno.h>
   3
   4#include "i40evf.h"
   5#include "i40e_prototype.h"
   6#include "i40evf_client.h"
   7
   8static
   9const char i40evf_client_interface_version_str[] = I40EVF_CLIENT_VERSION_STR;
  10static struct i40e_client *vf_registered_client;
  11static LIST_HEAD(i40evf_devices);
  12static DEFINE_MUTEX(i40evf_device_mutex);
  13
  14static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
  15                                       struct i40e_client *client,
  16                                       u8 *msg, u16 len);
  17
  18static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
  19                                      struct i40e_client *client,
  20                                      struct i40e_qvlist_info *qvlist_info);
  21
  22static struct i40e_ops i40evf_lan_ops = {
  23        .virtchnl_send = i40evf_client_virtchnl_send,
  24        .setup_qvlist = i40evf_client_setup_qvlist,
  25};
  26
  27/**
  28 * i40evf_notify_client_message - call the client message receive callback
  29 * @vsi: the VSI associated with this client
  30 * @msg: message buffer
  31 * @len: length of message
  32 *
  33 * If there is a client to this VSI, call the client
  34 **/
  35void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len)
  36{
  37        struct i40e_client_instance *cinst;
  38
  39        if (!vsi)
  40                return;
  41
  42        cinst = vsi->back->cinst;
  43        if (!cinst || !cinst->client || !cinst->client->ops ||
  44            !cinst->client->ops->virtchnl_receive) {
  45                dev_dbg(&vsi->back->pdev->dev,
  46                        "Cannot locate client instance virtchnl_receive function\n");
  47                return;
  48        }
  49        cinst->client->ops->virtchnl_receive(&cinst->lan_info,  cinst->client,
  50                                             msg, len);
  51}
  52
  53/**
  54 * i40evf_notify_client_l2_params - call the client notify callback
  55 * @vsi: the VSI with l2 param changes
  56 *
  57 * If there is a client to this VSI, call the client
  58 **/
  59void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
  60{
  61        struct i40e_client_instance *cinst;
  62        struct i40e_params params;
  63
  64        if (!vsi)
  65                return;
  66
  67        cinst = vsi->back->cinst;
  68        memset(&params, 0, sizeof(params));
  69        params.mtu = vsi->netdev->mtu;
  70        params.link_up = vsi->back->link_up;
  71        params.qos.prio_qos[0].qs_handle = vsi->qs_handle;
  72
  73        if (!cinst || !cinst->client || !cinst->client->ops ||
  74            !cinst->client->ops->l2_param_change) {
  75                dev_dbg(&vsi->back->pdev->dev,
  76                        "Cannot locate client instance l2_param_change function\n");
  77                return;
  78        }
  79        cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client,
  80                                            &params);
  81}
  82
  83/**
  84 * i40evf_notify_client_open - call the client open callback
  85 * @vsi: the VSI with netdev opened
  86 *
  87 * If there is a client to this netdev, call the client with open
  88 **/
  89void i40evf_notify_client_open(struct i40e_vsi *vsi)
  90{
  91        struct i40evf_adapter *adapter = vsi->back;
  92        struct i40e_client_instance *cinst = adapter->cinst;
  93        int ret;
  94
  95        if (!cinst || !cinst->client || !cinst->client->ops ||
  96            !cinst->client->ops->open) {
  97                dev_dbg(&vsi->back->pdev->dev,
  98                        "Cannot locate client instance open function\n");
  99                return;
 100        }
 101        if (!(test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state))) {
 102                ret = cinst->client->ops->open(&cinst->lan_info, cinst->client);
 103                if (!ret)
 104                        set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
 105        }
 106}
 107
 108/**
 109 * i40evf_client_release_qvlist - send a message to the PF to release iwarp qv map
 110 * @ldev: pointer to L2 context.
 111 *
 112 * Return 0 on success or < 0 on error
 113 **/
 114static int i40evf_client_release_qvlist(struct i40e_info *ldev)
 115{
 116        struct i40evf_adapter *adapter = ldev->vf;
 117        i40e_status err;
 118
 119        if (adapter->aq_required)
 120                return -EAGAIN;
 121
 122        err = i40e_aq_send_msg_to_pf(&adapter->hw,
 123                        VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
 124                        I40E_SUCCESS, NULL, 0, NULL);
 125
 126        if (err)
 127                dev_err(&adapter->pdev->dev,
 128                        "Unable to send iWarp vector release message to PF, error %d, aq status %d\n",
 129                        err, adapter->hw.aq.asq_last_status);
 130
 131        return err;
 132}
 133
 134/**
 135 * i40evf_notify_client_close - call the client close callback
 136 * @vsi: the VSI with netdev closed
 137 * @reset: true when close called due to reset pending
 138 *
 139 * If there is a client to this netdev, call the client with close
 140 **/
 141void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset)
 142{
 143        struct i40evf_adapter *adapter = vsi->back;
 144        struct i40e_client_instance *cinst = adapter->cinst;
 145
 146        if (!cinst || !cinst->client || !cinst->client->ops ||
 147            !cinst->client->ops->close) {
 148                dev_dbg(&vsi->back->pdev->dev,
 149                        "Cannot locate client instance close function\n");
 150                return;
 151        }
 152        cinst->client->ops->close(&cinst->lan_info, cinst->client, reset);
 153        i40evf_client_release_qvlist(&cinst->lan_info);
 154        clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
 155}
 156
 157/**
 158 * i40evf_client_add_instance - add a client instance to the instance list
 159 * @adapter: pointer to the board struct
 160 * @client: pointer to a client struct in the client list.
 161 *
 162 * Returns cinst ptr on success, NULL on failure
 163 **/
 164static struct i40e_client_instance *
 165i40evf_client_add_instance(struct i40evf_adapter *adapter)
 166{
 167        struct i40e_client_instance *cinst = NULL;
 168        struct netdev_hw_addr *mac = NULL;
 169        struct i40e_vsi *vsi = &adapter->vsi;
 170        int i;
 171
 172        if (!vf_registered_client)
 173                goto out;
 174
 175        if (adapter->cinst) {
 176                cinst = adapter->cinst;
 177                goto out;
 178        }
 179
 180        cinst = kzalloc(sizeof(*cinst), GFP_KERNEL);
 181        if (!cinst)
 182                goto out;
 183
 184        cinst->lan_info.vf = (void *)adapter;
 185        cinst->lan_info.netdev = vsi->netdev;
 186        cinst->lan_info.pcidev = adapter->pdev;
 187        cinst->lan_info.fid = 0;
 188        cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF;
 189        cinst->lan_info.hw_addr = adapter->hw.hw_addr;
 190        cinst->lan_info.ops = &i40evf_lan_ops;
 191        cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR;
 192        cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR;
 193        cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD;
 194        set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
 195
 196        cinst->lan_info.msix_count = adapter->num_iwarp_msix;
 197        cinst->lan_info.msix_entries =
 198                        &adapter->msix_entries[adapter->iwarp_base_vector];
 199
 200        for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
 201                cinst->lan_info.params.qos.prio_qos[i].tc = 0;
 202                cinst->lan_info.params.qos.prio_qos[i].qs_handle =
 203                                                                vsi->qs_handle;
 204        }
 205
 206        mac = list_first_entry(&cinst->lan_info.netdev->dev_addrs.list,
 207                               struct netdev_hw_addr, list);
 208        if (mac)
 209                ether_addr_copy(cinst->lan_info.lanmac, mac->addr);
 210        else
 211                dev_err(&adapter->pdev->dev, "MAC address list is empty!\n");
 212
 213        cinst->client = vf_registered_client;
 214        adapter->cinst = cinst;
 215out:
 216        return cinst;
 217}
 218
 219/**
 220 * i40evf_client_del_instance - removes a client instance from the list
 221 * @adapter: pointer to the board struct
 222 * @client: pointer to the client struct
 223 *
 224 **/
 225static
 226void i40evf_client_del_instance(struct i40evf_adapter *adapter)
 227{
 228        kfree(adapter->cinst);
 229        adapter->cinst = NULL;
 230}
 231
 232/**
 233 * i40evf_client_subtask - client maintenance work
 234 * @adapter: board private structure
 235 **/
 236void i40evf_client_subtask(struct i40evf_adapter *adapter)
 237{
 238        struct i40e_client *client = vf_registered_client;
 239        struct i40e_client_instance *cinst;
 240        int ret = 0;
 241
 242        if (adapter->state < __I40EVF_DOWN)
 243                return;
 244
 245        /* first check client is registered */
 246        if (!client)
 247                return;
 248
 249        /* Add the client instance to the instance list */
 250        cinst = i40evf_client_add_instance(adapter);
 251        if (!cinst)
 252                return;
 253
 254        dev_info(&adapter->pdev->dev, "Added instance of Client %s\n",
 255                 client->name);
 256
 257        if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
 258                /* Send an Open request to the client */
 259
 260                if (client->ops && client->ops->open)
 261                        ret = client->ops->open(&cinst->lan_info, client);
 262                if (!ret)
 263                        set_bit(__I40E_CLIENT_INSTANCE_OPENED,
 264                                &cinst->state);
 265                else
 266                        /* remove client instance */
 267                        i40evf_client_del_instance(adapter);
 268        }
 269}
 270
 271/**
 272 * i40evf_lan_add_device - add a lan device struct to the list of lan devices
 273 * @adapter: pointer to the board struct
 274 *
 275 * Returns 0 on success or none 0 on error
 276 **/
 277int i40evf_lan_add_device(struct i40evf_adapter *adapter)
 278{
 279        struct i40e_device *ldev;
 280        int ret = 0;
 281
 282        mutex_lock(&i40evf_device_mutex);
 283        list_for_each_entry(ldev, &i40evf_devices, list) {
 284                if (ldev->vf == adapter) {
 285                        ret = -EEXIST;
 286                        goto out;
 287                }
 288        }
 289        ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
 290        if (!ldev) {
 291                ret = -ENOMEM;
 292                goto out;
 293        }
 294        ldev->vf = adapter;
 295        INIT_LIST_HEAD(&ldev->list);
 296        list_add(&ldev->list, &i40evf_devices);
 297        dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
 298                 adapter->hw.bus.bus_id, adapter->hw.bus.device,
 299                 adapter->hw.bus.func);
 300
 301        /* Since in some cases register may have happened before a device gets
 302         * added, we can schedule a subtask to go initiate the clients.
 303         */
 304        adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
 305
 306out:
 307        mutex_unlock(&i40evf_device_mutex);
 308        return ret;
 309}
 310
 311/**
 312 * i40evf_lan_del_device - removes a lan device from the device list
 313 * @adapter: pointer to the board struct
 314 *
 315 * Returns 0 on success or non-0 on error
 316 **/
 317int i40evf_lan_del_device(struct i40evf_adapter *adapter)
 318{
 319        struct i40e_device *ldev, *tmp;
 320        int ret = -ENODEV;
 321
 322        mutex_lock(&i40evf_device_mutex);
 323        list_for_each_entry_safe(ldev, tmp, &i40evf_devices, list) {
 324                if (ldev->vf == adapter) {
 325                        dev_info(&adapter->pdev->dev,
 326                                 "Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
 327                                 adapter->hw.bus.bus_id, adapter->hw.bus.device,
 328                                 adapter->hw.bus.func);
 329                        list_del(&ldev->list);
 330                        kfree(ldev);
 331                        ret = 0;
 332                        break;
 333                }
 334        }
 335
 336        mutex_unlock(&i40evf_device_mutex);
 337        return ret;
 338}
 339
 340/**
 341 * i40evf_client_release - release client specific resources
 342 * @client: pointer to the registered client
 343 *
 344 **/
 345static void i40evf_client_release(struct i40e_client *client)
 346{
 347        struct i40e_client_instance *cinst;
 348        struct i40e_device *ldev;
 349        struct i40evf_adapter *adapter;
 350
 351        mutex_lock(&i40evf_device_mutex);
 352        list_for_each_entry(ldev, &i40evf_devices, list) {
 353                adapter = ldev->vf;
 354                cinst = adapter->cinst;
 355                if (!cinst)
 356                        continue;
 357                if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
 358                        if (client->ops && client->ops->close)
 359                                client->ops->close(&cinst->lan_info, client,
 360                                                   false);
 361                        i40evf_client_release_qvlist(&cinst->lan_info);
 362                        clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
 363
 364                        dev_warn(&adapter->pdev->dev,
 365                                 "Client %s instance closed\n", client->name);
 366                }
 367                /* delete the client instance */
 368                i40evf_client_del_instance(adapter);
 369                dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n",
 370                         client->name);
 371        }
 372        mutex_unlock(&i40evf_device_mutex);
 373}
 374
 375/**
 376 * i40evf_client_prepare - prepare client specific resources
 377 * @client: pointer to the registered client
 378 *
 379 **/
 380static void i40evf_client_prepare(struct i40e_client *client)
 381{
 382        struct i40e_device *ldev;
 383        struct i40evf_adapter *adapter;
 384
 385        mutex_lock(&i40evf_device_mutex);
 386        list_for_each_entry(ldev, &i40evf_devices, list) {
 387                adapter = ldev->vf;
 388                /* Signal the watchdog to service the client */
 389                adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
 390        }
 391        mutex_unlock(&i40evf_device_mutex);
 392}
 393
 394/**
 395 * i40evf_client_virtchnl_send - send a message to the PF instance
 396 * @ldev: pointer to L2 context.
 397 * @client: Client pointer.
 398 * @msg: pointer to message buffer
 399 * @len: message length
 400 *
 401 * Return 0 on success or < 0 on error
 402 **/
 403static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
 404                                       struct i40e_client *client,
 405                                       u8 *msg, u16 len)
 406{
 407        struct i40evf_adapter *adapter = ldev->vf;
 408        i40e_status err;
 409
 410        if (adapter->aq_required)
 411                return -EAGAIN;
 412
 413        err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP,
 414                                     I40E_SUCCESS, msg, len, NULL);
 415        if (err)
 416                dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n",
 417                        err, adapter->hw.aq.asq_last_status);
 418
 419        return err;
 420}
 421
 422/**
 423 * i40evf_client_setup_qvlist - send a message to the PF to setup iwarp qv map
 424 * @ldev: pointer to L2 context.
 425 * @client: Client pointer.
 426 * @qv_info: queue and vector list
 427 *
 428 * Return 0 on success or < 0 on error
 429 **/
 430static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
 431                                      struct i40e_client *client,
 432                                      struct i40e_qvlist_info *qvlist_info)
 433{
 434        struct virtchnl_iwarp_qvlist_info *v_qvlist_info;
 435        struct i40evf_adapter *adapter = ldev->vf;
 436        struct i40e_qv_info *qv_info;
 437        i40e_status err;
 438        u32 v_idx, i;
 439        u32 msg_size;
 440
 441        if (adapter->aq_required)
 442                return -EAGAIN;
 443
 444        /* A quick check on whether the vectors belong to the client */
 445        for (i = 0; i < qvlist_info->num_vectors; i++) {
 446                qv_info = &qvlist_info->qv_info[i];
 447                if (!qv_info)
 448                        continue;
 449                v_idx = qv_info->v_idx;
 450                if ((v_idx >=
 451                    (adapter->iwarp_base_vector + adapter->num_iwarp_msix)) ||
 452                    (v_idx < adapter->iwarp_base_vector))
 453                        return -EINVAL;
 454        }
 455
 456        v_qvlist_info = (struct virtchnl_iwarp_qvlist_info *)qvlist_info;
 457        msg_size = sizeof(struct virtchnl_iwarp_qvlist_info) +
 458                        (sizeof(struct virtchnl_iwarp_qv_info) *
 459                        (v_qvlist_info->num_vectors - 1));
 460
 461        adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP);
 462        err = i40e_aq_send_msg_to_pf(&adapter->hw,
 463                        VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP,
 464                        I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL);
 465
 466        if (err) {
 467                dev_err(&adapter->pdev->dev,
 468                        "Unable to send iWarp vector config message to PF, error %d, aq status %d\n",
 469                        err, adapter->hw.aq.asq_last_status);
 470                goto out;
 471        }
 472
 473        err = -EBUSY;
 474        for (i = 0; i < 5; i++) {
 475                msleep(100);
 476                if (!(adapter->client_pending &
 477                      BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) {
 478                        err = 0;
 479                        break;
 480                }
 481        }
 482out:
 483        return err;
 484}
 485
 486/**
 487 * i40evf_register_client - Register a i40e client driver with the L2 driver
 488 * @client: pointer to the i40e_client struct
 489 *
 490 * Returns 0 on success or non-0 on error
 491 **/
 492int i40evf_register_client(struct i40e_client *client)
 493{
 494        int ret = 0;
 495
 496        if (!client) {
 497                ret = -EIO;
 498                goto out;
 499        }
 500
 501        if (strlen(client->name) == 0) {
 502                pr_info("i40evf: Failed to register client with no name\n");
 503                ret = -EIO;
 504                goto out;
 505        }
 506
 507        if (vf_registered_client) {
 508                pr_info("i40evf: Client %s has already been registered!\n",
 509                        client->name);
 510                ret = -EEXIST;
 511                goto out;
 512        }
 513
 514        if ((client->version.major != I40EVF_CLIENT_VERSION_MAJOR) ||
 515            (client->version.minor != I40EVF_CLIENT_VERSION_MINOR)) {
 516                pr_info("i40evf: Failed to register client %s due to mismatched client interface version\n",
 517                        client->name);
 518                pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n",
 519                        client->version.major, client->version.minor,
 520                        client->version.build,
 521                        i40evf_client_interface_version_str);
 522                ret = -EIO;
 523                goto out;
 524        }
 525
 526        vf_registered_client = client;
 527
 528        i40evf_client_prepare(client);
 529
 530        pr_info("i40evf: Registered client %s with return code %d\n",
 531                client->name, ret);
 532out:
 533        return ret;
 534}
 535EXPORT_SYMBOL(i40evf_register_client);
 536
 537/**
 538 * i40evf_unregister_client - Unregister a i40e client driver with the L2 driver
 539 * @client: pointer to the i40e_client struct
 540 *
 541 * Returns 0 on success or non-0 on error
 542 **/
 543int i40evf_unregister_client(struct i40e_client *client)
 544{
 545        int ret = 0;
 546
 547        /* When a unregister request comes through we would have to send
 548         * a close for each of the client instances that were opened.
 549         * client_release function is called to handle this.
 550         */
 551        i40evf_client_release(client);
 552
 553        if (vf_registered_client != client) {
 554                pr_info("i40evf: Client %s has not been registered\n",
 555                        client->name);
 556                ret = -ENODEV;
 557                goto out;
 558        }
 559        vf_registered_client = NULL;
 560        pr_info("i40evf: Unregistered client %s\n", client->name);
 561out:
 562        return ret;
 563}
 564EXPORT_SYMBOL(i40evf_unregister_client);
 565