Commit 81a43620 authored by Geetha sowjanya's avatar Geetha sowjanya Committed by David S. Miller
Browse files

octeontx2-pf: Add RSS multi group support



Hardware supports 8 RSS groups per interface. Currently we are using
only group '0'. This patch allows user to create new RSS groups/contexts
and use the same as destination for flow steering rules.

usage:
To steer the traffic to RQ 2,3

ethtool -X eth0 weight 0 0 1 1 context new
(It will print the allocated context id number)
New RSS context is 1

ethtool -N eth0 flow-type tcp4 dst-port 80 context 1 loc 1

To delete the context
ethtool -X eth0 context 1 delete

When an RSS context is removed, the active classification
rules using this context are also removed.

Change-log:

v4
- Fixed compiletime warning.
- Address Saeed's comments on v3.

v3
- Coverted otx2_set_rxfh() to use new function.

v2
- Removed unrelated whitespace
- Coverted otx2_get_rxfh() to use new function.

Signed-off-by: default avatarSunil Kovvuri Goutham <sgoutham@marvell.com>
Signed-off-by: default avatarGeetha sowjanya <gakula@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f011539e
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -270,14 +270,17 @@ int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
	return err;
}

int otx2_set_rss_table(struct otx2_nic *pfvf)
int otx2_set_rss_table(struct otx2_nic *pfvf, int ctx_id)
{
	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
	const int index = rss->rss_size * ctx_id;
	struct mbox *mbox = &pfvf->mbox;
	struct otx2_rss_ctx *rss_ctx;
	struct nix_aq_enq_req *aq;
	int idx, err;

	mutex_lock(&mbox->lock);
	rss_ctx = rss->rss_ctx[ctx_id];
	/* Get memory to put this msg */
	for (idx = 0; idx < rss->rss_size; idx++) {
		aq = otx2_mbox_alloc_msg_nix_aq_enq(mbox);
@@ -297,10 +300,10 @@ int otx2_set_rss_table(struct otx2_nic *pfvf)
			}
		}

		aq->rss.rq = rss->ind_tbl[idx];
		aq->rss.rq = rss_ctx->ind_tbl[idx];

		/* Fill AQ info */
		aq->qidx = idx;
		aq->qidx = index + idx;
		aq->ctype = NIX_AQ_CTYPE_RSS;
		aq->op = NIX_AQ_INSTOP_INIT;
	}
