Author: zbb
Date: Wed May 11 13:22:13 2016
New Revision: 299444
URL: https://svnweb.freebsd.org/changeset/base/299444

Log:
  Add HW RSS support to VNIC driver
  
  Based on v1.0 driver provided by Cavium under BSD license.
  Support in-hardware RSS to distribute IP, UDP and TCP traffic
  among available RX Queues and hence multiple CPUs.
  
  Reviewed by:  wma
  Obtained from:        Semihalf
  Sponsored by: Cavium
  Differential Revision: https://reviews.freebsd.org/D6230

Modified:
  head/sys/dev/vnic/nic.h
  head/sys/dev/vnic/nic_main.c
  head/sys/dev/vnic/nicvf_main.c
  head/sys/dev/vnic/nicvf_queues.c

Modified: head/sys/dev/vnic/nic.h
==============================================================================
--- head/sys/dev/vnic/nic.h     Wed May 11 13:20:29 2016        (r299443)
+++ head/sys/dev/vnic/nic.h     Wed May 11 13:22:13 2016        (r299444)
@@ -176,6 +176,24 @@ struct msix_entry {
 #define        NIC_MAX_RSS_IDR_TBL_SIZE        (1 << NIC_MAX_RSS_HASH_BITS)
 #define        RSS_HASH_KEY_SIZE               5 /* 320 bit key */
 
+struct nicvf_rss_info {
+       boolean_t enable;
+#define        RSS_L2_EXTENDED_HASH_ENA        (1UL << 0)
+#define        RSS_IP_HASH_ENA                 (1UL << 1)
+#define        RSS_TCP_HASH_ENA                (1UL << 2)
+#define        RSS_TCP_SYN_DIS                 (1UL << 3)
+#define        RSS_UDP_HASH_ENA                (1UL << 4)
+#define        RSS_L4_EXTENDED_HASH_ENA        (1UL << 5)
+#define        RSS_ROCE_ENA                    (1UL << 6)
+#define        RSS_L3_BI_DIRECTION_ENA         (1UL << 7)
+#define        RSS_L4_BI_DIRECTION_ENA         (1UL << 8)
+       uint64_t cfg;
+       uint8_t  hash_bits;
+       uint16_t rss_size;
+       uint8_t  ind_tbl[NIC_MAX_RSS_IDR_TBL_SIZE];
+       uint64_t key[RSS_HASH_KEY_SIZE];
+};
+
 enum rx_stats_reg_offset {
        RX_OCTS = 0x0,
        RX_UCAST = 0x1,
@@ -285,6 +303,7 @@ struct nicvf {
        boolean_t               tns_mode:1;
        boolean_t               sqs_mode:1;
        bool                    loopback_supported:1;
+       struct nicvf_rss_info   rss_info;
        uint16_t                mtu;
        struct queue_set        *qs;
        uint8_t                 rx_queues;

Modified: head/sys/dev/vnic/nic_main.c
==============================================================================
--- head/sys/dev/vnic/nic_main.c        Wed May 11 13:20:29 2016        
(r299443)
+++ head/sys/dev/vnic/nic_main.c        Wed May 11 13:22:13 2016        
(r299444)
@@ -103,6 +103,7 @@ struct nicpf {
        uint8_t                 duplex[MAX_LMAC];
        uint32_t                speed[MAX_LMAC];
        uint16_t                cpi_base[MAX_NUM_VFS_SUPPORTED];
+       uint16_t                rssi_base[MAX_NUM_VFS_SUPPORTED];
        uint16_t                rss_ind_tbl_size;
 
        /* MSI-X */
@@ -744,6 +745,58 @@ nic_config_cpi(struct nicpf *nic, struct
                        rssi = ((cpi - cpi_base) & 0x38) >> 3;
        }
        nic->cpi_base[cfg->vf_id] = cpi_base;
+       nic->rssi_base[cfg->vf_id] = rssi_base;
+}
+
+/* Responsds to VF with its RSS indirection table size */
+static void
+nic_send_rss_size(struct nicpf *nic, int vf)
+{
+       union nic_mbx mbx = {};
+       uint64_t  *msg;
+
+       msg = (uint64_t *)&mbx;
+
+       mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
+       mbx.rss_size.ind_tbl_size = nic->rss_ind_tbl_size;
+       nic_send_msg_to_vf(nic, vf, &mbx);
+}
+
+/*
+ * Receive side scaling configuration
+ * configure:
+ * - RSS index
+ * - indir table i.e hash::RQ mapping
+ * - no of hash bits to consider
+ */
+static void
+nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
+{
+       uint8_t qset, idx;
+       uint64_t cpi_cfg, cpi_base, rssi_base, rssi;
+       uint64_t idx_addr;
+
+       idx = 0;
+       rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset;
+
+       rssi = rssi_base;
+       qset = cfg->vf_id;
+
+       for (; rssi < (rssi_base + cfg->tbl_len); rssi++) {
+               nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
+                   (qset << 3) | (cfg->ind_tbl[idx] & 0x7));
+               idx++;
+       }
+
+       cpi_base = nic->cpi_base[cfg->vf_id];
+       if (pass1_silicon(nic->dev))
+               idx_addr = NIC_PF_CPI_0_2047_CFG;
+       else
+               idx_addr = NIC_PF_MPI_0_2047_CFG;
+       cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3));
+       cpi_cfg &= ~(0xFUL << 20);
+       cpi_cfg |= (cfg->hash_bits << 20);
+       nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg);
 }
 
 /*
@@ -896,6 +949,13 @@ nic_handle_mbx_intr(struct nicpf *nic, i
        case NIC_MBOX_MSG_CPI_CFG:
                nic_config_cpi(nic, &mbx.cpi_cfg);
                break;
+       case NIC_MBOX_MSG_RSS_SIZE:
+               nic_send_rss_size(nic, vf);
+               goto unlock;
+       case NIC_MBOX_MSG_RSS_CFG:
+       case NIC_MBOX_MSG_RSS_CFG_CONT: /* fall through */
+               nic_config_rss(nic, &mbx.rss_cfg);
+               break;
        case NIC_MBOX_MSG_CFG_DONE:
                /* Last message of VF config msg sequence */
                nic->vf_info[vf].vf_enabled = TRUE;

