linux/drivers/net/ethernet/cisco/enic/enic_res.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008-2010 Cisco Systems, Inc.  All rights reserved.
   3 * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
   4 *
   5 * This program is free software; you may redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; version 2 of the License.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  10 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  11 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  12 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  13 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  14 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  15 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  16 * SOFTWARE.
  17 *
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/errno.h>
  22#include <linux/types.h>
  23#include <linux/pci.h>
  24#include <linux/netdevice.h>
  25
  26#include "wq_enet_desc.h"
  27#include "rq_enet_desc.h"
  28#include "cq_enet_desc.h"
  29#include "vnic_resource.h"
  30#include "vnic_enet.h"
  31#include "vnic_dev.h"
  32#include "vnic_wq.h"
  33#include "vnic_rq.h"
  34#include "vnic_cq.h"
  35#include "vnic_intr.h"
  36#include "vnic_stats.h"
  37#include "vnic_nic.h"
  38#include "vnic_rss.h"
  39#include "enic_res.h"
  40#include "enic.h"
  41
  42int enic_get_vnic_config(struct enic *enic)
  43{
  44        struct vnic_enet_config *c = &enic->config;
  45        int err;
  46
  47        err = vnic_dev_get_mac_addr(enic->vdev, enic->mac_addr);
  48        if (err) {
  49                dev_err(enic_get_dev(enic),
  50                        "Error getting MAC addr, %d\n", err);
  51                return err;
  52        }
  53
  54#define GET_CONFIG(m) \
  55        do { \
  56                err = vnic_dev_spec(enic->vdev, \
  57                        offsetof(struct vnic_enet_config, m), \
  58                        sizeof(c->m), &c->m); \
  59                if (err) { \
  60                        dev_err(enic_get_dev(enic), \
  61                                "Error getting %s, %d\n", #m, err); \
  62                        return err; \
  63                } \
  64        } while (0)
  65
  66        GET_CONFIG(flags);
  67        GET_CONFIG(wq_desc_count);
  68        GET_CONFIG(rq_desc_count);
  69        GET_CONFIG(mtu);
  70        GET_CONFIG(intr_timer_type);
  71        GET_CONFIG(intr_mode);
  72        GET_CONFIG(intr_timer_usec);
  73        GET_CONFIG(loop_tag);
  74        GET_CONFIG(num_arfs);
  75
  76        c->wq_desc_count =
  77                min_t(u32, ENIC_MAX_WQ_DESCS,
  78                max_t(u32, ENIC_MIN_WQ_DESCS,
  79                c->wq_desc_count));
  80        c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
  81
  82        c->rq_desc_count =
  83                min_t(u32, ENIC_MAX_RQ_DESCS,
  84                max_t(u32, ENIC_MIN_RQ_DESCS,
  85                c->rq_desc_count));
  86        c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
  87
  88        if (c->mtu == 0)
  89                c->mtu = 1500;
  90        c->mtu = min_t(u16, ENIC_MAX_MTU,
  91                max_t(u16, ENIC_MIN_MTU,
  92                c->mtu));
  93
  94        c->intr_timer_usec = min_t(u32, c->intr_timer_usec,
  95                vnic_dev_get_intr_coal_timer_max(enic->vdev));
  96
  97        dev_info(enic_get_dev(enic),
  98                "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
  99                enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
 100
 101        dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s "
 102                "tso/lro %s/%s rss %s intr mode %s type %s timer %d usec "
 103                "loopback tag 0x%04x\n",
 104                ENIC_SETTING(enic, TXCSUM) ? "yes" : "no",
 105                ENIC_SETTING(enic, RXCSUM) ? "yes" : "no",
 106                ENIC_SETTING(enic, TSO) ? "yes" : "no",
 107                ENIC_SETTING(enic, LRO) ? "yes" : "no",
 108                ENIC_SETTING(enic, RSS) ? "yes" : "no",
 109                c->intr_mode == VENET_INTR_MODE_INTX ? "INTx" :
 110                c->intr_mode == VENET_INTR_MODE_MSI ? "MSI" :
 111                c->intr_mode == VENET_INTR_MODE_ANY ? "any" :
 112                "unknown",
 113                c->intr_timer_type == VENET_INTR_TYPE_MIN ? "min" :
 114                c->intr_timer_type == VENET_INTR_TYPE_IDLE ? "idle" :
 115                "unknown",
 116                c->intr_timer_usec,
 117                c->loop_tag);
 118
 119        return 0;
 120}
 121
 122int enic_add_vlan(struct enic *enic, u16 vlanid)
 123{
 124        u64 a0 = vlanid, a1 = 0;
 125        int wait = 1000;
 126        int err;
 127
 128        err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
 129        if (err)
 130                dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
 131
 132        return err;
 133}
 134
 135int enic_del_vlan(struct enic *enic, u16 vlanid)
 136{
 137        u64 a0 = vlanid, a1 = 0;
 138        int wait = 1000;
 139        int err;
 140
 141        err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
 142        if (err)
 143                dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
 144
 145        return err;
 146}
 147
 148int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
 149        u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
 150        u8 ig_vlan_strip_en)
 151{
 152        enum vnic_devcmd_cmd cmd = CMD_NIC_CFG;
 153        u64 a0, a1;
 154        u32 nic_cfg;
 155        int wait = 1000;
 156
 157        vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
 158                rss_hash_type, rss_hash_bits, rss_base_cpu,
 159                rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
 160
 161        a0 = nic_cfg;
 162        a1 = 0;
 163
 164        if (rss_hash_type & (NIC_CFG_RSS_HASH_TYPE_UDP_IPV4 |
 165                             NIC_CFG_RSS_HASH_TYPE_UDP_IPV6))
 166                cmd = CMD_NIC_CFG_CHK;
 167
 168        return vnic_dev_cmd(enic->vdev, cmd, &a0, &a1, wait);
 169}
 170
 171int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
 172{
 173        u64 a0 = (u64)key_pa, a1 = len;
 174        int wait = 1000;
 175
 176        return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
 177}
 178
 179int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
 180{
 181        u64 a0 = (u64)cpu_pa, a1 = len;
 182        int wait = 1000;
 183
 184        return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
 185}
 186
 187void enic_free_vnic_resources(struct enic *enic)
 188{
 189        unsigned int i;
 190
 191        for (i = 0; i < enic->wq_count; i++)
 192                vnic_wq_free(&enic->wq[i]);
 193        for (i = 0; i < enic->rq_count; i++)
 194                vnic_rq_free(&enic->rq[i]);
 195        for (i = 0; i < enic->cq_count; i++)
 196                vnic_cq_free(&enic->cq[i]);
 197        for (i = 0; i < enic->intr_count; i++)
 198                vnic_intr_free(&enic->intr[i]);
 199}
 200
 201void enic_get_res_counts(struct enic *enic)
 202{
 203        enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
 204        enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
 205        enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
 206        enic->intr_count = vnic_dev_get_res_count(enic->vdev,
 207                RES_TYPE_INTR_CTRL);
 208
 209        dev_info(enic_get_dev(enic),
 210                "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
 211                enic->wq_count, enic->rq_count,
 212                enic->cq_count, enic->intr_count);
 213}
 214
 215void enic_init_vnic_resources(struct enic *enic)
 216{
 217        enum vnic_dev_intr_mode intr_mode;
 218        unsigned int mask_on_assertion;
 219        unsigned int interrupt_offset;
 220        unsigned int error_interrupt_enable;
 221        unsigned int error_interrupt_offset;
 222        unsigned int cq_index;
 223        unsigned int i;
 224
 225        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
 226
 227        /* Init RQ/WQ resources.
 228         *
 229         * RQ[0 - n-1] point to CQ[0 - n-1]
 230         * WQ[0 - m-1] point to CQ[n - n+m-1]
 231         *
 232         * Error interrupt is not enabled for MSI.
 233         */
 234
 235        switch (intr_mode) {
 236        case VNIC_DEV_INTR_MODE_INTX:
 237        case VNIC_DEV_INTR_MODE_MSIX:
 238                error_interrupt_enable = 1;
 239                error_interrupt_offset = enic->intr_count - 2;
 240                break;
 241        default:
 242                error_interrupt_enable = 0;
 243                error_interrupt_offset = 0;
 244                break;
 245        }
 246
 247        for (i = 0; i < enic->rq_count; i++) {
 248                cq_index = i;
 249                vnic_rq_init(&enic->rq[i],
 250                        cq_index,
 251                        error_interrupt_enable,
 252                        error_interrupt_offset);
 253        }
 254
 255        for (i = 0; i < enic->wq_count; i++) {
 256                cq_index = enic->rq_count + i;
 257                vnic_wq_init(&enic->wq[i],
 258                        cq_index,
 259                        error_interrupt_enable,
 260                        error_interrupt_offset);
 261        }
 262
 263        /* Init CQ resources
 264         *
 265         * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
 266         * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
 267         */
 268
 269        for (i = 0; i < enic->cq_count; i++) {
 270
 271                switch (intr_mode) {
 272                case VNIC_DEV_INTR_MODE_MSIX:
 273                        interrupt_offset = i;
 274                        break;
 275                default:
 276                        interrupt_offset = 0;
 277                        break;
 278                }
 279
 280                vnic_cq_init(&enic->cq[i],
 281                        0 /* flow_control_enable */,
 282                        1 /* color_enable */,
 283                        0 /* cq_head */,
 284                        0 /* cq_tail */,
 285                        1 /* cq_tail_color */,
 286                        1 /* interrupt_enable */,
 287                        1 /* cq_entry_enable */,
 288                        0 /* cq_message_enable */,
 289                        interrupt_offset,
 290                        0 /* cq_message_addr */);
 291        }
 292
 293        /* Init INTR resources
 294         *
 295         * mask_on_assertion is not used for INTx due to the level-
 296         * triggered nature of INTx
 297         */
 298
 299        switch (intr_mode) {
 300        case VNIC_DEV_INTR_MODE_MSI:
 301        case VNIC_DEV_INTR_MODE_MSIX:
 302                mask_on_assertion = 1;
 303                break;
 304        default:
 305                mask_on_assertion = 0;
 306                break;
 307        }
 308
 309        for (i = 0; i < enic->intr_count; i++) {
 310                vnic_intr_init(&enic->intr[i],
 311                        enic->config.intr_timer_usec,
 312                        enic->config.intr_timer_type,
 313                        mask_on_assertion);
 314        }
 315}
 316
 317int enic_alloc_vnic_resources(struct enic *enic)
 318{
 319        enum vnic_dev_intr_mode intr_mode;
 320        unsigned int i;
 321        int err;
 322
 323        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
 324
 325        dev_info(enic_get_dev(enic), "vNIC resources used:  "
 326                "wq %d rq %d cq %d intr %d intr mode %s\n",
 327                enic->wq_count, enic->rq_count,
 328                enic->cq_count, enic->intr_count,
 329                intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
 330                intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
 331                intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
 332                "unknown");
 333
 334        /* Allocate queue resources
 335         */
 336
 337        for (i = 0; i < enic->wq_count; i++) {
 338                err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
 339                        enic->config.wq_desc_count,
 340                        sizeof(struct wq_enet_desc));
 341                if (err)
 342                        goto err_out_cleanup;
 343        }
 344
 345        for (i = 0; i < enic->rq_count; i++) {
 346                err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
 347                        enic->config.rq_desc_count,
 348                        sizeof(struct rq_enet_desc));
 349                if (err)
 350                        goto err_out_cleanup;
 351        }
 352
 353        for (i = 0; i < enic->cq_count; i++) {
 354                if (i < enic->rq_count)
 355                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
 356                                enic->config.rq_desc_count,
 357                                sizeof(struct cq_enet_rq_desc));
 358                else
 359                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
 360                                enic->config.wq_desc_count,
 361                                sizeof(struct cq_enet_wq_desc));
 362                if (err)
 363                        goto err_out_cleanup;
 364        }
 365
 366        for (i = 0; i < enic->intr_count; i++) {
 367                err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
 368                if (err)
 369                        goto err_out_cleanup;
 370        }
 371
 372        /* Hook remaining resource
 373         */
 374
 375        enic->legacy_pba = vnic_dev_get_res(enic->vdev,
 376                RES_TYPE_INTR_PBA_LEGACY, 0);
 377        if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
 378                dev_err(enic_get_dev(enic),
 379                        "Failed to hook legacy pba resource\n");
 380                err = -ENODEV;
 381                goto err_out_cleanup;
 382        }
 383
 384        return 0;
 385
 386err_out_cleanup:
 387        enic_free_vnic_resources(enic);
 388
 389        return err;
 390}
 391