@@ -335,9 +338,10 @@ void otx2_set_rss_key(struct otx2_nic *pfvf)
int otx2_rss_init(struct otx2_nic *pfvf)
{
	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
	struct otx2_rss_ctx *rss_ctx;
	int idx, ret = 0;

	rss->rss_size = sizeof(rss->ind_tbl);
	rss->rss_size = sizeof(*rss->rss_ctx[DEFAULT_RSS_CONTEXT_GROUP]);

	/* Init RSS key if it is not setup already */
	if (!rss->enable)
@@ -345,13 +349,19 @@ int otx2_rss_init(struct otx2_nic *pfvf)
	otx2_set_rss_key(pfvf);

	if (!netif_is_rxfh_configured(pfvf->netdev)) {
		/* Default indirection table */
		/* Set RSS group 0 as default indirection table */
		rss->rss_ctx[DEFAULT_RSS_CONTEXT_GROUP] = kzalloc(rss->rss_size,
								  GFP_KERNEL);
		if (!rss->rss_ctx[DEFAULT_RSS_CONTEXT_GROUP])
			return -ENOMEM;

		rss_ctx = rss->rss_ctx[DEFAULT_RSS_CONTEXT_GROUP];
		for (idx = 0; idx < rss->rss_size; idx++)
			rss->ind_tbl[idx] =
			rss_ctx->ind_tbl[idx] =
				ethtool_rxfh_indir_default(idx,
							   pfvf->hw.rx_queues);
	}
	ret = otx2_set_rss_table(pfvf);
	ret = otx2_set_rss_table(pfvf, DEFAULT_RSS_CONTEXT_GROUP);
	if (ret)
		return ret;

@@ -986,7 +996,7 @@ int otx2_config_nix(struct otx2_nic *pfvf)
	nixlf->sq_cnt = pfvf->hw.tx_queues;
	nixlf->cq_cnt = pfvf->qset.cq_cnt;
	nixlf->rss_sz = MAX_RSS_INDIR_TBL_SIZE;
	nixlf->rss_grps = 1; /* Single RSS indir table supported, for now */
	nixlf->rss_grps = MAX_RSS_GROUPS;
	nixlf->xqe_sz = NIX_XQESZ_W16;
	/* We don't know absolute NPA LF idx attached.
	 * AF will replace 'RVU_DEFAULT_PF_FUNC' with
+8 −3
Original line number Diff line number Diff line
@@ -51,13 +51,17 @@ enum arua_mapped_qtypes {
#define NIX_LF_POISON_VEC			0x82

/* RSS configuration */
struct otx2_rss_ctx {
	u8  ind_tbl[MAX_RSS_INDIR_TBL_SIZE];
};

struct otx2_rss_info {
	u8 enable;
	u32 flowkey_cfg;
	u16 rss_size;
	u8  ind_tbl[MAX_RSS_INDIR_TBL_SIZE];
#define RSS_HASH_KEY_SIZE	44   /* 352 bit key */
	u8  key[RSS_HASH_KEY_SIZE];
	struct otx2_rss_ctx	*rss_ctx[MAX_RSS_GROUPS];
};

/* NIX (or NPC) RX errors */
@@ -643,7 +647,7 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
int otx2_rss_init(struct otx2_nic *pfvf);
int otx2_set_flowkey_cfg(struct otx2_nic *pfvf);
void otx2_set_rss_key(struct otx2_nic *pfvf);
int otx2_set_rss_table(struct otx2_nic *pfvf);
int otx2_set_rss_table(struct otx2_nic *pfvf, int ctx_id);

/* Mbox handlers */
void mbox_handler_msix_offset(struct otx2_nic *pfvf,
@@ -684,10 +688,11 @@ int otx2_get_flow(struct otx2_nic *pfvf,
int otx2_get_all_flows(struct otx2_nic *pfvf,
		       struct ethtool_rxnfc *nfc, u32 *rule_locs);
int otx2_add_flow(struct otx2_nic *pfvf,
		  struct ethtool_rx_flow_spec *fsp);
		  struct ethtool_rxnfc *nfc);
int otx2_remove_flow(struct otx2_nic *pfvf, u32 location);
int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
			      struct npc_install_flow_req *req);
void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id);
int otx2_del_macfilter(struct net_device *netdev, const u8 *mac);
int otx2_add_macfilter(struct net_device *netdev, const u8 *mac);
int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable);
+105 −28
Original line number Diff line number Diff line
@@ -581,7 +581,7 @@ static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
		break;
	case ETHTOOL_SRXCLSRLINS:
		if (netif_running(dev) && ntuple)
			ret = otx2_add_flow(pfvf, &nfc->fs);
			ret = otx2_add_flow(pfvf, nfc);
		break;
	case ETHTOOL_SRXCLSRLDEL:
		if (netif_running(dev) && ntuple)
@@ -641,42 +641,50 @@ static u32 otx2_get_rxfh_key_size(struct net_device *netdev)

static u32 otx2_get_rxfh_indir_size(struct net_device *dev)
{
	struct otx2_nic *pfvf = netdev_priv(dev);

	return pfvf->hw.rss_info.rss_size;
	return  MAX_RSS_INDIR_TBL_SIZE;
}

/* Get RSS configuration */
static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
			 u8 *hkey, u8 *hfunc)
