Commit 8c8e6406 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: abm: add simple RED offload



Offload simple RED configurations.  For now support only DCTCP
like scenarios where min and max are the same.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 25e0036f
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
#include <linux/netdevice.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>

#include "../nfpcore/nfp.h"
#include "../nfpcore/nfp_cpp.h"
@@ -55,6 +57,84 @@ static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id)
	       FIELD_PREP(NFP_ABM_PORTID_ID, id);
}

static void
nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink,
		    u32 handle)
{
	struct nfp_port *port = nfp_port_from_netdev(netdev);

	if (handle != alink->qdiscs[0].handle)
		return;

	alink->qdiscs[0].handle = TC_H_UNSPEC;
	port->tc_offload_cnt = 0;
	nfp_abm_ctrl_set_all_q_lvls(alink, ~0);
}

static int
nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
		    struct tc_red_qopt_offload *opt)
{
	struct nfp_port *port = nfp_port_from_netdev(netdev);
	int err;

	if (opt->set.min != opt->set.max || !opt->set.is_ecn) {
		nfp_warn(alink->abm->app->cpp,
			 "RED offload failed - unsupported parameters\n");
		err = -EINVAL;
		goto err_destroy;
	}
	err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min);
	if (err)
		goto err_destroy;

	alink->qdiscs[0].handle = opt->handle;
	port->tc_offload_cnt = 1;

	return 0;
err_destroy:
	if (alink->qdiscs[0].handle != TC_H_UNSPEC)
		nfp_abm_red_destroy(netdev, alink, alink->qdiscs[0].handle);
	return err;
}

static int
nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink,
		     struct tc_red_qopt_offload *opt)
{
	if (opt->parent != TC_H_ROOT)
		return -EOPNOTSUPP;

	switch (opt->command) {
	case TC_RED_REPLACE:
		return nfp_abm_red_replace(netdev, alink, opt);
	case TC_RED_DESTROY:
		nfp_abm_red_destroy(netdev, alink, opt->handle);
		return 0;
	default:
		return -EOPNOTSUPP;
	}
}

static int
nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev,
		 enum tc_setup_type type, void *type_data)
{
	struct nfp_repr *repr = netdev_priv(netdev);
	struct nfp_port *port;

	port = nfp_port_from_netdev(netdev);
	if (!port || port->type != NFP_PORT_PF_PORT)
		return -EOPNOTSUPP;

	switch (type) {
	case TC_SETUP_QDISC_RED:
		return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data);
	default:
		return -EOPNOTSUPP;
	}
}

static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id)
{
	enum nfp_repr_type rtype;
@@ -403,6 +483,8 @@ const struct nfp_app_type app_abm = {
	.vnic_alloc	= nfp_abm_vnic_alloc,
	.vnic_free	= nfp_abm_vnic_free,

	.setup_tc	= nfp_abm_setup_tc,

	.eswitch_mode_get	= nfp_abm_eswitch_mode_get,
	.eswitch_mode_set	= nfp_abm_eswitch_mode_set,

+10 −0
Original line number Diff line number Diff line
@@ -58,18 +58,28 @@ struct nfp_abm {
	const struct nfp_rtsym *q_lvls;
};

/**
 * struct nfp_red_qdisc - representation of single RED Qdisc
 * @handle:	handle of currently offloaded RED Qdisc
 */
struct nfp_red_qdisc {
	u32 handle;
};

/**
 * struct nfp_abm_link - port tuple of a ABM NIC
 * @abm:	back pointer to nfp_abm
 * @vnic:	data vNIC
 * @id:		id of the data vNIC
 * @queue_base:	id of base to host queue within PCIe (not QC idx)
 * @qdiscs:	array of qdiscs
 */
struct nfp_abm_link {
	struct nfp_abm *abm;
	struct nfp_net *vnic;
	unsigned int id;
	unsigned int queue_base;
	struct nfp_red_qdisc qdiscs[1];
};

void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink);