Commit 4dca1319 authored by David S. Miller's avatar David S. Miller

Merge branch 'sarx5-VCAP-debugfs'

netdev.vger.kernel.org archive mirror
Steen Hegelund says:

====================
net: Add support for VCAP debugFS in Sparx5

This provides support for getting VCAP instance, VCAP rule and VCAP port
keyset configuration information via the debug file system.

It builds on top of the initial IS2 VCAP support found in these series:

https://lore.kernel.org/all/20221020130904.1215072-1-steen.hegelund@microchip.com/
https://lore.kernel.org/all/20221109114116.3612477-1-steen.hegelund@microchip.com/
https://lore.kernel.org/all/20221111130519.1459549-1-steen.hegelund@microchip.com/

Functionality:
==============

The VCAP API exposes a /sys/kernel/debug/sparx5/vcaps folder containing
the following entries:

- raw_<vcap>_<instance>
    This is a raw dump of the VCAP instance with a line for each available
    VCAP rule.  This information is limited to the VCAP rule address, the
    rule size and the rule keyset name as this requires very little
    information from the VCAP cache.

    This can be used to detect if a valid rule is stored at the correct
    address.

- <vcap>_<instance>
    This dumps the VCAP instance configuration: address ranges, chain id
    ranges, word size of keys and actions etc, and for each VCAP rule the
    details of keys (values and masks) and actions are shown.

    This is useful when discovering if the expected rule is present and in
    which order it will be matched.

- <interface>
    This shows the keyset configuration per lookup and traffic type and the
    set of sticky bits (common for all interfaces). This is cleared when
    shown, so it is possible to sample over a period of time.

    It also shows if this port/lookup is enabled for matching in the VCAP.

    This can be used to find out which keyset the traffic being sent to a
    port, will be matched against, and if such traffic has been seen by one
    of the ports.

Delivery:
=========

This is current plan for delivering the full VCAP feature set of Sparx5:

- TC protocol all support for IS2 VCAP
- Sparx5 IS0 VCAP support
- TC policer and drop action support (depends on the Sparx5 QoS support
  upstreamed separately)
- Sparx5 ES0 VCAP support
- TC flower template support
- TC matchall filter support for mirroring and policing ports
- TC flower filter mirror action support
- Sparx5 ES2 VCAP support

Version History:
================
v2      Removed a 'support' folder (used for integration testing) that had
        been added in patch 6/8 by a mistake.
        Wrapped long lines.

