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

Commit 4bfbe53f authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cxgb4-add-hash-filter-support-to-tc-flower-offload'



Rahul Lakkireddy says:

====================
cxgb4: add hash-filter support to tc-flower offload

This series of patches add support to create hash-filters; a.k.a
exact-match filters, to tc-flower offload.  T6 supports creating
~500K hash-filters in hw and can theoretically be expanded up to
~1 million.

Patch 1 fetches and saves the configured hw filter tuple field shifts
and filter mask.

Patch 2 initializes the driver to use hash-filter configuration.

Patch 3 adds support to create hash filters in hw.

Patch 4 adds support to delete hash filters in hw.

Patch 5 adds support to retrieve filter stats for hash filters.

Patch 6 converts the flower table to use rhashtable instead of
static hlist.

Patch 7 finally adds support to create hash filters via tc-flower
offload.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1f2c897c 3eb8b62d
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -287,10 +287,18 @@ struct tp_params {
	 * places we store their offsets here, or a -1 if the field isn't
	 * present.
	 */
	int vlan_shift;
	int vnic_shift;
	int fcoe_shift;
	int port_shift;
	int vnic_shift;
	int vlan_shift;
	int tos_shift;
	int protocol_shift;
	int ethertype_shift;
	int macmatch_shift;
	int matchtype_shift;
	int frag_shift;

	u64 hash_filter_mask;
};

struct vpd_params {
@@ -358,6 +366,7 @@ struct adapter_params {
	unsigned char crypto;		/* HW capability for crypto */

	unsigned char bypass;
	unsigned char hash_filter;

	unsigned int ofldq_wr_cred;
	bool ulptx_memwrite_dsgl;          /* use of T5 DSGL allowed */
@@ -909,8 +918,10 @@ struct adapter {
	struct chcr_stats_debug chcr_stats;

	/* TC flower offload */
	DECLARE_HASHTABLE(flower_anymatch_tbl, 9);
	struct rhashtable flower_tbl;
	struct rhashtable_params flower_ht_params;
	struct timer_list flower_stats_timer;
	struct work_struct flower_stats_work;

	/* Ethtool Dump */
	struct ethtool_dump eth_dump;
@@ -1041,6 +1052,7 @@ struct ch_filter_specification {
	 * matching that doesn't exist as a (value, mask) tuple.
	 */
	uint32_t type:1;        /* 0 => IPv4, 1 => IPv6 */
	u32 hash:1;		/* 0 => wild-card, 1 => exact-match */

	/* Packet dispatch information.  Ingress packets which match the
	 * filter rules will be dropped, passed to the host or switched back
@@ -1098,7 +1110,14 @@ enum {
};

enum {
	NAT_MODE_ALL = 7,	/* NAT on entire 4-tuple */
	NAT_MODE_NONE = 0,	/* No NAT performed */
	NAT_MODE_DIP,		/* NAT on Dst IP */
	NAT_MODE_DIP_DP,	/* NAT on Dst IP, Dst Port */
	NAT_MODE_DIP_DP_SIP,	/* NAT on Dst IP, Dst Port and Src IP */
	NAT_MODE_DIP_DP_SP,	/* NAT on Dst IP, Dst Port and Src Port */
	NAT_MODE_SIP_SP,	/* NAT on Src IP and Src Port */
	NAT_MODE_DIP_SIP_SP,	/* NAT on Dst IP, Src IP and Src Port */
	NAT_MODE_ALL		/* NAT on entire 4-tuple */
};

/* Host shadow copy of ingress filter entry.  This is in host native format
@@ -1132,6 +1151,11 @@ static inline int is_offload(const struct adapter *adap)
	return adap->params.offload;
}

static inline int is_hashfilter(const struct adapter *adap)
{
	return adap->params.hash_filter;
}

static inline int is_pci_uld(const struct adapter *adap)
{
	return adap->params.crypto;
+868 −60

File changed.

Preview size limit exceeded, changes collapsed.

+8 −0
Original line number Diff line number Diff line
@@ -37,7 +37,12 @@

#include "t4_msg.h"

#define WORD_MASK	0xffffffff

void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl);
void hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl);
void hash_del_filter_rpl(struct adapter *adap,
			 const struct cpl_abort_rpl_rss *rpl);
void clear_filter(struct adapter *adap, struct filter_entry *f);

int set_filter_wr(struct adapter *adapter, int fidx);
@@ -45,4 +50,7 @@ int delete_filter(struct adapter *adapter, unsigned int fidx);

int writable_filter(struct filter_entry *f);
void clear_all_filters(struct adapter *adapter);
int init_hash_filter(struct adapter *adap);
bool is_filter_exact_match(struct adapter *adap,
			   struct ch_filter_specification *fs);
#endif /* __CXGB4_FILTER_H */
+21 −5
Original line number Diff line number Diff line
@@ -572,6 +572,14 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
		const struct cpl_set_tcb_rpl *p = (void *)rsp;

		filter_rpl(q->adap, p);
	} else if (opcode == CPL_ACT_OPEN_RPL) {
		const struct cpl_act_open_rpl *p = (void *)rsp;

		hash_filter_rpl(q->adap, p);
	} else if (opcode == CPL_ABORT_RPL_RSS) {
		const struct cpl_abort_rpl_rss *p = (void *)rsp;

		hash_del_filter_rpl(q->adap, p);
	} else
		dev_err(q->adap->pdev_dev,
			"unexpected CPL %#x on FW event queue\n", opcode);
@@ -3963,7 +3971,8 @@ static int adap_init0(struct adapter *adap)
	if (ret < 0)
		goto bye;

	if (caps_cmd.ofldcaps) {
	if (caps_cmd.ofldcaps ||
	    (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER))) {
		/* query offload-related parameters */
		params[0] = FW_PARAM_DEV(NTID);
		params[1] = FW_PARAM_PFVF(SERVER_START);
@@ -4000,9 +4009,14 @@ static int adap_init0(struct adapter *adap)
		adap->vres.ddp.size = val[4] - val[3] + 1;
		adap->params.ofldq_wr_cred = val[5];

		if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) {
			if (init_hash_filter(adap) < 0)
				goto bye;
		} else {
			adap->params.offload = 1;
			adap->num_ofld_uld += 1;
		}
	}
	if (caps_cmd.rdmacaps) {
		params[0] = FW_PARAM_PFVF(STAG_START);
		params[1] = FW_PARAM_PFVF(STAG_END);
@@ -5168,10 +5182,12 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
			dev_warn(&pdev->dev,
				 "could not offload tc u32, continuing\n");

		cxgb4_init_tc_flower(adapter);
		if (cxgb4_init_tc_flower(adapter))
			dev_warn(&pdev->dev,
				 "could not offload tc flower, continuing\n");
	}

