Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2008-2010 Cisco Systems, Inc.  All rights reserved.
0004  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/errno.h>
0009 #include <linux/types.h>
0010 #include <linux/pci.h>
0011 #include <linux/netdevice.h>
0012 
0013 #include "wq_enet_desc.h"
0014 #include "rq_enet_desc.h"
0015 #include "cq_enet_desc.h"
0016 #include "vnic_resource.h"
0017 #include "vnic_enet.h"
0018 #include "vnic_dev.h"
0019 #include "vnic_wq.h"
0020 #include "vnic_rq.h"
0021 #include "vnic_cq.h"
0022 #include "vnic_intr.h"
0023 #include "vnic_stats.h"
0024 #include "vnic_nic.h"
0025 #include "vnic_rss.h"
0026 #include "enic_res.h"
0027 #include "enic.h"
0028 
0029 int enic_get_vnic_config(struct enic *enic)
0030 {
0031     struct vnic_enet_config *c = &enic->config;
0032     int err;
0033 
0034     err = vnic_dev_get_mac_addr(enic->vdev, enic->mac_addr);
0035     if (err) {
0036         dev_err(enic_get_dev(enic),
0037             "Error getting MAC addr, %d\n", err);
0038         return err;
0039     }
0040 
0041 #define GET_CONFIG(m) \
0042     do { \
0043         err = vnic_dev_spec(enic->vdev, \
0044             offsetof(struct vnic_enet_config, m), \
0045             sizeof(c->m), &c->m); \
0046         if (err) { \
0047             dev_err(enic_get_dev(enic), \
0048                 "Error getting %s, %d\n", #m, err); \
0049             return err; \
0050         } \
0051     } while (0)
0052 
0053     GET_CONFIG(flags);
0054     GET_CONFIG(wq_desc_count);
0055     GET_CONFIG(rq_desc_count);
0056     GET_CONFIG(mtu);
0057     GET_CONFIG(intr_timer_type);
0058     GET_CONFIG(intr_mode);
0059     GET_CONFIG(intr_timer_usec);
0060     GET_CONFIG(loop_tag);
0061     GET_CONFIG(num_arfs);
0062 
0063     c->wq_desc_count =
0064         min_t(u32, ENIC_MAX_WQ_DESCS,
0065         max_t(u32, ENIC_MIN_WQ_DESCS,
0066         c->wq_desc_count));
0067     c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
0068 
0069     c->rq_desc_count =
0070         min_t(u32, ENIC_MAX_RQ_DESCS,
0071         max_t(u32, ENIC_MIN_RQ_DESCS,
0072         c->rq_desc_count));
0073     c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
0074 
0075     if (c->mtu == 0)
0076         c->mtu = 1500;
0077     c->mtu = min_t(u16, ENIC_MAX_MTU,
0078         max_t(u16, ENIC_MIN_MTU,
0079         c->mtu));
0080 
0081     c->intr_timer_usec = min_t(u32, c->intr_timer_usec,
0082         vnic_dev_get_intr_coal_timer_max(enic->vdev));
0083 
0084     dev_info(enic_get_dev(enic),
0085         "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
0086         enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
0087 
0088     dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s "
0089         "tso/lro %s/%s rss %s intr mode %s type %s timer %d usec "
0090         "loopback tag 0x%04x\n",
0091         ENIC_SETTING(enic, TXCSUM) ? "yes" : "no",
0092         ENIC_SETTING(enic, RXCSUM) ? "yes" : "no",
0093         ENIC_SETTING(enic, TSO) ? "yes" : "no",
0094         ENIC_SETTING(enic, LRO) ? "yes" : "no",
0095         ENIC_SETTING(enic, RSS) ? "yes" : "no",
0096         c->intr_mode == VENET_INTR_MODE_INTX ? "INTx" :
0097         c->intr_mode == VENET_INTR_MODE_MSI ? "MSI" :
0098         c->intr_mode == VENET_INTR_MODE_ANY ? "any" :
0099         "unknown",
0100         c->intr_timer_type == VENET_INTR_TYPE_MIN ? "min" :
0101         c->intr_timer_type == VENET_INTR_TYPE_IDLE ? "idle" :
0102         "unknown",
0103         c->intr_timer_usec,
0104         c->loop_tag);
0105 
0106     return 0;
0107 }
0108 
0109 int enic_add_vlan(struct enic *enic, u16 vlanid)
0110 {
0111     u64 a0 = vlanid, a1 = 0;
0112     int wait = 1000;
0113     int err;
0114 
0115     err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
0116     if (err)
0117         dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
0118 
0119     return err;
0120 }
0121 
0122 int enic_del_vlan(struct enic *enic, u16 vlanid)
0123 {
0124     u64 a0 = vlanid, a1 = 0;
0125     int wait = 1000;
0126     int err;
0127 
0128     err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
0129     if (err)
0130         dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
0131 
0132     return err;
0133 }
0134 
0135 int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
0136     u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
0137     u8 ig_vlan_strip_en)
0138 {
0139     enum vnic_devcmd_cmd cmd = CMD_NIC_CFG;
0140     u64 a0, a1;
0141     u32 nic_cfg;
0142     int wait = 1000;
0143 
0144     vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
0145         rss_hash_type, rss_hash_bits, rss_base_cpu,
0146         rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
0147 
0148     a0 = nic_cfg;
0149     a1 = 0;
0150 
0151     if (rss_hash_type & (NIC_CFG_RSS_HASH_TYPE_UDP_IPV4 |
0152                  NIC_CFG_RSS_HASH_TYPE_UDP_IPV6))
0153         cmd = CMD_NIC_CFG_CHK;
0154 
0155     return vnic_dev_cmd(enic->vdev, cmd, &a0, &a1, wait);
0156 }
0157 
0158 int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
0159 {
0160     u64 a0 = (u64)key_pa, a1 = len;
0161     int wait = 1000;
0162 
0163     return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
0164 }
0165 
0166 int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
0167 {
0168     u64 a0 = (u64)cpu_pa, a1 = len;
0169     int wait = 1000;
0170 
0171     return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
0172 }
0173 
0174 void enic_free_vnic_resources(struct enic *enic)
0175 {
0176     unsigned int i;
0177 
0178     for (i = 0; i < enic->wq_count; i++)
0179         vnic_wq_free(&enic->wq[i]);
0180     for (i = 0; i < enic->rq_count; i++)
0181         vnic_rq_free(&enic->rq[i]);
0182     for (i = 0; i < enic->cq_count; i++)
0183         vnic_cq_free(&enic->cq[i]);
0184     for (i = 0; i < enic->intr_count; i++)
0185         vnic_intr_free(&enic->intr[i]);
0186 }
0187 
0188 void enic_get_res_counts(struct enic *enic)
0189 {
0190     enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
0191     enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
0192     enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
0193     enic->intr_count = vnic_dev_get_res_count(enic->vdev,
0194         RES_TYPE_INTR_CTRL);
0195 
0196     dev_info(enic_get_dev(enic),
0197         "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
0198         enic->wq_count, enic->rq_count,
0199         enic->cq_count, enic->intr_count);
0200 }
0201 
0202 void enic_init_vnic_resources(struct enic *enic)
0203 {
0204     enum vnic_dev_intr_mode intr_mode;
0205     unsigned int mask_on_assertion;
0206     unsigned int interrupt_offset;
0207     unsigned int error_interrupt_enable;
0208     unsigned int error_interrupt_offset;
0209     unsigned int cq_index;
0210     unsigned int i;
0211 
0212     intr_mode = vnic_dev_get_intr_mode(enic->vdev);
0213 
0214     /* Init RQ/WQ resources.
0215      *
0216      * RQ[0 - n-1] point to CQ[0 - n-1]
0217      * WQ[0 - m-1] point to CQ[n - n+m-1]
0218      *
0219      * Error interrupt is not enabled for MSI.
0220      */
0221 
0222     switch (intr_mode) {
0223     case VNIC_DEV_INTR_MODE_INTX:
0224     case VNIC_DEV_INTR_MODE_MSIX:
0225         error_interrupt_enable = 1;
0226         error_interrupt_offset = enic->intr_count - 2;
0227         break;
0228     default:
0229         error_interrupt_enable = 0;
0230         error_interrupt_offset = 0;
0231         break;
0232     }
0233 
0234     for (i = 0; i < enic->rq_count; i++) {
0235         cq_index = i;
0236         vnic_rq_init(&enic->rq[i],
0237             cq_index,
0238             error_interrupt_enable,
0239             error_interrupt_offset);
0240     }
0241 
0242     for (i = 0; i < enic->wq_count; i++) {
0243         cq_index = enic->rq_count + i;
0244         vnic_wq_init(&enic->wq[i],
0245             cq_index,
0246             error_interrupt_enable,
0247             error_interrupt_offset);
0248     }
0249 
0250     /* Init CQ resources
0251      *
0252      * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
0253      * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
0254      */
0255 
0256     for (i = 0; i < enic->cq_count; i++) {
0257 
0258         switch (intr_mode) {
0259         case VNIC_DEV_INTR_MODE_MSIX:
0260             interrupt_offset = i;
0261             break;
0262         default:
0263             interrupt_offset = 0;
0264             break;
0265         }
0266 
0267         vnic_cq_init(&enic->cq[i],
0268             0 /* flow_control_enable */,
0269             1 /* color_enable */,
0270             0 /* cq_head */,
0271             0 /* cq_tail */,
0272             1 /* cq_tail_color */,
0273             1 /* interrupt_enable */,
0274             1 /* cq_entry_enable */,
0275             0 /* cq_message_enable */,
0276             interrupt_offset,
0277             0 /* cq_message_addr */);
0278     }
0279 
0280     /* Init INTR resources
0281      *
0282      * mask_on_assertion is not used for INTx due to the level-
0283      * triggered nature of INTx
0284      */
0285 
0286     switch (intr_mode) {
0287     case VNIC_DEV_INTR_MODE_MSI:
0288     case VNIC_DEV_INTR_MODE_MSIX:
0289         mask_on_assertion = 1;
0290         break;
0291     default:
0292         mask_on_assertion = 0;
0293         break;
0294     }
0295 
0296     for (i = 0; i < enic->intr_count; i++) {
0297         vnic_intr_init(&enic->intr[i],
0298             enic->config.intr_timer_usec,
0299             enic->config.intr_timer_type,
0300             mask_on_assertion);
0301     }
0302 }
0303 
0304 int enic_alloc_vnic_resources(struct enic *enic)
0305 {
0306     enum vnic_dev_intr_mode intr_mode;
0307     unsigned int i;
0308     int err;
0309 
0310     intr_mode = vnic_dev_get_intr_mode(enic->vdev);
0311 
0312     dev_info(enic_get_dev(enic), "vNIC resources used:  "
0313         "wq %d rq %d cq %d intr %d intr mode %s\n",
0314         enic->wq_count, enic->rq_count,
0315         enic->cq_count, enic->intr_count,
0316         intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
0317         intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
0318         intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
0319         "unknown");
0320 
0321     /* Allocate queue resources
0322      */
0323 
0324     for (i = 0; i < enic->wq_count; i++) {
0325         err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
0326             enic->config.wq_desc_count,
0327             sizeof(struct wq_enet_desc));
0328         if (err)
0329             goto err_out_cleanup;
0330     }
0331 
0332     for (i = 0; i < enic->rq_count; i++) {
0333         err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
0334             enic->config.rq_desc_count,
0335             sizeof(struct rq_enet_desc));
0336         if (err)
0337             goto err_out_cleanup;
0338     }
0339 
0340     for (i = 0; i < enic->cq_count; i++) {
0341         if (i < enic->rq_count)
0342             err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
0343                 enic->config.rq_desc_count,
0344                 sizeof(struct cq_enet_rq_desc));
0345         else
0346             err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
0347                 enic->config.wq_desc_count,
0348                 sizeof(struct cq_enet_wq_desc));
0349         if (err)
0350             goto err_out_cleanup;
0351     }
0352 
0353     for (i = 0; i < enic->intr_count; i++) {
0354         err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
0355         if (err)
0356             goto err_out_cleanup;
0357     }
0358 
0359     /* Hook remaining resource
0360      */
0361 
0362     enic->legacy_pba = vnic_dev_get_res(enic->vdev,
0363         RES_TYPE_INTR_PBA_LEGACY, 0);
0364     if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
0365         dev_err(enic_get_dev(enic),
0366             "Failed to hook legacy pba resource\n");
0367         err = -ENODEV;
0368         goto err_out_cleanup;
0369     }
0370 
0371     return 0;
0372 
0373 err_out_cleanup:
0374     enic_free_vnic_resources(enic);
0375 
0376     return err;
0377 }