static int otx2_rss_ctx_delete(struct otx2_nic *pfvf, int ctx_id)
{
	struct otx2_nic *pfvf = netdev_priv(dev);
	struct otx2_rss_info *rss;
	int idx;
	struct otx2_rss_info *rss = &pfvf->hw.rss_info;

	rss = &pfvf->hw.rss_info;
	otx2_rss_ctx_flow_del(pfvf, ctx_id);
	kfree(rss->rss_ctx[ctx_id]);
	rss->rss_ctx[ctx_id] = NULL;

	if (indir) {
		for (idx = 0; idx < rss->rss_size; idx++)
			indir[idx] = rss->ind_tbl[idx];
	return 0;
}

	if (hkey)
		memcpy(hkey, rss->key, sizeof(rss->key));
static int otx2_rss_ctx_create(struct otx2_nic *pfvf,
			       u32 *rss_context)
{
	struct otx2_rss_info *rss = &pfvf->hw.rss_info;
	u8 ctx;

	if (hfunc)
		*hfunc = ETH_RSS_HASH_TOP;
	for (ctx = 0; ctx < MAX_RSS_GROUPS; ctx++) {
		if (!rss->rss_ctx[ctx])
			break;
	}
	if (ctx == MAX_RSS_GROUPS)
		return -EINVAL;

	rss->rss_ctx[ctx] = kzalloc(sizeof(*rss->rss_ctx[ctx]), GFP_KERNEL);
	if (!rss->rss_ctx[ctx])
		return -ENOMEM;
	*rss_context = ctx;

	return 0;
}

/* Configure RSS table and hash key */
static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
			 const u8 *hkey, const u8 hfunc)
/* RSS context configuration */
static int otx2_set_rxfh_context(struct net_device *dev, const u32 *indir,
				 const u8 *hkey, const u8 hfunc,
				 u32 *rss_context, bool delete)
{
	struct otx2_nic *pfvf = netdev_priv(dev);
	struct otx2_rss_ctx *rss_ctx;
	struct otx2_rss_info *rss;
	int idx;
	int ret, idx;

	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
		return -EOPNOTSUPP;
@@ -688,18 +696,83 @@ static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
		return -EIO;
	}

	if (hkey) {
		memcpy(rss->key, hkey, sizeof(rss->key));
		otx2_set_rss_key(pfvf);
	}
	if (delete)
		return otx2_rss_ctx_delete(pfvf, *rss_context);

	if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
		ret = otx2_rss_ctx_create(pfvf, rss_context);
		if (ret)
			return ret;
	}
	if (indir) {
		rss_ctx = rss->rss_ctx[*rss_context];
		for (idx = 0; idx < rss->rss_size; idx++)
			rss->ind_tbl[idx] = indir[idx];
			rss_ctx->ind_tbl[idx] = indir[idx];
	}
	otx2_set_rss_table(pfvf, *rss_context);

	if (hkey) {
		memcpy(rss->key, hkey, sizeof(rss->key));
		otx2_set_rss_key(pfvf);
	return 0;
}

	otx2_set_rss_table(pfvf);
static int otx2_get_rxfh_context(struct net_device *dev, u32 *indir,
				 u8 *hkey, u8 *hfunc, u32 rss_context)
{
	struct otx2_nic *pfvf = netdev_priv(dev);
	struct otx2_rss_ctx *rss_ctx;
	struct otx2_rss_info *rss;
	int idx, rx_queues;

	rss = &pfvf->hw.rss_info;

	if (hfunc)
		*hfunc = ETH_RSS_HASH_TOP;

	if (!indir)
		return 0;

	if (!rss->enable && rss_context == DEFAULT_RSS_CONTEXT_GROUP) {
		rx_queues = pfvf->hw.rx_queues;
		for (idx = 0; idx < MAX_RSS_INDIR_TBL_SIZE; idx++)
			indir[idx] = ethtool_rxfh_indir_default(idx, rx_queues);
		return 0;
	}
	if (rss_context >= MAX_RSS_GROUPS)
		return -ENOENT;

	rss_ctx = rss->rss_ctx[rss_context];
	if (!rss_ctx)
		return -ENOENT;

	if (indir) {
		for (idx = 0; idx < rss->rss_size; idx++)
			indir[idx] = rss_ctx->ind_tbl[idx];
	}
	if (hkey)
		memcpy(hkey, rss->key, sizeof(rss->key));

	return 0;
}

/* Get RSS configuration */
static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
			 u8 *hkey, u8 *hfunc)
{
	return otx2_get_rxfh_context(dev, indir, hkey, hfunc,
				     DEFAULT_RSS_CONTEXT_GROUP);
}

