Index: head/sys/dev/vnic/nic.h =================================================================== --- head/sys/dev/vnic/nic.h +++ head/sys/dev/vnic/nic.h @@ -176,6 +176,24 @@ #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 @@ 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; Index: head/sys/dev/vnic/nic_main.c =================================================================== --- head/sys/dev/vnic/nic_main.c +++ head/sys/dev/vnic/nic_main.c @@ -103,6 +103,7 @@ 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 @@ 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 @@ 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; Index: head/sys/dev/vnic/nicvf_main.c =================================================================== --- head/sys/dev/vnic/nicvf_main.c +++ head/sys/dev/vnic/nicvf_main.c @@ -140,6 +140,7 @@ 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 @@ 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 @@ 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_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) { Index: head/sys/dev/vnic/nicvf_queues.c =================================================================== --- head/sys/dev/vnic/nicvf_queues.c +++ head/sys/dev/vnic/nicvf_queues.c @@ -1611,8 +1611,7 @@ /* 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;