	if (is_offload(adapter)) {
	if (is_offload(adapter) || is_hashfilter(adapter)) {
		if (t4_read_reg(adapter, LE_DB_CONFIG_A) & HASHEN_F) {
			u32 hash_base, hash_reg;

+88 −38
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <net/tc_act/tc_vlan.h>

#include "cxgb4.h"
#include "cxgb4_filter.h"
#include "cxgb4_tc_flower.h"

#define STATS_CHECK_PERIOD (HZ / 2)
@@ -74,13 +75,8 @@ static struct ch_tc_flower_entry *allocate_flower_entry(void)
static struct ch_tc_flower_entry *ch_flower_lookup(struct adapter *adap,
						   unsigned long flower_cookie)
{
	struct ch_tc_flower_entry *flower_entry;

	hash_for_each_possible_rcu(adap->flower_anymatch_tbl, flower_entry,
				   link, flower_cookie)
		if (flower_entry->tc_flower_cookie == flower_cookie)
			return flower_entry;
	return NULL;
	return rhashtable_lookup_fast(&adap->flower_tbl, &flower_cookie,
				      adap->flower_ht_params);
}

static void cxgb4_process_flow_match(struct net_device *dev,
@@ -677,12 +673,17 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
	cxgb4_process_flow_match(dev, cls, fs);
	cxgb4_process_flow_actions(dev, cls, fs);

	fs->hash = is_filter_exact_match(adap, fs);
	if (fs->hash) {
		fidx = 0;
	} else {
		fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
		if (fidx < 0) {
			netdev_err(dev, "%s: No fidx for offload.\n", __func__);
			ret = -ENOMEM;
			goto free_entry;
		}
	}

	init_completion(&ctx.completion);
	ret = __cxgb4_set_filter(dev, fidx, fs, &ctx);
@@ -707,12 +708,17 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
		goto free_entry;
	}

	INIT_HLIST_NODE(&ch_flower->link);
	ch_flower->tc_flower_cookie = cls->cookie;
	ch_flower->filter_id = ctx.tid;
	hash_add_rcu(adap->flower_anymatch_tbl, &ch_flower->link, cls->cookie);
	ret = rhashtable_insert_fast(&adap->flower_tbl, &ch_flower->node,
				     adap->flower_ht_params);
	if (ret)
		goto del_filter;

	return ret;
	return 0;

del_filter:
	cxgb4_del_filter(dev, ch_flower->filter_id, &ch_flower->fs);

free_entry:
	kfree(ch_flower);
@@ -730,32 +736,45 @@ int cxgb4_tc_flower_destroy(struct net_device *dev,
	if (!ch_flower)
		return -ENOENT;

	ret = cxgb4_del_filter(dev, ch_flower->filter_id);
	ret = cxgb4_del_filter(dev, ch_flower->filter_id, &ch_flower->fs);
	if (ret)
		goto err;

	hash_del_rcu(&ch_flower->link);
	ret = rhashtable_remove_fast(&adap->flower_tbl, &ch_flower->node,
				     adap->flower_ht_params);
	if (ret) {
		netdev_err(dev, "Flow remove from rhashtable failed");
		goto err;
	}
	kfree_rcu(ch_flower, rcu);

err:
	return ret;
}

static void ch_flower_stats_cb(struct timer_list *t)
static void ch_flower_stats_handler(struct work_struct *work)
{
	struct adapter *adap = from_timer(adap, t, flower_stats_timer);
	struct adapter *adap = container_of(work, struct adapter,
					    flower_stats_work);
	struct ch_tc_flower_entry *flower_entry;
	struct ch_tc_flower_stats *ofld_stats;
	unsigned int i;
	struct rhashtable_iter iter;
	u64 packets;
	u64 bytes;
	int ret;

	rcu_read_lock();
	hash_for_each_rcu(adap->flower_anymatch_tbl, i, flower_entry, link) {
	rhashtable_walk_enter(&adap->flower_tbl, &iter);
	do {
		flower_entry = ERR_PTR(rhashtable_walk_start(&iter));
		if (IS_ERR(flower_entry))
			goto walk_stop;

		while ((flower_entry = rhashtable_walk_next(&iter)) &&
		       !IS_ERR(flower_entry)) {
			ret = cxgb4_get_filter_counters(adap->port[0],
							flower_entry->filter_id,
						&packets, &bytes);
							&packets, &bytes,
							flower_entry->fs.hash);
			if (!ret) {
				spin_lock(&flower_entry->lock);
				ofld_stats = &flower_entry->stats;
@@ -767,10 +786,20 @@ static void ch_flower_stats_cb(struct timer_list *t)
				spin_unlock(&flower_entry->lock);
			}
		}
	rcu_read_unlock();
walk_stop:
		rhashtable_walk_stop(&iter);
	} while (flower_entry == ERR_PTR(-EAGAIN));
	rhashtable_walk_exit(&iter);
	mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
}

static void ch_flower_stats_cb(struct timer_list *t)
{
	struct adapter *adap = from_timer(adap, t, flower_stats_timer);

	schedule_work(&adap->flower_stats_work);
}

int cxgb4_tc_flower_stats(struct net_device *dev,
			  struct tc_cls_flower_offload *cls)
{
@@ -788,7 +817,8 @@ int cxgb4_tc_flower_stats(struct net_device *dev,
	}

	ret = cxgb4_get_filter_counters(dev, ch_flower->filter_id,
					&packets, &bytes);
					&packets, &bytes,
					ch_flower->fs.hash);
	if (ret < 0)
		goto err;

@@ -812,15 +842,35 @@ int cxgb4_tc_flower_stats(struct net_device *dev,
	return ret;
}

void cxgb4_init_tc_flower(struct adapter *adap)
static const struct rhashtable_params cxgb4_tc_flower_ht_params = {
	.nelem_hint = 384,
	.head_offset = offsetof(struct ch_tc_flower_entry, node),
	.key_offset = offsetof(struct ch_tc_flower_entry, tc_flower_cookie),
	.key_len = sizeof(((struct ch_tc_flower_entry *)0)->tc_flower_cookie),
	.max_size = 524288,
	.min_size = 512,
	.automatic_shrinking = true
};

int cxgb4_init_tc_flower(struct adapter *adap)
{
	hash_init(adap->flower_anymatch_tbl);
	int ret;

	adap->flower_ht_params = cxgb4_tc_flower_ht_params;
	ret = rhashtable_init(&adap->flower_tbl, &adap->flower_ht_params);
	if (ret)
		return ret;

	INIT_WORK(&adap->flower_stats_work, ch_flower_stats_handler);
	timer_setup(&adap->flower_stats_timer, ch_flower_stats_cb, 0);
	mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
	return 0;
}

void cxgb4_cleanup_tc_flower(struct adapter *adap)
{
	if (adap->flower_stats_timer.function)
		del_timer_sync(&adap->flower_stats_timer);
	cancel_work_sync(&adap->flower_stats_work);
	rhashtable_destroy(&adap->flower_tbl);
}
Loading