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

sparx5_vlan.c (6202B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/* Microchip Sparx5 Switch driver
      3 *
      4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
      5 */
      6
      7#include "sparx5_main_regs.h"
      8#include "sparx5_main.h"
      9
     10static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)
     11{
     12	u32 mask[3];
     13
     14	/* Divide up mask in 32 bit words */
     15	bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);
     16
     17	/* Output mask to respective registers */
     18	spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid));
     19	spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid));
     20	spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid));
     21
     22	return 0;
     23}
     24
     25void sparx5_vlan_init(struct sparx5 *sparx5)
     26{
     27	u16 vid;
     28
     29	spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),
     30		 ANA_L3_VLAN_CTRL_VLAN_ENA,
     31		 sparx5,
     32		 ANA_L3_VLAN_CTRL);
     33
     34	/* Map VLAN = FID */
     35	for (vid = NULL_VID; vid < VLAN_N_VID; vid++)
     36		spx5_rmw(ANA_L3_VLAN_CFG_VLAN_FID_SET(vid),
     37			 ANA_L3_VLAN_CFG_VLAN_FID,
     38			 sparx5,
     39			 ANA_L3_VLAN_CFG(vid));
     40}
     41
     42void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)
     43{
     44	struct sparx5_port *port = sparx5->ports[portno];
     45
     46	/* Configure PVID */
     47	spx5_rmw(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(0) |
     48		 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid),
     49		 ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA |
     50		 ANA_CL_VLAN_CTRL_PORT_VID,
     51		 sparx5,
     52		 ANA_CL_VLAN_CTRL(port->portno));
     53}
     54
     55int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
     56			bool untagged)
     57{
     58	struct sparx5 *sparx5 = port->sparx5;
     59	int ret;
     60
     61	/* Untagged egress vlan classification */
     62	if (untagged && port->vid != vid) {
     63		if (port->vid) {
     64			netdev_err(port->ndev,
     65				   "Port already has a native VLAN: %d\n",
     66				   port->vid);
     67			return -EBUSY;
     68		}
     69		port->vid = vid;
     70	}
     71
     72	/* Make the port a member of the VLAN */
     73	set_bit(port->portno, sparx5->vlan_mask[vid]);
     74	ret = sparx5_vlant_set_mask(sparx5, vid);
     75	if (ret)
     76		return ret;
     77
     78	/* Default ingress vlan classification */
     79	if (pvid)
     80		port->pvid = vid;
     81
     82	sparx5_vlan_port_apply(sparx5, port);
     83
     84	return 0;
     85}
     86
     87int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
     88{
     89	struct sparx5 *sparx5 = port->sparx5;
     90	int ret;
     91
     92	/* 8021q removes VID 0 on module unload for all interfaces
     93	 * with VLAN filtering feature. We need to keep it to receive
     94	 * untagged traffic.
     95	 */
     96	if (vid == 0)
     97		return 0;
     98
     99	/* Stop the port from being a member of the vlan */
    100	clear_bit(port->portno, sparx5->vlan_mask[vid]);
    101	ret = sparx5_vlant_set_mask(sparx5, vid);
    102	if (ret)
    103		return ret;
    104
    105	/* Ingress */
    106	if (port->pvid == vid)
    107		port->pvid = 0;
    108
    109	/* Egress */
    110	if (port->vid == vid)
    111		port->vid = 0;
    112
    113	sparx5_vlan_port_apply(sparx5, port);
    114
    115	return 0;
    116}
    117
    118void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
    119{
    120	struct sparx5 *sparx5 = port->sparx5;
    121	u32 val, mask;
    122
    123	/* mask is spread across 3 registers x 32 bit */
    124	if (port->portno < 32) {
    125		mask = BIT(port->portno);
    126		val = enable ? mask : 0;
    127		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));
    128	} else if (port->portno < 64) {
    129		mask = BIT(port->portno - 32);
    130		val = enable ? mask : 0;
    131		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));
    132	} else if (port->portno < SPX5_PORTS) {
    133		mask = BIT(port->portno - 64);
    134		val = enable ? mask : 0;
    135		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));
    136	} else {
    137		netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
    138	}
    139}
    140
    141void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])
    142{
    143	portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));
    144	portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid));
    145	portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid));
    146}
    147
    148void sparx5_update_fwd(struct sparx5 *sparx5)
    149{
    150	DECLARE_BITMAP(workmask, SPX5_PORTS);
    151	u32 mask[3];
    152	int port;
    153
    154	/* Divide up fwd mask in 32 bit words */
    155	bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
    156
    157	/* Update flood masks */
    158	for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {
    159		spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
    160		spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
    161		spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
    162	}
    163
    164	/* Update SRC masks */
    165	for (port = 0; port < SPX5_PORTS; port++) {
    166		if (test_bit(port, sparx5->bridge_fwd_mask)) {
    167			/* Allow to send to all bridged but self */
    168			bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);
    169			clear_bit(port, workmask);
    170			bitmap_to_arr32(mask, workmask, SPX5_PORTS);
    171			spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));
    172			spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));
    173			spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));
    174		} else {
    175			spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));
    176			spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));
    177			spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));
    178		}
    179	}
    180
    181	/* Learning enabled only for bridged ports */
    182	bitmap_and(workmask, sparx5->bridge_fwd_mask,
    183		   sparx5->bridge_lrn_mask, SPX5_PORTS);
    184	bitmap_to_arr32(mask, workmask, SPX5_PORTS);
    185
    186	/* Apply learning mask */
    187	spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);
    188	spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);
    189	spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);
    190}
    191
    192void sparx5_vlan_port_apply(struct sparx5 *sparx5,
    193			    struct sparx5_port *port)
    194
    195{
    196	u32 val;
    197
    198	/* Configure PVID, vlan aware */
    199	val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |
    200		ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |
    201		ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);
    202	spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));
    203
    204	val = 0;
    205	if (port->vlan_aware && !port->pvid)
    206		/* If port is vlan-aware and tagged, drop untagged and
    207		 * priority tagged frames.
    208		 */
    209		val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |
    210			ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |
    211			ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);
    212	spx5_wr(val, sparx5,
    213		ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
    214
    215	/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
    216	val = REW_TAG_CTRL_TAG_TPID_CFG_SET(0);
    217	if (port->vlan_aware) {
    218		if (port->vid)
    219			/* Tag all frames except when VID == DEFAULT_VLAN */
    220			val |= REW_TAG_CTRL_TAG_CFG_SET(1);
    221		else
    222			val |= REW_TAG_CTRL_TAG_CFG_SET(3);
    223	}
    224	spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));
    225
    226	/* Egress VID */
    227	spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
    228		 REW_PORT_VLAN_CFG_PORT_VID,
    229		 sparx5,
    230		 REW_PORT_VLAN_CFG(port->portno));
    231}