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

lan966x_vlan.c (9029B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3#include "lan966x_main.h"
      4
      5#define VLANACCESS_CMD_IDLE		0
      6#define VLANACCESS_CMD_READ		1
      7#define VLANACCESS_CMD_WRITE		2
      8#define VLANACCESS_CMD_INIT		3
      9
     10static int lan966x_vlan_get_status(struct lan966x *lan966x)
     11{
     12	return lan_rd(lan966x, ANA_VLANACCESS);
     13}
     14
     15static int lan966x_vlan_wait_for_completion(struct lan966x *lan966x)
     16{
     17	u32 val;
     18
     19	return readx_poll_timeout(lan966x_vlan_get_status,
     20		lan966x, val,
     21		(val & ANA_VLANACCESS_VLAN_TBL_CMD) ==
     22		VLANACCESS_CMD_IDLE,
     23		TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
     24}
     25
     26static void lan966x_vlan_set_mask(struct lan966x *lan966x, u16 vid)
     27{
     28	u16 mask = lan966x->vlan_mask[vid];
     29	bool cpu_dis;
     30
     31	cpu_dis = !(mask & BIT(CPU_PORT));
     32
     33	/* Set flags and the VID to configure */
     34	lan_rmw(ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(cpu_dis) |
     35		ANA_VLANTIDX_V_INDEX_SET(vid),
     36		ANA_VLANTIDX_VLAN_PGID_CPU_DIS |
     37		ANA_VLANTIDX_V_INDEX,
     38		lan966x, ANA_VLANTIDX);
     39
     40	/* Set the vlan port members mask */
     41	lan_rmw(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(mask),
     42		ANA_VLAN_PORT_MASK_VLAN_PORT_MASK,
     43		lan966x, ANA_VLAN_PORT_MASK);
     44
     45	/* Issue a write command */
     46	lan_rmw(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_WRITE),
     47		ANA_VLANACCESS_VLAN_TBL_CMD,
     48		lan966x, ANA_VLANACCESS);
     49
     50	if (lan966x_vlan_wait_for_completion(lan966x))
     51		dev_err(lan966x->dev, "Vlan set mask failed\n");
     52}
     53
     54static void lan966x_vlan_port_add_vlan_mask(struct lan966x_port *port, u16 vid)
     55{
     56	struct lan966x *lan966x = port->lan966x;
     57	u8 p = port->chip_port;
     58
     59	lan966x->vlan_mask[vid] |= BIT(p);
     60	lan966x_vlan_set_mask(lan966x, vid);
     61}
     62
     63static void lan966x_vlan_port_del_vlan_mask(struct lan966x_port *port, u16 vid)
     64{
     65	struct lan966x *lan966x = port->lan966x;
     66	u8 p = port->chip_port;
     67
     68	lan966x->vlan_mask[vid] &= ~BIT(p);
     69	lan966x_vlan_set_mask(lan966x, vid);
     70}
     71
     72static bool lan966x_vlan_port_any_vlan_mask(struct lan966x *lan966x, u16 vid)
     73{
     74	return !!(lan966x->vlan_mask[vid] & ~BIT(CPU_PORT));
     75}
     76
     77static void lan966x_vlan_cpu_add_vlan_mask(struct lan966x *lan966x, u16 vid)
     78{
     79	lan966x->vlan_mask[vid] |= BIT(CPU_PORT);
     80	lan966x_vlan_set_mask(lan966x, vid);
     81}
     82
     83static void lan966x_vlan_cpu_del_vlan_mask(struct lan966x *lan966x, u16 vid)
     84{
     85	lan966x->vlan_mask[vid] &= ~BIT(CPU_PORT);
     86	lan966x_vlan_set_mask(lan966x, vid);
     87}
     88
     89static void lan966x_vlan_cpu_add_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
     90{
     91	__set_bit(vid, lan966x->cpu_vlan_mask);
     92}
     93
     94static void lan966x_vlan_cpu_del_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
     95{
     96	__clear_bit(vid, lan966x->cpu_vlan_mask);
     97}
     98
     99bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
    100{
    101	return test_bit(vid, lan966x->cpu_vlan_mask);
    102}
    103
    104static u16 lan966x_vlan_port_get_pvid(struct lan966x_port *port)
    105{
    106	struct lan966x *lan966x = port->lan966x;
    107
    108	if (!(lan966x->bridge_mask & BIT(port->chip_port)))
    109		return HOST_PVID;
    110
    111	return port->vlan_aware ? port->pvid : UNAWARE_PVID;
    112}
    113
    114int lan966x_vlan_port_set_vid(struct lan966x_port *port, u16 vid,
    115			      bool pvid, bool untagged)
    116{
    117	struct lan966x *lan966x = port->lan966x;
    118
    119	/* Egress vlan classification */
    120	if (untagged && port->vid != vid) {
    121		if (port->vid) {
    122			dev_err(lan966x->dev,
    123				"Port already has a native VLAN: %d\n",
    124				port->vid);
    125			return -EBUSY;
    126		}
    127		port->vid = vid;
    128	}
    129
    130	/* Default ingress vlan classification */
    131	if (pvid)
    132		port->pvid = vid;
    133
    134	return 0;
    135}
    136
    137static void lan966x_vlan_port_remove_vid(struct lan966x_port *port, u16 vid)
    138{
    139	if (port->pvid == vid)
    140		port->pvid = 0;
    141
    142	if (port->vid == vid)
    143		port->vid = 0;
    144}
    145
    146void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
    147				      bool vlan_aware)
    148{
    149	port->vlan_aware = vlan_aware;
    150}
    151
    152void lan966x_vlan_port_apply(struct lan966x_port *port)
    153{
    154	struct lan966x *lan966x = port->lan966x;
    155	u16 pvid;
    156	u32 val;
    157
    158	pvid = lan966x_vlan_port_get_pvid(port);
    159
    160	/* Ingress clasification (ANA_PORT_VLAN_CFG) */
    161	/* Default vlan to classify for untagged frames (may be zero) */
    162	val = ANA_VLAN_CFG_VLAN_VID_SET(pvid);
    163	if (port->vlan_aware)
    164		val |= ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
    165		       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1);
    166
    167	lan_rmw(val,
    168		ANA_VLAN_CFG_VLAN_VID | ANA_VLAN_CFG_VLAN_AWARE_ENA |
    169		ANA_VLAN_CFG_VLAN_POP_CNT,
    170		lan966x, ANA_VLAN_CFG(port->chip_port));
    171
    172	/* Drop frames with multicast source address */
    173	val = ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1);
    174	if (port->vlan_aware && !pvid)
    175		/* If port is vlan-aware and tagged, drop untagged and priority
    176		 * tagged frames.
    177		 */
    178		val |= ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |
    179		       ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |
    180		       ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);
    181
    182	lan_wr(val, lan966x, ANA_DROP_CFG(port->chip_port));
    183
    184	/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
    185	val = REW_TAG_CFG_TAG_TPID_CFG_SET(0);
    186	if (port->vlan_aware) {
    187		if (port->vid)
    188			/* Tag all frames except when VID == DEFAULT_VLAN */
    189			val |= REW_TAG_CFG_TAG_CFG_SET(1);
    190		else
    191			val |= REW_TAG_CFG_TAG_CFG_SET(3);
    192	}
    193
    194	/* Update only some bits in the register */
    195	lan_rmw(val,
    196		REW_TAG_CFG_TAG_TPID_CFG | REW_TAG_CFG_TAG_CFG,
    197		lan966x, REW_TAG_CFG(port->chip_port));
    198
    199	/* Set default VLAN and tag type to 8021Q */
    200	lan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021Q) |
    201		REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
    202		REW_PORT_VLAN_CFG_PORT_TPID |
    203		REW_PORT_VLAN_CFG_PORT_VID,
    204		lan966x, REW_PORT_VLAN_CFG(port->chip_port));
    205}
    206
    207void lan966x_vlan_port_add_vlan(struct lan966x_port *port,
    208				u16 vid,
    209				bool pvid,
    210				bool untagged)
    211{
    212	struct lan966x *lan966x = port->lan966x;
    213
    214	/* If the CPU(br) is already part of the vlan then add the fdb
    215	 * entries in MAC table to copy the frames to the CPU(br).
    216	 * If the CPU(br) is not part of the vlan then it would
    217	 * just drop the frames.
    218	 */
    219	if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, vid)) {
    220		lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
    221		lan966x_fdb_write_entries(lan966x, vid);
    222		lan966x_mdb_write_entries(lan966x, vid);
    223	}
    224
    225	lan966x_vlan_port_set_vid(port, vid, pvid, untagged);
    226	lan966x_vlan_port_add_vlan_mask(port, vid);
    227	lan966x_vlan_port_apply(port);
    228}
    229
    230void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid)
    231{
    232	struct lan966x *lan966x = port->lan966x;
    233
    234	lan966x_vlan_port_remove_vid(port, vid);
    235	lan966x_vlan_port_del_vlan_mask(port, vid);
    236	lan966x_vlan_port_apply(port);
    237
    238	/* In case there are no other ports in vlan then remove the CPU from
    239	 * that vlan but still keep it in the mask because it may be needed
    240	 * again then another port gets added in that vlan
    241	 */
    242	if (!lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
    243		lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
    244		lan966x_fdb_erase_entries(lan966x, vid);
    245		lan966x_mdb_erase_entries(lan966x, vid);
    246	}
    247}
    248
    249void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid)
    250{
    251	/* Add an entry in the MAC table for the CPU
    252	 * Add the CPU part of the vlan only if there is another port in that
    253	 * vlan otherwise all the broadcast frames in that vlan will go to CPU
    254	 * even if none of the ports are in the vlan and then the CPU will just
    255	 * need to discard these frames. It is required to store this
    256	 * information so when a front port is added then it would add also the
    257	 * CPU port.
    258	 */
    259	if (lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
    260		lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
    261		lan966x_mdb_write_entries(lan966x, vid);
    262	}
    263
    264	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, vid);
    265	lan966x_fdb_write_entries(lan966x, vid);
    266}
    267
    268void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid)
    269{
    270	/* Remove the CPU part of the vlan */
    271	lan966x_vlan_cpu_del_cpu_vlan_mask(lan966x, vid);
    272	lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
    273	lan966x_fdb_erase_entries(lan966x, vid);
    274	lan966x_mdb_erase_entries(lan966x, vid);
    275}
    276
    277void lan966x_vlan_init(struct lan966x *lan966x)
    278{
    279	u16 port, vid;
    280
    281	/* Clear VLAN table, by default all ports are members of all VLANS */
    282	lan_rmw(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),
    283		ANA_VLANACCESS_VLAN_TBL_CMD,
    284		lan966x, ANA_VLANACCESS);
    285	lan966x_vlan_wait_for_completion(lan966x);
    286
    287	for (vid = 1; vid < VLAN_N_VID; vid++) {
    288		lan966x->vlan_mask[vid] = 0;
    289		lan966x_vlan_set_mask(lan966x, vid);
    290	}
    291
    292	/* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */
    293	lan966x->vlan_mask[HOST_PVID] =
    294		GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);
    295	lan966x_vlan_set_mask(lan966x, HOST_PVID);
    296
    297	lan966x->vlan_mask[UNAWARE_PVID] =
    298		GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);
    299	lan966x_vlan_set_mask(lan966x, UNAWARE_PVID);
    300
    301	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, UNAWARE_PVID);
    302
    303	/* Configure the CPU port to be vlan aware */
    304	lan_wr(ANA_VLAN_CFG_VLAN_VID_SET(0) |
    305	       ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
    306	       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),
    307	       lan966x, ANA_VLAN_CFG(CPU_PORT));
    308
    309	/* Set vlan ingress filter mask to all ports */
    310	lan_wr(GENMASK(lan966x->num_phys_ports, 0),
    311	       lan966x, ANA_VLANMASK);
    312
    313	for (port = 0; port < lan966x->num_phys_ports; port++) {
    314		lan_wr(0, lan966x, REW_PORT_VLAN_CFG(port));
    315		lan_wr(0, lan966x, REW_TAG_CFG(port));
    316	}
    317}