cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

prestera_devlink.c (16790B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
      3
      4#include <net/devlink.h>
      5
      6#include "prestera_devlink.h"
      7#include "prestera_hw.h"
      8
      9/* All driver-specific traps must be documented in
     10 * Documentation/networking/devlink/prestera.rst
     11 */
     12enum {
     13	DEVLINK_PRESTERA_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
     14	DEVLINK_PRESTERA_TRAP_ID_ARP_BC,
     15	DEVLINK_PRESTERA_TRAP_ID_IS_IS,
     16	DEVLINK_PRESTERA_TRAP_ID_OSPF,
     17	DEVLINK_PRESTERA_TRAP_ID_IP_BC_MAC,
     18	DEVLINK_PRESTERA_TRAP_ID_ROUTER_MC,
     19	DEVLINK_PRESTERA_TRAP_ID_VRRP,
     20	DEVLINK_PRESTERA_TRAP_ID_DHCP,
     21	DEVLINK_PRESTERA_TRAP_ID_MAC_TO_ME,
     22	DEVLINK_PRESTERA_TRAP_ID_IPV4_OPTIONS,
     23	DEVLINK_PRESTERA_TRAP_ID_IP_DEFAULT_ROUTE,
     24	DEVLINK_PRESTERA_TRAP_ID_IP_TO_ME,
     25	DEVLINK_PRESTERA_TRAP_ID_IPV4_ICMP_REDIRECT,
     26	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_0,
     27	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_1,
     28	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_2,
     29	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_3,
     30	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_4,
     31	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_5,
     32	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_6,
     33	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_7,
     34	DEVLINK_PRESTERA_TRAP_ID_BGP,
     35	DEVLINK_PRESTERA_TRAP_ID_SSH,
     36	DEVLINK_PRESTERA_TRAP_ID_TELNET,
     37	DEVLINK_PRESTERA_TRAP_ID_ICMP,
     38	DEVLINK_PRESTERA_TRAP_ID_MET_RED,
     39	DEVLINK_PRESTERA_TRAP_ID_IP_SIP_IS_ZERO,
     40	DEVLINK_PRESTERA_TRAP_ID_IP_UC_DIP_DA_MISMATCH,
     41	DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IPV4_HDR,
     42	DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IP_ADDR,
     43	DEVLINK_PRESTERA_TRAP_ID_INVALID_SA,
     44	DEVLINK_PRESTERA_TRAP_ID_LOCAL_PORT,
     45	DEVLINK_PRESTERA_TRAP_ID_PORT_NO_VLAN,
     46	DEVLINK_PRESTERA_TRAP_ID_RXDMA_DROP,
     47};
     48
     49#define DEVLINK_PRESTERA_TRAP_NAME_ARP_BC \
     50	"arp_bc"
     51#define DEVLINK_PRESTERA_TRAP_NAME_IS_IS \
     52	"is_is"
     53#define DEVLINK_PRESTERA_TRAP_NAME_OSPF \
     54	"ospf"
     55#define DEVLINK_PRESTERA_TRAP_NAME_IP_BC_MAC \
     56	"ip_bc_mac"
     57#define DEVLINK_PRESTERA_TRAP_NAME_ROUTER_MC \
     58	"router_mc"
     59#define DEVLINK_PRESTERA_TRAP_NAME_VRRP \
     60	"vrrp"
     61#define DEVLINK_PRESTERA_TRAP_NAME_DHCP \
     62	"dhcp"
     63#define DEVLINK_PRESTERA_TRAP_NAME_MAC_TO_ME \
     64	"mac_to_me"
     65#define DEVLINK_PRESTERA_TRAP_NAME_IPV4_OPTIONS \
     66	"ipv4_options"
     67#define DEVLINK_PRESTERA_TRAP_NAME_IP_DEFAULT_ROUTE \
     68	"ip_default_route"
     69#define DEVLINK_PRESTERA_TRAP_NAME_IP_TO_ME \
     70	"ip_to_me"
     71#define DEVLINK_PRESTERA_TRAP_NAME_IPV4_ICMP_REDIRECT \
     72	"ipv4_icmp_redirect"
     73#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_0 \
     74	"acl_code_0"
     75#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_1 \
     76	"acl_code_1"
     77#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_2 \
     78	"acl_code_2"
     79#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_3 \
     80	"acl_code_3"
     81#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_4 \
     82	"acl_code_4"
     83#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_5 \
     84	"acl_code_5"
     85#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_6 \
     86	"acl_code_6"
     87#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_7 \
     88	"acl_code_7"
     89#define DEVLINK_PRESTERA_TRAP_NAME_BGP \
     90	"bgp"
     91#define DEVLINK_PRESTERA_TRAP_NAME_SSH \
     92	"ssh"
     93#define DEVLINK_PRESTERA_TRAP_NAME_TELNET \
     94	"telnet"
     95#define DEVLINK_PRESTERA_TRAP_NAME_ICMP \
     96	"icmp"
     97#define DEVLINK_PRESTERA_TRAP_NAME_RXDMA_DROP \
     98	"rxdma_drop"
     99#define DEVLINK_PRESTERA_TRAP_NAME_PORT_NO_VLAN \
    100	"port_no_vlan"
    101#define DEVLINK_PRESTERA_TRAP_NAME_LOCAL_PORT \
    102	"local_port"
    103#define DEVLINK_PRESTERA_TRAP_NAME_INVALID_SA \
    104	"invalid_sa"
    105#define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IP_ADDR \
    106	"illegal_ip_addr"
    107#define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IPV4_HDR \
    108	"illegal_ipv4_hdr"
    109#define DEVLINK_PRESTERA_TRAP_NAME_IP_UC_DIP_DA_MISMATCH \
    110	"ip_uc_dip_da_mismatch"
    111#define DEVLINK_PRESTERA_TRAP_NAME_IP_SIP_IS_ZERO \
    112	"ip_sip_is_zero"
    113#define DEVLINK_PRESTERA_TRAP_NAME_MET_RED \
    114	"met_red"
    115
    116struct prestera_trap {
    117	struct devlink_trap trap;
    118	u8 cpu_code;
    119};
    120
    121struct prestera_trap_item {
    122	enum devlink_trap_action action;
    123	void *trap_ctx;
    124};
    125
    126struct prestera_trap_data {
    127	struct prestera_switch *sw;
    128	struct prestera_trap_item *trap_items_arr;
    129	u32 traps_count;
    130};
    131
    132#define PRESTERA_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
    133
    134#define PRESTERA_TRAP_CONTROL(_id, _group_id, _action)			      \
    135	DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,			      \
    136			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
    137			     PRESTERA_TRAP_METADATA)
    138
    139#define PRESTERA_TRAP_DRIVER_CONTROL(_id, _group_id)			      \
    140	DEVLINK_TRAP_DRIVER(CONTROL, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id,    \
    141			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
    142			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
    143			    PRESTERA_TRAP_METADATA)
    144
    145#define PRESTERA_TRAP_EXCEPTION(_id, _group_id)				      \
    146	DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,			      \
    147			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
    148			     PRESTERA_TRAP_METADATA)
    149
    150#define PRESTERA_TRAP_DRIVER_EXCEPTION(_id, _group_id)			      \
    151	DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id,  \
    152			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
    153			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
    154			    PRESTERA_TRAP_METADATA)
    155
    156#define PRESTERA_TRAP_DRIVER_DROP(_id, _group_id)			      \
    157	DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_PRESTERA_TRAP_ID_##_id,	      \
    158			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
    159			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
    160			    PRESTERA_TRAP_METADATA)
    161
    162static const struct devlink_trap_group prestera_trap_groups_arr[] = {
    163	/* No policer is associated with following groups (policerid == 0)*/
    164	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
    165	DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 0),
    166	DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 0),
    167	DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 0),
    168	DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 0),
    169	DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 0),
    170	DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
    171	DEVLINK_TRAP_GROUP_GENERIC(OSPF, 0),
    172	DEVLINK_TRAP_GROUP_GENERIC(STP, 0),
    173	DEVLINK_TRAP_GROUP_GENERIC(LACP, 0),
    174	DEVLINK_TRAP_GROUP_GENERIC(LLDP, 0),
    175	DEVLINK_TRAP_GROUP_GENERIC(VRRP, 0),
    176	DEVLINK_TRAP_GROUP_GENERIC(DHCP, 0),
    177	DEVLINK_TRAP_GROUP_GENERIC(BGP, 0),
    178	DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 0),
    179	DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 0),
    180};
    181
    182/* Initialize trap list, as well as associate CPU code with them. */
    183static struct prestera_trap prestera_trap_items_arr[] = {
    184	{
    185		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ARP_BC, NEIGH_DISCOVERY),
    186		.cpu_code = 5,
    187	},
    188	{
    189		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IS_IS, LOCAL_DELIVERY),
    190		.cpu_code = 13,
    191	},
    192	{
    193		.trap = PRESTERA_TRAP_DRIVER_CONTROL(OSPF, OSPF),
    194		.cpu_code = 16,
    195	},
    196	{
    197		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_BC_MAC, LOCAL_DELIVERY),
    198		.cpu_code = 19,
    199	},
    200	{
    201		.trap = PRESTERA_TRAP_CONTROL(STP, STP, TRAP),
    202		.cpu_code = 26,
    203	},
    204	{
    205		.trap = PRESTERA_TRAP_CONTROL(LACP, LACP, TRAP),
    206		.cpu_code = 27,
    207	},
    208	{
    209		.trap = PRESTERA_TRAP_CONTROL(LLDP, LLDP, TRAP),
    210		.cpu_code = 28,
    211	},
    212	{
    213		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ROUTER_MC, LOCAL_DELIVERY),
    214		.cpu_code = 29,
    215	},
    216	{
    217		.trap = PRESTERA_TRAP_DRIVER_CONTROL(VRRP, VRRP),
    218		.cpu_code = 30,
    219	},
    220	{
    221		.trap = PRESTERA_TRAP_DRIVER_CONTROL(DHCP, DHCP),
    222		.cpu_code = 33,
    223	},
    224	{
    225		.trap = PRESTERA_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
    226		.cpu_code = 63,
    227	},
    228	{
    229		.trap = PRESTERA_TRAP_DRIVER_CONTROL(MAC_TO_ME, LOCAL_DELIVERY),
    230		.cpu_code = 65,
    231	},
    232	{
    233		.trap = PRESTERA_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
    234		.cpu_code = 133,
    235	},
    236	{
    237		.trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_OPTIONS,
    238						       L3_EXCEPTIONS),
    239		.cpu_code = 141,
    240	},
    241	{
    242		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_DEFAULT_ROUTE,
    243						     LOCAL_DELIVERY),
    244		.cpu_code = 160,
    245	},
    246	{
    247		.trap = PRESTERA_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
    248					      TRAP),
    249		.cpu_code = 161,
    250	},
    251	{
    252		.trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_ICMP_REDIRECT,
    253						       L3_EXCEPTIONS),
    254		.cpu_code = 180,
    255	},
    256	{
    257		.trap = PRESTERA_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
    258					      TRAP),
    259		.cpu_code = 188,
    260	},
    261	{
    262		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_0, ACL_TRAP),
    263		.cpu_code = 192,
    264	},
    265	{
    266		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_1, ACL_TRAP),
    267		.cpu_code = 193,
    268	},
    269	{
    270		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_2, ACL_TRAP),
    271		.cpu_code = 194,
    272	},
    273	{
    274		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_3, ACL_TRAP),
    275		.cpu_code = 195,
    276	},
    277	{
    278		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_4, ACL_TRAP),
    279		.cpu_code = 196,
    280	},
    281	{
    282		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_5, ACL_TRAP),
    283		.cpu_code = 197,
    284	},
    285	{
    286		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_6, ACL_TRAP),
    287		.cpu_code = 198,
    288	},
    289	{
    290		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_7, ACL_TRAP),
    291		.cpu_code = 199,
    292	},
    293	{
    294		.trap = PRESTERA_TRAP_DRIVER_CONTROL(BGP, BGP),
    295		.cpu_code = 206,
    296	},
    297	{
    298		.trap = PRESTERA_TRAP_DRIVER_CONTROL(SSH, LOCAL_DELIVERY),
    299		.cpu_code = 207,
    300	},
    301	{
    302		.trap = PRESTERA_TRAP_DRIVER_CONTROL(TELNET, LOCAL_DELIVERY),
    303		.cpu_code = 208,
    304	},
    305	{
    306		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ICMP, LOCAL_DELIVERY),
    307		.cpu_code = 209,
    308	},
    309	{
    310		.trap = PRESTERA_TRAP_DRIVER_DROP(RXDMA_DROP, BUFFER_DROPS),
    311		.cpu_code = 37,
    312	},
    313	{
    314		.trap = PRESTERA_TRAP_DRIVER_DROP(PORT_NO_VLAN, L2_DROPS),
    315		.cpu_code = 39,
    316	},
    317	{
    318		.trap = PRESTERA_TRAP_DRIVER_DROP(LOCAL_PORT, L2_DROPS),
    319		.cpu_code = 56,
    320	},
    321	{
    322		.trap = PRESTERA_TRAP_DRIVER_DROP(INVALID_SA, L2_DROPS),
    323		.cpu_code = 60,
    324	},
    325	{
    326		.trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IP_ADDR, L3_DROPS),
    327		.cpu_code = 136,
    328	},
    329	{
    330		.trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IPV4_HDR, L3_DROPS),
    331		.cpu_code = 137,
    332	},
    333	{
    334		.trap = PRESTERA_TRAP_DRIVER_DROP(IP_UC_DIP_DA_MISMATCH,
    335						  L3_DROPS),
    336		.cpu_code = 138,
    337	},
    338	{
    339		.trap = PRESTERA_TRAP_DRIVER_DROP(IP_SIP_IS_ZERO, L3_DROPS),
    340		.cpu_code = 145,
    341	},
    342	{
    343		.trap = PRESTERA_TRAP_DRIVER_DROP(MET_RED, BUFFER_DROPS),
    344		.cpu_code = 185,
    345	},
    346};
    347
    348static int prestera_drop_counter_get(struct devlink *devlink,
    349				     const struct devlink_trap *trap,
    350				     u64 *p_drops);
    351
    352static int prestera_dl_info_get(struct devlink *dl,
    353				struct devlink_info_req *req,
    354				struct netlink_ext_ack *extack)
    355{
    356	struct prestera_switch *sw = devlink_priv(dl);
    357	char buf[16];
    358	int err;
    359
    360	err = devlink_info_driver_name_put(req, PRESTERA_DRV_NAME);
    361	if (err)
    362		return err;
    363
    364	snprintf(buf, sizeof(buf), "%d.%d.%d",
    365		 sw->dev->fw_rev.maj,
    366		 sw->dev->fw_rev.min,
    367		 sw->dev->fw_rev.sub);
    368
    369	return devlink_info_version_running_put(req,
    370					       DEVLINK_INFO_VERSION_GENERIC_FW,
    371					       buf);
    372}
    373
    374static int prestera_trap_init(struct devlink *devlink,
    375			      const struct devlink_trap *trap, void *trap_ctx);
    376
    377static int prestera_trap_action_set(struct devlink *devlink,
    378				    const struct devlink_trap *trap,
    379				    enum devlink_trap_action action,
    380				    struct netlink_ext_ack *extack);
    381
    382static const struct devlink_ops prestera_dl_ops = {
    383	.info_get = prestera_dl_info_get,
    384	.trap_init = prestera_trap_init,
    385	.trap_action_set = prestera_trap_action_set,
    386	.trap_drop_counter_get = prestera_drop_counter_get,
    387};
    388
    389struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev)
    390{
    391	struct devlink *dl;
    392
    393	dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch),
    394			   dev->dev);
    395
    396	return devlink_priv(dl);
    397}
    398
    399void prestera_devlink_free(struct prestera_switch *sw)
    400{
    401	struct devlink *dl = priv_to_devlink(sw);
    402
    403	devlink_free(dl);
    404}
    405
    406void prestera_devlink_register(struct prestera_switch *sw)
    407{
    408	struct devlink *dl = priv_to_devlink(sw);
    409
    410	devlink_register(dl);
    411}
    412
    413void prestera_devlink_unregister(struct prestera_switch *sw)
    414{
    415	struct devlink *dl = priv_to_devlink(sw);
    416
    417	devlink_unregister(dl);
    418}
    419
    420int prestera_devlink_port_register(struct prestera_port *port)
    421{
    422	struct prestera_switch *sw = port->sw;
    423	struct devlink *dl = priv_to_devlink(sw);
    424	struct devlink_port_attrs attrs = {};
    425	int err;
    426
    427	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
    428	attrs.phys.port_number = port->fp_id;
    429	attrs.switch_id.id_len = sizeof(sw->id);
    430	memcpy(attrs.switch_id.id, &sw->id, attrs.switch_id.id_len);
    431
    432	devlink_port_attrs_set(&port->dl_port, &attrs);
    433
    434	err = devlink_port_register(dl, &port->dl_port, port->fp_id);
    435	if (err) {
    436		dev_err(prestera_dev(sw), "devlink_port_register failed: %d\n", err);
    437		return err;
    438	}
    439
    440	return 0;
    441}
    442
    443void prestera_devlink_port_unregister(struct prestera_port *port)
    444{
    445	devlink_port_unregister(&port->dl_port);
    446}
    447
    448void prestera_devlink_port_set(struct prestera_port *port)
    449{
    450	devlink_port_type_eth_set(&port->dl_port, port->dev);
    451}
    452
    453void prestera_devlink_port_clear(struct prestera_port *port)
    454{
    455	devlink_port_type_clear(&port->dl_port);
    456}
    457
    458struct devlink_port *prestera_devlink_get_port(struct net_device *dev)
    459{
    460	struct prestera_port *port = netdev_priv(dev);
    461
    462	return &port->dl_port;
    463}
    464
    465int prestera_devlink_traps_register(struct prestera_switch *sw)
    466{
    467	const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr);
    468	const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr);
    469	struct devlink *devlink = priv_to_devlink(sw);
    470	struct prestera_trap_data *trap_data;
    471	struct prestera_trap *prestera_trap;
    472	int err, i;
    473
    474	trap_data = kzalloc(sizeof(*trap_data), GFP_KERNEL);
    475	if (!trap_data)
    476		return -ENOMEM;
    477
    478	trap_data->trap_items_arr = kcalloc(traps_count,
    479					    sizeof(struct prestera_trap_item),
    480					    GFP_KERNEL);
    481	if (!trap_data->trap_items_arr) {
    482		err = -ENOMEM;
    483		goto err_trap_items_alloc;
    484	}
    485
    486	trap_data->sw = sw;
    487	trap_data->traps_count = traps_count;
    488	sw->trap_data = trap_data;
    489
    490	err = devlink_trap_groups_register(devlink, prestera_trap_groups_arr,
    491					   groups_count);
    492	if (err)
    493		goto err_groups_register;
    494
    495	for (i = 0; i < traps_count; i++) {
    496		prestera_trap = &prestera_trap_items_arr[i];
    497		err = devlink_traps_register(devlink, &prestera_trap->trap, 1,
    498					     sw);
    499		if (err)
    500			goto err_trap_register;
    501	}
    502
    503	return 0;
    504
    505err_trap_register:
    506	for (i--; i >= 0; i--) {
    507		prestera_trap = &prestera_trap_items_arr[i];
    508		devlink_traps_unregister(devlink, &prestera_trap->trap, 1);
    509	}
    510	devlink_trap_groups_unregister(devlink, prestera_trap_groups_arr,
    511				       groups_count);
    512err_groups_register:
    513	kfree(trap_data->trap_items_arr);
    514err_trap_items_alloc:
    515	kfree(trap_data);
    516	return err;
    517}
    518
    519static struct prestera_trap_item *
    520prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code)
    521{
    522	struct prestera_trap_data *trap_data = sw->trap_data;
    523	struct prestera_trap *prestera_trap;
    524	int i;
    525
    526	for (i = 0; i < trap_data->traps_count; i++) {
    527		prestera_trap = &prestera_trap_items_arr[i];
    528		if (cpu_code == prestera_trap->cpu_code)
    529			return &trap_data->trap_items_arr[i];
    530	}
    531
    532	return NULL;
    533}
    534
    535void prestera_devlink_trap_report(struct prestera_port *port,
    536				  struct sk_buff *skb, u8 cpu_code)
    537{
    538	struct prestera_trap_item *trap_item;
    539	struct devlink *devlink;
    540
    541	devlink = port->dl_port.devlink;
    542
    543	trap_item = prestera_get_trap_item_by_cpu_code(port->sw, cpu_code);
    544	if (unlikely(!trap_item))
    545		return;
    546
    547	devlink_trap_report(devlink, skb, trap_item->trap_ctx,
    548			    &port->dl_port, NULL);
    549}
    550
    551static struct prestera_trap_item *
    552prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id)
    553{
    554	struct prestera_trap_data *trap_data = sw->trap_data;
    555	int i;
    556
    557	for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) {
    558		if (prestera_trap_items_arr[i].trap.id == trap_id)
    559			return &trap_data->trap_items_arr[i];
    560	}
    561
    562	return NULL;
    563}
    564
    565static int prestera_trap_init(struct devlink *devlink,
    566			      const struct devlink_trap *trap, void *trap_ctx)
    567{
    568	struct prestera_switch *sw = devlink_priv(devlink);
    569	struct prestera_trap_item *trap_item;
    570
    571	trap_item = prestera_devlink_trap_item_lookup(sw, trap->id);
    572	if (WARN_ON(!trap_item))
    573		return -EINVAL;
    574
    575	trap_item->trap_ctx = trap_ctx;
    576	trap_item->action = trap->init_action;
    577
    578	return 0;
    579}
    580
    581static int prestera_trap_action_set(struct devlink *devlink,
    582				    const struct devlink_trap *trap,
    583				    enum devlink_trap_action action,
    584				    struct netlink_ext_ack *extack)
    585{
    586	/* Currently, driver does not support trap action altering */
    587	return -EOPNOTSUPP;
    588}
    589
    590static int prestera_drop_counter_get(struct devlink *devlink,
    591				     const struct devlink_trap *trap,
    592				     u64 *p_drops)
    593{
    594	struct prestera_switch *sw = devlink_priv(devlink);
    595	enum prestera_hw_cpu_code_cnt_t cpu_code_type =
    596		PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP;
    597	struct prestera_trap *prestera_trap =
    598		container_of(trap, struct prestera_trap, trap);
    599
    600	return prestera_hw_cpu_code_counters_get(sw, prestera_trap->cpu_code,
    601						 cpu_code_type, p_drops);
    602}
    603
    604void prestera_devlink_traps_unregister(struct prestera_switch *sw)
    605{
    606	struct prestera_trap_data *trap_data = sw->trap_data;
    607	struct devlink *dl = priv_to_devlink(sw);
    608	const struct devlink_trap *trap;
    609	int i;
    610
    611	for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) {
    612		trap = &prestera_trap_items_arr[i].trap;
    613		devlink_traps_unregister(dl, trap, 1);
    614	}
    615
    616	devlink_trap_groups_unregister(dl, prestera_trap_groups_arr,
    617				       ARRAY_SIZE(prestera_trap_groups_arr));
    618	kfree(trap_data->trap_items_arr);
    619	kfree(trap_data);
    620}