brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · fa34a73 Raw
324 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include "lan966x_main.h"4 5#define VLANACCESS_CMD_IDLE		06#define VLANACCESS_CMD_READ		17#define VLANACCESS_CMD_WRITE		28#define VLANACCESS_CMD_INIT		39 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 classification (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	lan_rmw(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(port->vlan_aware) |173		DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA_SET(port->vlan_aware),174		DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |175		DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA,176		lan966x, DEV_MAC_TAGS_CFG(port->chip_port));177 178	/* Drop frames with multicast source address */179	val = ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1);180	if (port->vlan_aware && !pvid)181		/* If port is vlan-aware and tagged, drop untagged and priority182		 * tagged frames.183		 */184		val |= ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |185		       ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |186		       ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);187 188	lan_wr(val, lan966x, ANA_DROP_CFG(port->chip_port));189 190	/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */191	val = REW_TAG_CFG_TAG_TPID_CFG_SET(0);192	if (port->vlan_aware) {193		if (port->vid)194			/* Tag all frames except when VID == DEFAULT_VLAN */195			val |= REW_TAG_CFG_TAG_CFG_SET(1);196		else197			val |= REW_TAG_CFG_TAG_CFG_SET(3);198	}199 200	/* Update only some bits in the register */201	lan_rmw(val,202		REW_TAG_CFG_TAG_TPID_CFG | REW_TAG_CFG_TAG_CFG,203		lan966x, REW_TAG_CFG(port->chip_port));204 205	/* Set default VLAN and tag type to 8021Q */206	lan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021Q) |207		REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),208		REW_PORT_VLAN_CFG_PORT_TPID |209		REW_PORT_VLAN_CFG_PORT_VID,210		lan966x, REW_PORT_VLAN_CFG(port->chip_port));211}212 213void lan966x_vlan_port_add_vlan(struct lan966x_port *port,214				u16 vid,215				bool pvid,216				bool untagged)217{218	struct lan966x *lan966x = port->lan966x;219 220	/* If the CPU(br) is already part of the vlan then add the fdb221	 * entries in MAC table to copy the frames to the CPU(br).222	 * If the CPU(br) is not part of the vlan then it would223	 * just drop the frames.224	 */225	if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, vid)) {226		lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);227		lan966x_fdb_write_entries(lan966x, vid);228		lan966x_mdb_write_entries(lan966x, vid);229	}230 231	lan966x_vlan_port_set_vid(port, vid, pvid, untagged);232	lan966x_vlan_port_add_vlan_mask(port, vid);233	lan966x_vlan_port_apply(port);234}235 236void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid)237{238	struct lan966x *lan966x = port->lan966x;239 240	lan966x_vlan_port_remove_vid(port, vid);241	lan966x_vlan_port_del_vlan_mask(port, vid);242	lan966x_vlan_port_apply(port);243 244	/* In case there are no other ports in vlan then remove the CPU from245	 * that vlan but still keep it in the mask because it may be needed246	 * again then another port gets added in that vlan247	 */248	if (!lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {249		lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);250		lan966x_fdb_erase_entries(lan966x, vid);251		lan966x_mdb_erase_entries(lan966x, vid);252	}253}254 255void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid)256{257	/* Add an entry in the MAC table for the CPU258	 * Add the CPU part of the vlan only if there is another port in that259	 * vlan otherwise all the broadcast frames in that vlan will go to CPU260	 * even if none of the ports are in the vlan and then the CPU will just261	 * need to discard these frames. It is required to store this262	 * information so when a front port is added then it would add also the263	 * CPU port.264	 */265	if (lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {266		lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);267		lan966x_mdb_write_entries(lan966x, vid);268	}269 270	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, vid);271	lan966x_fdb_write_entries(lan966x, vid);272}273 274void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid)275{276	/* Remove the CPU part of the vlan */277	lan966x_vlan_cpu_del_cpu_vlan_mask(lan966x, vid);278	lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);279	lan966x_fdb_erase_entries(lan966x, vid);280	lan966x_mdb_erase_entries(lan966x, vid);281}282 283void lan966x_vlan_init(struct lan966x *lan966x)284{285	u16 port, vid;286 287	/* Clear VLAN table, by default all ports are members of all VLANS */288	lan_rmw(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),289		ANA_VLANACCESS_VLAN_TBL_CMD,290		lan966x, ANA_VLANACCESS);291	lan966x_vlan_wait_for_completion(lan966x);292 293	for (vid = 1; vid < VLAN_N_VID; vid++) {294		lan966x->vlan_mask[vid] = 0;295		lan966x_vlan_set_mask(lan966x, vid);296	}297 298	/* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */299	lan966x->vlan_mask[HOST_PVID] =300		GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);301	lan966x_vlan_set_mask(lan966x, HOST_PVID);302 303	lan966x->vlan_mask[UNAWARE_PVID] =304		GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);305	lan966x_vlan_set_mask(lan966x, UNAWARE_PVID);306 307	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, UNAWARE_PVID);308 309	/* Configure the CPU port to be vlan aware */310	lan_wr(ANA_VLAN_CFG_VLAN_VID_SET(0) |311	       ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |312	       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),313	       lan966x, ANA_VLAN_CFG(CPU_PORT));314 315	/* Set vlan ingress filter mask to all ports */316	lan_wr(GENMASK(lan966x->num_phys_ports, 0),317	       lan966x, ANA_VLANMASK);318 319	for (port = 0; port < lan966x->num_phys_ports; port++) {320		lan_wr(0, lan966x, REW_PORT_VLAN_CFG(port));321		lan_wr(0, lan966x, REW_TAG_CFG(port));322	}323}324