/* Configure RSS table and hash key */
static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
			 const u8 *hkey, const u8 hfunc)
{

	u32 rss_context = DEFAULT_RSS_CONTEXT_GROUP;

	return otx2_set_rxfh_context(dev, indir, hkey, hfunc, &rss_context, 0);
}

static u32 otx2_get_msglevel(struct net_device *netdev)
@@ -771,6 +844,8 @@ static const struct ethtool_ops otx2_ethtool_ops = {
	.get_rxfh_indir_size	= otx2_get_rxfh_indir_size,
	.get_rxfh		= otx2_get_rxfh,
	.set_rxfh		= otx2_set_rxfh,
	.get_rxfh_context	= otx2_get_rxfh_context,
	.set_rxfh_context	= otx2_set_rxfh_context,
	.get_msglevel		= otx2_get_msglevel,
	.set_msglevel		= otx2_set_msglevel,
	.get_pauseparam		= otx2_get_pauseparam,
@@ -866,6 +941,8 @@ static const struct ethtool_ops otx2vf_ethtool_ops = {
	.get_rxfh_indir_size	= otx2_get_rxfh_indir_size,
	.get_rxfh		= otx2_get_rxfh,
	.set_rxfh		= otx2_set_rxfh,
	.get_rxfh_context	= otx2_get_rxfh_context,
	.set_rxfh_context	= otx2_set_rxfh_context,
	.get_ringparam		= otx2_get_ringparam,
	.set_ringparam		= otx2_set_ringparam,
	.get_coalesce		= otx2_get_coalesce,
+32 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ struct otx2_flow {
	u32 location;
	u16 entry;
	bool is_vf;
	u8 rss_ctx_id;
	int vf;
};

@@ -245,6 +246,7 @@ int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
	list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
		if (iter->location == location) {
			nfc->fs = iter->flow_spec;
			nfc->rss_context = iter->rss_ctx_id;
			return 0;
		}
	}
@@ -429,7 +431,7 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
	struct flow_msg *pkt = &req->packet;
	u32 flow_type;

	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
	switch (flow_type) {
	/* bits not set in mask are don't care */
	case ETHER_FLOW:
@@ -532,9 +534,13 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
		/* change to unicast only if action of default entry is not
		 * requested by user
		 */
		if (req->op != NIX_RX_ACTION_DEFAULT)
		if (flow->flow_spec.flow_type & FLOW_RSS) {
			req->op = NIX_RX_ACTIONOP_RSS;
			req->index = flow->rss_ctx_id;
		} else {
			req->op = NIX_RX_ACTIONOP_UCAST;
			req->index = ethtool_get_flow_spec_ring(ring_cookie);
		}
		vf = ethtool_get_flow_spec_ring_vf(ring_cookie);
		if (vf > pci_num_vf(pfvf->pdev)) {
			mutex_unlock(&pfvf->mbox.lock);
@@ -555,14 +561,16 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
	return err;
}

int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rx_flow_spec *fsp)
int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
{
	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
	u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
	struct ethtool_rx_flow_spec *fsp = &nfc->fs;
	struct otx2_flow *flow;
	bool new = false;
	u32 ring;
	int err;

	ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
	if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
		return -ENOMEM;

@@ -585,6 +593,9 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rx_flow_spec *fsp)
	/* struct copy */
	flow->flow_spec = *fsp;

	if (fsp->flow_type & FLOW_RSS)
		flow->rss_ctx_id = nfc->rss_context;

	err = otx2_add_flow_msg(pfvf, flow);
	if (err) {
		if (new)
@@ -647,6 +658,22 @@ int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
	return 0;
}

void otx2_rss_ctx_flow_del(struct otx2_nic *pfvf, int ctx_id)
{
	struct otx2_flow *flow, *tmp;
	int err;

	list_for_each_entry_safe(flow, tmp, &pfvf->flow_cfg->flow_list, list) {
		if (flow->rss_ctx_id != ctx_id)
			continue;
		err = otx2_remove_flow(pfvf, flow->location);
		if (err)
			netdev_warn(pfvf->netdev,
				    "Can't delete the rule %d associated with this rss group err:%d",
				    flow->location, err);
	}
}

int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
{
	struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;