Modified: head/sys/dev/vnic/nicvf_main.c
==============================================================================
--- head/sys/dev/vnic/nicvf_main.c      Wed May 11 13:20:29 2016        
(r299443)
+++ head/sys/dev/vnic/nicvf_main.c      Wed May 11 13:22:13 2016        
(r299444)
@@ -140,6 +140,7 @@ static int nicvf_allocate_net_interrupts
 static void nicvf_release_all_interrupts(struct nicvf *);
 static int nicvf_hw_set_mac_addr(struct nicvf *, uint8_t *);
 static void nicvf_config_cpi(struct nicvf *);
+static int nicvf_rss_init(struct nicvf *);
 static int nicvf_init_resources(struct nicvf *);
 
 static int nicvf_setup_ifnet(struct nicvf *);
@@ -245,6 +246,9 @@ nicvf_attach(device_t dev)
        nic->cpi_alg = CPI_ALG_NONE;
        NICVF_CORE_LOCK(nic);
        nicvf_config_cpi(nic);
+       /* Configure receive side scaling */
+       if (nic->qs->rq_cnt > 1)
+               nicvf_rss_init(nic);
        NICVF_CORE_UNLOCK(nic);
 
        err = nicvf_setup_ifnet(nic);
@@ -940,6 +944,10 @@ nicvf_handle_mbx_intr(struct nicvf *nic)
        case NIC_MBOX_MSG_NACK:
                nic->pf_nacked = TRUE;
                break;
+       case NIC_MBOX_MSG_RSS_SIZE:
+               nic->rss_info.rss_size = mbx.rss_size.ind_tbl_size;
+               nic->pf_acked = TRUE;
+               break;
        case NIC_MBOX_MSG_BGX_STATS:
                nicvf_read_bgx_stats(nic, &mbx.bgx_stats);
                nic->pf_acked = TRUE;
@@ -990,6 +998,100 @@ nicvf_config_cpi(struct nicvf *nic)
        nicvf_send_msg_to_pf(nic, &mbx);
 }
 
