Skip to content

Commit

Permalink
net: microchip: sparx5: Add tc matchall filter and enable VCAP lookups
Browse files Browse the repository at this point in the history
Use a tc matchall rule with a goto action to the VCAP specific chain to
enable the VCAP lookups.
If the matchall rule is removed the VCAP lookups will be disabled
again using its cookie as lookup to find the VCAP instance.

To enable the Sparx5 IS2 VCAP on eth0 you would use this command:

    tc filter add dev eth0 ingress prio 5 handle 5 matchall \
        skip_sw action goto chain 8000000

as the first lookup in IS2 has chain id 8000000

Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steen Hegelund authored and David S. Miller committed Nov 11, 2022
1 parent 242df4f commit 6745671
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 9 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/microchip/sparx5/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \
sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \
sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o sparx5_tc_matchall.o

sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o

Expand Down
9 changes: 7 additions & 2 deletions drivers/net/ethernet/microchip/sparx5/sparx5_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ static int sparx5_tc_block_cb(enum tc_setup_type type,
{
struct net_device *ndev = cb_priv;

if (type == TC_SETUP_CLSFLOWER)
switch (type) {
case TC_SETUP_CLSMATCHALL:
return sparx5_tc_matchall(ndev, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return sparx5_tc_flower(ndev, type_data, ingress);
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
}

static int sparx5_tc_block_cb_ingress(enum tc_setup_type type,
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/microchip/sparx5/sparx5_tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define __SPARX5_TC_H__

#include <net/flow_offload.h>
#include <net/pkt_cls.h>
#include <linux/netdevice.h>

/* Controls how PORT_MASK is applied */
Expand All @@ -23,6 +24,10 @@ enum SPX5_PORT_MASK_MODE {
int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);

int sparx5_tc_matchall(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress);

int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress);

Expand Down
97 changes: 97 additions & 0 deletions drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0+
/* Microchip VCAP API
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/

#include "sparx5_tc.h"
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"

static int sparx5_tc_matchall_replace(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct flow_action_entry *action;
struct sparx5 *sparx5;
int err;

if (!flow_offload_has_one_action(&tmo->rule->action)) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Only one action per filter is supported");
return -EOPNOTSUPP;
}
action = &tmo->rule->action.entries[0];

sparx5 = port->sparx5;
switch (action->id) {
case FLOW_ACTION_GOTO:
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
action->chain_index, tmo->cookie,
true);
if (err == -EFAULT) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Unsupported goto chain");
return -EOPNOTSUPP;
}
if (err == -EADDRINUSE) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"VCAP already enabled");
return -EOPNOTSUPP;
}
if (err) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Could not enable VCAP lookups");
return err;
}
break;
default:
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
return -EOPNOTSUPP;
}
return 0;
}

static int sparx5_tc_matchall_destroy(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5;
int err;

sparx5 = port->sparx5;
if (!tmo->rule && tmo->cookie) {
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0,
tmo->cookie, false);
if (err)
return err;
return 0;
}
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
return -EOPNOTSUPP;
}

int sparx5_tc_matchall(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
if (!tc_cls_can_offload_and_chain0(ndev, &tmo->common)) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Only chain zero is supported");
return -EOPNOTSUPP;
}

switch (tmo->command) {
case TC_CLSMATCHALL_REPLACE:
return sparx5_tc_matchall_replace(ndev, tmo, ingress);
case TC_CLSMATCHALL_DESTROY:
return sparx5_tc_matchall_destroy(ndev, tmo, ingress);
default:
return -EOPNOTSUPP;
}
}
29 changes: 24 additions & 5 deletions drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,28 @@ static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype,
return 0;
}

/* Enable all lookups in the VCAP instance */
static int sparx5_vcap_enable(struct net_device *ndev,
struct vcap_admin *admin,
bool enable)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5;
int portno;

sparx5 = port->sparx5;
portno = port->portno;

/* For now we only consider IS2 */
if (enable)
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
else
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
return 0;
}

/* API callback operations: only IS2 is supported for now */
static struct vcap_operations sparx5_vcap_ops = {
.validate_keyset = sparx5_vcap_validate_keyset,
Expand All @@ -500,6 +522,7 @@ static struct vcap_operations sparx5_vcap_ops = {
.update = sparx5_vcap_update,
.move = sparx5_vcap_move,
.port_info = sparx5_port_info,
.enable = sparx5_vcap_enable,
};

/* Enable lookups per port and set the keyset generation: only IS2 for now */
Expand All @@ -509,11 +532,6 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
int portno, lookup;
u32 keysel;

/* enable all 4 lookups on all ports */
for (portno = 0; portno < SPX5_PORTS; ++portno)
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));

/* all traffic types generate the MAC_ETYPE keyset for now in all
* lookups on all ports
*/
Expand Down Expand Up @@ -566,6 +584,7 @@ sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
INIT_LIST_HEAD(&admin->enabled);
admin->vtype = cfg->vtype;
admin->vinst = cfg->vinst;
admin->lookups = cfg->lookups;
Expand Down
120 changes: 119 additions & 1 deletion drivers/net/ethernet/microchip/vcap/vcap_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ struct vcap_stream_iter {
const struct vcap_typegroup *tg; /* current typegroup */
};

/* Stores the filter cookie that enabled the port */
struct vcap_enabled_port {
struct list_head list; /* for insertion in enabled ports list */
struct net_device *ndev; /* the enabled port */
unsigned long cookie; /* filter that enabled the port */
};

static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset)
{
Expand Down Expand Up @@ -516,7 +523,7 @@ static int vcap_api_check(struct vcap_control *ctrl)
!ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
!ctrl->ops->cache_write || !ctrl->ops->cache_read ||
!ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
!ctrl->ops->port_info) {
!ctrl->ops->port_info || !ctrl->ops->enable) {
pr_err("%s:%d: client operations are missing\n",
__func__, __LINE__);
return -ENOENT;
Expand Down Expand Up @@ -1128,6 +1135,7 @@ EXPORT_SYMBOL_GPL(vcap_del_rule);
/* Delete all rules in the VCAP instance */
int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
{
struct vcap_enabled_port *eport, *next_eport;
struct vcap_rule_internal *ri, *next_ri;
int ret = vcap_api_check(vctrl);

Expand All @@ -1139,6 +1147,13 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
kfree(ri);
}
admin->last_used_addr = admin->last_valid_addr;

/* Remove list of enabled ports */
list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
list_del(&eport->list);
kfree(eport);
}

