From patchwork Fri Jul 18 02:45:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Helin" X-Patchwork-Id: 51 Return-Path: Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 32BAF959 for ; Fri, 18 Jul 2014 04:44:34 +0200 (CEST) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP; 17 Jul 2014 19:45:32 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,682,1400050800"; d="scan'208";a="563544553" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by fmsmga001.fm.intel.com with ESMTP; 17 Jul 2014 19:45:30 -0700 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id s6I2jSM1025162; Fri, 18 Jul 2014 10:45:28 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id s6I2jPkV014661; Fri, 18 Jul 2014 10:45:27 +0800 Received: (from hzhan75@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id s6I2jPt8014657; Fri, 18 Jul 2014 10:45:25 +0800 From: Helin Zhang To: dev@dpdk.org Date: Fri, 18 Jul 2014 10:45:19 +0800 Message-Id: <1405651521-14545-2-git-send-email-helin.zhang@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: <1405651521-14545-1-git-send-email-helin.zhang@intel.com> References: <1405651521-14545-1-git-send-email-helin.zhang@intel.com> Subject: [dpdk-dev] [PATCH 1/3] i40evf: add RSS support in VF X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 18 Jul 2014 02:44:35 -0000 Add VF RSS support in Poll Mode Driver, as it is supported by hardware. Signed-off-by: Helin Zhang Acked-by: Cunming Liang Acked-by: Jijiang Liu --- lib/librte_pmd_i40e/i40e_ethdev.c | 4 +- lib/librte_pmd_i40e/i40e_ethdev.h | 40 ++++++- lib/librte_pmd_i40e/i40e_ethdev_vf.c | 208 +++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+), 3 deletions(-) diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c index 9ed31b5..85e8b18 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.c +++ b/lib/librte_pmd_i40e/i40e_ethdev.c @@ -3747,7 +3747,7 @@ DONE: } /* Configure hash enable flags for RSS */ -static uint64_t +uint64_t i40e_config_hena(uint64_t flags) { uint64_t hena = 0; @@ -3782,7 +3782,7 @@ i40e_config_hena(uint64_t flags) } /* Parse the hash enable flags */ -static uint64_t +uint64_t i40e_parse_hena(uint64_t flags) { uint64_t rss_hf = 0; diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h index 64deef2..1d42cd2 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.h +++ b/lib/librte_pmd_i40e/i40e_ethdev.h @@ -68,6 +68,36 @@ I40E_FLAG_HEADER_SPLIT_ENABLED | \ I40E_FLAG_FDIR) +#define I40E_RSS_OFFLOAD_ALL ( \ + ETH_RSS_NONF_IPV4_UDP | \ + ETH_RSS_NONF_IPV4_TCP | \ + ETH_RSS_NONF_IPV4_SCTP | \ + ETH_RSS_NONF_IPV4_OTHER | \ + ETH_RSS_FRAG_IPV4 | \ + ETH_RSS_NONF_IPV6_UDP | \ + ETH_RSS_NONF_IPV6_TCP | \ + ETH_RSS_NONF_IPV6_SCTP | \ + ETH_RSS_NONF_IPV6_OTHER | \ + ETH_RSS_FRAG_IPV6 | \ + ETH_RSS_L2_PAYLOAD) + +/* All bits of RSS hash enable */ +#define I40E_RSS_HENA_ALL ( \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ + (1ULL << I40E_FILTER_PCTYPE_FCOE_OX) | \ + (1ULL << I40E_FILTER_PCTYPE_FCOE_RX) | \ + (1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \ + (1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD)) + struct i40e_adapter; TAILQ_HEAD(i40e_mac_filter_list, i40e_mac_filter); @@ -253,6 +283,8 @@ struct i40e_vf_tx_queues { * Structure to store private data specific for VF instance. */ struct i40e_vf { + struct i40e_adapter *adapter; /* The adapter this VF associate to */ + struct rte_eth_dev_data *dev_data; /* Pointer to the device data */ uint16_t num_queue_pairs; uint16_t max_pkt_len; /* Maximum packet length */ bool promisc_unicast_enabled; @@ -310,8 +342,10 @@ int i40e_dev_link_update(struct rte_eth_dev *dev, void i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi); void i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi); int i40e_vsi_vlan_pvid_set(struct i40e_vsi *vsi, - struct i40e_vsi_vlan_pvid_info *info); + struct i40e_vsi_vlan_pvid_info *info); int i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on); +uint64_t i40e_config_hena(uint64_t flags); +uint64_t i40e_parse_hena(uint64_t flags); /* I40E_DEV_PRIVATE_TO */ #define I40E_DEV_PRIVATE_TO_PF(adapter) \ @@ -361,6 +395,10 @@ i40e_get_vsi_from_adapter(struct i40e_adapter *adapter) #define I40E_PF_TO_ADAPTER(pf) \ ((struct i40e_adapter *)pf->adapter) +/* I40E_VF_TO */ +#define I40E_VF_TO_HW(vf) \ + (&(((struct i40e_vf *)vf)->adapter->hw)) + static inline void i40e_init_adminq_parameter(struct i40e_hw *hw) { diff --git a/lib/librte_pmd_i40e/i40e_ethdev_vf.c b/lib/librte_pmd_i40e/i40e_ethdev_vf.c index 2726bfb..bef34cb 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev_vf.c +++ b/lib/librte_pmd_i40e/i40e_ethdev_vf.c @@ -125,6 +125,19 @@ static void i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev); static int i40evf_get_link_status(struct rte_eth_dev *dev, struct rte_eth_link *link); static int i40evf_init_vlan(struct rte_eth_dev *dev); +static int i40evf_config_rss(struct i40e_vf *vf); +static int i40evf_dev_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf); +static int i40evf_dev_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf); +static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); +static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); + +/* Default hash key buffer for RSS */ +static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1]; + static struct eth_dev_ops i40evf_eth_dev_ops = { .dev_configure = i40evf_dev_configure, .dev_start = i40evf_dev_start, @@ -144,6 +157,10 @@ static struct eth_dev_ops i40evf_eth_dev_ops = { .rx_queue_release = i40e_dev_rx_queue_release, .tx_queue_setup = i40e_dev_tx_queue_setup, .tx_queue_release = i40e_dev_tx_queue_release, + .reta_update = i40evf_dev_rss_reta_update, + .reta_query = i40evf_dev_rss_reta_query, + .rss_hash_update = i40evf_dev_rss_hash_update, + .rss_hash_conf_get = i40evf_dev_rss_hash_conf_get, }; static int @@ -941,6 +958,8 @@ i40evf_init_vf(struct rte_eth_dev *dev) struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); + vf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); + vf->dev_data = dev->data; err = i40evf_set_mac_type(hw); if (err) { PMD_INIT_LOG(ERR, "set_mac_type failed: %d\n", err); @@ -1194,11 +1213,13 @@ i40evf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static int i40evf_rx_init(struct rte_eth_dev *dev) { + struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); uint16_t i, j; struct i40e_rx_queue **rxq = (struct i40e_rx_queue **)dev->data->rx_queues; struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + i40evf_config_rss(vf); for (i = 0; i < dev->data->nb_rx_queues; i++) { if (i40e_alloc_rx_queue_mbufs(rxq[i]) != 0) { PMD_DRV_LOG(ERR, "alloc rx queues mbufs failed\n"); @@ -1445,3 +1466,190 @@ i40evf_dev_close(struct rte_eth_dev *dev) i40evf_reset_vf(hw); i40e_shutdown_adminq(hw); } + +static int +i40evf_hw_rss_hash_set(struct i40e_hw *hw, struct rte_eth_rss_conf *rss_conf) +{ + uint32_t *hash_key; + uint8_t hash_key_len; + uint64_t rss_hf, hena; + + hash_key = (uint32_t *)(rss_conf->rss_key); + hash_key_len = rss_conf->rss_key_len; + if (hash_key != NULL && hash_key_len >= + (I40E_VFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { + uint16_t i; + + for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) + I40E_WRITE_REG(hw, I40E_VFQF_HKEY(i), hash_key[i]); + } + + rss_hf = rss_conf->rss_hf; + hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0)); + hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32; + hena &= ~I40E_RSS_HENA_ALL; + hena |= i40e_config_hena(rss_hf); + I40E_WRITE_REG(hw, I40E_VFQF_HENA(0), (uint32_t)hena); + I40E_WRITE_REG(hw, I40E_VFQF_HENA(1), (uint32_t)(hena >> 32)); + I40EVF_WRITE_FLUSH(hw); + + return 0; +} + +static void +i40evf_disable_rss(struct i40e_vf *vf) +{ + struct i40e_hw *hw = I40E_VF_TO_HW(vf); + uint64_t hena; + + hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0)); + hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32; + hena &= ~I40E_RSS_HENA_ALL; + I40E_WRITE_REG(hw, I40E_VFQF_HENA(0), (uint32_t)hena); + I40E_WRITE_REG(hw, I40E_VFQF_HENA(1), (uint32_t)(hena >> 32)); + I40EVF_WRITE_FLUSH(hw); +} + +static int +i40evf_config_rss(struct i40e_vf *vf) +{ + struct i40e_hw *hw = I40E_VF_TO_HW(vf); + struct rte_eth_rss_conf rss_conf; + uint32_t i, j, lut = 0, nb_q = (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4; + + if (vf->dev_data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) { + i40evf_disable_rss(vf); + PMD_DRV_LOG(DEBUG, "RSS not configured\n"); + return 0; + } + + /* Fill out the look up table */ + for (i = 0, j = 0; i < nb_q; i++, j++) { + if (j >= vf->num_queue_pairs) + j = 0; + lut = (lut << 8) | j; + if ((i & 3) == 3) + I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut); + } + + rss_conf = vf->dev_data->dev_conf.rx_adv_conf.rss_conf; + if ((rss_conf.rss_hf & I40E_RSS_OFFLOAD_ALL) == 0) { + i40evf_disable_rss(vf); + PMD_DRV_LOG(DEBUG, "No hash flag is set\n"); + return 0; + } + + if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < nb_q) { + /* Calculate the default hash key */ + for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) + rss_key_default[i] = (uint32_t)rte_rand(); + rss_conf.rss_key = (uint8_t *)rss_key_default; + rss_conf.rss_key_len = nb_q; + } + + return i40evf_hw_rss_hash_set(hw, &rss_conf); +} + +static int +i40evf_dev_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2; + uint32_t lut, l; + + for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { + if (i < max) + mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); + else + mask = (uint8_t)((reta_conf->mask_hi >> + (i - max)) & 0xF); + if (!mask) + continue; + if (mask == 0xf) + l = 0; + else + l = I40E_READ_REG(hw, I40E_VFQF_HLUT(i >> 2)); + + for (j = 0, lut = 0; j < 4; j++) { + if (mask & (0x1 << j)) + lut |= reta_conf->reta[i + j] << (8 * j); + else + lut |= l & (0xff << (8 * j)); + } + I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut); + } + + return 0; +} + +static int +i40evf_dev_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2; + uint32_t lut; + + for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { + if (i < max) + mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); + else + mask = (uint8_t)((reta_conf->mask_hi >> + (i - max)) & 0xF); + if (!mask) + continue; + lut = I40E_READ_REG(hw, I40E_VFQF_HLUT(i >> 2)); + for (j = 0; j < 4; j++) { + if (mask & (0x1 << j)) + reta_conf->reta[i + j] = + (uint8_t)((lut >> (8 * j)) & 0xFF); + } + } + + return 0; +} + +static int +i40evf_dev_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint64_t rss_hf = rss_conf->rss_hf & I40E_RSS_OFFLOAD_ALL; + uint64_t hena; + + hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0)); + hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32; + if (!(hena & I40E_RSS_HENA_ALL)) { /* RSS disabled */ + if (rss_hf != 0) /* Enable RSS */ + return -EINVAL; + return 0; + } + + /* RSS enabled */ + if (rss_hf == 0) /* Disable RSS */ + return -EINVAL; + + return i40evf_hw_rss_hash_set(hw, rss_conf); +} + +static int +i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t *hash_key = (uint32_t *)(rss_conf->rss_key); + uint64_t hena; + uint16_t i; + + if (hash_key) { + for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) + hash_key[i] = I40E_READ_REG(hw, I40E_VFQF_HKEY(i)); + rss_conf->rss_key_len = i * sizeof(uint32_t); + } + hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0)); + hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32; + rss_conf->rss_hf = i40e_parse_hena(hena); + + return 0; +}