+static void
+nicvf_get_rss_size(struct nicvf *nic)
+{
+       union nic_mbx mbx = {};
+
+       mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
+       mbx.rss_size.vf_id = nic->vf_id;
+       nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static void
+nicvf_config_rss(struct nicvf *nic)
+{
+       union nic_mbx mbx = {};
+       struct nicvf_rss_info *rss;
+       int ind_tbl_len;
+       int i, nextq;
+
+       rss = &nic->rss_info;
+       ind_tbl_len = rss->rss_size;
+       nextq = 0;
+
+       mbx.rss_cfg.vf_id = nic->vf_id;
+       mbx.rss_cfg.hash_bits = rss->hash_bits;
+       while (ind_tbl_len != 0) {
+               mbx.rss_cfg.tbl_offset = nextq;
+               mbx.rss_cfg.tbl_len = MIN(ind_tbl_len,
+                   RSS_IND_TBL_LEN_PER_MBX_MSG);
+               mbx.rss_cfg.msg = mbx.rss_cfg.tbl_offset ?
+                   NIC_MBOX_MSG_RSS_CFG_CONT : NIC_MBOX_MSG_RSS_CFG;
+
+               for (i = 0; i < mbx.rss_cfg.tbl_len; i++)
+                       mbx.rss_cfg.ind_tbl[i] = rss->ind_tbl[nextq++];
+
+               nicvf_send_msg_to_pf(nic, &mbx);
+
+               ind_tbl_len -= mbx.rss_cfg.tbl_len;
+       }
+}
+
+static void
+nicvf_set_rss_key(struct nicvf *nic)
+{
+       struct nicvf_rss_info *rss;
+       uint64_t key_addr;
+       int idx;
+
+       rss = &nic->rss_info;
+       key_addr = NIC_VNIC_RSS_KEY_0_4;
+
+       for (idx = 0; idx < RSS_HASH_KEY_SIZE; idx++) {
+               nicvf_reg_write(nic, key_addr, rss->key[idx]);
+               key_addr += sizeof(uint64_t);
+       }
+}
+
+static int
+nicvf_rss_init(struct nicvf *nic)
+{
+       struct nicvf_rss_info *rss;
+       int idx;
+
+       nicvf_get_rss_size(nic);
+
+       rss = &nic->rss_info;
+       if (nic->cpi_alg != CPI_ALG_NONE) {
+               rss->enable = FALSE;
+               rss->hash_bits = 0;
+               return (ENXIO);
+       }
+
+       rss->enable = TRUE;
+
+       /* Using the HW reset value for now */
+       rss->key[0] = 0xFEED0BADFEED0BADUL;
+       rss->key[1] = 0xFEED0BADFEED0BADUL;
+       rss->key[2] = 0xFEED0BADFEED0BADUL;
+       rss->key[3] = 0xFEED0BADFEED0BADUL;
+       rss->key[4] = 0xFEED0BADFEED0BADUL;
+
+       nicvf_set_rss_key(nic);
+
+       rss->cfg = RSS_IP_HASH_ENA | RSS_TCP_HASH_ENA | RSS_UDP_HASH_ENA;
+       nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss->cfg);
+
+       rss->hash_bits = fls(rss->rss_size) - 1;
+       for (idx = 0; idx < rss->rss_size; idx++)
+               rss->ind_tbl[idx] = idx % nic->rx_queues;
+
+       nicvf_config_rss(nic);
+
+       return (0);
+}
+
 static int
 nicvf_init_resources(struct nicvf *nic)
 {

Modified: head/sys/dev/vnic/nicvf_queues.c
==============================================================================
--- head/sys/dev/vnic/nicvf_queues.c    Wed May 11 13:20:29 2016        
(r299443)
+++ head/sys/dev/vnic/nicvf_queues.c    Wed May 11 13:22:13 2016        
(r299444)
@@ -1611,8 +1611,7 @@ nicvf_set_qset_resources(struct nicvf *n
 
        /* Set count of each queue */
        qs->rbdr_cnt = RBDR_CNT;
-       /* With no RSS we stay with single RQ */
-       qs->rq_cnt = 1;
+       qs->rq_cnt = RCV_QUEUE_CNT;
 
        qs->sq_cnt = SND_QUEUE_CNT;
        qs->cq_cnt = CMP_QUEUE_CNT;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to