return 0;
}
EXPORT_SYMBOL_GPL(vcap_del_rules);
Expand Down Expand Up @@ -1459,6 +1474,109 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
}
EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);

/* Check if this port is already enabled for this VCAP instance */
static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
unsigned long cookie)
{
struct vcap_enabled_port *eport;

list_for_each_entry(eport, &admin->enabled, list)
if (eport->cookie == cookie || eport->ndev == ndev)
return true;

return false;
}

/* Enable this port for this VCAP instance */
static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
unsigned long cookie)
{
struct vcap_enabled_port *eport;

eport = kzalloc(sizeof(*eport), GFP_KERNEL);
if (!eport)
return -ENOMEM;

eport->ndev = ndev;
eport->cookie = cookie;
list_add_tail(&eport->list, &admin->enabled);

return 0;
}

/* Disable this port for this VCAP instance */
static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
unsigned long cookie)
{
struct vcap_enabled_port *eport;

list_for_each_entry(eport, &admin->enabled, list) {
if (eport->cookie == cookie && eport->ndev == ndev) {
list_del(&eport->list);
kfree(eport);
return 0;
}
}

return -ENOENT;
}

/* Find the VCAP instance that enabled the port using a specific filter */
static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
unsigned long cookie)
{
struct vcap_enabled_port *eport;
struct vcap_admin *admin;

list_for_each_entry(admin, &vctrl->list, list)
list_for_each_entry(eport, &admin->enabled, list)
if (eport->cookie == cookie)
return admin;

return NULL;
}

/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int chain_id, unsigned long cookie, bool enable)
{
struct vcap_admin *admin;
int err;

err = vcap_api_check(vctrl);
if (err)
return err;

if (!ndev)
return -ENODEV;

if (chain_id)
admin = vcap_find_admin(vctrl, chain_id);
else
admin = vcap_find_admin_by_cookie(vctrl, cookie);
if (!admin)
return -ENOENT;

/* first instance and first chain */
if (admin->vinst || chain_id > admin->first_cid)
return -EFAULT;

err = vctrl->ops->enable(ndev, admin, enable);
if (err)
return err;

if (chain_id) {
if (vcap_is_enabled(admin, ndev, cookie))
return -EADDRINUSE;
vcap_enable(admin, ndev, cookie);
} else {
vcap_disable(admin, ndev, cookie);
}

return 0;
}
EXPORT_SYMBOL_GPL(vcap_enable_lookups);

#ifdef CONFIG_VCAP_KUNIT_TEST
#include "vcap_api_kunit.c"
#endif
6 changes: 6 additions & 0 deletions drivers/net/ethernet/microchip/vcap/vcap_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ enum vcap_rule_error {
struct vcap_admin {
struct list_head list; /* for insertion in vcap_control */
struct list_head rules; /* list of rules */
struct list_head enabled; /* list of enabled ports */
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
int first_cid; /* first chain id in this vcap */
Expand Down Expand Up @@ -255,6 +256,11 @@ struct vcap_operations {
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out,
int arg);
/* enable/disable the lookups in a vcap instance */
int (*enable)
(struct net_device *ndev,
struct vcap_admin *admin,
bool enable);
};

/* VCAP API Client control interface */
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/microchip/vcap/vcap_api_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ enum vcap_bit {
VCAP_BIT_1
};

/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int chain_id, unsigned long cookie, bool enable);

/* VCAP rule operations */
/* Allocate a rule and fill in the basic information */
struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
Expand Down

0 comments on commit 6745671

Please sign in to comment.