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        u64 a0, a1;
 153        u32 nic_cfg;
 154        int wait = 1000;
 155
 156        vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
 157                rss_hash_type, rss_hash_bits, rss_base_cpu,
 158                rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
 159
 160        a0 = nic_cfg;
 161        a1 = 0;
 162
 163        return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
 164}
 165
 166int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
 167{
 168        u64 a0 = (u64)key_pa, a1 = len;
 169        int wait = 1000;
 170
 171        return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
 172}
 173
 174int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
 175{
 176        u64 a0 = (u64)cpu_pa, a1 = len;
 177        int wait = 1000;
 178
 179        return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
 180}
 181
 182void enic_free_vnic_resources(struct enic *enic)
 183{
 184        unsigned int i;
 185
 186        for (i = 0; i < enic->wq_count; i++)
 187                vnic_wq_free(&enic->wq[i]);
 188        for (i = 0; i < enic->rq_count; i++)
 189                vnic_rq_free(&enic->rq[i]);
 190        for (i = 0; i < enic->cq_count; i++)
 191                vnic_cq_free(&enic->cq[i]);
 192        for (i = 0; i < enic->intr_count; i++)
 193                vnic_intr_free(&enic->intr[i]);
 194}
 195
 196void enic_get_res_counts(struct enic *enic)
 197{
 198        enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
 199        enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
 200        enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
 201        enic->intr_count = vnic_dev_get_res_count(enic->vdev,
 202                RES_TYPE_INTR_CTRL);
 203
 204        dev_info(enic_get_dev(enic),
 205                "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
 206                enic->wq_count, enic->rq_count,
 207                enic->cq_count, enic->intr_count);
 208}
 209
 210void enic_init_vnic_resources(struct enic *enic)
 211{
 212        enum vnic_dev_intr_mode intr_mode;
 213        unsigned int mask_on_assertion;
 214        unsigned int interrupt_offset;
 215        unsigned int error_interrupt_enable;
 216        unsigned int error_interrupt_offset;
 217        unsigned int cq_index;
 218        unsigned int i;
 219
 220        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
 221
 222        /* Init RQ/WQ resources.
 223         *
 224         * RQ[0 - n-1] point to CQ[0 - n-1]
 225         * WQ[0 - m-1] point to CQ[n - n+m-1]
 226         *
 227         * Error interrupt is not enabled for MSI.
 228         */
 229
 230        switch (intr_mode) {
 231        case VNIC_DEV_INTR_MODE_INTX:
 232        case VNIC_DEV_INTR_MODE_MSIX:
 233                error_interrupt_enable = 1;
 234                error_interrupt_offset = enic->intr_count - 2;
 235                break;
 236        default:
 237                error_interrupt_enable = 0;
 238                error_interrupt_offset = 0;
 239                break;
 240        }
 241
 242        for (i = 0; i < enic->rq_count; i++) {
 243                cq_index = i;
 244                vnic_rq_init(&enic->rq[i],
 245                        cq_index,
 246                        error_interrupt_enable,
 247                        error_interrupt_offset);
 248        }
 249
 250        for (i = 0; i < enic->wq_count; i++) {
 251                cq_index = enic->rq_count + i;
 252                vnic_wq_init(&enic->wq[i],
 253                        cq_index,
 254                        error_interrupt_enable,
 255                        error_interrupt_offset);
 256        }
 257
 258        /* Init CQ resources
 259         *
 260         * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
 261         * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
 262         */
 263
 264        for (i = 0; i < enic->cq_count; i++) {
 265
 266                switch (intr_mode) {
 267                case VNIC_DEV_INTR_MODE_MSIX:
 268                        interrupt_offset = i;
 269                        break;
 270                default:
 271                        interrupt_offset = 0;
 272                        break;
 273                }
 274
 275                vnic_cq_init(&enic->cq[i],
 276                        0 /* flow_control_enable */,
 277                        1 /* color_enable */,
 278                        0 /* cq_head */,
 279                        0 /* cq_tail */,
 280                        1 /* cq_tail_color */,
 281                        1 /* interrupt_enable */,
 282                        1 /* cq_entry_enable */,
 283                        0 /* cq_message_enable */,
 284                        interrupt_offset,
 285                        0 /* cq_message_addr */);
 286        }
 287
 288        /* Init INTR resources
 289         *
 290         * mask_on_assertion is not used for INTx due to the level-
 291         * triggered nature of INTx
 292         */
 293
 294        switch (intr_mode) {
 295        case VNIC_DEV_INTR_MODE_MSI:
 296        case VNIC_DEV_INTR_MODE_MSIX:
 297                mask_on_assertion = 1;
 298                break;
 299        default:
 300                mask_on_assertion = 0;
 301                break;
 302        }
 303
 304        for (i = 0; i < enic->intr_count; i++) {
 305                vnic_intr_init(&enic->intr[i],
 306                        enic->config.intr_timer_usec,
 307                        enic->config.intr_timer_type,
 308                        mask_on_assertion);
 309        }
 310}
 311
 312int enic_alloc_vnic_resources(struct enic *enic)
 313{
 314        enum vnic_dev_intr_mode intr_mode;
 315        unsigned int i;
 316        int err;
 317
 318        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
 319
 320        dev_info(enic_get_dev(enic), "vNIC resources used:  "
 321                "wq %d rq %d cq %d intr %d intr mode %s\n",
 322                enic->wq_count, enic->rq_count,
 323                enic->cq_count, enic->intr_count,
 324                intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
 325                intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
 326                intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
 327                "unknown");
 328
 329        /* Allocate queue resources
 330         */
 331
 332        for (i = 0; i < enic->wq_count; i++) {
 333                err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
 334                        enic->config.wq_desc_count,
 335                        sizeof(struct wq_enet_desc));
 336                if (err)
 337                        goto err_out_cleanup;
 338        }
 339
 340        for (i = 0; i < enic->rq_count; i++) {
 341                err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
 342                        enic->config.rq_desc_count,
 343                        sizeof(struct rq_enet_desc));
 344                if (err)
 345                        goto err_out_cleanup;
 346        }
 347
 348        for (i = 0; i < enic->cq_count; i++) {
 349                if (i < enic->rq_count)
 350                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
 351                                enic->config.rq_desc_count,
 352                                sizeof(struct cq_enet_rq_desc));
 353                else
 354                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
 355                                enic->config.wq_desc_count,
 356                                sizeof(struct cq_enet_wq_desc));
 357                if (err)
 358                        goto err_out_cleanup;
 359        }
 360
 361        for (i = 0; i < enic->intr_count; i++) {
 362                err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
 363                if (err)
 364                        goto err_out_cleanup;
 365        }
 366
 367        /* Hook remaining resource
 368         */
 369
 370        enic->legacy_pba = vnic_dev_get_res(enic->vdev,
 371                RES_TYPE_INTR_PBA_LEGACY, 0);
 372        if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
 373                dev_err(enic_get_dev(enic),
 374                        "Failed to hook legacy pba resource\n");
 375                err = -ENODEV;
 376                goto err_out_cleanup;
 377        }
 378
 379        return 0;
 380
 381err_out_cleanup:
 382        enic_free_vnic_resources(enic);
 383
 384        return err;
 385}
 386