brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · ac001ae Raw
239 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip Sparx5 Switch driver3 *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 interfaces93	 * with VLAN filtering feature. We need to keep it to receive94	 * 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_clear(struct sparx5 *spx5, int pgid)142{143	spx5_wr(0, spx5, ANA_AC_PGID_CFG(pgid));144	spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid));145	spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid));146}147 148void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])149{150	portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));151	portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid));152	portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid));153}154 155void sparx5_update_fwd(struct sparx5 *sparx5)156{157	DECLARE_BITMAP(workmask, SPX5_PORTS);158	u32 mask[3];159	int port;160 161	/* Divide up fwd mask in 32 bit words */162	bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);163 164	/* Update flood masks */165	for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {166		spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));167		spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));168		spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));169	}170 171	/* Update SRC masks */172	for (port = 0; port < SPX5_PORTS; port++) {173		if (test_bit(port, sparx5->bridge_fwd_mask)) {174			/* Allow to send to all bridged but self */175			bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);176			clear_bit(port, workmask);177			bitmap_to_arr32(mask, workmask, SPX5_PORTS);178			spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));179			spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));180			spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));181		} else {182			spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));183			spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));184			spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));185		}186	}187 188	/* Learning enabled only for bridged ports */189	bitmap_and(workmask, sparx5->bridge_fwd_mask,190		   sparx5->bridge_lrn_mask, SPX5_PORTS);191	bitmap_to_arr32(mask, workmask, SPX5_PORTS);192 193	/* Apply learning mask */194	spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);195	spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);196	spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);197}198 199void sparx5_vlan_port_apply(struct sparx5 *sparx5,200			    struct sparx5_port *port)201 202{203	u32 val;204 205	/* Configure PVID, vlan aware */206	val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |207		ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |208		ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);209	spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));210 211	val = 0;212	if (port->vlan_aware && !port->pvid)213		/* If port is vlan-aware and tagged, drop untagged and214		 * priority tagged frames.215		 */216		val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |217			ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |218			ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);219	spx5_wr(val, sparx5,220		ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));221 222	/* Egress configuration (REW_TAG_CFG): VLAN tag selected via IFH */223	val = REW_TAG_CTRL_TAG_TPID_CFG_SET(5);224	if (port->vlan_aware) {225		if (port->vid)226			/* Tag all frames except when VID == DEFAULT_VLAN */227			val |= REW_TAG_CTRL_TAG_CFG_SET(1);228		else229			val |= REW_TAG_CTRL_TAG_CFG_SET(3);230	}231	spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));232 233	/* Egress VID */234	spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),235		 REW_PORT_VLAN_CFG_PORT_VID,236		 sparx5,237		 REW_PORT_VLAN_CFG(port->portno));238}239