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
This commit is contained in:
Zbigniew Bodek 2016-05-11 13:22:13 +00:00
parent ec6f8f42db
commit 8191a87959
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299444
4 changed files with 182 additions and 2 deletions

View File

@ -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;

View File

@ -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 cpi_cfg_msg *cfg)
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, int vf)
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;

View File

@ -140,6 +140,7 @@ static int nicvf_allocate_net_interrupts(struct nicvf *);
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)
{

View File

@ -1611,8 +1611,7 @@ nicvf_set_qset_resources(struct nicvf *nic)
/* 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;