[PATCH net-next 2/4] net:hns: Add Hip06 "RSS(Receive Side Scaling)" support to HNS Driver
Yisen.Zhuang(Zhuangyuzeng)
Yisen.Zhuang at huawei.com
Wed Oct 21 19:01:07 PDT 2015
Please check my comment below. thanks.
Yisen
On 2015/10/20 23:01, Salil wrote:
> From: Salil Mehta <salil.mehta at huawei.com>
>
> This patch adds the support of "RSS (Receive Side Scaling)" feature
> provided by the Hip06 ethernet hardware to the HNS ethernet
> driver.
>
> This feature helps in distributing the different flows (mapped as
> hash by hardware using Toeplitz Hash) to different Queues asssociated
> with the processor cores. The mapping of flow-hash values to the
> different queues is stored in indirection table (which is per Packet-
> parse-Engine/PPE). This patch also provides the changes to re-program
> the (flow-hash<->Qid) mapping using the ethtool.
>
> Signed-off-by: Salil Mehta <salil.mehta at huawei.com>
> ---
> drivers/net/ethernet/hisilicon/hns/hnae.h | 6 ++
> drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 81 ++++++++++++++++++++-
> drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 74 ++++++++++++++++++-
> drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h | 33 +++++++--
> drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h | 14 ++++
> drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 69 ++++++++++++++++++
> 6 files changed, 267 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
> index 70a662c..3edcade 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hnae.h
> +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
> @@ -483,6 +483,12 @@ struct hnae_ae_ops {
> enum hnae_led_state status);
> void (*get_regs)(struct hnae_handle *handle, void *data);
> int (*get_regs_len)(struct hnae_handle *handle);
> + u32 (*get_rss_key_size)(struct hnae_handle *handle);
> + u32 (*get_rss_indir_size)(struct hnae_handle *handle);
> + int (*get_rss)(struct hnae_handle *handle, u32 *indir, u8 *key,
> + u8 *hfunc);
> + int (*set_rss)(struct hnae_handle *handle, const u32 *indir,
> + const u8 *key, const u8 hfunc);
> };
>
> struct hnae_ae_dev {
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
> index c3d64ce..791c289 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
> @@ -748,6 +748,81 @@ int hns_ae_get_regs_len(struct hnae_handle *handle)
> return total_num;
> }
>
> +static u32 hns_ae_get_rss_key_size(struct hnae_handle *handle)
> +{
> + struct hns_ppe_cb *ppe_cb = hns_get_ppe_cb(handle);
> +
> + if (!hns_ppe_is_rss_supported(ppe_cb)) {
> + pr_err("RSS feature is not supported on this hardware\n");
> + return 0;
use dev_err rather than pr_err.
> + }
> +
> + return HNS_PPEV2_RSS_KEY_SIZE;
> +}
> +
> +static u32 hns_ae_get_rss_indir_size(struct hnae_handle *handle)
> +{
> + struct hns_ppe_cb *ppe_cb = hns_get_ppe_cb(handle);
> +
> + if (!hns_ppe_is_rss_supported(ppe_cb)) {
> + pr_err("RSS feature is not supported on this hardware\n");
> + return 0;
use dev_err rather than pr_err.
> + }
> +
> + return HNS_PPEV2_RSS_IND_TBL_SIZE;
> +}
> +
> +static int hns_ae_get_rss(struct hnae_handle *handle, u32 *indir, u8 *key,
> + u8 *hfunc)
> +{
> + struct hns_ppe_cb *ppe_cb = hns_get_ppe_cb(handle);
> + u32 i;
> +
> + if (!hns_ppe_is_rss_supported(ppe_cb)) {
> + pr_err("RSS feature is not supported on this hardware\n");
> + return -EOPNOTSUPP;
use dev_err rather than pr_err.
> + }
> +
> + /* currently we support only one type of hash function i.e. Toep hash */
> + if (hfunc)
> + *hfunc = ETH_RSS_HASH_TOP;
> +
> + /* get the RSS Key required by the user */
> + if (key)
> + memcpy(key, ppe_cb->rss_key, HNS_PPEV2_RSS_KEY_SIZE);
> +
> + /* update the current hash->queue mappings from the shadow RSS table */
> + for (i = 0; i < HNS_PPEV2_RSS_IND_TBL_SIZE; i++)
> + indir[i] = ppe_cb->rss_indir_table[i];
> +
> + return 0;
> +}
> +
> +static int hns_ae_set_rss(struct hnae_handle *handle, const u32 *indir,
> + const u8 *key, const u8 hfunc)
> +{
> + struct hns_ppe_cb *ppe_cb = hns_get_ppe_cb(handle);
> + u32 i;
> +
> + if (!hns_ppe_is_rss_supported(ppe_cb)) {
> + pr_err("RSS feature is not supported on this hardware\n");
> + return -EOPNOTSUPP;
use dev_err rather than pr_err.
> + }
> +
> + /* set the RSS Hash Key if specififed by the user */
> + if (key)
> + hns_ppe_set_rss_key(ppe_cb, (int *)key);
> +
> + /* update the shadow RSS table */
> + for (i = 0; i < HNS_PPEV2_RSS_IND_TBL_SIZE; i++)
> + ppe_cb->rss_indir_table[i] = i;
Moving this into hns_ppe_set_indir_table will be better.
> +
> + /* now update the hardware */
> + hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table);
> +
> + return 0;
> +}
> +
> static struct hnae_ae_ops hns_dsaf_ops = {
> .get_handle = hns_ae_get_handle,
> .put_handle = hns_ae_put_handle,
> @@ -782,7 +857,11 @@ static struct hnae_ae_ops hns_dsaf_ops = {
> .update_led_status = hns_ae_update_led_status,
> .set_led_id = hns_ae_cpld_set_led_id,
> .get_regs = hns_ae_get_regs,
> - .get_regs_len = hns_ae_get_regs_len
> + .get_regs_len = hns_ae_get_regs_len,
> + .get_rss_key_size = hns_ae_get_rss_key_size,
> + .get_rss_indir_size = hns_ae_get_rss_indir_size,
> + .get_rss = hns_ae_get_rss,
> + .set_rss = hns_ae_set_rss
> };
>
> int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev)
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
> index 9531992..adaece3 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
> @@ -19,6 +19,56 @@
>
> #include "hns_dsaf_ppe.h"
>
> +int hns_ppe_is_rss_supported(struct hns_ppe_cb *ppe_cb)
return bool.
> +{
> + struct ppe_common_cb *ppe_common_cb = ppe_cb->ppe_common_cb;
> + struct dsaf_device *dsaf_dev = ppe_common_cb->dsaf_dev;
> + int ret = 0;
> +
> + /* Not all versions support RSS feature */
> + if (!AE_IS_VER1(dsaf_dev->dsaf_ver))
> + ret = 1;
> +
> + return ret;
> +}
> +
> +void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb,
> + const u32 rss_key[HNS_PPEV2_RSS_KEY_NUM])
> +{
> + int key_item = 0;
> +
> + for (key_item = 0; key_item < HNS_PPEV2_RSS_KEY_NUM; key_item++)
> + dsaf_write_dev(ppe_cb, PPEV2_RSS_KEY_REG + key_item * 0x4,
> + rss_key[key_item]);
also need modify ppe_cb->rss_key.
> +}
> +
> +void hns_ppe_set_indir_table(struct hns_ppe_cb *ppe_cb,
> + const u32 rss_tab[HNS_PPEV2_RSS_IND_TBL_SIZE])
> +{
> + int i;
> + int reg_value;
> +
> + for (i = 0; i < (HNS_PPEV2_RSS_IND_TBL_SIZE / 4); i++) {
> + reg_value = dsaf_read_dev(ppe_cb,
> + PPEV2_INDRECTION_TBL_REG + i * 0x4);
> +
> + dsaf_set_field(reg_value, PPEV2_CFG_RSS_TBL_4N0_M,
> + PPEV2_CFG_RSS_TBL_4N0_S,
> + rss_tab[i * 4 + 0] & 0x1F);
> + dsaf_set_field(reg_value, PPEV2_CFG_RSS_TBL_4N1_M,
> + PPEV2_CFG_RSS_TBL_4N1_S,
> + rss_tab[i * 4 + 1] & 0x1F);
> + dsaf_set_field(reg_value, PPEV2_CFG_RSS_TBL_4N2_M,
> + PPEV2_CFG_RSS_TBL_4N2_S,
> + rss_tab[i * 4 + 2] & 0x1F);
> + dsaf_set_field(reg_value, PPEV2_CFG_RSS_TBL_4N3_M,
> + PPEV2_CFG_RSS_TBL_4N3_S,
> + rss_tab[i * 4 + 3] & 0x1F);
> + dsaf_write_dev(
> + ppe_cb, PPEV2_INDRECTION_TBL_REG + i * 0x4, reg_value);
> + }
> +}
> +
> static void __iomem *hns_ppe_common_get_ioaddr(
> struct ppe_common_cb *ppe_common)
> {
> @@ -266,13 +316,26 @@ static void hns_ppe_exc_irq_en(struct hns_ppe_cb *ppe_cb, int en)
>
> /**
> * ppe_init_hw - init ppe
> - * @ppe_device: ppe device
> + * @ppe_cb: ppe device
> */
> static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
> {
> struct ppe_common_cb *ppe_common_cb = ppe_cb->ppe_common_cb;
> u32 port = ppe_cb->port;
> struct dsaf_device *dsaf_dev = ppe_common_cb->dsaf_dev;
> + int i;
> + /* Set default RSS key and indrection table*/
> + const u32 rss_key[HNS_PPEV2_RSS_KEY_NUM] = {
> + 0x6d5a56da, 0x255b0ec2,
> + 0x4167253d, 0x43a38fb0,
> + 0xd0ca2bcb, 0xae7b30b4,
> + 0x77cb2da3, 0x8030f20c,
> + 0x6a42b73b, 0xbeac01fa,
> + };
> +
> + /* set default RSS key and remember it */
> + for (i = 0; i < HNS_PPEV2_RSS_KEY_NUM; i++)
> + ppe_cb->rss_key[i] = rss_key[i];
Moving this into hns_ppe_set_rss_key.
>
> hns_ppe_srst_by_port(dsaf_dev, port, 0);
> mdelay(10);
> @@ -285,8 +348,17 @@ static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
> hns_ppe_set_port_mode(ppe_cb, PPE_MODE_GE);
> else
> hns_ppe_set_port_mode(ppe_cb, PPE_MODE_XGE);
> +
> hns_ppe_checksum_hw(ppe_cb, 0xffffffff);
> hns_ppe_cnt_clr_ce(ppe_cb);
> +
> + if (!AE_IS_VER1(dsaf_dev->dsaf_ver)) {
> + hns_ppe_set_rss_key(ppe_cb, rss_key);
> +
> + for (i = 0; i < HNS_PPEV2_RSS_IND_TBL_SIZE; i++)
> + ppe_cb->rss_indir_table[i] = i;
Moving this into hns_ppe_set_indir_table.
> + hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table);
> + }
> }
>
> /**
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
> index 4894f9a..6d3545d 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
> @@ -25,15 +25,24 @@
>
> #define ETH_PPE_DUMP_NUM 576
> #define ETH_PPE_STATIC_NUM 12
> +
> +#define HNS_PPEV2_RSS_IND_TBL_SIZE 256
> +#define HNS_PPEV2_RSS_KEY_SIZE 40 /* in bytes or 320 bits */
> +#define HNS_PPEV2_RSS_KEY_NUM (HNS_PPEV2_RSS_KEY_SIZE / sizeof(u32))
> +
> enum ppe_qid_mode {
> - PPE_QID_MODE0 = 0, /* fixed queue id mode */
> - PPE_QID_MODE1, /* switch:128VM non switch:6Port/4VM/4TC */
> - PPE_QID_MODE2, /* switch:32VM/4TC non switch:6Port/16VM */
> - PPE_QID_MODE3, /* switch:4TC/8TAG non switch:2Port/64VM */
> - PPE_QID_MODE4, /* switch:8VM/16TAG non switch:2Port/16VM/4TC */
> - PPE_QID_MODE5, /* non switch:6Port/16TAG */
> - PPE_QID_MODE6, /* non switch:6Port/2VM/8TC */
> - PPE_QID_MODE7, /* non switch:2Port/8VM/8TC */
> + PPE_QID_MODE0 = 0, /* fixed queue id mode */
> + PPE_QID_MODE1, /* switch:128VM non switch:6Port/4VM/4TC */
> + PPE_QID_MODE2, /* switch:32VM/4TC non switch:6Port/16VM */
> + PPE_QID_MODE3, /* switch:4TC/8RSS non switch:2Port/64VM */
> + PPE_QID_MODE4, /* switch:8VM/16RSS non switch:2Port/16VM/4TC */
> + PPE_QID_MODE5, /* switch:16VM/8TC non switch:6Port/16RSS */
> + PPE_QID_MODE6, /* switch:32VM/4RSS non switch:6Port/2VM/8TC */
> + PPE_QID_MODE7, /* switch:32RSS non switch:2Port/8VM/8TC */
> + PPE_QID_MODE8, /* switch:6VM/4TC/4RSS non switch:2Port/16VM/4RSS */
> + PPE_QID_MODE9, /* non switch:2Port/32VM/2RSS */
> + PPE_QID_MODE10, /* non switch:2Port/32RSS */
> + PPE_QID_MODE11, /* non switch:2Port/4TC/16RSS */
> };
>
> enum ppe_port_mode {
> @@ -72,6 +81,8 @@ struct hns_ppe_cb {
> u8 port; /* port id in dsaf */
> void __iomem *io_base;
> int virq;
> + u32 rss_indir_table[HNS_PPEV2_RSS_IND_TBL_SIZE]; /*shadow indir tab */
> + u32 rss_key[HNS_PPEV2_RSS_KEY_NUM]; /* rss hash key */
> };
>
> struct ppe_common_cb {
> @@ -102,4 +113,10 @@ void hns_ppe_get_regs(struct hns_ppe_cb *ppe_cb, void *data);
>
> void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data);
> void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data);
> +
> +void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb,
> + const u32 rss_key[HNS_PPEV2_RSS_KEY_NUM]);
> +void hns_ppe_set_indir_table(struct hns_ppe_cb *ppe_cb,
> + const u32 rss_tab[HNS_PPEV2_RSS_IND_TBL_SIZE]);
> +int hns_ppe_is_rss_supported(struct hns_ppe_cb *ppe_cb);
> #endif /* _HNS_DSAF_PPE_H */
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
> index 8b1ad00..a5ebcc6 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
> @@ -348,6 +348,8 @@
> #define PPE_ECO0_REG 0x32C
> #define PPE_ECO1_REG 0x330
> #define PPE_ECO2_REG 0x334
> +#define PPEV2_INDRECTION_TBL_REG 0x800
> +#define PPEV2_RSS_KEY_REG 0x900
>
> #define RCB_COM_CFG_ENDIAN_REG 0x0
> #define RCB_COM_CFG_SYS_FSH_REG 0xC
> @@ -834,6 +836,18 @@
> #define PPE_CFG_QID_MODE_CF_QID_MODE_S 8
> #define PPE_CFG_QID_MODE_CF_QID_MODE_M (0x7 << PPE_CFG_QID_MODE_CF_QID_MODE_S)
>
> +#define PPEV2_CFG_RSS_TBL_4N0_S 0
> +#define PPEV2_CFG_RSS_TBL_4N0_M (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N0_S)
> +
> +#define PPEV2_CFG_RSS_TBL_4N1_S 8
> +#define PPEV2_CFG_RSS_TBL_4N1_M (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N1_S)
> +
> +#define PPEV2_CFG_RSS_TBL_4N2_S 16
> +#define PPEV2_CFG_RSS_TBL_4N2_M (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N2_S)
> +
> +#define PPEV2_CFG_RSS_TBL_4N3_S 24
> +#define PPEV2_CFG_RSS_TBL_4N3_M (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N3_S)
> +
> #define PPE_CNT_CLR_CE_B 0
> #define PPE_CNT_CLR_SNAP_EN_B 1
>
> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
> index 9df63ae..b379810 100644
> --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
> +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
> @@ -1187,6 +1187,71 @@ static int hns_nic_nway_reset(struct net_device *netdev)
> return ret;
> }
>
> +static u32
> +hns_get_rss_key_size(struct net_device *netdev)
> +{
> + struct hns_nic_priv *priv = netdev_priv(netdev);
> + struct hnae_ae_ops *ops;
> + u32 ret;
> +
> + ops = priv->ae_handle->dev->ops;
> + ret = ops->get_rss_key_size(priv->ae_handle);
> +
> + return ret;
> +}
> +
> +static u32
> +hns_get_rss_indir_size(struct net_device *netdev)
> +{
> + struct hns_nic_priv *priv = netdev_priv(netdev);
> + struct hnae_ae_ops *ops;
> + u32 ret;
> +
> + ops = priv->ae_handle->dev->ops;
> + ret = ops->get_rss_indir_size(priv->ae_handle);
> +
> + return ret;
> +}
> +
> +static int
> +hns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
> +{
> + struct hns_nic_priv *priv = netdev_priv(netdev);
> + struct hnae_ae_ops *ops;
> + int ret;
> +
> + ops = priv->ae_handle->dev->ops;
> +
> + if (!indir)
> + return 0;
> +
> + ret = ops->get_rss(priv->ae_handle, indir, key, hfunc);
> +
> + return 0;
> +}
> +
> +static int
> +hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
> + const u8 hfunc)
> +{
> + struct hns_nic_priv *priv = netdev_priv(netdev);
> + struct hnae_ae_ops *ops;
> + int ret;
> +
> + ops = priv->ae_handle->dev->ops;
> +
> + /* currently hfunc can only be Toeplitz hash */
> + if (key ||
> + (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
> + return -EOPNOTSUPP;
> + if (!indir)
> + return 0;
> +
> + ret = ops->set_rss(priv->ae_handle, indir, key, hfunc);
> +
> + return 0;
> +}
> +
> static struct ethtool_ops hns_ethtool_ops = {
> .get_drvinfo = hns_nic_get_drvinfo,
> .get_link = hns_nic_get_link,
> @@ -1206,6 +1271,10 @@ static struct ethtool_ops hns_ethtool_ops = {
> .get_regs_len = hns_get_regs_len,
> .get_regs = hns_get_regs,
> .nway_reset = hns_nic_nway_reset,
> + .get_rxfh_key_size = hns_get_rss_key_size,
> + .get_rxfh_indir_size = hns_get_rss_indir_size,
> + .get_rxfh = hns_get_rss,
> + .set_rxfh = hns_set_rss,
> };
>
> void hns_ethtool_set_ops(struct net_device *ndev)
>
More information about the linux-arm-kernel
mailing list