linux/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
<<
>>
Prefs
   1/* Broadcom NetXtreme-C/E network driver.
   2 *
   3 * Copyright (c) 2016-2018 Broadcom Limited
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation.
   8 */
   9
  10#include <linux/module.h>
  11
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/interrupt.h>
  15#include <linux/pci.h>
  16#include <linux/netdevice.h>
  17#include <linux/rtnetlink.h>
  18#include <linux/bitops.h>
  19#include <linux/irq.h>
  20#include <asm/byteorder.h>
  21#include <linux/bitmap.h>
  22
  23#include "bnxt_hsi.h"
  24#include "bnxt.h"
  25#include "bnxt_ulp.h"
  26
  27static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
  28                             struct bnxt_ulp_ops *ulp_ops, void *handle)
  29{
  30        struct net_device *dev = edev->net;
  31        struct bnxt *bp = netdev_priv(dev);
  32        struct bnxt_ulp *ulp;
  33
  34        ASSERT_RTNL();
  35        if (ulp_id >= BNXT_MAX_ULP)
  36                return -EINVAL;
  37
  38        ulp = &edev->ulp_tbl[ulp_id];
  39        if (rcu_access_pointer(ulp->ulp_ops)) {
  40                netdev_err(bp->dev, "ulp id %d already registered\n", ulp_id);
  41                return -EBUSY;
  42        }
  43        if (ulp_id == BNXT_ROCE_ULP) {
  44                unsigned int max_stat_ctxs;
  45
  46                max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
  47                if (max_stat_ctxs <= BNXT_MIN_ROCE_STAT_CTXS ||
  48                    bp->cp_nr_rings == max_stat_ctxs)
  49                        return -ENOMEM;
  50        }
  51
  52        atomic_set(&ulp->ref_count, 0);
  53        ulp->handle = handle;
  54        rcu_assign_pointer(ulp->ulp_ops, ulp_ops);
  55
  56        if (ulp_id == BNXT_ROCE_ULP) {
  57                if (test_bit(BNXT_STATE_OPEN, &bp->state))
  58                        bnxt_hwrm_vnic_cfg(bp, 0);
  59        }
  60
  61        return 0;
  62}
  63
  64static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
  65{
  66        struct net_device *dev = edev->net;
  67        struct bnxt *bp = netdev_priv(dev);
  68        struct bnxt_ulp *ulp;
  69        int i = 0;
  70
  71        ASSERT_RTNL();
  72        if (ulp_id >= BNXT_MAX_ULP)
  73                return -EINVAL;
  74
  75        ulp = &edev->ulp_tbl[ulp_id];
  76        if (!rcu_access_pointer(ulp->ulp_ops)) {
  77                netdev_err(bp->dev, "ulp id %d not registered\n", ulp_id);
  78                return -EINVAL;
  79        }
  80        if (ulp_id == BNXT_ROCE_ULP && ulp->msix_requested)
  81                edev->en_ops->bnxt_free_msix(edev, ulp_id);
  82
  83        if (ulp->max_async_event_id)
  84                bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0);
  85
  86        RCU_INIT_POINTER(ulp->ulp_ops, NULL);
  87        synchronize_rcu();
  88        ulp->max_async_event_id = 0;
  89        ulp->async_events_bmap = NULL;
  90        while (atomic_read(&ulp->ref_count) != 0 && i < 10) {
  91                msleep(100);
  92                i++;
  93        }
  94        return 0;
  95}
  96
  97static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
  98{
  99        struct bnxt_en_dev *edev = bp->edev;
 100        int num_msix, idx, i;
 101
 102        num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
 103        idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
 104        for (i = 0; i < num_msix; i++) {
 105                ent[i].vector = bp->irq_tbl[idx + i].vector;
 106                ent[i].ring_idx = idx + i;
 107                ent[i].db_offset = (idx + i) * 0x80;
 108        }
 109}
 110
 111static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
 112                              struct bnxt_msix_entry *ent, int num_msix)
 113{
 114        struct net_device *dev = edev->net;
 115        struct bnxt *bp = netdev_priv(dev);
 116        int max_idx, max_cp_rings;
 117        int avail_msix, idx;
 118        int rc = 0;
 119
 120        ASSERT_RTNL();
 121        if (ulp_id != BNXT_ROCE_ULP)
 122                return -EINVAL;
 123
 124        if (!(bp->flags & BNXT_FLAG_USING_MSIX))
 125                return -ENODEV;
 126
 127        if (edev->ulp_tbl[ulp_id].msix_requested)
 128                return -EAGAIN;
 129
 130        max_cp_rings = bnxt_get_max_func_cp_rings(bp);
 131        avail_msix = bnxt_get_avail_msix(bp, num_msix);
 132        if (!avail_msix)
 133                return -ENOMEM;
 134        if (avail_msix > num_msix)
 135                avail_msix = num_msix;
 136
 137        if (BNXT_NEW_RM(bp)) {
 138                idx = bp->cp_nr_rings;
 139        } else {
 140                max_idx = min_t(int, bp->total_irqs, max_cp_rings);
 141                idx = max_idx - avail_msix;
 142        }
 143        edev->ulp_tbl[ulp_id].msix_base = idx;
 144        edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
 145        if (bp->total_irqs < (idx + avail_msix)) {
 146                if (netif_running(dev)) {
 147                        bnxt_close_nic(bp, true, false);
 148                        rc = bnxt_open_nic(bp, true, false);
 149                } else {
 150                        rc = bnxt_reserve_rings(bp, true);
 151                }
 152        }
 153        if (rc) {
 154                edev->ulp_tbl[ulp_id].msix_requested = 0;
 155                return -EAGAIN;
 156        }
 157
 158        if (BNXT_NEW_RM(bp)) {
 159                struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
 160                int resv_msix;
 161
 162                resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
 163                avail_msix = min_t(int, resv_msix, avail_msix);
 164                edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
 165        }
 166        bnxt_fill_msix_vecs(bp, ent);
 167        edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
 168        return avail_msix;
 169}
 170
 171static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id)
 172{
 173        struct net_device *dev = edev->net;
 174        struct bnxt *bp = netdev_priv(dev);
 175
 176        ASSERT_RTNL();
 177        if (ulp_id != BNXT_ROCE_ULP)
 178                return -EINVAL;
 179
 180        if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
 181                return 0;
 182
 183        edev->ulp_tbl[ulp_id].msix_requested = 0;
 184        edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
 185        if (netif_running(dev)) {
 186                bnxt_close_nic(bp, true, false);
 187                bnxt_open_nic(bp, true, false);
 188        }
 189        return 0;
 190}
 191
 192int bnxt_get_ulp_msix_num(struct bnxt *bp)
 193{
 194        if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
 195                struct bnxt_en_dev *edev = bp->edev;
 196
 197                return edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
 198        }
 199        return 0;
 200}
 201
 202int bnxt_get_ulp_msix_base(struct bnxt *bp)
 203{
 204        if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
 205                struct bnxt_en_dev *edev = bp->edev;
 206
 207                if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
 208                        return edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
 209        }
 210        return 0;
 211}
 212
 213int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
 214{
 215        if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP))
 216                return BNXT_MIN_ROCE_STAT_CTXS;
 217
 218        return 0;
 219}
 220
 221static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
 222                         struct bnxt_fw_msg *fw_msg)
 223{
 224        struct net_device *dev = edev->net;
 225        struct bnxt *bp = netdev_priv(dev);
 226        struct input *req;
 227        int rc;
 228
 229        mutex_lock(&bp->hwrm_cmd_lock);
 230        req = fw_msg->msg;
 231        req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
 232        rc = _hwrm_send_message(bp, fw_msg->msg, fw_msg->msg_len,
 233                                fw_msg->timeout);
 234        if (!rc) {
 235                struct output *resp = bp->hwrm_cmd_resp_addr;
 236                u32 len = le16_to_cpu(resp->resp_len);
 237
 238                if (fw_msg->resp_max_len < len)
 239                        len = fw_msg->resp_max_len;
 240
 241                memcpy(fw_msg->resp, resp, len);
 242        }
 243        mutex_unlock(&bp->hwrm_cmd_lock);
 244        return rc;
 245}
 246
 247static void bnxt_ulp_get(struct bnxt_ulp *ulp)
 248{
 249        atomic_inc(&ulp->ref_count);
 250}
 251
 252static void bnxt_ulp_put(struct bnxt_ulp *ulp)
 253{
 254        atomic_dec(&ulp->ref_count);
 255}
 256
 257void bnxt_ulp_stop(struct bnxt *bp)
 258{
 259        struct bnxt_en_dev *edev = bp->edev;
 260        struct bnxt_ulp_ops *ops;
 261        int i;
 262
 263        if (!edev)
 264                return;
 265
 266        for (i = 0; i < BNXT_MAX_ULP; i++) {
 267                struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 268
 269                ops = rtnl_dereference(ulp->ulp_ops);
 270                if (!ops || !ops->ulp_stop)
 271                        continue;
 272                ops->ulp_stop(ulp->handle);
 273        }
 274}
 275
 276void bnxt_ulp_start(struct bnxt *bp)
 277{
 278        struct bnxt_en_dev *edev = bp->edev;
 279        struct bnxt_ulp_ops *ops;
 280        int i;
 281
 282        if (!edev)
 283                return;
 284
 285        for (i = 0; i < BNXT_MAX_ULP; i++) {
 286                struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 287
 288                ops = rtnl_dereference(ulp->ulp_ops);
 289                if (!ops || !ops->ulp_start)
 290                        continue;
 291                ops->ulp_start(ulp->handle);
 292        }
 293}
 294
 295void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs)
 296{
 297        struct bnxt_en_dev *edev = bp->edev;
 298        struct bnxt_ulp_ops *ops;
 299        int i;
 300
 301        if (!edev)
 302                return;
 303
 304        for (i = 0; i < BNXT_MAX_ULP; i++) {
 305                struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 306
 307                rcu_read_lock();
 308                ops = rcu_dereference(ulp->ulp_ops);
 309                if (!ops || !ops->ulp_sriov_config) {
 310                        rcu_read_unlock();
 311                        continue;
 312                }
 313                bnxt_ulp_get(ulp);
 314                rcu_read_unlock();
 315                ops->ulp_sriov_config(ulp->handle, num_vfs);
 316                bnxt_ulp_put(ulp);
 317        }
 318}
 319
 320void bnxt_ulp_shutdown(struct bnxt *bp)
 321{
 322        struct bnxt_en_dev *edev = bp->edev;
 323        struct bnxt_ulp_ops *ops;
 324        int i;
 325
 326        if (!edev)
 327                return;
 328
 329        for (i = 0; i < BNXT_MAX_ULP; i++) {
 330                struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 331
 332                ops = rtnl_dereference(ulp->ulp_ops);
 333                if (!ops || !ops->ulp_shutdown)
 334                        continue;
 335                ops->ulp_shutdown(ulp->handle);
 336        }
 337}
 338
 339void bnxt_ulp_irq_stop(struct bnxt *bp)
 340{
 341        struct bnxt_en_dev *edev = bp->edev;
 342        struct bnxt_ulp_ops *ops;
 343
 344        if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
 345                return;
 346
 347        if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
 348                struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
 349
 350                if (!ulp->msix_requested)
 351                        return;
 352
 353                ops = rtnl_dereference(ulp->ulp_ops);
 354                if (!ops || !ops->ulp_irq_stop)
 355                        return;
 356                ops->ulp_irq_stop(ulp->handle);
 357        }
 358}
 359
 360void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
 361{
 362        struct bnxt_en_dev *edev = bp->edev;
 363        struct bnxt_ulp_ops *ops;
 364
 365        if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
 366                return;
 367
 368        if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
 369                struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
 370                struct bnxt_msix_entry *ent = NULL;
 371
 372                if (!ulp->msix_requested)
 373                        return;
 374
 375                ops = rtnl_dereference(ulp->ulp_ops);
 376                if (!ops || !ops->ulp_irq_restart)
 377                        return;
 378
 379                if (!err) {
 380                        ent = kcalloc(ulp->msix_requested, sizeof(*ent),
 381                                      GFP_KERNEL);
 382                        if (!ent)
 383                                return;
 384                        bnxt_fill_msix_vecs(bp, ent);
 385                }
 386                ops->ulp_irq_restart(ulp->handle, ent);
 387                kfree(ent);
 388        }
 389}
 390
 391void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
 392{
 393        u16 event_id = le16_to_cpu(cmpl->event_id);
 394        struct bnxt_en_dev *edev = bp->edev;
 395        struct bnxt_ulp_ops *ops;
 396        int i;
 397
 398        if (!edev)
 399                return;
 400
 401        rcu_read_lock();
 402        for (i = 0; i < BNXT_MAX_ULP; i++) {
 403                struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 404
 405                ops = rcu_dereference(ulp->ulp_ops);
 406                if (!ops || !ops->ulp_async_notifier)
 407                        continue;
 408                if (!ulp->async_events_bmap ||
 409                    event_id > ulp->max_async_event_id)
 410                        continue;
 411
 412                /* Read max_async_event_id first before testing the bitmap. */
 413                smp_rmb();
 414                if (test_bit(event_id, ulp->async_events_bmap))
 415                        ops->ulp_async_notifier(ulp->handle, cmpl);
 416        }
 417        rcu_read_unlock();
 418}
 419
 420static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id,
 421                                      unsigned long *events_bmap, u16 max_id)
 422{
 423        struct net_device *dev = edev->net;
 424        struct bnxt *bp = netdev_priv(dev);
 425        struct bnxt_ulp *ulp;
 426
 427        if (ulp_id >= BNXT_MAX_ULP)
 428                return -EINVAL;
 429
 430        ulp = &edev->ulp_tbl[ulp_id];
 431        ulp->async_events_bmap = events_bmap;
 432        /* Make sure bnxt_ulp_async_events() sees this order */
 433        smp_wmb();
 434        ulp->max_async_event_id = max_id;
 435        bnxt_hwrm_func_rgtr_async_events(bp, events_bmap, max_id + 1);
 436        return 0;
 437}
 438
 439static const struct bnxt_en_ops bnxt_en_ops_tbl = {
 440        .bnxt_register_device   = bnxt_register_dev,
 441        .bnxt_unregister_device = bnxt_unregister_dev,
 442        .bnxt_request_msix      = bnxt_req_msix_vecs,
 443        .bnxt_free_msix         = bnxt_free_msix_vecs,
 444        .bnxt_send_fw_msg       = bnxt_send_msg,
 445        .bnxt_register_fw_async_events  = bnxt_register_async_events,
 446};
 447
 448struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
 449{
 450        struct bnxt *bp = netdev_priv(dev);
 451        struct bnxt_en_dev *edev;
 452
 453        edev = bp->edev;
 454        if (!edev) {
 455                edev = kzalloc(sizeof(*edev), GFP_KERNEL);
 456                if (!edev)
 457                        return ERR_PTR(-ENOMEM);
 458                edev->en_ops = &bnxt_en_ops_tbl;
 459                if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
 460                        edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
 461                if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
 462                        edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
 463                edev->net = dev;
 464                edev->pdev = bp->pdev;
 465                bp->edev = edev;
 466        }
 467        return bp->edev;
 468}
 469