v1      Initial version
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 418e0721 552b7d13
......@@ -12,6 +12,7 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.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
sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o
# Provide include files
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
......@@ -763,6 +763,8 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
/* Default values, some from DT */
sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT;
sparx5->debugfs_root = debugfs_create_dir("sparx5", NULL);
ports = of_get_child_by_name(np, "ethernet-ports");
if (!ports) {
dev_err(sparx5->dev, "no ethernet-ports child node found\n");
......@@ -906,6 +908,7 @@ static int mchp_sparx5_remove(struct platform_device *pdev)
{
struct sparx5 *sparx5 = platform_get_drvdata(pdev);
debugfs_remove_recursive(sparx5->debugfs_root);
if (sparx5->xtr_irq) {
disable_irq(sparx5->xtr_irq);
sparx5->xtr_irq = -ENXIO;
......
......@@ -17,6 +17,7 @@
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/hrtimer.h>
#include <linux/debugfs.h>
#include "sparx5_main_regs.h"
......@@ -292,6 +293,8 @@ struct sparx5 {
struct vcap_control *vcap_ctrl;
/* PGID allocation map */
u8 pgid_map[PGID_TABLE_SIZE];
/* Common root for debugfs */
struct dentry *debugfs_root;
};
/* sparx5_switchdev.c */
......
......@@ -648,7 +648,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
return PTR_ERR(vrule);
vrule->cookie = fco->cookie;
sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
l3_proto = ETH_P_ALL;
err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
if (err)
goto out;
err = sparx5_tc_add_rule_counter(admin, vrule);
if (err)
......
// SPDX-License-Identifier: GPL-2.0+
/* Microchip Sparx5 Switch driver VCAP debugFS implementation
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/
#include <linux/types.h>
#include <linux/list.h>
#include "sparx5_vcap_debugfs.h"
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"
#include "sparx5_vcap_ag_api.h"
static void sparx5_vcap_port_keys(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct sparx5_port *port,
struct vcap_output_print *out)
{
int lookup;
u32 value;
out->prf(out->dst, " port[%02d] (%s): ", port->portno,
netdev_name(port->ndev));
for (lookup = 0; lookup < admin->lookups; ++lookup) {
out->prf(out->dst, "\n Lookup %d: ", lookup);
/* Get lookup state */
value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_CFG(port->portno));
out->prf(out->dst, "\n state: ");
if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
/* Get key selection state */
value = spx5_rd(sparx5,
ANA_ACL_VCAP_S2_KEY_SEL(port->portno, lookup));
out->prf(out->dst, "\n noneth: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_NONETH_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_NONETH_CUSTOM_1:
out->prf(out->dst, "custom1");
break;
case VCAP_IS2_PS_NONETH_CUSTOM_2:
out->prf(out->dst, "custom2");
break;
case VCAP_IS2_PS_NONETH_NO_LOOKUP:
out->prf(out->dst, "none");
break;
}
out->prf(out->dst, "\n ipv4_mc: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:
out->prf(out->dst, "ip4_tcp_udp ip4_other");
break;
case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
case VCAP_IS2_PS_IPV4_MC_IP4_VID:
out->prf(out->dst, "ip4_vid");
break;
}
out->prf(out->dst, "\n ipv4_uc: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:
out->prf(out->dst, "ip4_tcp_udp ip4_other");
break;
case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
}
out->prf(out->dst, "\n ipv6_mc: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
case VCAP_IS2_PS_IPV6_MC_IP6_VID:
out->prf(out->dst, "ip6_vid");
break;
case VCAP_IS2_PS_IPV6_MC_IP6_STD:
out->prf(out->dst, "ip6_std");
break;
case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
out->prf(out->dst, "ip4_tcp_udp ipv4_other");
break;
}
out->prf(out->dst, "\n ipv6_uc: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
case VCAP_IS2_PS_IPV6_UC_IP6_STD:
out->prf(out->dst, "ip6_std");
break;
case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:
out->prf(out->dst, "ip4_tcp_udp ip4_other");
break;
}
out->prf(out->dst, "\n arp: ");
switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_ARP_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_IS2_PS_ARP_ARP:
out->prf(out->dst, "arp");
break;
}
}
out->prf(out->dst, "\n");
}
static void sparx5_vcap_port_stickies(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
int lookup;
u32 value;
out->prf(out->dst, " Sticky bits: ");
for (lookup = 0; lookup < admin->lookups; ++lookup) {
out->prf(out->dst, "\n Lookup %d: ", lookup);
/* Get lookup sticky bits */
value = spx5_rd(sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_GET(value))
out->prf(out->dst, " sel_clm");
if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY_GET(value))
out->prf(out->dst, " sel_irleg");
if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY_GET(value))
out->prf(out->dst, " sel_erleg");
if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY_GET(value))
out->prf(out->dst, " sel_port");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY_GET(value))
out->prf(out->dst, " custom2");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY_GET(value))
out->prf(out->dst, " custom1");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY_GET(value))
out->prf(out->dst, " oam");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
out->prf(out->dst, " ip6_vid");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
out->prf(out->dst, " ip6_std");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY_GET(value))
out->prf(out->dst, " ip6_tcpudp");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
out->prf(out->dst, " ip_7tuple");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
out->prf(out->dst, " ip4_vid");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
out->prf(out->dst, " ip4_tcpudp");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
out->prf(out->dst, " ip4_other");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
out->prf(out->dst, " arp");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY_GET(value))
out->prf(out->dst, " mac_snap");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY_GET(value))
out->prf(out->dst, " mac_llc");
if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
out->prf(out->dst, " mac_etype");
/* Clear stickies */
spx5_wr(value, sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
}
out->prf(out->dst, "\n");
}
/* Provide port information via a callback interface */
int sparx5_port_info(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
const struct vcap_info *vcap;
struct vcap_control *vctrl;
vctrl = sparx5->vcap_ctrl;
vcap = &vctrl->vcaps[admin->vtype];
out->prf(out->dst, "%s:\n", vcap->name);
sparx5_vcap_port_keys(sparx5, admin, port, out);
sparx5_vcap_port_stickies(sparx5, admin, out);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Microchip Sparx5 Switch driver VCAP implementation
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/
#ifndef __SPARX5_VCAP_DEBUGFS_H__
#define __SPARX5_VCAP_DEBUGFS_H__
#include <linux/netdevice.h>
#include <vcap_api.h>
#include <vcap_api_client.h>
#if defined(CONFIG_DEBUG_FS)
/* Provide port information via a callback interface */
int sparx5_port_info(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out);
#else
static inline int sparx5_port_info(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
return 0;
}
#endif
#endif /* __SPARX5_VCAP_DEBUGFS_H__ */
......@@ -12,10 +12,12 @@
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "vcap_api_debugfs.h"
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"
#include "sparx5_vcap_ag_api.h"
#include "sparx5_vcap_debugfs.h"
#define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */
#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */
......@@ -30,54 +32,6 @@
ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \
ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp))
/* IS2 port keyset selection control */
/* IS2 non-ethernet traffic type keyset generation */
enum vcap_is2_port_sel_noneth {
VCAP_IS2_PS_NONETH_MAC_ETYPE,
VCAP_IS2_PS_NONETH_CUSTOM_1,
VCAP_IS2_PS_NONETH_CUSTOM_2,
VCAP_IS2_PS_NONETH_NO_LOOKUP
};
/* IS2 IPv4 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_uc {
VCAP_IS2_PS_IPV4_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_UC_IP_7TUPLE,
};
/* IS2 IPv4 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_mc {
VCAP_IS2_PS_IPV4_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV4_MC_IP4_VID,
};
/* IS2 IPv6 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_uc {
VCAP_IS2_PS_IPV6_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_UC_IP6_STD,
VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER,
};
/* IS2 IPv6 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_mc {
VCAP_IS2_PS_IPV6_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_MC_IP6_VID,
VCAP_IS2_PS_IPV6_MC_IP6_STD,
VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER,
};
/* IS2 ARP traffic type keyset generation */
enum vcap_is2_port_sel_arp {
VCAP_IS2_PS_ARP_MAC_ETYPE,
VCAP_IS2_PS_ARP_ARP,
};
static struct sparx5_vcap_inst {
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
......@@ -548,15 +502,6 @@ static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
sparx5_vcap_wait_super_update(sparx5);
}
/* Provide port information via a callback interface */
static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype,
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out, int arg)
{
/* this will be added later */
return 0;
}
/* Enable all lookups in the VCAP instance */
static int sparx5_vcap_enable(struct net_device *ndev,
struct vcap_admin *admin,
......@@ -634,6 +579,7 @@ static void sparx5_vcap_admin_free(struct vcap_admin *admin)
{
if (!admin)
return;
mutex_destroy(&admin->lock);
kfree(admin->cache.keystream);
kfree(admin->cache.maskstream);
kfree(admin->cache.actionstream);
......@@ -653,6 +599,7 @@ sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
INIT_LIST_HEAD(&admin->enabled);
mutex_init(&admin->lock);
admin->vtype = cfg->vtype;
admin->vinst = cfg->vinst;
admin->lookups = cfg->lookups;
......@@ -702,6 +649,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5)
const struct sparx5_vcap_inst *cfg;
struct vcap_control *ctrl;
struct vcap_admin *admin;
struct dentry *dir;
int err = 0, idx;
/* Create a VCAP control instance that owns the platform specific VCAP
......@@ -740,6 +688,11 @@ int sparx5_vcap_init(struct sparx5 *sparx5)
sparx5_vcap_port_key_selection(sparx5, admin);
list_add_tail(&admin->list, &ctrl->list);
}
dir = vcap_debugfs(sparx5->dev, sparx5->debugfs_root, ctrl);
for (idx = 0; idx < SPX5_PORTS; ++idx)
if (sparx5->ports[idx])
vcap_port_debugfs(sparx5->dev, dir, ctrl,
sparx5->ports[idx]->ndev);
return err;
}
......
......@@ -17,4 +17,52 @@
#define SPARX5_VCAP_CID_IS2_MAX \
(VCAP_CID_INGRESS_STAGE2_L3 + VCAP_CID_LOOKUP_SIZE - 1) /* IS2 Max */
/* IS2 port keyset selection control */
/* IS2 non-ethernet traffic type keyset generation */
enum vcap_is2_port_sel_noneth {
VCAP_IS2_PS_NONETH_MAC_ETYPE,
VCAP_IS2_PS_NONETH_CUSTOM_1,
VCAP_IS2_PS_NONETH_CUSTOM_2,
VCAP_IS2_PS_NONETH_NO_LOOKUP
};
/* IS2 IPv4 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_uc {
VCAP_IS2_PS_IPV4_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_UC_IP_7TUPLE,
};
/* IS2 IPv4 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv4_mc {
VCAP_IS2_PS_IPV4_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV4_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV4_MC_IP4_VID,
};
/* IS2 IPv6 unicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_uc {
VCAP_IS2_PS_IPV6_UC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_UC_IP6_STD,
VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER,
};
/* IS2 IPv6 multicast traffic type keyset generation */
enum vcap_is2_port_sel_ipv6_mc {
VCAP_IS2_PS_IPV6_MC_MAC_ETYPE,
VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_MC_IP6_VID,
VCAP_IS2_PS_IPV6_MC_IP6_STD,
VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER,
};
/* IS2 ARP traffic type keyset generation */
enum vcap_is2_port_sel_arp {
VCAP_IS2_PS_ARP_MAC_ETYPE,
VCAP_IS2_PS_ARP_ARP,
};
#endif /* __SPARX5_VCAP_IMPL_H__ */
......@@ -40,6 +40,7 @@ config VCAP_KUNIT_TEST
bool "KUnit test for VCAP library" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on KUNIT=y && VCAP=y && y
select DEBUG_FS
default KUNIT_ALL_TESTS
help
This builds unit tests for the VCAP library.
......
......@@ -5,5 +5,6 @@
obj-$(CONFIG_VCAP) += vcap.o
obj-$(CONFIG_VCAP_KUNIT_TEST) += vcap_model_kunit.o
vcap-$(CONFIG_DEBUG_FS) += vcap_api_debugfs.o
vcap-y += vcap_api.o
......@@ -6,28 +6,7 @@
#include <linux/types.h>
#include "vcap_api.h"
#include "vcap_api_client.h"
#define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data)
/* Private VCAP API rule data */
struct vcap_rule_internal {
struct vcap_rule data; /* provided by the client */
struct list_head list; /* for insertion in the vcap admin list of rules */
struct vcap_admin *admin; /* vcap hw instance */
struct net_device *ndev; /* the interface that the rule applies to */
struct vcap_control *vctrl; /* the client control */
u32 sort_key; /* defines the position in the VCAP */
int keyset_sw; /* subwords in a keyset */
int actionset_sw; /* subwords in an actionset */
int keyset_sw_regs; /* registers in a subword in an keyset */
int actionset_sw_regs; /* registers in a subword in an actionset */
int size; /* the size of the rule: max(entry, action) */
u32 addr; /* address in the VCAP at insertion */
u32 counter_id; /* counter id (if a dedicated counter is available) */
struct vcap_counter counter; /* last read counter value */
};
#include "vcap_api_private.h"
/* Moving a rule in the VCAP address space */
struct vcap_rule_move {
......@@ -36,16 +15,6 @@ struct vcap_rule_move {
int count; /* blocksize of addresses to move */
};
/* Bit iterator for the VCAP cache streams */
struct vcap_stream_iter {
u32 offset; /* bit offset from the stream start */
u32 sw_width; /* subword width in bits */
u32 regs_per_sw; /* registers per subword */
u32 reg_idx; /* current register index */
u32 reg_bitpos; /* bit offset in current register */
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 */
......@@ -53,8 +22,8 @@ struct vcap_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)
void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset)
{
memset(itr, 0, sizeof(*itr));
itr->offset = offset;
......@@ -74,7 +43,7 @@ static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
}
}
static void vcap_iter_update(struct vcap_stream_iter *itr)
void vcap_iter_update(struct vcap_stream_iter *itr)
{
int sw_idx, sw_bitpos;
......@@ -86,15 +55,15 @@ static void vcap_iter_update(struct vcap_stream_iter *itr)
itr->reg_bitpos = sw_bitpos % 32;
}
static void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset)
void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset)
{
vcap_iter_set(itr, sw_width, tg, offset);
vcap_iter_skip_tg(itr);
vcap_iter_update(itr);
}
static void vcap_iter_next(struct vcap_stream_iter *itr)
void vcap_iter_next(struct vcap_stream_iter *itr)
{
itr->offset++;
vcap_iter_skip_tg(itr);
......@@ -179,9 +148,9 @@ static void vcap_encode_typegroups(u32 *stream, int sw_width,
}
/* Return the list of keyfields for the keyset */
static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset)
const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset)
{
/* Check that the keyset exists in the vcap keyset list */
if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
......@@ -190,9 +159,9 @@ static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
}
/* Return the keyset information for the keyset */
static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset)
const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset)
{
const struct vcap_set *kset;
......@@ -206,7 +175,7 @@ static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
}
/* Return the typegroup table for the matching keyset (using subword size) */
static const struct vcap_typegroup *
const struct vcap_typegroup *
vcap_keyfield_typegroup(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset)
{
......@@ -219,8 +188,8 @@ vcap_keyfield_typegroup(struct vcap_control *vctrl,
}
/* Return the number of keyfields in the keyset */
static int vcap_keyfield_count(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset)
int vcap_keyfield_count(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset)
{
/* Check that the keyset exists in the vcap keyset list */
if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
......@@ -347,7 +316,7 @@ static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
}
/* Return the list of actionfields for the actionset */
static const struct vcap_field *
const struct vcap_field *
vcap_actionfields(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset)
{
......@@ -357,7 +326,7 @@ vcap_actionfields(struct vcap_control *vctrl,
return vctrl->vcaps[vt].actionfield_set_map[actionset];
}
static const struct vcap_set *
const struct vcap_set *
vcap_actionfieldset(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset)
{
......@@ -373,7 +342,7 @@ vcap_actionfieldset(struct vcap_control *vctrl,
}
/* Return the typegroup table for the matching actionset (using subword size) */
static const struct vcap_typegroup *
const struct vcap_typegroup *
vcap_actionfield_typegroup(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset)
{
......@@ -386,9 +355,9 @@ vcap_actionfield_typegroup(struct vcap_control *vctrl,
}
/* Return the number of actionfields in the actionset */
static int vcap_actionfield_count(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_actionfield_set actionset)
int vcap_actionfield_count(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_actionfield_set actionset)
{
/* Check that the actionset exists in the vcap actionset list */
if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
......@@ -515,7 +484,7 @@ static int vcap_encode_rule(struct vcap_rule_internal *ri)
return 0;
}
static int vcap_api_check(struct vcap_control *ctrl)
int vcap_api_check(struct vcap_control *ctrl)
{
if (!ctrl) {
pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
......@@ -533,7 +502,7 @@ static int vcap_api_check(struct vcap_control *ctrl)
return 0;
}
static void vcap_erase_cache(struct vcap_rule_internal *ri)
void vcap_erase_cache(struct vcap_rule_internal *ri)
{
ri->vctrl->ops->cache_erase(ri->admin);
}
......@@ -609,7 +578,7 @@ int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
/* Make a shallow copy of the rule without the fields */
static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
{
struct vcap_rule_internal *duprule;
......@@ -813,9 +782,16 @@ const char *vcap_keyfield_name(struct vcap_control *vctrl,
}
EXPORT_SYMBOL_GPL(vcap_keyfield_name);
/* map actionset id to a string with the actionset name */
const char *vcap_actionset_name(struct vcap_control *vctrl,
enum vcap_actionfield_set actionset)
{
return vctrl->stats->actionfield_set_names[actionset];
}
/* map action field id to a string with the action name */
static const char *vcap_actionfield_name(struct vcap_control *vctrl,
enum vcap_action_field action)
const char *vcap_actionfield_name(struct vcap_control *vctrl,
enum vcap_action_field action)
{
return vctrl->stats->actionfield_names[action];
}
......@@ -1078,6 +1054,7 @@ int vcap_add_rule(struct vcap_rule *rule)
if (ret)
return ret;
/* Insert the new rule in the list of vcap rules */
mutex_lock(&ri->admin->lock);
ret = vcap_insert_rule(ri, &move);
if (ret < 0) {
pr_err("%s:%d: could not insert rule in vcap list: %d\n",
......@@ -1096,6 +1073,7 @@ int vcap_add_rule(struct vcap_rule *rule)
if (ret)
pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
out:
mutex_unlock(&ri->admin->lock);
return ret;
}
EXPORT_SYMBOL_GPL(vcap_add_rule);
......@@ -1245,13 +1223,15 @@ int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
gap = vcap_fill_rule_gap(ri);
/* Delete the rule from the list of rules and the cache */
mutex_lock(&admin->lock);
list_del(&ri->list);
vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
kfree(ri);
mutex_unlock(&admin->lock);
/* Update the last used address */
/* Update the last used address, set to default when no rules */
if (list_empty(&admin->rules)) {
admin->last_used_addr = admin->last_valid_addr;
admin->last_used_addr = admin->last_valid_addr + 1;
} else {
elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
list);
......@@ -1270,6 +1250,8 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
if (ret)
return ret;
mutex_lock(&admin->lock);
list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
list_del(&ri->list);
......@@ -1282,6 +1264,7 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
list_del(&eport->list);
kfree(eport);
}
mutex_unlock(&admin->lock);
return 0;
}
......@@ -1711,10 +1694,13 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
if (chain_id) {
if (vcap_is_enabled(admin, ndev, cookie))
return -EADDRINUSE;
mutex_lock(&admin->lock);
vcap_enable(admin, ndev, cookie);
} else {
mutex_lock(&admin->lock);
vcap_disable(admin, ndev, cookie);
}
mutex_unlock(&admin->lock);
return 0;
}
......
......@@ -167,6 +167,7 @@ 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 */
struct mutex lock; /* control access to rules */
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
int first_cid; /* first chain id in this vcap */
......@@ -203,6 +204,13 @@ struct vcap_keyset_list {
enum vcap_keyfield_set *keysets; /* the list of keysets */
};
/* Client output printf-like function with destination */
struct vcap_output_print {
__printf(2, 3)
void (*prf)(void *out, const char *fmt, ...);
void *dst;
};
/* Client supplied VCAP callback operations */
struct vcap_operations {
/* validate port keyset operation */
......@@ -252,10 +260,8 @@ struct vcap_operations {
/* informational */
int (*port_info)
(struct net_device *ndev,
enum vcap_type vtype,
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out,
int arg);
struct vcap_admin *admin,
struct vcap_output_print *out);
/* enable/disable the lookups in a vcap instance */
int (*enable)
(struct net_device *ndev,
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API_DEBUGFS__
#define __VCAP_API_DEBUGFS__
#include <linux/types.h>
#include <linux/debugfs.h>
#include <linux/netdevice.h>
#include "vcap_api.h"
#if defined(CONFIG_DEBUG_FS)
void vcap_port_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl,
struct net_device *ndev);
/* Create a debugFS entry for a vcap instance */
struct dentry *vcap_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl);
#else
static inline void vcap_port_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl,
struct net_device *ndev)
{
}
static inline struct dentry *vcap_debugfs(struct device *dev,
struct dentry *parent,
struct vcap_control *vctrl)
{
return NULL;
}
#endif
#endif /* __VCAP_API_DEBUGFS__ */
This diff is collapsed.
......@@ -204,9 +204,9 @@ static void test_cache_move(struct net_device *ndev, struct vcap_admin *admin,
}
/* Provide port information via a callback interface */
static int vcap_test_port_info(struct net_device *ndev, enum vcap_type vtype,
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out, int arg)
static int vcap_test_port_info(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
return 0;
}
......@@ -1691,7 +1691,7 @@ static void vcap_api_rule_remove_at_end_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 0, test_move_count);
KUNIT_EXPECT_EQ(test, 780, test_init_start);
KUNIT_EXPECT_EQ(test, 12, test_init_count);
KUNIT_EXPECT_EQ(test, 3071, admin.last_used_addr);
KUNIT_EXPECT_EQ(test, 3072, admin.last_used_addr);
}
static void vcap_api_rule_remove_in_middle_test(struct kunit *test)
......@@ -1766,7 +1766,7 @@ static void vcap_api_rule_remove_in_middle_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 0, test_move_count);
KUNIT_EXPECT_EQ(test, 798, test_init_start);
KUNIT_EXPECT_EQ(test, 2, test_init_count);
KUNIT_EXPECT_EQ(test, 799, admin.last_used_addr);
KUNIT_EXPECT_EQ(test, 800, admin.last_used_addr);
}
static void vcap_api_rule_remove_in_front_test(struct kunit *test)
......@@ -1805,7 +1805,7 @@ static void vcap_api_rule_remove_in_front_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 0, test_move_count);
KUNIT_EXPECT_EQ(test, 780, test_init_start);
KUNIT_EXPECT_EQ(test, 12, test_init_count);
KUNIT_EXPECT_EQ(test, 799, admin.last_used_addr);
KUNIT_EXPECT_EQ(test, 800, admin.last_used_addr);
test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 20, 400, 6, 792);
test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 30, 300, 3, 789);
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API_PRIVATE__
#define __VCAP_API_PRIVATE__
#include <linux/types.h>
#include "vcap_api.h"
#include "vcap_api_client.h"
#define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data)
/* Private VCAP API rule data */
struct vcap_rule_internal {
struct vcap_rule data; /* provided by the client */
struct list_head list; /* the vcap admin list of rules */
struct vcap_admin *admin; /* vcap hw instance */
struct net_device *ndev; /* the interface that the rule applies to */
struct vcap_control *vctrl; /* the client control */
u32 sort_key; /* defines the position in the VCAP */
int keyset_sw; /* subwords in a keyset */
int actionset_sw; /* subwords in an actionset */
int keyset_sw_regs; /* registers in a subword in an keyset */
int actionset_sw_regs; /* registers in a subword in an actionset */
int size; /* the size of the rule: max(entry, action) */
u32 addr; /* address in the VCAP at insertion */
u32 counter_id; /* counter id (if a dedicated counter is available) */
struct vcap_counter counter; /* last read counter value */
};
/* Bit iterator for the VCAP cache streams */
struct vcap_stream_iter {
u32 offset; /* bit offset from the stream start */
u32 sw_width; /* subword width in bits */
u32 regs_per_sw; /* registers per subword */
u32 reg_idx; /* current register index */
u32 reg_bitpos; /* bit offset in current register */
const struct vcap_typegroup *tg; /* current typegroup */
};
/* Check that the control has a valid set of callbacks */
int vcap_api_check(struct vcap_control *ctrl);
/* Make a shallow copy of the rule without the fields */
struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri);
/* Erase the VCAP cache area used or encoding and decoding */
void vcap_erase_cache(struct vcap_rule_internal *ri);
/* Iterator functionality */
void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset);
void vcap_iter_next(struct vcap_stream_iter *itr);
void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset);
void vcap_iter_update(struct vcap_stream_iter *itr);
/* Keyset and keyfield functionality */
/* Return the keyset information for the keyset */
const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset);
/* Return the number of keyfields in the keyset */
int vcap_keyfield_count(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset);
/* Return the typegroup table for the matching keyset (using subword size) */
const struct vcap_typegroup *
vcap_keyfield_typegroup(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset);
/* Return the list of keyfields for the keyset */
const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset);
/* Actionset and actionfield functionality */
/* Return the actionset information for the actionset */
const struct vcap_set *
vcap_actionfieldset(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset);
/* Return the number of actionfields in the actionset */
int vcap_actionfield_count(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_actionfield_set actionset);
/* Return the typegroup table for the matching actionset (using subword size) */
const struct vcap_typegroup *
vcap_actionfield_typegroup(struct vcap_control *vctrl, enum vcap_type vt,
enum vcap_actionfield_set actionset);
/* Return the list of actionfields for the actionset */
const struct vcap_field *
vcap_actionfields(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset);
/* Map actionset id to a string with the actionset name */
const char *vcap_actionset_name(struct vcap_control *vctrl,
enum vcap_actionfield_set actionset);
/* Map key field id to a string with the key name */
const char *vcap_actionfield_name(struct vcap_control *vctrl,
enum vcap_action_field action);
#endif /* __VCAP_API_PRIVATE__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment