Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 421e9526 authored by Xue Chaojing's avatar Xue Chaojing Committed by David S. Miller
Browse files

hinic: add rss support



This patch adds rss support for the HINIC driver.

Signed-off-by: default avatarXue Chaojing <xuechaojing@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 760f1dc2
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
enum hinic_flags {
	HINIC_LINK_UP = BIT(0),
	HINIC_INTF_UP = BIT(1),
	HINIC_RSS_ENABLE = BIT(2),
};

struct hinic_rx_mode_work {
@@ -29,6 +30,23 @@ struct hinic_rx_mode_work {
	u32                     rx_mode;
};

struct hinic_rss_type {
	u8 tcp_ipv6_ext;
	u8 ipv6_ext;
	u8 tcp_ipv6;
	u8 ipv6;
	u8 tcp_ipv4;
	u8 ipv4;
	u8 udp_ipv6;
	u8 udp_ipv4;
};

enum hinic_rss_hash_type {
	HINIC_RSS_HASH_ENGINE_TYPE_XOR,
	HINIC_RSS_HASH_ENGINE_TYPE_TOEP,
	HINIC_RSS_HASH_ENGINE_TYPE_MAX,
};

struct hinic_dev {
	struct net_device               *netdev;
	struct hinic_hwdev              *hwdev;
@@ -36,6 +54,8 @@ struct hinic_dev {
	u32                             msg_enable;
	unsigned int                    tx_weight;
	unsigned int                    rx_weight;
	u16				num_qps;
	u16				max_qps;

	unsigned int                    flags;

@@ -50,6 +70,12 @@ struct hinic_dev {

	struct hinic_txq_stats          tx_stats;
	struct hinic_rxq_stats          rx_stats;

	u8				rss_tmpl_idx;
	u8				rss_hash_engine;
	u16				num_rss;
	u16				rss_limit;
	struct hinic_rss_type		rss_type;
};

#endif
+7 −3
Original line number Diff line number Diff line
@@ -89,9 +89,6 @@ static int get_capability(struct hinic_hwdev *hwdev,
	if (nic_cap->num_qps > HINIC_Q_CTXT_MAX)
		nic_cap->num_qps = HINIC_Q_CTXT_MAX;

	/* num_qps must be power of 2 */
	nic_cap->num_qps = BIT(fls(nic_cap->num_qps) - 1);

	nic_cap->max_qps = dev_cap->max_sqs + 1;
	if (nic_cap->max_qps != (dev_cap->max_rqs + 1))
		return -EFAULT;
@@ -874,6 +871,13 @@ void hinic_free_hwdev(struct hinic_hwdev *hwdev)
	hinic_free_hwif(hwdev->hwif);
}

int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev)
{
	struct hinic_cap *nic_cap = &hwdev->nic_cap;

	return nic_cap->max_qps;
}

/**
 * hinic_hwdev_num_qps - return the number QPs available for use
 * @hwdev: the NIC HW device
+26 −0
Original line number Diff line number Diff line
@@ -47,6 +47,14 @@ enum hinic_port_cmd {

	HINIC_PORT_CMD_SET_PORT_STATE   = 41,

	HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,

	HINIC_PORT_CMD_SET_RSS_HASH_ENGINE  = 45,

	HINIC_PORT_CMD_RSS_TEMP_MGR	= 49,

	HINIC_PORT_CMD_RSS_CFG		= 66,

	HINIC_PORT_CMD_FWCTXT_INIT      = 69,

	HINIC_PORT_CMD_SET_FUNC_STATE   = 93,
@@ -62,6 +70,22 @@ enum hinic_port_cmd {
	HINIC_PORT_CMD_SET_LRO_TIMER	= 244,
};

enum hinic_ucode_cmd {
	HINIC_UCODE_CMD_MODIFY_QUEUE_CONTEXT    = 0,
	HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
	HINIC_UCODE_CMD_ARM_SQ,
	HINIC_UCODE_CMD_ARM_RQ,
	HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
	HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
	HINIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
	HINIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
	HINIC_UCODE_CMD_SET_IQ_ENABLE,
	HINIC_UCODE_CMD_SET_RQ_FLUSH            = 10
};

#define NIC_RSS_CMD_TEMP_ALLOC  0x01
#define NIC_RSS_CMD_TEMP_FREE   0x02

enum hinic_mgmt_msg_cmd {
	HINIC_MGMT_MSG_CMD_BASE         = 160,

@@ -221,6 +245,8 @@ struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev);

void hinic_free_hwdev(struct hinic_hwdev *hwdev);

int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev);

int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev);

struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i);
+16 −0
Original line number Diff line number Diff line
@@ -230,6 +230,22 @@
#define HINIC_GET_RX_PKT_TYPE(offload_type)	\
			RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)

#define HINIC_RSS_TYPE_VALID_SHIFT			23
#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT		24
#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT			25
#define HINIC_RSS_TYPE_TCP_IPV6_SHIFT			26
#define HINIC_RSS_TYPE_IPV6_SHIFT			27
#define HINIC_RSS_TYPE_TCP_IPV4_SHIFT			28
#define HINIC_RSS_TYPE_IPV4_SHIFT			29
#define HINIC_RSS_TYPE_UDP_IPV6_SHIFT			30
#define HINIC_RSS_TYPE_UDP_IPV4_SHIFT			31

#define HINIC_RSS_TYPE_SET(val, member)                        \
		(((u32)(val) & 0x1) << HINIC_RSS_TYPE_##member##_SHIFT)

#define HINIC_RSS_TYPE_GET(val, member)                        \
		(((u32)(val) >> HINIC_RSS_TYPE_##member##_SHIFT) & 0x1)

enum hinic_l4offload_type {
	HINIC_L4_OFF_DISABLE            = 0,
	HINIC_TCP_OFFLOAD_ENABLE        = 1,
+121 −5
Original line number Diff line number Diff line
@@ -382,11 +382,118 @@ static int hinic_configure_max_qnum(struct hinic_dev *nic_dev)
	return 0;
}

static int hinic_rss_init(struct hinic_dev *nic_dev)
{
	u32 indir_tbl[HINIC_RSS_INDIR_SIZE] = { 0 };
	u8 default_rss_key[HINIC_RSS_KEY_SIZE];
	u8 tmpl_idx = nic_dev->rss_tmpl_idx;
	int err, i;

	netdev_rss_key_fill(default_rss_key, sizeof(default_rss_key));
	for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
		indir_tbl[i] = ethtool_rxfh_indir_default(i, nic_dev->num_rss);

	err = hinic_rss_set_template_tbl(nic_dev, tmpl_idx, default_rss_key);
	if (err)
		return err;

	err = hinic_rss_set_indir_tbl(nic_dev, tmpl_idx, indir_tbl);
	if (err)
		return err;

	err = hinic_set_rss_type(nic_dev, tmpl_idx, nic_dev->rss_type);
	if (err)
		return err;

	err = hinic_rss_set_hash_engine(nic_dev, tmpl_idx,
					nic_dev->rss_hash_engine);
	if (err)
		return err;

	err = hinic_rss_cfg(nic_dev, 1, tmpl_idx);
	if (err)
		return err;

	return 0;
}

static void hinic_rss_deinit(struct hinic_dev *nic_dev)
{
	hinic_rss_cfg(nic_dev, 0, nic_dev->rss_tmpl_idx);
}

static void hinic_init_rss_parameters(struct hinic_dev *nic_dev)
{
	nic_dev->rss_hash_engine = HINIC_RSS_HASH_ENGINE_TYPE_XOR;
	nic_dev->rss_type.tcp_ipv6_ext = 1;
	nic_dev->rss_type.ipv6_ext = 1;
	nic_dev->rss_type.tcp_ipv6 = 1;
	nic_dev->rss_type.ipv6 = 1;
	nic_dev->rss_type.tcp_ipv4 = 1;
	nic_dev->rss_type.ipv4 = 1;
	nic_dev->rss_type.udp_ipv6 = 1;
	nic_dev->rss_type.udp_ipv4 = 1;
}

static void hinic_enable_rss(struct hinic_dev *nic_dev)
{
	struct net_device *netdev = nic_dev->netdev;
	struct hinic_hwdev *hwdev = nic_dev->hwdev;
	struct hinic_hwif *hwif = hwdev->hwif;
	struct pci_dev *pdev = hwif->pdev;
	int i, node, err = 0;
	u16 num_cpus = 0;

	nic_dev->max_qps = hinic_hwdev_max_num_qps(hwdev);
	if (nic_dev->max_qps <= 1) {
		nic_dev->flags &= ~HINIC_RSS_ENABLE;
		nic_dev->rss_limit = nic_dev->max_qps;
		nic_dev->num_qps = nic_dev->max_qps;
		nic_dev->num_rss = nic_dev->max_qps;

		return;
	}

	err = hinic_rss_template_alloc(nic_dev, &nic_dev->rss_tmpl_idx);
	if (err) {
		netif_err(nic_dev, drv, netdev,
			  "Failed to alloc tmpl_idx for rss, can't enable rss for this function\n");
		nic_dev->flags &= ~HINIC_RSS_ENABLE;
		nic_dev->max_qps = 1;
		nic_dev->rss_limit = nic_dev->max_qps;
		nic_dev->num_qps = nic_dev->max_qps;
		nic_dev->num_rss = nic_dev->max_qps;

		return;
	}

	nic_dev->flags |= HINIC_RSS_ENABLE;

	for (i = 0; i < num_online_cpus(); i++) {
		node = cpu_to_node(i);
		if (node == dev_to_node(&pdev->dev))
			num_cpus++;
	}

	if (!num_cpus)
		num_cpus = num_online_cpus();

	nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);

	nic_dev->rss_limit = nic_dev->num_qps;
	nic_dev->num_rss = nic_dev->num_qps;

	hinic_init_rss_parameters(nic_dev);
	err = hinic_rss_init(nic_dev);
	if (err)
		netif_err(nic_dev, drv, netdev, "Failed to init rss\n");
}

static int hinic_open(struct net_device *netdev)
{
	struct hinic_dev *nic_dev = netdev_priv(netdev);
	enum hinic_port_link_state link_state;
	int err, ret, num_qps;
	int err, ret;

	if (!(nic_dev->flags & HINIC_INTF_UP)) {
		err = hinic_hwdev_ifup(nic_dev->hwdev);
@@ -411,6 +518,8 @@ static int hinic_open(struct net_device *netdev)
		goto err_create_rxqs;
	}

	hinic_enable_rss(nic_dev);

	err = hinic_configure_max_qnum(nic_dev);
	if (err) {
		netif_err(nic_dev, drv, nic_dev->netdev,
@@ -418,9 +527,8 @@ static int hinic_open(struct net_device *netdev)
		goto err_port_state;
	}

	num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
	netif_set_real_num_tx_queues(netdev, num_qps);
	netif_set_real_num_rx_queues(netdev, num_qps);
	netif_set_real_num_tx_queues(netdev, nic_dev->num_qps);
	netif_set_real_num_rx_queues(netdev, nic_dev->num_qps);

	err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE);
	if (err) {
@@ -476,9 +584,12 @@ static int hinic_open(struct net_device *netdev)
	if (ret)
		netif_warn(nic_dev, drv, netdev,
			   "Failed to revert port state\n");

err_port_state:
	free_rxqs(nic_dev);
	if (nic_dev->flags & HINIC_RSS_ENABLE) {
		hinic_rss_deinit(nic_dev);
		hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
	}

err_create_rxqs:
	free_txqs(nic_dev);
@@ -522,6 +633,11 @@ static int hinic_close(struct net_device *netdev)
		return err;
	}

	if (nic_dev->flags & HINIC_RSS_ENABLE) {
		hinic_rss_deinit(nic_dev);
		hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
	}

	free_rxqs(nic_dev);
	free_txqs(nic_dev);

Loading