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:
parent
ec6f8f42db
commit
8191a87959
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299444
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user