From: Alfredo Cardigliano Date: Sun, 19 Jan 2020 15:53:52 +0000 (+0100) Subject: net/ionic: support RSS X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=22e7171bc63b51f22254b1178cf6c4c290da3bcf;p=dpdk.git net/ionic: support RSS Add code to manipulate the RSS configuration used by the adapter. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini index 8fde998c15..9a155251cb 100644 --- a/doc/guides/nics/features/ionic.ini +++ b/doc/guides/nics/features/ionic.ini @@ -16,6 +16,9 @@ TSO = Y Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y +RSS hash = Y +RSS key update = Y +RSS reta update = Y VLAN filter = Y VLAN offload = Y Flow control = Y diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c index 0f5418f1ba..5d546b92bf 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -35,6 +35,14 @@ static int ionic_flow_ctrl_get(struct rte_eth_dev *eth_dev, static int ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev, struct rte_eth_fc_conf *fc_conf); static int ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask); +static int ionic_dev_rss_reta_update(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size); +static int ionic_dev_rss_reta_query(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size); +static int ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_conf *rss_conf); +static int ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_conf *rss_conf); int ionic_logtype; @@ -90,6 +98,10 @@ static const struct eth_dev_ops ionic_eth_dev_ops = { .tx_queue_start = ionic_dev_tx_queue_start, .tx_queue_stop = ionic_dev_tx_queue_stop, .vlan_offload_set = ionic_vlan_offload_set, + .reta_update = ionic_dev_rss_reta_update, + .reta_query = ionic_dev_rss_reta_query, + .rss_hash_conf_get = ionic_dev_rss_hash_conf_get, + .rss_hash_update = ionic_dev_rss_hash_update, }; /* @@ -263,6 +275,10 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev, dev_info->min_mtu = IONIC_MIN_MTU; dev_info->max_mtu = IONIC_MAX_MTU; + dev_info->hash_key_size = IONIC_RSS_HASH_KEY_SIZE; + dev_info->reta_size = ident->lif.eth.rss_ind_tbl_sz; + dev_info->flow_type_rss_offloads = IONIC_ETH_RSS_OFFLOAD_ALL; + dev_info->speed_capa = ETH_LINK_SPEED_10G | ETH_LINK_SPEED_25G | @@ -405,6 +421,165 @@ ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask) return 0; } +static int +ionic_dev_rss_reta_update(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev); + struct ionic_adapter *adapter = lif->adapter; + struct ionic_identity *ident = &adapter->ident; + uint32_t i, j, index, num; + + IONIC_PRINT_CALL(); + + if (!lif->rss_ind_tbl) { + IONIC_PRINT(ERR, "RSS RETA not initialized, " + "can't update the table"); + return -EINVAL; + } + + if (reta_size != ident->lif.eth.rss_ind_tbl_sz) { + IONIC_PRINT(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)", + reta_size, ident->lif.eth.rss_ind_tbl_sz); + return -EINVAL; + } + + num = lif->adapter->ident.lif.eth.rss_ind_tbl_sz / RTE_RETA_GROUP_SIZE; + + for (i = 0; i < num; i++) { + for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) { + if (reta_conf[i].mask & ((uint64_t)1 << j)) { + index = (i * RTE_RETA_GROUP_SIZE) + j; + lif->rss_ind_tbl[index] = reta_conf[i].reta[j]; + } + } + } + + return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL); +} + +static int +ionic_dev_rss_reta_query(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev); + struct ionic_adapter *adapter = lif->adapter; + struct ionic_identity *ident = &adapter->ident; + int i, num; + + IONIC_PRINT_CALL(); + + if (reta_size != ident->lif.eth.rss_ind_tbl_sz) { + IONIC_PRINT(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)", + reta_size, ident->lif.eth.rss_ind_tbl_sz); + return -EINVAL; + } + + if (!lif->rss_ind_tbl) { + IONIC_PRINT(ERR, "RSS RETA has not been built yet"); + return -EINVAL; + } + + num = reta_size / RTE_RETA_GROUP_SIZE; + + for (i = 0; i < num; i++) { + memcpy(reta_conf->reta, + &lif->rss_ind_tbl[i * RTE_RETA_GROUP_SIZE], + RTE_RETA_GROUP_SIZE); + reta_conf++; + } + + return 0; +} + +static int +ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev); + uint64_t rss_hf = 0; + + IONIC_PRINT_CALL(); + + if (!lif->rss_ind_tbl) { + IONIC_PRINT(NOTICE, "RSS not enabled"); + return 0; + } + + /* Get key value (if not null, rss_key is 40-byte) */ + if (rss_conf->rss_key != NULL && + rss_conf->rss_key_len >= IONIC_RSS_HASH_KEY_SIZE) + memcpy(rss_conf->rss_key, lif->rss_hash_key, + IONIC_RSS_HASH_KEY_SIZE); + + if (lif->rss_types & IONIC_RSS_TYPE_IPV4) + rss_hf |= ETH_RSS_IPV4; + if (lif->rss_types & IONIC_RSS_TYPE_IPV4_TCP) + rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP; + if (lif->rss_types & IONIC_RSS_TYPE_IPV4_UDP) + rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP; + if (lif->rss_types & IONIC_RSS_TYPE_IPV6) + rss_hf |= ETH_RSS_IPV6; + if (lif->rss_types & IONIC_RSS_TYPE_IPV6_TCP) + rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP; + if (lif->rss_types & IONIC_RSS_TYPE_IPV6_UDP) + rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP; + + rss_conf->rss_hf = rss_hf; + + return 0; +} + +static int +ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev); + uint32_t rss_types = 0; + uint8_t *key = NULL; + + IONIC_PRINT_CALL(); + + if (rss_conf->rss_key) + key = rss_conf->rss_key; + + if ((rss_conf->rss_hf & IONIC_ETH_RSS_OFFLOAD_ALL) == 0) { + /* + * Can't disable rss through hash flags, + * if it is enabled by default during init + */ + if (lif->rss_ind_tbl) + return -EINVAL; + } else { + /* Can't enable rss if disabled by default during init */ + if (!lif->rss_ind_tbl) + return -EINVAL; + + if (rss_conf->rss_hf & ETH_RSS_IPV4) + rss_types |= IONIC_RSS_TYPE_IPV4; + if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) + rss_types |= IONIC_RSS_TYPE_IPV4_TCP; + if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) + rss_types |= IONIC_RSS_TYPE_IPV4_UDP; + if (rss_conf->rss_hf & ETH_RSS_IPV6) + rss_types |= IONIC_RSS_TYPE_IPV6; + if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) + rss_types |= IONIC_RSS_TYPE_IPV6_TCP; + if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) + rss_types |= IONIC_RSS_TYPE_IPV6_UDP; + + ionic_lif_rss_config(lif, rss_types, key, NULL); + } + + return 0; +} + static int ionic_dev_configure(struct rte_eth_dev *eth_dev) { diff --git a/drivers/net/ionic/ionic_ethdev.h b/drivers/net/ionic/ionic_ethdev.h index 7228d89692..578e2301fa 100644 --- a/drivers/net/ionic/ionic_ethdev.h +++ b/drivers/net/ionic/ionic_ethdev.h @@ -5,6 +5,14 @@ #ifndef _IONIC_ETHDEV_H_ #define _IONIC_ETHDEV_H_ +#define IONIC_ETH_RSS_OFFLOAD_ALL ( \ + ETH_RSS_IPV4 | \ + ETH_RSS_NONFRAG_IPV4_TCP | \ + ETH_RSS_NONFRAG_IPV4_UDP | \ + ETH_RSS_IPV6 | \ + ETH_RSS_NONFRAG_IPV6_TCP | \ + ETH_RSS_NONFRAG_IPV6_UDP) + #define IONIC_ETH_DEV_TO_LIF(eth_dev) ((struct ionic_lif *) \ (eth_dev)->data->dev_private) #define IONIC_ETH_DEV_TO_ADAPTER(eth_dev) \ diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c index 69830cd633..b7b4efbf25 100644 --- a/drivers/net/ionic/ionic_lif.c +++ b/drivers/net/ionic/ionic_lif.c @@ -775,6 +775,97 @@ ionic_lif_free(struct ionic_lif *lif) } } +int +ionic_lif_rss_config(struct ionic_lif *lif, + const uint16_t types, const uint8_t *key, const uint32_t *indir) +{ + struct ionic_admin_ctx ctx = { + .pending_work = true, + .cmd.lif_setattr = { + .opcode = IONIC_CMD_LIF_SETATTR, + .attr = IONIC_LIF_ATTR_RSS, + .rss.types = types, + .rss.addr = lif->rss_ind_tbl_pa, + }, + }; + unsigned int i; + + IONIC_PRINT_CALL(); + + lif->rss_types = types; + + if (key) + memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE); + + if (indir) + for (i = 0; i < lif->adapter->ident.lif.eth.rss_ind_tbl_sz; i++) + lif->rss_ind_tbl[i] = indir[i]; + + memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key, + IONIC_RSS_HASH_KEY_SIZE); + + return ionic_adminq_post_wait(lif, &ctx); +} + +static int +ionic_lif_rss_setup(struct ionic_lif *lif) +{ + size_t tbl_size = sizeof(*lif->rss_ind_tbl) * + lif->adapter->ident.lif.eth.rss_ind_tbl_sz; + static const uint8_t toeplitz_symmetric_key[] = { + 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, + 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, + 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, + 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, + 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, + }; + uint32_t socket_id = rte_socket_id(); + uint32_t i; + int err; + + IONIC_PRINT_CALL(); + + lif->rss_ind_tbl_z = rte_eth_dma_zone_reserve(lif->eth_dev, + "rss_ind_tbl", + 0 /* queue_idx*/, tbl_size, IONIC_ALIGN, socket_id); + + if (!lif->rss_ind_tbl_z) { + IONIC_PRINT(ERR, "OOM"); + return -ENOMEM; + } + + lif->rss_ind_tbl = lif->rss_ind_tbl_z->addr; + lif->rss_ind_tbl_pa = lif->rss_ind_tbl_z->iova; + + /* Fill indirection table with 'default' values */ + for (i = 0; i < lif->adapter->ident.lif.eth.rss_ind_tbl_sz; i++) + lif->rss_ind_tbl[i] = i % lif->nrxqcqs; + + err = ionic_lif_rss_config(lif, IONIC_RSS_OFFLOAD_ALL, + toeplitz_symmetric_key, NULL); + if (err) + return err; + + return 0; +} + +static void +ionic_lif_rss_teardown(struct ionic_lif *lif) +{ + if (!lif->rss_ind_tbl) + return; + + if (lif->rss_ind_tbl_z) { + /* Disable RSS on the NIC */ + ionic_lif_rss_config(lif, 0x0, NULL, NULL); + + lif->rss_ind_tbl = NULL; + lif->rss_ind_tbl_pa = 0; + rte_memzone_free(lif->rss_ind_tbl_z); + lif->rss_ind_tbl_z = NULL; + } +} + static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq) { @@ -1293,6 +1384,7 @@ ionic_lif_deinit(struct ionic_lif *lif) return; ionic_rx_filters_deinit(lif); + ionic_lif_rss_teardown(lif); ionic_lif_qcq_deinit(lif, lif->notifyqcq); ionic_lif_qcq_deinit(lif, lif->adminqcq); @@ -1302,10 +1394,27 @@ ionic_lif_deinit(struct ionic_lif *lif) int ionic_lif_configure(struct ionic_lif *lif) { + struct ionic_identity *ident = &lif->adapter->ident; + uint32_t ntxqs_per_lif = + ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ]; + uint32_t nrxqs_per_lif = + ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ]; + uint32_t nrxqs = lif->eth_dev->data->nb_rx_queues; + uint32_t ntxqs = lif->eth_dev->data->nb_tx_queues; + lif->port_id = lif->eth_dev->data->port_id; - lif->nrxqcqs = 1; - lif->ntxqcqs = 1; + IONIC_PRINT(DEBUG, "Configuring LIF on port %u", + lif->port_id); + + if (nrxqs > 0) + nrxqs_per_lif = RTE_MIN(nrxqs_per_lif, nrxqs); + + if (ntxqs > 0) + ntxqs_per_lif = RTE_MIN(ntxqs_per_lif, ntxqs); + + lif->nrxqcqs = nrxqs_per_lif; + lif->ntxqcqs = ntxqs_per_lif; return 0; } @@ -1317,6 +1426,13 @@ ionic_lif_start(struct ionic_lif *lif) uint32_t i; int err; + IONIC_PRINT(DEBUG, "Setting RSS configuration on port %u", + lif->port_id); + + err = ionic_lif_rss_setup(lif); + if (err) + return err; + IONIC_PRINT(DEBUG, "Setting RX mode on port %u", lif->port_id); diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h index 5e7d9ae0c9..a6f579d1cd 100644 --- a/drivers/net/ionic/ionic_lif.h +++ b/drivers/net/ionic/ionic_lif.h @@ -17,6 +17,14 @@ #define IONIC_ADMINQ_LENGTH 16 /* must be a power of two */ #define IONIC_NOTIFYQ_LENGTH 64 /* must be a power of two */ +#define IONIC_RSS_OFFLOAD_ALL ( \ + IONIC_RSS_TYPE_IPV4 | \ + IONIC_RSS_TYPE_IPV4_TCP | \ + IONIC_RSS_TYPE_IPV4_UDP | \ + IONIC_RSS_TYPE_IPV6 | \ + IONIC_RSS_TYPE_IPV6_TCP | \ + IONIC_RSS_TYPE_IPV6_UDP) + #define IONIC_GET_SG_CNTR_IDX(num_sg_elems) (num_sg_elems) struct ionic_tx_stats { @@ -96,6 +104,11 @@ struct ionic_lif { uint32_t rx_mode; char name[IONIC_LIF_NAME_MAX_SZ]; uint8_t mac_addr[RTE_ETHER_ADDR_LEN]; + uint16_t rss_types; + uint8_t rss_hash_key[IONIC_RSS_HASH_KEY_SIZE]; + uint8_t *rss_ind_tbl; + rte_iova_t rss_ind_tbl_pa; + const struct rte_memzone *rss_ind_tbl_z; uint32_t info_sz; struct ionic_lif_info *info; rte_iova_t info_pa; @@ -156,6 +169,9 @@ void ionic_lif_rxq_deinit(struct ionic_qcq *qcq); int ionic_lif_txq_init(struct ionic_qcq *qcq); void ionic_lif_txq_deinit(struct ionic_qcq *qcq); +int ionic_lif_rss_config(struct ionic_lif *lif, const uint16_t types, + const uint8_t *key, const uint32_t *indir); + int ionic_lif_set_features(struct ionic_lif *lif); int ionic_notifyq_handler(struct ionic_lif *lif, int budget); diff --git a/drivers/net/ionic/ionic_rxtx.c b/drivers/net/ionic/ionic_rxtx.c index f3b46a262f..13919fc5af 100644 --- a/drivers/net/ionic/ionic_rxtx.c +++ b/drivers/net/ionic/ionic_rxtx.c @@ -700,6 +700,10 @@ ionic_rx_clean(struct ionic_queue *q, rxm->nb_segs++; } + /* RSS */ + pkt_flags |= PKT_RX_RSS_HASH; + rxm->hash.rss = cq_desc->rss_hash; + /* Vlan Strip */ if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) { pkt_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;