xref: /rk3399_rockchip-uboot/drivers/net/vsc9953.c (revision ba389e65e5bb64506ad35b3d7007ec1b3b9cf4de)
16706b115SCodrin Ciubotariu /*
2a857d5f8SCodrin Ciubotariu  *  Copyright 2014 - 2015 Freescale Semiconductor, Inc.
36706b115SCodrin Ciubotariu  *
46706b115SCodrin Ciubotariu  *  SPDX-License-Identifier:      GPL-2.0+
56706b115SCodrin Ciubotariu  *
66706b115SCodrin Ciubotariu  *  Driver for the Vitesse VSC9953 L2 Switch
76706b115SCodrin Ciubotariu  */
86706b115SCodrin Ciubotariu 
96706b115SCodrin Ciubotariu #include <asm/io.h>
106706b115SCodrin Ciubotariu #include <asm/fsl_serdes.h>
116706b115SCodrin Ciubotariu #include <fm_eth.h>
12cd348efaSShaohui Xie #include <fsl_memac.h>
139de05987SCodrin Ciubotariu #include <bitfield.h>
143cc8cfffSCodrin Ciubotariu #include <errno.h>
153cc8cfffSCodrin Ciubotariu #include <malloc.h>
166706b115SCodrin Ciubotariu #include <vsc9953.h>
1724a23debSCodrin Ciubotariu #include <ethsw.h>
186706b115SCodrin Ciubotariu 
196706b115SCodrin Ciubotariu static struct vsc9953_info vsc9953_l2sw = {
206706b115SCodrin Ciubotariu 		.port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
216706b115SCodrin Ciubotariu 		.port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
226706b115SCodrin Ciubotariu 		.port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
236706b115SCodrin Ciubotariu 		.port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
246706b115SCodrin Ciubotariu 		.port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
256706b115SCodrin Ciubotariu 		.port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
266706b115SCodrin Ciubotariu 		.port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
276706b115SCodrin Ciubotariu 		.port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
286706b115SCodrin Ciubotariu 		.port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
296706b115SCodrin Ciubotariu 		.port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
306706b115SCodrin Ciubotariu };
316706b115SCodrin Ciubotariu 
323cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus)
336706b115SCodrin Ciubotariu {
343cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
356706b115SCodrin Ciubotariu 		return;
366706b115SCodrin Ciubotariu 
373cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].bus = bus;
386706b115SCodrin Ciubotariu }
396706b115SCodrin Ciubotariu 
403cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_address(int port_no, int address)
416706b115SCodrin Ciubotariu {
423cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
436706b115SCodrin Ciubotariu 		return;
446706b115SCodrin Ciubotariu 
453cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].phyaddr = address;
466706b115SCodrin Ciubotariu }
476706b115SCodrin Ciubotariu 
483cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int)
496706b115SCodrin Ciubotariu {
503cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
516706b115SCodrin Ciubotariu 		return;
526706b115SCodrin Ciubotariu 
533cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enet_if = phy_int;
546706b115SCodrin Ciubotariu }
556706b115SCodrin Ciubotariu 
563cc8cfffSCodrin Ciubotariu void vsc9953_port_enable(int port_no)
576706b115SCodrin Ciubotariu {
583cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
596706b115SCodrin Ciubotariu 		return;
606706b115SCodrin Ciubotariu 
613cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 1;
626706b115SCodrin Ciubotariu }
636706b115SCodrin Ciubotariu 
643cc8cfffSCodrin Ciubotariu void vsc9953_port_disable(int port_no)
656706b115SCodrin Ciubotariu {
663cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
676706b115SCodrin Ciubotariu 		return;
686706b115SCodrin Ciubotariu 
693cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 0;
706706b115SCodrin Ciubotariu }
716706b115SCodrin Ciubotariu 
726706b115SCodrin Ciubotariu static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
736706b115SCodrin Ciubotariu 		int regnum, int value)
746706b115SCodrin Ciubotariu {
756706b115SCodrin Ciubotariu 	int timeout = 50000;
766706b115SCodrin Ciubotariu 
776706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
786706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
796706b115SCodrin Ciubotariu 			(0x1 << 1));
806706b115SCodrin Ciubotariu 	asm("sync");
816706b115SCodrin Ciubotariu 
826706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
836706b115SCodrin Ciubotariu 		udelay(1);
846706b115SCodrin Ciubotariu 
856706b115SCodrin Ciubotariu 	if (timeout == 0)
866706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO write\n");
876706b115SCodrin Ciubotariu }
886706b115SCodrin Ciubotariu 
896706b115SCodrin Ciubotariu static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
906706b115SCodrin Ciubotariu 		int regnum)
916706b115SCodrin Ciubotariu {
926706b115SCodrin Ciubotariu 	int value = 0xFFFF;
936706b115SCodrin Ciubotariu 	int timeout = 50000;
946706b115SCodrin Ciubotariu 
956706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
966706b115SCodrin Ciubotariu 		udelay(1);
976706b115SCodrin Ciubotariu 	if (timeout == 0) {
986706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO operation to finish\n");
996706b115SCodrin Ciubotariu 		return value;
1006706b115SCodrin Ciubotariu 	}
1016706b115SCodrin Ciubotariu 
1026706b115SCodrin Ciubotariu 	/* Put the address of the phy, and the register
1036706b115SCodrin Ciubotariu 	 * number into MIICMD
1046706b115SCodrin Ciubotariu 	 */
1056706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
1066706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
1076706b115SCodrin Ciubotariu 			(0x2 << 1));
1086706b115SCodrin Ciubotariu 
1096706b115SCodrin Ciubotariu 	timeout = 50000;
1106706b115SCodrin Ciubotariu 	/* Wait for the the indication that the read is done */
1116706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
1126706b115SCodrin Ciubotariu 		udelay(1);
1136706b115SCodrin Ciubotariu 	if (timeout == 0)
1146706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO read\n");
1156706b115SCodrin Ciubotariu 
1166706b115SCodrin Ciubotariu 	/* Grab the value read from the PHY */
1176706b115SCodrin Ciubotariu 	value = in_le32(&phyregs->miimdata);
1186706b115SCodrin Ciubotariu 
1196706b115SCodrin Ciubotariu 	if ((value & 0x00030000) == 0)
1206706b115SCodrin Ciubotariu 		return value & 0x0000ffff;
1216706b115SCodrin Ciubotariu 
1226706b115SCodrin Ciubotariu 	return value;
1236706b115SCodrin Ciubotariu }
1246706b115SCodrin Ciubotariu 
1256706b115SCodrin Ciubotariu static int init_phy(struct eth_device *dev)
1266706b115SCodrin Ciubotariu {
1276706b115SCodrin Ciubotariu 	struct vsc9953_port_info *l2sw_port = dev->priv;
1286706b115SCodrin Ciubotariu 	struct phy_device *phydev = NULL;
1296706b115SCodrin Ciubotariu 
1306706b115SCodrin Ciubotariu #ifdef CONFIG_PHYLIB
1316706b115SCodrin Ciubotariu 	if (!l2sw_port->bus)
1326706b115SCodrin Ciubotariu 		return 0;
1336706b115SCodrin Ciubotariu 	phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
1346706b115SCodrin Ciubotariu 			l2sw_port->enet_if);
1356706b115SCodrin Ciubotariu 	if (!phydev) {
1366706b115SCodrin Ciubotariu 		printf("Failed to connect\n");
1376706b115SCodrin Ciubotariu 		return -1;
1386706b115SCodrin Ciubotariu 	}
1396706b115SCodrin Ciubotariu 
1406706b115SCodrin Ciubotariu 	phydev->supported &= SUPPORTED_10baseT_Half |
1416706b115SCodrin Ciubotariu 			SUPPORTED_10baseT_Full |
1426706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Half |
1436706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Full |
1446706b115SCodrin Ciubotariu 			SUPPORTED_1000baseT_Full;
1456706b115SCodrin Ciubotariu 	phydev->advertising = phydev->supported;
1466706b115SCodrin Ciubotariu 
1476706b115SCodrin Ciubotariu 	l2sw_port->phydev = phydev;
1486706b115SCodrin Ciubotariu 
1496706b115SCodrin Ciubotariu 	phy_config(phydev);
1506706b115SCodrin Ciubotariu #endif
1516706b115SCodrin Ciubotariu 
1526706b115SCodrin Ciubotariu 	return 0;
1536706b115SCodrin Ciubotariu }
1546706b115SCodrin Ciubotariu 
1553cc8cfffSCodrin Ciubotariu static int vsc9953_port_init(int port_no)
1566706b115SCodrin Ciubotariu {
1576706b115SCodrin Ciubotariu 	struct eth_device *dev;
1586706b115SCodrin Ciubotariu 
1596706b115SCodrin Ciubotariu 	/* Internal ports never have a PHY */
1603cc8cfffSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no))
1616706b115SCodrin Ciubotariu 		return 0;
1626706b115SCodrin Ciubotariu 
1636706b115SCodrin Ciubotariu 	/* alloc eth device */
1646706b115SCodrin Ciubotariu 	dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
1656706b115SCodrin Ciubotariu 	if (!dev)
1663cc8cfffSCodrin Ciubotariu 		return -ENOMEM;
1676706b115SCodrin Ciubotariu 
1683cc8cfffSCodrin Ciubotariu 	sprintf(dev->name, "SW@PORT%d", port_no);
1693cc8cfffSCodrin Ciubotariu 	dev->priv = &vsc9953_l2sw.port[port_no];
1706706b115SCodrin Ciubotariu 	dev->init = NULL;
1716706b115SCodrin Ciubotariu 	dev->halt = NULL;
1726706b115SCodrin Ciubotariu 	dev->send = NULL;
1736706b115SCodrin Ciubotariu 	dev->recv = NULL;
1746706b115SCodrin Ciubotariu 
1756706b115SCodrin Ciubotariu 	if (init_phy(dev)) {
1766706b115SCodrin Ciubotariu 		free(dev);
1773cc8cfffSCodrin Ciubotariu 		return -ENODEV;
1786706b115SCodrin Ciubotariu 	}
1796706b115SCodrin Ciubotariu 
1806706b115SCodrin Ciubotariu 	return 0;
1816706b115SCodrin Ciubotariu }
1826706b115SCodrin Ciubotariu 
1839de05987SCodrin Ciubotariu static int vsc9953_vlan_table_poll_idle(void)
1849de05987SCodrin Ciubotariu {
1859de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1869de05987SCodrin Ciubotariu 	int timeout;
1879de05987SCodrin Ciubotariu 
1889de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1899de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
1909de05987SCodrin Ciubotariu 
1919de05987SCodrin Ciubotariu 	timeout = 50000;
1929de05987SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
1939de05987SCodrin Ciubotariu 		 VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
1949de05987SCodrin Ciubotariu 		udelay(1);
1959de05987SCodrin Ciubotariu 
1969de05987SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
1979de05987SCodrin Ciubotariu }
1989de05987SCodrin Ciubotariu 
199a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
200a2477924SCodrin Ciubotariu /* Add/remove a port to/from a VLAN */
201a2477924SCodrin Ciubotariu static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add)
202a2477924SCodrin Ciubotariu {
203a2477924SCodrin Ciubotariu 	u32 val;
204a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
205a2477924SCodrin Ciubotariu 
206a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
207a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
208a2477924SCodrin Ciubotariu 
209a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
210a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
211a2477924SCodrin Ciubotariu 		return;
212a2477924SCodrin Ciubotariu 	}
213a2477924SCodrin Ciubotariu 
214a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
215a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
216a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
217a2477924SCodrin Ciubotariu 
218a2477924SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
219a2477924SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
220a2477924SCodrin Ciubotariu 
221a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
222a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
223a2477924SCodrin Ciubotariu 		return;
224a2477924SCodrin Ciubotariu 	}
225a2477924SCodrin Ciubotariu 
226a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
227a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
228a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
229a2477924SCodrin Ciubotariu 
230a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_access);
231a2477924SCodrin Ciubotariu 	if (!add) {
232a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
233a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) &
234a2477924SCodrin Ciubotariu 		      ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
235a2477924SCodrin Ciubotariu 						 (1 << port_no)));
236a2477924SCodrin Ciubotariu 		 ;
237a2477924SCodrin Ciubotariu 	} else {
238a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
239a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) |
240a2477924SCodrin Ciubotariu 		      bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
241a2477924SCodrin Ciubotariu 					       (1 << port_no));
242a2477924SCodrin Ciubotariu 	}
243a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_access, val);
244a2477924SCodrin Ciubotariu 
245a2477924SCodrin Ciubotariu 	/* wait for VLAN table command to flush */
246a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
247a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
248a2477924SCodrin Ciubotariu 		return;
249a2477924SCodrin Ciubotariu 	}
250a2477924SCodrin Ciubotariu }
251a2477924SCodrin Ciubotariu 
252a2477924SCodrin Ciubotariu /* show VLAN membership for a port */
253a2477924SCodrin Ciubotariu static void vsc9953_vlan_membership_show(int port_no)
254a2477924SCodrin Ciubotariu {
255a2477924SCodrin Ciubotariu 	u32 val;
256a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
257a2477924SCodrin Ciubotariu 	u32 vid;
258a2477924SCodrin Ciubotariu 
259a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
260a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
261a2477924SCodrin Ciubotariu 
262a2477924SCodrin Ciubotariu 	printf("Port %d VLAN membership: ", port_no);
263a2477924SCodrin Ciubotariu 
264a2477924SCodrin Ciubotariu 	for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) {
265a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
266a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
267a2477924SCodrin Ciubotariu 			return;
268a2477924SCodrin Ciubotariu 		}
269a2477924SCodrin Ciubotariu 
270a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
271a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK,
272a2477924SCodrin Ciubotariu 					       vid);
273a2477924SCodrin Ciubotariu 		out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
274a2477924SCodrin Ciubotariu 
275a2477924SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
276a2477924SCodrin Ciubotariu 				VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
277a2477924SCodrin Ciubotariu 
278a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
279a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
280a2477924SCodrin Ciubotariu 			return;
281a2477924SCodrin Ciubotariu 		}
282a2477924SCodrin Ciubotariu 
283a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_access);
284a2477924SCodrin Ciubotariu 
285a2477924SCodrin Ciubotariu 		if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) &
286a2477924SCodrin Ciubotariu 		    (1 << port_no))
287a2477924SCodrin Ciubotariu 			printf("%d ", vid);
288a2477924SCodrin Ciubotariu 	}
289a2477924SCodrin Ciubotariu 	printf("\n");
290a2477924SCodrin Ciubotariu }
291a2477924SCodrin Ciubotariu #endif
292a2477924SCodrin Ciubotariu 
2939de05987SCodrin Ciubotariu /* vlan table set/clear all membership of vid */
2949de05987SCodrin Ciubotariu static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
2959de05987SCodrin Ciubotariu {
2969de05987SCodrin Ciubotariu 	uint val;
2979de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
2989de05987SCodrin Ciubotariu 
2999de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
3009de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3019de05987SCodrin Ciubotariu 
3029de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3039de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3049de05987SCodrin Ciubotariu 		return;
3059de05987SCodrin Ciubotariu 	}
3069de05987SCodrin Ciubotariu 
3079de05987SCodrin Ciubotariu 	/* read current vlan configuration */
3089de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3099de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3109de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3119de05987SCodrin Ciubotariu 
3129de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3139de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
3149de05987SCodrin Ciubotariu 
3159de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3169de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3179de05987SCodrin Ciubotariu 		return;
3189de05987SCodrin Ciubotariu 	}
3199de05987SCodrin Ciubotariu 
3209de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3219de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3229de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3239de05987SCodrin Ciubotariu 
3249de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3259de05987SCodrin Ciubotariu 			VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
3269de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_WRITE |
3279de05987SCodrin Ciubotariu 			(set_member ? VSC9953_VLAN_PORT_MASK : 0));
3289de05987SCodrin Ciubotariu }
3299de05987SCodrin Ciubotariu 
330a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
331a2477924SCodrin Ciubotariu /* Get PVID of a VSC9953 port */
332a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid)
333a2477924SCodrin Ciubotariu {
334a2477924SCodrin Ciubotariu 	u32 val;
335a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
336a2477924SCodrin Ciubotariu 
337a2477924SCodrin Ciubotariu 	/* Administrative down */
338a2477924SCodrin Ciubotariu 	if (vsc9953_l2sw.port[port_nr].enabled) {
339a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_nr);
340a2477924SCodrin Ciubotariu 		return -1;
341a2477924SCodrin Ciubotariu 	}
342a2477924SCodrin Ciubotariu 
343a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
344a2477924SCodrin Ciubotariu 				VSC9953_ANA_OFFSET);
345a2477924SCodrin Ciubotariu 
346a2477924SCodrin Ciubotariu 	/* Get ingress PVID */
347a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg);
348a2477924SCodrin Ciubotariu 	*pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK);
349a2477924SCodrin Ciubotariu 
350a2477924SCodrin Ciubotariu 	return 0;
351a2477924SCodrin Ciubotariu }
352a2477924SCodrin Ciubotariu #endif
353a2477924SCodrin Ciubotariu 
3549de05987SCodrin Ciubotariu /* Set PVID for a VSC9953 port */
3559de05987SCodrin Ciubotariu static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
3569de05987SCodrin Ciubotariu {
3579de05987SCodrin Ciubotariu 	uint val;
3589de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3599de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
3609de05987SCodrin Ciubotariu 
3619de05987SCodrin Ciubotariu 	/* Administrative down */
3629de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3639de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
3649de05987SCodrin Ciubotariu 		return;
3659de05987SCodrin Ciubotariu 	}
3669de05987SCodrin Ciubotariu 
3679de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
3689de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3699de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
3709de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
3719de05987SCodrin Ciubotariu 
3729de05987SCodrin Ciubotariu 	/* Set PVID on ingress */
3739de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
3749de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
3759de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
3769de05987SCodrin Ciubotariu 
3779de05987SCodrin Ciubotariu 	/* Set PVID on egress */
3789de05987SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
3799de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
3809de05987SCodrin Ciubotariu 				       pvid);
3819de05987SCodrin Ciubotariu 	out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
3829de05987SCodrin Ciubotariu }
3839de05987SCodrin Ciubotariu 
3849de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_pvid_set(int pvid)
3859de05987SCodrin Ciubotariu {
3869de05987SCodrin Ciubotariu 	int i;
3879de05987SCodrin Ciubotariu 
3889de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
3899de05987SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(i, pvid);
3909de05987SCodrin Ciubotariu }
3919de05987SCodrin Ciubotariu 
3929de05987SCodrin Ciubotariu /* Enable/disable vlan aware of a VSC9953 port */
3939de05987SCodrin Ciubotariu static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
3949de05987SCodrin Ciubotariu {
3959de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3969de05987SCodrin Ciubotariu 
3979de05987SCodrin Ciubotariu 	/* Administrative down */
3989de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3999de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
4009de05987SCodrin Ciubotariu 		return;
4019de05987SCodrin Ciubotariu 	}
4029de05987SCodrin Ciubotariu 
4039de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4049de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4059de05987SCodrin Ciubotariu 
4069de05987SCodrin Ciubotariu 	if (enabled)
4079de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4089de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4099de05987SCodrin Ciubotariu 	else
4109de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4119de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4129de05987SCodrin Ciubotariu }
4139de05987SCodrin Ciubotariu 
4149de05987SCodrin Ciubotariu /* Set all VSC9953 ports' vlan aware  */
4159de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_aware_set(int enabled)
4169de05987SCodrin Ciubotariu {
4179de05987SCodrin Ciubotariu 	int i;
4189de05987SCodrin Ciubotariu 
4199de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4209de05987SCodrin Ciubotariu 		vsc9953_port_vlan_aware_set(i, enabled);
4219de05987SCodrin Ciubotariu }
4229de05987SCodrin Ciubotariu 
4239de05987SCodrin Ciubotariu /* Enable/disable vlan pop count of a VSC9953 port */
4249de05987SCodrin Ciubotariu static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
4259de05987SCodrin Ciubotariu {
4269de05987SCodrin Ciubotariu 	uint val;
4279de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4289de05987SCodrin Ciubotariu 
4299de05987SCodrin Ciubotariu 	/* Administrative down */
4309de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
4319de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
4329de05987SCodrin Ciubotariu 		return;
4339de05987SCodrin Ciubotariu 	}
4349de05987SCodrin Ciubotariu 
4359de05987SCodrin Ciubotariu 	if (popcnt > 3 || popcnt < 0) {
4369de05987SCodrin Ciubotariu 		printf("Invalid pop count value: %d\n", port_no);
4379de05987SCodrin Ciubotariu 		return;
4389de05987SCodrin Ciubotariu 	}
4399de05987SCodrin Ciubotariu 
4409de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4419de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4429de05987SCodrin Ciubotariu 
4439de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
4449de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
4459de05987SCodrin Ciubotariu 				       popcnt);
4469de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
4479de05987SCodrin Ciubotariu }
4489de05987SCodrin Ciubotariu 
4499de05987SCodrin Ciubotariu /* Set all VSC9953 ports' pop count  */
4509de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
4519de05987SCodrin Ciubotariu {
4529de05987SCodrin Ciubotariu 	int i;
4539de05987SCodrin Ciubotariu 
4549de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4559de05987SCodrin Ciubotariu 		vsc9953_port_vlan_popcnt_set(i, popcnt);
4569de05987SCodrin Ciubotariu }
4579de05987SCodrin Ciubotariu 
4589de05987SCodrin Ciubotariu /* Enable/disable learning for frames dropped due to ingress filtering */
4599de05987SCodrin Ciubotariu static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
4609de05987SCodrin Ciubotariu {
4619de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4629de05987SCodrin Ciubotariu 
4639de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4649de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4659de05987SCodrin Ciubotariu 
4669de05987SCodrin Ciubotariu 	if (enable)
4679de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4689de05987SCodrin Ciubotariu 	else
4699de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4709de05987SCodrin Ciubotariu }
4719de05987SCodrin Ciubotariu 
4729de05987SCodrin Ciubotariu /* Egress untag modes of a VSC9953 port */
4739de05987SCodrin Ciubotariu enum egress_untag_mode {
4749de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ALL = 0,
4759de05987SCodrin Ciubotariu 	EGRESS_UNTAG_PVID_AND_ZERO,
4769de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ZERO,
4779de05987SCodrin Ciubotariu 	EGRESS_UNTAG_NONE,
4789de05987SCodrin Ciubotariu };
4799de05987SCodrin Ciubotariu 
480a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
481a2477924SCodrin Ciubotariu /* Get egress tagging configuration for a VSC9953 port */
482a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_egr_untag_get(int port_no,
483a2477924SCodrin Ciubotariu 					   enum egress_untag_mode *mode)
484a2477924SCodrin Ciubotariu {
485a2477924SCodrin Ciubotariu 	u32 val;
486a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
487a2477924SCodrin Ciubotariu 
488a2477924SCodrin Ciubotariu 	/* Administrative down */
489a2477924SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
490a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
491a2477924SCodrin Ciubotariu 		return -1;
492a2477924SCodrin Ciubotariu 	}
493a2477924SCodrin Ciubotariu 
494a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
495a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
496a2477924SCodrin Ciubotariu 
497a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
498a2477924SCodrin Ciubotariu 
499a2477924SCodrin Ciubotariu 	switch (val & VSC9953_TAG_CFG_MASK) {
500a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_NONE:
501a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ALL;
502a2477924SCodrin Ciubotariu 		return 0;
503a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO:
504a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_PVID_AND_ZERO;
505a2477924SCodrin Ciubotariu 		return 0;
506a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_ZERO:
507a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ZERO;
508a2477924SCodrin Ciubotariu 		return 0;
509a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL:
510a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_NONE;
511a2477924SCodrin Ciubotariu 		return 0;
512a2477924SCodrin Ciubotariu 	default:
513a2477924SCodrin Ciubotariu 		printf("Unknown egress tagging configuration for port %d\n",
514a2477924SCodrin Ciubotariu 		       port_no);
515a2477924SCodrin Ciubotariu 		return -1;
516a2477924SCodrin Ciubotariu 	}
517a2477924SCodrin Ciubotariu }
518a2477924SCodrin Ciubotariu 
519a2477924SCodrin Ciubotariu /* Show egress tagging configuration for a VSC9953 port */
520a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_show(int port_no)
521a2477924SCodrin Ciubotariu {
522a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
523a2477924SCodrin Ciubotariu 
524a2477924SCodrin Ciubotariu 	if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) {
525a2477924SCodrin Ciubotariu 		printf("%7d\t%17s\n", port_no, "-");
526a2477924SCodrin Ciubotariu 		return;
527a2477924SCodrin Ciubotariu 	}
528a2477924SCodrin Ciubotariu 
529a2477924SCodrin Ciubotariu 	printf("%7d\t", port_no);
530a2477924SCodrin Ciubotariu 	switch (mode) {
531a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
532a2477924SCodrin Ciubotariu 		printf("%17s\n", "all");
533a2477924SCodrin Ciubotariu 		break;
534a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
535a2477924SCodrin Ciubotariu 		printf("%17s\n", "none");
536a2477924SCodrin Ciubotariu 		break;
537a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
538a2477924SCodrin Ciubotariu 		printf("%17s\n", "PVID and 0");
539a2477924SCodrin Ciubotariu 		break;
540a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
541a2477924SCodrin Ciubotariu 		printf("%17s\n", "0");
542a2477924SCodrin Ciubotariu 		break;
543a2477924SCodrin Ciubotariu 	default:
544a2477924SCodrin Ciubotariu 		printf("%17s\n", "-");
545a2477924SCodrin Ciubotariu 	}
546a2477924SCodrin Ciubotariu }
547a2477924SCodrin Ciubotariu #endif
548a2477924SCodrin Ciubotariu 
5499de05987SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_set(int port_no,
5509de05987SCodrin Ciubotariu 					    enum egress_untag_mode mode)
5519de05987SCodrin Ciubotariu {
5529de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
5539de05987SCodrin Ciubotariu 
5549de05987SCodrin Ciubotariu 	/* Administrative down */
5559de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
5569de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
5579de05987SCodrin Ciubotariu 		return;
5589de05987SCodrin Ciubotariu 	}
5599de05987SCodrin Ciubotariu 
5609de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
5619de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
5629de05987SCodrin Ciubotariu 
5639de05987SCodrin Ciubotariu 	switch (mode) {
5649de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
5659de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
5669de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
5679de05987SCodrin Ciubotariu 		break;
5689de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
5699de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
5709de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
5719de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
5729de05987SCodrin Ciubotariu 		break;
5739de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
5749de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
5759de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
5769de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_ZERO);
5779de05987SCodrin Ciubotariu 		break;
5789de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
5799de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
5809de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
5819de05987SCodrin Ciubotariu 		break;
5829de05987SCodrin Ciubotariu 	default:
5839de05987SCodrin Ciubotariu 		printf("Unknown untag mode for port %d\n", port_no);
5849de05987SCodrin Ciubotariu 	}
5859de05987SCodrin Ciubotariu }
5869de05987SCodrin Ciubotariu 
5879de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_egress_untagged_set(
5889de05987SCodrin Ciubotariu 		enum egress_untag_mode mode)
5899de05987SCodrin Ciubotariu {
5909de05987SCodrin Ciubotariu 	int i;
5919de05987SCodrin Ciubotariu 
5929de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
5939de05987SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(i, mode);
5949de05987SCodrin Ciubotariu }
5959de05987SCodrin Ciubotariu 
596*ba389e65SCodrin Ciubotariu static int vsc9953_autoage_time_set(int age_period)
597*ba389e65SCodrin Ciubotariu {
598*ba389e65SCodrin Ciubotariu 	u32 autoage;
599*ba389e65SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
600*ba389e65SCodrin Ciubotariu 
601*ba389e65SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
602*ba389e65SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
603*ba389e65SCodrin Ciubotariu 
604*ba389e65SCodrin Ciubotariu 	if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
605*ba389e65SCodrin Ciubotariu 		return -EINVAL;
606*ba389e65SCodrin Ciubotariu 
607*ba389e65SCodrin Ciubotariu 	autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
608*ba389e65SCodrin Ciubotariu 					   VSC9953_AUTOAGE_PERIOD_MASK,
609*ba389e65SCodrin Ciubotariu 					   age_period);
610*ba389e65SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.auto_age, autoage);
611*ba389e65SCodrin Ciubotariu 
612*ba389e65SCodrin Ciubotariu 	return 0;
613*ba389e65SCodrin Ciubotariu }
614*ba389e65SCodrin Ciubotariu 
61524a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
61624a23debSCodrin Ciubotariu 
61724a23debSCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */
61824a23debSCodrin Ciubotariu static void vsc9953_port_status_set(int port_no, u8 enabled)
61924a23debSCodrin Ciubotariu {
62024a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
62124a23debSCodrin Ciubotariu 
62224a23debSCodrin Ciubotariu 	/* Administrative down */
62324a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled)
62424a23debSCodrin Ciubotariu 		return;
62524a23debSCodrin Ciubotariu 
62624a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
62724a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
62824a23debSCodrin Ciubotariu 
62924a23debSCodrin Ciubotariu 	if (enabled)
63024a23debSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
63124a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
63224a23debSCodrin Ciubotariu 	else
63324a23debSCodrin Ciubotariu 		clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
63424a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
63524a23debSCodrin Ciubotariu }
63624a23debSCodrin Ciubotariu 
63724a23debSCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */
63824a23debSCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_no)
63924a23debSCodrin Ciubotariu {
64024a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].phydev)
64124a23debSCodrin Ciubotariu 		return;
64224a23debSCodrin Ciubotariu 
64324a23debSCodrin Ciubotariu 	if (vsc9953_l2sw.port[port_no].phydev->drv->startup(
64424a23debSCodrin Ciubotariu 			vsc9953_l2sw.port[port_no].phydev))
64524a23debSCodrin Ciubotariu 		printf("Failed to start PHY for port %d\n", port_no);
64624a23debSCodrin Ciubotariu }
64724a23debSCodrin Ciubotariu 
64824a23debSCodrin Ciubotariu /* Print a VSC9953 port's configuration */
64924a23debSCodrin Ciubotariu static void vsc9953_port_config_show(int port_no)
65024a23debSCodrin Ciubotariu {
65124a23debSCodrin Ciubotariu 	int speed;
65224a23debSCodrin Ciubotariu 	int duplex;
65324a23debSCodrin Ciubotariu 	int link;
65424a23debSCodrin Ciubotariu 	u8 enabled;
65524a23debSCodrin Ciubotariu 	u32 val;
65624a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
65724a23debSCodrin Ciubotariu 
65824a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
65924a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
66024a23debSCodrin Ciubotariu 
66124a23debSCodrin Ciubotariu 	val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]);
66224a23debSCodrin Ciubotariu 	enabled = vsc9953_l2sw.port[port_no].enabled &&
66324a23debSCodrin Ciubotariu 		  (val & VSC9953_PORT_ENA);
66424a23debSCodrin Ciubotariu 
66524a23debSCodrin Ciubotariu 	/* internal ports (8 and 9) are fixed */
66624a23debSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no)) {
66724a23debSCodrin Ciubotariu 		link = 1;
66824a23debSCodrin Ciubotariu 		speed = SPEED_2500;
66924a23debSCodrin Ciubotariu 		duplex = DUPLEX_FULL;
67024a23debSCodrin Ciubotariu 	} else {
67124a23debSCodrin Ciubotariu 		if (vsc9953_l2sw.port[port_no].phydev) {
67224a23debSCodrin Ciubotariu 			link = vsc9953_l2sw.port[port_no].phydev->link;
67324a23debSCodrin Ciubotariu 			speed = vsc9953_l2sw.port[port_no].phydev->speed;
67424a23debSCodrin Ciubotariu 			duplex = vsc9953_l2sw.port[port_no].phydev->duplex;
67524a23debSCodrin Ciubotariu 		} else {
67624a23debSCodrin Ciubotariu 			link = -1;
67724a23debSCodrin Ciubotariu 			speed = -1;
67824a23debSCodrin Ciubotariu 			duplex = -1;
67924a23debSCodrin Ciubotariu 		}
68024a23debSCodrin Ciubotariu 	}
68124a23debSCodrin Ciubotariu 
68224a23debSCodrin Ciubotariu 	printf("%8d ", port_no);
68324a23debSCodrin Ciubotariu 	printf("%8s ", enabled == 1 ? "enabled" : "disabled");
68424a23debSCodrin Ciubotariu 	printf("%8s ", link == 1 ? "up" : "down");
68524a23debSCodrin Ciubotariu 
68624a23debSCodrin Ciubotariu 	switch (speed) {
68724a23debSCodrin Ciubotariu 	case SPEED_10:
68824a23debSCodrin Ciubotariu 		printf("%8d ", 10);
68924a23debSCodrin Ciubotariu 		break;
69024a23debSCodrin Ciubotariu 	case SPEED_100:
69124a23debSCodrin Ciubotariu 		printf("%8d ", 100);
69224a23debSCodrin Ciubotariu 		break;
69324a23debSCodrin Ciubotariu 	case SPEED_1000:
69424a23debSCodrin Ciubotariu 		printf("%8d ", 1000);
69524a23debSCodrin Ciubotariu 		break;
69624a23debSCodrin Ciubotariu 	case SPEED_2500:
69724a23debSCodrin Ciubotariu 		printf("%8d ", 2500);
69824a23debSCodrin Ciubotariu 		break;
69924a23debSCodrin Ciubotariu 	case SPEED_10000:
70024a23debSCodrin Ciubotariu 		printf("%8d ", 10000);
70124a23debSCodrin Ciubotariu 		break;
70224a23debSCodrin Ciubotariu 	default:
70324a23debSCodrin Ciubotariu 		printf("%8s ", "-");
70424a23debSCodrin Ciubotariu 	}
70524a23debSCodrin Ciubotariu 
70624a23debSCodrin Ciubotariu 	printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
70724a23debSCodrin Ciubotariu }
70824a23debSCodrin Ciubotariu 
70986719f0cSCodrin Ciubotariu /* Show VSC9953 ports' statistics */
71086719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_show(int port_no)
71186719f0cSCodrin Ciubotariu {
71286719f0cSCodrin Ciubotariu 	u32 rx_val;
71386719f0cSCodrin Ciubotariu 	u32 tx_val;
71486719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
71586719f0cSCodrin Ciubotariu 
71686719f0cSCodrin Ciubotariu 	/* Administrative down */
71786719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
71886719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
71986719f0cSCodrin Ciubotariu 		return;
72086719f0cSCodrin Ciubotariu 	}
72186719f0cSCodrin Ciubotariu 
72286719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
72386719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
72486719f0cSCodrin Ciubotariu 
72586719f0cSCodrin Ciubotariu 	printf("Statistics for L2 Switch port %d:\n", port_no);
72686719f0cSCodrin Ciubotariu 
72786719f0cSCodrin Ciubotariu 	/* Set counter view for our port */
72886719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no);
72986719f0cSCodrin Ciubotariu 
73086719f0cSCodrin Ciubotariu #define VSC9953_STATS_PRINTF "%-15s %10u"
73186719f0cSCodrin Ciubotariu 
73286719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames */
73386719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) +
73486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) +
73586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) +
73686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) +
73786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) +
73886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) +
73986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) +
74086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) +
74186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) +
74286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) +
74386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
74486719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
74586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
74686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
74786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
74886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
74986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
75086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
75186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
75286719f0cSCodrin Ciubotariu 	       "Rx frames:", rx_val, "Tx frames:", tx_val);
75386719f0cSCodrin Ciubotariu 
75486719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx bytes */
75586719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct);
75686719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct);
75786719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
75886719f0cSCodrin Ciubotariu 	       "Rx bytes:", rx_val, "Tx bytes:", tx_val);
75986719f0cSCodrin Ciubotariu 
76086719f0cSCodrin Ciubotariu 	/* Get number of Rx frames received ok and Tx frames sent ok */
76186719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) +
76286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) +
76386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) +
76486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) +
76586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) +
76686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) +
76786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) +
76886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) +
76986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) +
77086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) +
77186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) +
77286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) +
77386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) +
77486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) +
77586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) +
77686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7);
77786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
77886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
77986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
78086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
78186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
78286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
78386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
78486719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
78586719f0cSCodrin Ciubotariu 	       "Rx frames ok:", rx_val, "Tx frames ok:", tx_val);
78686719f0cSCodrin Ciubotariu 
78786719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx unicast frames */
78886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc);
78986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc);
79086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79186719f0cSCodrin Ciubotariu 	       "Rx unicast:", rx_val, "Tx unicast:", tx_val);
79286719f0cSCodrin Ciubotariu 
79386719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx broadcast frames */
79486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc);
79586719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc);
79686719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79786719f0cSCodrin Ciubotariu 	       "Rx broadcast:", rx_val, "Tx broadcast:", tx_val);
79886719f0cSCodrin Ciubotariu 
79986719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames of 64B */
80086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64);
80186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64);
80286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
80386719f0cSCodrin Ciubotariu 	       "Rx 64B:", rx_val, "Tx 64B:", tx_val);
80486719f0cSCodrin Ciubotariu 
80586719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 65B and 127B */
80686719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127);
80786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127);
80886719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
80986719f0cSCodrin Ciubotariu 	       "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val);
81086719f0cSCodrin Ciubotariu 
81186719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 128B and 255B */
81286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255);
81386719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255);
81486719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
81586719f0cSCodrin Ciubotariu 	       "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val);
81686719f0cSCodrin Ciubotariu 
81786719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 256B and 511B */
81886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511);
81986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511);
82086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
82186719f0cSCodrin Ciubotariu 	       "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val);
82286719f0cSCodrin Ciubotariu 
82386719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 512B and 1023B */
82486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023);
82586719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023);
82686719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
82786719f0cSCodrin Ciubotariu 	       "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val);
82886719f0cSCodrin Ciubotariu 
82986719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 1024B and 1526B */
83086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526);
83186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526);
83286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83386719f0cSCodrin Ciubotariu 	       "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val);
83486719f0cSCodrin Ciubotariu 
83586719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx jumbo frames */
83686719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
83786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
83886719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83986719f0cSCodrin Ciubotariu 	       "Rx jumbo:", rx_val, "Tx jumbo:", tx_val);
84086719f0cSCodrin Ciubotariu 
84186719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx dropped frames */
84286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
84386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) +
84486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) +
84586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) +
84686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) +
84786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) +
84886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) +
84986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) +
85086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) +
85186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) +
85286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) +
85386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) +
85486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) +
85586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) +
85686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) +
85786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) +
85886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) +
85986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7);
86086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) +
86186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
86286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
86386719f0cSCodrin Ciubotariu 	       "Rx drops:", rx_val, "Tx drops:", tx_val);
86486719f0cSCodrin Ciubotariu 
86586719f0cSCodrin Ciubotariu 	/*
86686719f0cSCodrin Ciubotariu 	 * Get number of Rx frames with CRC or alignment errors
86786719f0cSCodrin Ciubotariu 	 * and number of detected Tx collisions
86886719f0cSCodrin Ciubotariu 	 */
86986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc);
87086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col);
87186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
87286719f0cSCodrin Ciubotariu 	       "Rx CRC&align:", rx_val, "Tx coll:", tx_val);
87386719f0cSCodrin Ciubotariu 
87486719f0cSCodrin Ciubotariu 	/*
87586719f0cSCodrin Ciubotariu 	 * Get number of Rx undersized frames and
87686719f0cSCodrin Ciubotariu 	 * number of Tx aged frames
87786719f0cSCodrin Ciubotariu 	 */
87886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short);
87986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
88086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
88186719f0cSCodrin Ciubotariu 	       "Rx undersize:", rx_val, "Tx aged:", tx_val);
88286719f0cSCodrin Ciubotariu 
88386719f0cSCodrin Ciubotariu 	/* Get number of Rx oversized frames */
88486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long);
88586719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val);
88686719f0cSCodrin Ciubotariu 
88786719f0cSCodrin Ciubotariu 	/* Get number of Rx fragmented frames */
88886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag);
88986719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val);
89086719f0cSCodrin Ciubotariu 
89186719f0cSCodrin Ciubotariu 	/* Get number of Rx jabber errors */
89286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber);
89386719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val);
89486719f0cSCodrin Ciubotariu 
89586719f0cSCodrin Ciubotariu 	/*
89686719f0cSCodrin Ciubotariu 	 * Get number of Rx frames filtered due to classification rules or
89786719f0cSCodrin Ciubotariu 	 * no destination ports
89886719f0cSCodrin Ciubotariu 	 */
89986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
90086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local);
90186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val);
90286719f0cSCodrin Ciubotariu 
90386719f0cSCodrin Ciubotariu 	printf("\n");
90486719f0cSCodrin Ciubotariu }
90586719f0cSCodrin Ciubotariu 
90686719f0cSCodrin Ciubotariu /* Clear statistics for a VSC9953 port */
90786719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_clear(int port_no)
90886719f0cSCodrin Ciubotariu {
90986719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
91086719f0cSCodrin Ciubotariu 
91186719f0cSCodrin Ciubotariu 	/* Administrative down */
91286719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
91386719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
91486719f0cSCodrin Ciubotariu 		return;
91586719f0cSCodrin Ciubotariu 	}
91686719f0cSCodrin Ciubotariu 
91786719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
91886719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
91986719f0cSCodrin Ciubotariu 
92086719f0cSCodrin Ciubotariu 	/* Clear all counter groups for our ports */
92186719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no |
92286719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX |
92386719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_DR);
92486719f0cSCodrin Ciubotariu }
92586719f0cSCodrin Ciubotariu 
92668c929daSCodrin Ciubotariu enum port_learn_mode {
92768c929daSCodrin Ciubotariu 	PORT_LEARN_NONE,
92868c929daSCodrin Ciubotariu 	PORT_LEARN_AUTO
92968c929daSCodrin Ciubotariu };
93068c929daSCodrin Ciubotariu 
93168c929daSCodrin Ciubotariu /* Set learning configuration for a VSC9953 port */
93268c929daSCodrin Ciubotariu static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode)
93368c929daSCodrin Ciubotariu {
93468c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
93568c929daSCodrin Ciubotariu 
93668c929daSCodrin Ciubotariu 	/* Administrative down */
93768c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
93868c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
93968c929daSCodrin Ciubotariu 		return;
94068c929daSCodrin Ciubotariu 	}
94168c929daSCodrin Ciubotariu 
94268c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
94368c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
94468c929daSCodrin Ciubotariu 
94568c929daSCodrin Ciubotariu 	switch (mode) {
94668c929daSCodrin Ciubotariu 	case PORT_LEARN_NONE:
94768c929daSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].port_cfg,
94868c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_DROP |
94968c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_CPU |
95068c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_AUTO |
95168c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_ENA);
95268c929daSCodrin Ciubotariu 		break;
95368c929daSCodrin Ciubotariu 	case PORT_LEARN_AUTO:
95468c929daSCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg,
95568c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_DROP |
95668c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_CPU,
95768c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_ENA |
95868c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_AUTO);
95968c929daSCodrin Ciubotariu 		break;
96068c929daSCodrin Ciubotariu 	default:
96168c929daSCodrin Ciubotariu 		printf("Unknown learn mode for port %d\n", port_no);
96268c929daSCodrin Ciubotariu 	}
96368c929daSCodrin Ciubotariu }
96468c929daSCodrin Ciubotariu 
96568c929daSCodrin Ciubotariu /* Get learning configuration for a VSC9953 port */
96668c929daSCodrin Ciubotariu static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode)
96768c929daSCodrin Ciubotariu {
96868c929daSCodrin Ciubotariu 	u32 val;
96968c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
97068c929daSCodrin Ciubotariu 
97168c929daSCodrin Ciubotariu 	/* Administrative down */
97268c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
97368c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
97468c929daSCodrin Ciubotariu 		return -1;
97568c929daSCodrin Ciubotariu 	}
97668c929daSCodrin Ciubotariu 
97768c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
97868c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
97968c929daSCodrin Ciubotariu 
98068c929daSCodrin Ciubotariu 	/* For now we only support HW learning (auto) and no learning */
98168c929daSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
98268c929daSCodrin Ciubotariu 	if ((val & (VSC9953_PORT_CFG_LEARN_ENA |
98368c929daSCodrin Ciubotariu 		    VSC9953_PORT_CFG_LEARN_AUTO)) ==
98468c929daSCodrin Ciubotariu 	    (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO))
98568c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_AUTO;
98668c929daSCodrin Ciubotariu 	else
98768c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_NONE;
98868c929daSCodrin Ciubotariu 
98968c929daSCodrin Ciubotariu 	return 0;
99068c929daSCodrin Ciubotariu }
99168c929daSCodrin Ciubotariu 
99222449858SCodrin Ciubotariu /* wait for FDB to become available */
99322449858SCodrin Ciubotariu static int vsc9953_mac_table_poll_idle(void)
99422449858SCodrin Ciubotariu {
99522449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
99622449858SCodrin Ciubotariu 	u32 timeout;
99722449858SCodrin Ciubotariu 
99822449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
99922449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
100022449858SCodrin Ciubotariu 
100122449858SCodrin Ciubotariu 	timeout = 50000;
100222449858SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.mac_access) &
100322449858SCodrin Ciubotariu 			 VSC9953_MAC_CMD_MASK) !=
100422449858SCodrin Ciubotariu 		VSC9953_MAC_CMD_IDLE) && --timeout)
100522449858SCodrin Ciubotariu 		udelay(1);
100622449858SCodrin Ciubotariu 
100722449858SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
100822449858SCodrin Ciubotariu }
100922449858SCodrin Ciubotariu 
101022449858SCodrin Ciubotariu /* enum describing available commands for the MAC table */
101122449858SCodrin Ciubotariu enum mac_table_cmd {
101222449858SCodrin Ciubotariu 	MAC_TABLE_READ,
101322449858SCodrin Ciubotariu 	MAC_TABLE_LOOKUP,
101422449858SCodrin Ciubotariu 	MAC_TABLE_WRITE,
101522449858SCodrin Ciubotariu 	MAC_TABLE_LEARN,
101622449858SCodrin Ciubotariu 	MAC_TABLE_FORGET,
101722449858SCodrin Ciubotariu 	MAC_TABLE_GET_NEXT,
101822449858SCodrin Ciubotariu 	MAC_TABLE_AGE,
101922449858SCodrin Ciubotariu };
102022449858SCodrin Ciubotariu 
102122449858SCodrin Ciubotariu /* Issues a command to the FDB table */
102222449858SCodrin Ciubotariu static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd)
102322449858SCodrin Ciubotariu {
102422449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
102522449858SCodrin Ciubotariu 
102622449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
102722449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
102822449858SCodrin Ciubotariu 
102922449858SCodrin Ciubotariu 	switch (cmd) {
103022449858SCodrin Ciubotariu 	case MAC_TABLE_READ:
103122449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
103222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID,
103322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_READ);
103422449858SCodrin Ciubotariu 		break;
103522449858SCodrin Ciubotariu 	case MAC_TABLE_LOOKUP:
103622449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
103722449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ |
103822449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
103922449858SCodrin Ciubotariu 		break;
104022449858SCodrin Ciubotariu 	case MAC_TABLE_WRITE:
104122449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
104222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
104322449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
104422449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_WRITE |
104522449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED);
104622449858SCodrin Ciubotariu 		break;
104722449858SCodrin Ciubotariu 	case MAC_TABLE_LEARN:
104822449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
104922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
105022449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
105122449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_LEARN |
105222449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED |
105322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
105422449858SCodrin Ciubotariu 		break;
105522449858SCodrin Ciubotariu 	case MAC_TABLE_FORGET:
105622449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
105722449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
105822449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
105922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_FORGET);
106022449858SCodrin Ciubotariu 		break;
106122449858SCodrin Ciubotariu 	case MAC_TABLE_GET_NEXT:
106222449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
106322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
106422449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
106522449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_NEXT);
106622449858SCodrin Ciubotariu 		break;
106722449858SCodrin Ciubotariu 	case MAC_TABLE_AGE:
106822449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
106922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
107022449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
107122449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_AGE);
107222449858SCodrin Ciubotariu 		break;
107322449858SCodrin Ciubotariu 	default:
107422449858SCodrin Ciubotariu 		printf("Unknown MAC table command\n");
107522449858SCodrin Ciubotariu 	}
107622449858SCodrin Ciubotariu 
107722449858SCodrin Ciubotariu 	if (vsc9953_mac_table_poll_idle() < 0) {
107822449858SCodrin Ciubotariu 		debug("MAC table timeout\n");
107922449858SCodrin Ciubotariu 		return -1;
108022449858SCodrin Ciubotariu 	}
108122449858SCodrin Ciubotariu 
108222449858SCodrin Ciubotariu 	return 0;
108322449858SCodrin Ciubotariu }
108422449858SCodrin Ciubotariu 
108522449858SCodrin Ciubotariu /* show the FDB entries that correspond to a port and a VLAN */
108622449858SCodrin Ciubotariu static void vsc9953_mac_table_show(int port_no, int vid)
108722449858SCodrin Ciubotariu {
108822449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
108922449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
109022449858SCodrin Ciubotariu 	int i;
109122449858SCodrin Ciubotariu 	u32 val;
109222449858SCodrin Ciubotariu 	u32 vlan;
109322449858SCodrin Ciubotariu 	u32 mach;
109422449858SCodrin Ciubotariu 	u32 macl;
109522449858SCodrin Ciubotariu 	u32 dest_indx;
109622449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
109722449858SCodrin Ciubotariu 
109822449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
109922449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
110022449858SCodrin Ciubotariu 
110122449858SCodrin Ciubotariu 	/* disable auto learning */
110222449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
110322449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
110422449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
110522449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
110622449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
110722449858SCodrin Ciubotariu 		}
110822449858SCodrin Ciubotariu 	} else {
110922449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
111022449858SCodrin Ciubotariu 							  &mode[port_no]);
111122449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
111222449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
111322449858SCodrin Ciubotariu 	}
111422449858SCodrin Ciubotariu 
111522449858SCodrin Ciubotariu 	/* write port and vid to get selected FDB entries */
111622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
111722449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
111822449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
111922449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
112022449858SCodrin Ciubotariu 	}
112122449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
112222449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK,
112322449858SCodrin Ciubotariu 					       vid) | VSC9953_AGE_VID_EN;
112422449858SCodrin Ciubotariu 	}
112522449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
112622449858SCodrin Ciubotariu 
112722449858SCodrin Ciubotariu 	/* set MAC and VLAN to 0 to look from beginning */
112822449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana_tables.mach_data,
112922449858SCodrin Ciubotariu 		     VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK);
113022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, 0);
113122449858SCodrin Ciubotariu 
113222449858SCodrin Ciubotariu 	/* get entries */
113322449858SCodrin Ciubotariu 	printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID");
113422449858SCodrin Ciubotariu 	do {
113522449858SCodrin Ciubotariu 		if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) {
113622449858SCodrin Ciubotariu 			debug("GET NEXT MAC table command failed\n");
113722449858SCodrin Ciubotariu 			break;
113822449858SCodrin Ciubotariu 		}
113922449858SCodrin Ciubotariu 
114022449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mac_access);
114122449858SCodrin Ciubotariu 
114222449858SCodrin Ciubotariu 		/* get out when an invalid entry is found */
114322449858SCodrin Ciubotariu 		if (!(val & VSC9953_MAC_CMD_VALID))
114422449858SCodrin Ciubotariu 			break;
114522449858SCodrin Ciubotariu 
114622449858SCodrin Ciubotariu 		switch (val & VSC9953_MAC_ENTRYTYPE_MASK) {
114722449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_NORMAL:
114822449858SCodrin Ciubotariu 			printf("%10s ", "Dynamic");
114922449858SCodrin Ciubotariu 			break;
115022449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_LOCKED:
115122449858SCodrin Ciubotariu 			printf("%10s ", "Static");
115222449858SCodrin Ciubotariu 			break;
115322449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV4MCAST:
115422449858SCodrin Ciubotariu 			printf("%10s ", "IPv4 Mcast");
115522449858SCodrin Ciubotariu 			break;
115622449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV6MCAST:
115722449858SCodrin Ciubotariu 			printf("%10s ", "IPv6 Mcast");
115822449858SCodrin Ciubotariu 			break;
115922449858SCodrin Ciubotariu 		default:
116022449858SCodrin Ciubotariu 			printf("%10s ", "Unknown");
116122449858SCodrin Ciubotariu 		}
116222449858SCodrin Ciubotariu 
116322449858SCodrin Ciubotariu 		dest_indx = bitfield_extract_by_mask(val,
116422449858SCodrin Ciubotariu 						     VSC9953_MAC_DESTIDX_MASK);
116522449858SCodrin Ciubotariu 
116622449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mach_data);
116722449858SCodrin Ciubotariu 		vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK);
116822449858SCodrin Ciubotariu 		mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK);
116922449858SCodrin Ciubotariu 		macl = in_le32(&l2ana_reg->ana_tables.macl_data);
117022449858SCodrin Ciubotariu 
117122449858SCodrin Ciubotariu 		printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff,
117222449858SCodrin Ciubotariu 		       mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff,
117322449858SCodrin Ciubotariu 		       (macl >> 8) & 0xff, macl & 0xff);
117422449858SCodrin Ciubotariu 		printf("%5d ", dest_indx);
117522449858SCodrin Ciubotariu 		printf("%4d\n", vlan);
117622449858SCodrin Ciubotariu 	} while (1);
117722449858SCodrin Ciubotariu 
117822449858SCodrin Ciubotariu 	/* set learning mode to previous value */
117922449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
118022449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
118122449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
118222449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
118322449858SCodrin Ciubotariu 		}
118422449858SCodrin Ciubotariu 	} else {
118522449858SCodrin Ciubotariu 		/* If administrative down, skip */
118622449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
118722449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
118822449858SCodrin Ciubotariu 	}
118922449858SCodrin Ciubotariu 
119022449858SCodrin Ciubotariu 	/* reset FDB port and VLAN FDB selection */
119122449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
119222449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
119322449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
119422449858SCodrin Ciubotariu }
119522449858SCodrin Ciubotariu 
119622449858SCodrin Ciubotariu /* Add a static FDB entry */
119722449858SCodrin Ciubotariu static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid)
119822449858SCodrin Ciubotariu {
119922449858SCodrin Ciubotariu 	u32 val;
120022449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
120122449858SCodrin Ciubotariu 
120222449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
120322449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
120422449858SCodrin Ciubotariu 
120522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
120622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
120722449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
120822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
120922449858SCodrin Ciubotariu 
121022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
121122449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
121222449858SCodrin Ciubotariu 		 (mac[5] << 0));
121322449858SCodrin Ciubotariu 
121422449858SCodrin Ciubotariu 	/* set on which port is the MAC address added */
121522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
121622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no);
121722449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mac_access, val);
121822449858SCodrin Ciubotariu 
121922449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0)
122022449858SCodrin Ciubotariu 		return -1;
122122449858SCodrin Ciubotariu 
122222449858SCodrin Ciubotariu 	/* check if the MAC address was indeed added */
122322449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
122422449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
122522449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
122622449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
122722449858SCodrin Ciubotariu 
122822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
122922449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
123022449858SCodrin Ciubotariu 		 (mac[5] << 0));
123122449858SCodrin Ciubotariu 
123222449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0)
123322449858SCodrin Ciubotariu 		return -1;
123422449858SCodrin Ciubotariu 
123522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
123622449858SCodrin Ciubotariu 
123722449858SCodrin Ciubotariu 	if ((port_no != bitfield_extract_by_mask(val,
123822449858SCodrin Ciubotariu 						 VSC9953_MAC_DESTIDX_MASK))) {
123922449858SCodrin Ciubotariu 		printf("Failed to add MAC address\n");
124022449858SCodrin Ciubotariu 		return -1;
124122449858SCodrin Ciubotariu 	}
124222449858SCodrin Ciubotariu 	return 0;
124322449858SCodrin Ciubotariu }
124422449858SCodrin Ciubotariu 
124522449858SCodrin Ciubotariu /* Delete a FDB entry */
124622449858SCodrin Ciubotariu static int vsc9953_mac_table_del(uchar mac[6], u16 vid)
124722449858SCodrin Ciubotariu {
124822449858SCodrin Ciubotariu 	u32 val;
124922449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
125022449858SCodrin Ciubotariu 
125122449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
125222449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
125322449858SCodrin Ciubotariu 
125422449858SCodrin Ciubotariu 	/* check first if MAC entry is present */
125522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
125622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
125722449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
125822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
125922449858SCodrin Ciubotariu 
126022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
126122449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
126222449858SCodrin Ciubotariu 		 (mac[5] << 0));
126322449858SCodrin Ciubotariu 
126422449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
126522449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
126622449858SCodrin Ciubotariu 		return -1;
126722449858SCodrin Ciubotariu 	}
126822449858SCodrin Ciubotariu 
126922449858SCodrin Ciubotariu 	if (!(in_le32(&l2ana_reg->ana_tables.mac_access) &
127022449858SCodrin Ciubotariu 	      VSC9953_MAC_CMD_VALID)) {
127122449858SCodrin Ciubotariu 		printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ",
127222449858SCodrin Ciubotariu 		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
127322449858SCodrin Ciubotariu 		printf("VLAN: %d does not exist.\n", vid);
127422449858SCodrin Ciubotariu 		return -1;
127522449858SCodrin Ciubotariu 	}
127622449858SCodrin Ciubotariu 
127722449858SCodrin Ciubotariu 	/* FDB entry found, proceed to delete */
127822449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
127922449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
128022449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
128122449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
128222449858SCodrin Ciubotariu 
128322449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
128422449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
128522449858SCodrin Ciubotariu 
128622449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0)
128722449858SCodrin Ciubotariu 		return -1;
128822449858SCodrin Ciubotariu 
128922449858SCodrin Ciubotariu 	/* check if the MAC entry is still in FDB */
129022449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
129122449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
129222449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
129322449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
129422449858SCodrin Ciubotariu 
129522449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
129622449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
129722449858SCodrin Ciubotariu 
129822449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
129922449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
130022449858SCodrin Ciubotariu 		return -1;
130122449858SCodrin Ciubotariu 	}
130222449858SCodrin Ciubotariu 	if (in_le32(&l2ana_reg->ana_tables.mac_access) &
130322449858SCodrin Ciubotariu 	    VSC9953_MAC_CMD_VALID) {
130422449858SCodrin Ciubotariu 		printf("Failed to delete MAC address\n");
130522449858SCodrin Ciubotariu 		return -1;
130622449858SCodrin Ciubotariu 	}
130722449858SCodrin Ciubotariu 
130822449858SCodrin Ciubotariu 	return 0;
130922449858SCodrin Ciubotariu }
131022449858SCodrin Ciubotariu 
131122449858SCodrin Ciubotariu /* age the unlocked entries in FDB */
131222449858SCodrin Ciubotariu static void vsc9953_mac_table_age(int port_no, int vid)
131322449858SCodrin Ciubotariu {
131422449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
131522449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
131622449858SCodrin Ciubotariu 	u32 val;
131722449858SCodrin Ciubotariu 	int i;
131822449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
131922449858SCodrin Ciubotariu 
132022449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
132122449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
132222449858SCodrin Ciubotariu 
132322449858SCodrin Ciubotariu 	/* set port and VID for selective aging */
132422449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
132522449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
132622449858SCodrin Ciubotariu 		/* disable auto learning */
132722449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
132822449858SCodrin Ciubotariu 							  &mode[port_no]);
132922449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
133022449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
133122449858SCodrin Ciubotariu 
133222449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
133322449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
133422449858SCodrin Ciubotariu 	} else {
133522449858SCodrin Ciubotariu 		/* disable auto learning on all ports */
133622449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
133722449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
133822449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
133922449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
134022449858SCodrin Ciubotariu 		}
134122449858SCodrin Ciubotariu 	}
134222449858SCodrin Ciubotariu 
134322449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
134422449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) |
134522449858SCodrin Ciubotariu 		      VSC9953_AGE_VID_EN;
134622449858SCodrin Ciubotariu 	}
134722449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
134822449858SCodrin Ciubotariu 
134922449858SCodrin Ciubotariu 	/* age the dynamic FDB entries */
135022449858SCodrin Ciubotariu 	vsc9953_mac_table_cmd(MAC_TABLE_AGE);
135122449858SCodrin Ciubotariu 
135222449858SCodrin Ciubotariu 	/* clear previously set port and VID */
135322449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
135422449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
135522449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
135622449858SCodrin Ciubotariu 
135722449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
135822449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
135922449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
136022449858SCodrin Ciubotariu 	} else {
136122449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
136222449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
136322449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
136422449858SCodrin Ciubotariu 		}
136522449858SCodrin Ciubotariu 	}
136622449858SCodrin Ciubotariu }
136722449858SCodrin Ciubotariu 
136822449858SCodrin Ciubotariu /* Delete all the dynamic FDB entries */
136922449858SCodrin Ciubotariu static void vsc9953_mac_table_flush(int port, int vid)
137022449858SCodrin Ciubotariu {
137122449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
137222449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
137322449858SCodrin Ciubotariu }
137422449858SCodrin Ciubotariu 
1375a2477924SCodrin Ciubotariu enum egress_vlan_tag {
1376a2477924SCodrin Ciubotariu 	EGR_TAG_CLASS = 0,
1377a2477924SCodrin Ciubotariu 	EGR_TAG_PVID,
1378a2477924SCodrin Ciubotariu };
1379a2477924SCodrin Ciubotariu 
1380a2477924SCodrin Ciubotariu /* Set egress tag mode for a VSC9953 port */
1381a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_set(int port_no,
1382a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag mode)
1383a2477924SCodrin Ciubotariu {
1384a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1385a2477924SCodrin Ciubotariu 
1386a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1387a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1388a2477924SCodrin Ciubotariu 
1389a2477924SCodrin Ciubotariu 	switch (mode) {
1390a2477924SCodrin Ciubotariu 	case EGR_TAG_CLASS:
1391a2477924SCodrin Ciubotariu 		clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1392a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1393a2477924SCodrin Ciubotariu 		break;
1394a2477924SCodrin Ciubotariu 	case EGR_TAG_PVID:
1395a2477924SCodrin Ciubotariu 		setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1396a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1397a2477924SCodrin Ciubotariu 		break;
1398a2477924SCodrin Ciubotariu 	default:
1399a2477924SCodrin Ciubotariu 		printf("Unknown egress VLAN tag mode for port %d\n", port_no);
1400a2477924SCodrin Ciubotariu 	}
1401a2477924SCodrin Ciubotariu }
1402a2477924SCodrin Ciubotariu 
1403a2477924SCodrin Ciubotariu /* Get egress tag mode for a VSC9953 port */
1404a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_get(int port_no,
1405a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag *mode)
1406a2477924SCodrin Ciubotariu {
1407a2477924SCodrin Ciubotariu 	u32 val;
1408a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1409a2477924SCodrin Ciubotariu 
1410a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1411a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1412a2477924SCodrin Ciubotariu 
1413a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
1414a2477924SCodrin Ciubotariu 	if (val & VSC9953_TAG_VID_PVID)
1415a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_PVID;
1416a2477924SCodrin Ciubotariu 	else
1417a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_CLASS;
1418a2477924SCodrin Ciubotariu }
1419a2477924SCodrin Ciubotariu 
142021d214fcSCodrin Ciubotariu /* VSC9953 VLAN learning modes */
142121d214fcSCodrin Ciubotariu enum vlan_learning_mode {
142221d214fcSCodrin Ciubotariu 	SHARED_VLAN_LEARNING,
142321d214fcSCodrin Ciubotariu 	PRIVATE_VLAN_LEARNING,
142421d214fcSCodrin Ciubotariu };
142521d214fcSCodrin Ciubotariu 
142621d214fcSCodrin Ciubotariu /* Set VLAN learning mode for VSC9953 */
142721d214fcSCodrin Ciubotariu static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)
142821d214fcSCodrin Ciubotariu {
142921d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
143021d214fcSCodrin Ciubotariu 
143121d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
143221d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
143321d214fcSCodrin Ciubotariu 
143421d214fcSCodrin Ciubotariu 	switch (lrn_mode) {
143521d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
143621d214fcSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
143721d214fcSCodrin Ciubotariu 		break;
143821d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
143921d214fcSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
144021d214fcSCodrin Ciubotariu 		break;
144121d214fcSCodrin Ciubotariu 	default:
144221d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learn mode\n");
144321d214fcSCodrin Ciubotariu 	}
144421d214fcSCodrin Ciubotariu }
144521d214fcSCodrin Ciubotariu 
144621d214fcSCodrin Ciubotariu /* Get VLAN learning mode for VSC9953 */
144721d214fcSCodrin Ciubotariu static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode)
144821d214fcSCodrin Ciubotariu {
144921d214fcSCodrin Ciubotariu 	u32 val;
145021d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
145121d214fcSCodrin Ciubotariu 
145221d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
145321d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
145421d214fcSCodrin Ciubotariu 
145521d214fcSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.agen_ctrl);
145621d214fcSCodrin Ciubotariu 
145721d214fcSCodrin Ciubotariu 	if (!(val & VSC9953_FID_MASK_ALL)) {
145821d214fcSCodrin Ciubotariu 		*lrn_mode = PRIVATE_VLAN_LEARNING;
145921d214fcSCodrin Ciubotariu 	} else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) {
146021d214fcSCodrin Ciubotariu 		*lrn_mode = SHARED_VLAN_LEARNING;
146121d214fcSCodrin Ciubotariu 	} else {
146221d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
146321d214fcSCodrin Ciubotariu 		return -EINVAL;
146421d214fcSCodrin Ciubotariu 	}
146521d214fcSCodrin Ciubotariu 
146621d214fcSCodrin Ciubotariu 	return 0;
146721d214fcSCodrin Ciubotariu }
146821d214fcSCodrin Ciubotariu 
14695ed1bacdSCodrin Ciubotariu /* Enable/disable VLAN ingress filtering on a VSC9953 port */
14705ed1bacdSCodrin Ciubotariu static void vsc9953_port_ingress_filtering_set(int port_no, int enabled)
14715ed1bacdSCodrin Ciubotariu {
14725ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
14735ed1bacdSCodrin Ciubotariu 
14745ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
14755ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
14765ed1bacdSCodrin Ciubotariu 
14775ed1bacdSCodrin Ciubotariu 	if (enabled)
14785ed1bacdSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
14795ed1bacdSCodrin Ciubotariu 	else
14805ed1bacdSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
14815ed1bacdSCodrin Ciubotariu }
14825ed1bacdSCodrin Ciubotariu 
14835ed1bacdSCodrin Ciubotariu /* Return VLAN ingress filtering on a VSC9953 port */
14845ed1bacdSCodrin Ciubotariu static int vsc9953_port_ingress_filtering_get(int port_no)
14855ed1bacdSCodrin Ciubotariu {
14865ed1bacdSCodrin Ciubotariu 	u32 val;
14875ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
14885ed1bacdSCodrin Ciubotariu 
14895ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
14905ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
14915ed1bacdSCodrin Ciubotariu 
14925ed1bacdSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.vlan_mask);
14935ed1bacdSCodrin Ciubotariu 	return !!(val & (1 << port_no));
14945ed1bacdSCodrin Ciubotariu }
14955ed1bacdSCodrin Ciubotariu 
149624a23debSCodrin Ciubotariu static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
149724a23debSCodrin Ciubotariu {
149824a23debSCodrin Ciubotariu 	int i;
149924a23debSCodrin Ciubotariu 	u8 enabled;
150024a23debSCodrin Ciubotariu 
150124a23debSCodrin Ciubotariu 	/* Last keyword should tell us if we should enable/disable the port */
150224a23debSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
150324a23debSCodrin Ciubotariu 	    ethsw_id_enable)
150424a23debSCodrin Ciubotariu 		enabled = 1;
150524a23debSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
150624a23debSCodrin Ciubotariu 		 ethsw_id_disable)
150724a23debSCodrin Ciubotariu 		enabled = 0;
150824a23debSCodrin Ciubotariu 	else
150924a23debSCodrin Ciubotariu 		return CMD_RET_USAGE;
151024a23debSCodrin Ciubotariu 
151124a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
151224a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
151324a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
151424a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
151524a23debSCodrin Ciubotariu 		}
151624a23debSCodrin Ciubotariu 		vsc9953_port_status_set(parsed_cmd->port, enabled);
151724a23debSCodrin Ciubotariu 	} else {
151824a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
151924a23debSCodrin Ciubotariu 			vsc9953_port_status_set(i, enabled);
152024a23debSCodrin Ciubotariu 	}
152124a23debSCodrin Ciubotariu 
152224a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
152324a23debSCodrin Ciubotariu }
152424a23debSCodrin Ciubotariu 
152524a23debSCodrin Ciubotariu static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd)
152624a23debSCodrin Ciubotariu {
152724a23debSCodrin Ciubotariu 	int i;
152824a23debSCodrin Ciubotariu 
152924a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
153024a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
153124a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
153224a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
153324a23debSCodrin Ciubotariu 		}
153424a23debSCodrin Ciubotariu 		vsc9953_phy_autoneg(parsed_cmd->port);
153524a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
153624a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed",
153724a23debSCodrin Ciubotariu 		       "Duplex");
153824a23debSCodrin Ciubotariu 		vsc9953_port_config_show(parsed_cmd->port);
153924a23debSCodrin Ciubotariu 
154024a23debSCodrin Ciubotariu 	} else {
154124a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
154224a23debSCodrin Ciubotariu 			vsc9953_phy_autoneg(i);
154324a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
154424a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed", "Duplex");
154524a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
154624a23debSCodrin Ciubotariu 			vsc9953_port_config_show(i);
154724a23debSCodrin Ciubotariu 	}
154824a23debSCodrin Ciubotariu 
154924a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
155024a23debSCodrin Ciubotariu }
155124a23debSCodrin Ciubotariu 
155286719f0cSCodrin Ciubotariu static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd)
155386719f0cSCodrin Ciubotariu {
155486719f0cSCodrin Ciubotariu 	int i;
155586719f0cSCodrin Ciubotariu 
155686719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
155786719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
155886719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
155986719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
156086719f0cSCodrin Ciubotariu 		}
156186719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_show(parsed_cmd->port);
156286719f0cSCodrin Ciubotariu 	} else {
156386719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
156486719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_show(i);
156586719f0cSCodrin Ciubotariu 	}
156686719f0cSCodrin Ciubotariu 
156786719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
156886719f0cSCodrin Ciubotariu }
156986719f0cSCodrin Ciubotariu 
157086719f0cSCodrin Ciubotariu static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def
157186719f0cSCodrin Ciubotariu 					     *parsed_cmd)
157286719f0cSCodrin Ciubotariu {
157386719f0cSCodrin Ciubotariu 	int i;
157486719f0cSCodrin Ciubotariu 
157586719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
157686719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
157786719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
157886719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
157986719f0cSCodrin Ciubotariu 		}
158086719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_clear(parsed_cmd->port);
158186719f0cSCodrin Ciubotariu 	} else {
158286719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
158386719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_clear(i);
158486719f0cSCodrin Ciubotariu 	}
158586719f0cSCodrin Ciubotariu 
158686719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
158786719f0cSCodrin Ciubotariu }
158886719f0cSCodrin Ciubotariu 
158968c929daSCodrin Ciubotariu static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd)
159068c929daSCodrin Ciubotariu {
159168c929daSCodrin Ciubotariu 	int i;
159268c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
159368c929daSCodrin Ciubotariu 
159468c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
159568c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
159668c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
159768c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
159868c929daSCodrin Ciubotariu 		}
159968c929daSCodrin Ciubotariu 		if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode))
160068c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
160168c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
160268c929daSCodrin Ciubotariu 		switch (mode) {
160368c929daSCodrin Ciubotariu 		case PORT_LEARN_NONE:
160468c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "disable");
160568c929daSCodrin Ciubotariu 			break;
160668c929daSCodrin Ciubotariu 		case PORT_LEARN_AUTO:
160768c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "auto");
160868c929daSCodrin Ciubotariu 			break;
160968c929daSCodrin Ciubotariu 		default:
161068c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "-");
161168c929daSCodrin Ciubotariu 		}
161268c929daSCodrin Ciubotariu 	} else {
161368c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
161468c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
161568c929daSCodrin Ciubotariu 			if (vsc9953_port_learn_mode_get(i, &mode))
161668c929daSCodrin Ciubotariu 				continue;
161768c929daSCodrin Ciubotariu 			switch (mode) {
161868c929daSCodrin Ciubotariu 			case PORT_LEARN_NONE:
161968c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "disable");
162068c929daSCodrin Ciubotariu 				break;
162168c929daSCodrin Ciubotariu 			case PORT_LEARN_AUTO:
162268c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "auto");
162368c929daSCodrin Ciubotariu 				break;
162468c929daSCodrin Ciubotariu 			default:
162568c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "-");
162668c929daSCodrin Ciubotariu 			}
162768c929daSCodrin Ciubotariu 		}
162868c929daSCodrin Ciubotariu 	}
162968c929daSCodrin Ciubotariu 
163068c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
163168c929daSCodrin Ciubotariu }
163268c929daSCodrin Ciubotariu 
163368c929daSCodrin Ciubotariu static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
163468c929daSCodrin Ciubotariu {
163568c929daSCodrin Ciubotariu 	int i;
163668c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
163768c929daSCodrin Ciubotariu 
163868c929daSCodrin Ciubotariu 	/* Last keyword should tell us the learn mode */
163968c929daSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
164068c929daSCodrin Ciubotariu 	    ethsw_id_auto)
164168c929daSCodrin Ciubotariu 		mode = PORT_LEARN_AUTO;
164268c929daSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
164368c929daSCodrin Ciubotariu 		 ethsw_id_disable)
164468c929daSCodrin Ciubotariu 		mode = PORT_LEARN_NONE;
164568c929daSCodrin Ciubotariu 	else
164668c929daSCodrin Ciubotariu 		return CMD_RET_USAGE;
164768c929daSCodrin Ciubotariu 
164868c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
164968c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
165068c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
165168c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
165268c929daSCodrin Ciubotariu 		}
165368c929daSCodrin Ciubotariu 		vsc9953_port_learn_mode_set(parsed_cmd->port, mode);
165468c929daSCodrin Ciubotariu 	} else {
165568c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
165668c929daSCodrin Ciubotariu 			vsc9953_port_learn_mode_set(i, mode);
165768c929daSCodrin Ciubotariu 	}
165868c929daSCodrin Ciubotariu 
165968c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
166068c929daSCodrin Ciubotariu }
166168c929daSCodrin Ciubotariu 
166222449858SCodrin Ciubotariu static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd)
166322449858SCodrin Ciubotariu {
166422449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
166522449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
166622449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
166722449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
166822449858SCodrin Ciubotariu 	}
166922449858SCodrin Ciubotariu 
167022449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
167122449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
167222449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
167322449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
167422449858SCodrin Ciubotariu 	}
167522449858SCodrin Ciubotariu 
167622449858SCodrin Ciubotariu 	vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid);
167722449858SCodrin Ciubotariu 
167822449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
167922449858SCodrin Ciubotariu }
168022449858SCodrin Ciubotariu 
168122449858SCodrin Ciubotariu static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd)
168222449858SCodrin Ciubotariu {
168322449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
168422449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
168522449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
168622449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
168722449858SCodrin Ciubotariu 	}
168822449858SCodrin Ciubotariu 
168922449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
169022449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
169122449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
169222449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
169322449858SCodrin Ciubotariu 	}
169422449858SCodrin Ciubotariu 
169522449858SCodrin Ciubotariu 	vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid);
169622449858SCodrin Ciubotariu 
169722449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
169822449858SCodrin Ciubotariu }
169922449858SCodrin Ciubotariu 
170022449858SCodrin Ciubotariu static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd)
170122449858SCodrin Ciubotariu {
170222449858SCodrin Ciubotariu 	int vid;
170322449858SCodrin Ciubotariu 
170422449858SCodrin Ciubotariu 	/* a port number must be present */
170522449858SCodrin Ciubotariu 	if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) {
170622449858SCodrin Ciubotariu 		printf("Please specify a port\n");
170722449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
170822449858SCodrin Ciubotariu 	}
170922449858SCodrin Ciubotariu 
171022449858SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
171122449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
171222449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
171322449858SCodrin Ciubotariu 	}
171422449858SCodrin Ciubotariu 
171522449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
171622449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
171722449858SCodrin Ciubotariu 
171822449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
171922449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
172022449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
172122449858SCodrin Ciubotariu 	}
172222449858SCodrin Ciubotariu 
172322449858SCodrin Ciubotariu 	if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid))
172422449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
172522449858SCodrin Ciubotariu 
172622449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
172722449858SCodrin Ciubotariu }
172822449858SCodrin Ciubotariu 
172922449858SCodrin Ciubotariu static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd)
173022449858SCodrin Ciubotariu {
173122449858SCodrin Ciubotariu 	int vid;
173222449858SCodrin Ciubotariu 
173322449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
173422449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
173522449858SCodrin Ciubotariu 
173622449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
173722449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
173822449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
173922449858SCodrin Ciubotariu 	}
174022449858SCodrin Ciubotariu 
174122449858SCodrin Ciubotariu 	if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid))
174222449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
174322449858SCodrin Ciubotariu 
174422449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
174522449858SCodrin Ciubotariu }
174622449858SCodrin Ciubotariu 
1747a2477924SCodrin Ciubotariu static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd)
1748a2477924SCodrin Ciubotariu {
1749a2477924SCodrin Ciubotariu 	int i;
1750a2477924SCodrin Ciubotariu 	int pvid;
1751a2477924SCodrin Ciubotariu 
1752a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1753a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1754a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1755a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1756a2477924SCodrin Ciubotariu 		}
1757a2477924SCodrin Ciubotariu 
1758a2477924SCodrin Ciubotariu 		if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid))
1759a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1760a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
1761a2477924SCodrin Ciubotariu 		printf("%7d %7d\n", parsed_cmd->port, pvid);
1762a2477924SCodrin Ciubotariu 	} else {
1763a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
1764a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1765a2477924SCodrin Ciubotariu 			if (vsc9953_port_vlan_pvid_get(i, &pvid))
1766a2477924SCodrin Ciubotariu 				continue;
1767a2477924SCodrin Ciubotariu 			printf("%7d %7d\n", i, pvid);
1768a2477924SCodrin Ciubotariu 		}
1769a2477924SCodrin Ciubotariu 	}
1770a2477924SCodrin Ciubotariu 
1771a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1772a2477924SCodrin Ciubotariu }
1773a2477924SCodrin Ciubotariu 
1774a2477924SCodrin Ciubotariu static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd)
1775a2477924SCodrin Ciubotariu {
1776a2477924SCodrin Ciubotariu 	/* PVID number should be set in parsed_cmd->vid */
1777a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
1778a2477924SCodrin Ciubotariu 		printf("Please set a pvid value\n");
1779a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
1780a2477924SCodrin Ciubotariu 	}
1781a2477924SCodrin Ciubotariu 
1782a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
1783a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
1784a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
1785a2477924SCodrin Ciubotariu 	}
1786a2477924SCodrin Ciubotariu 
1787a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1788a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1789a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1790a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1791a2477924SCodrin Ciubotariu 		}
1792a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid);
1793a2477924SCodrin Ciubotariu 	} else {
1794a2477924SCodrin Ciubotariu 		vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid);
1795a2477924SCodrin Ciubotariu 	}
1796a2477924SCodrin Ciubotariu 
1797a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1798a2477924SCodrin Ciubotariu }
1799a2477924SCodrin Ciubotariu 
1800a2477924SCodrin Ciubotariu static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd)
1801a2477924SCodrin Ciubotariu {
1802a2477924SCodrin Ciubotariu 	int i;
1803a2477924SCodrin Ciubotariu 
1804a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1805a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1806a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1807a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1808a2477924SCodrin Ciubotariu 		}
1809a2477924SCodrin Ciubotariu 		vsc9953_vlan_membership_show(parsed_cmd->port);
1810a2477924SCodrin Ciubotariu 	} else {
1811a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1812a2477924SCodrin Ciubotariu 			vsc9953_vlan_membership_show(i);
1813a2477924SCodrin Ciubotariu 	}
1814a2477924SCodrin Ciubotariu 
1815a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1816a2477924SCodrin Ciubotariu }
1817a2477924SCodrin Ciubotariu 
1818a2477924SCodrin Ciubotariu static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd)
1819a2477924SCodrin Ciubotariu {
1820a2477924SCodrin Ciubotariu 	int i;
1821a2477924SCodrin Ciubotariu 	int add;
1822a2477924SCodrin Ciubotariu 
1823a2477924SCodrin Ciubotariu 	/* VLAN should be set in parsed_cmd->vid */
1824a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
1825a2477924SCodrin Ciubotariu 		printf("Please set a vlan value\n");
1826a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
1827a2477924SCodrin Ciubotariu 	}
1828a2477924SCodrin Ciubotariu 
1829a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
1830a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
1831a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
1832a2477924SCodrin Ciubotariu 	}
1833a2477924SCodrin Ciubotariu 
1834a2477924SCodrin Ciubotariu 	/* keywords add/delete should be the last but one in array */
1835a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
1836a2477924SCodrin Ciubotariu 	    ethsw_id_add)
1837a2477924SCodrin Ciubotariu 		add = 1;
1838a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
1839a2477924SCodrin Ciubotariu 		 ethsw_id_del)
1840a2477924SCodrin Ciubotariu 		add = 0;
1841a2477924SCodrin Ciubotariu 	else
1842a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
1843a2477924SCodrin Ciubotariu 
1844a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1845a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1846a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1847a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1848a2477924SCodrin Ciubotariu 		}
1849a2477924SCodrin Ciubotariu 		vsc9953_vlan_table_membership_set(parsed_cmd->vid,
1850a2477924SCodrin Ciubotariu 						  parsed_cmd->port, add);
1851a2477924SCodrin Ciubotariu 	} else {
1852a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1853a2477924SCodrin Ciubotariu 			vsc9953_vlan_table_membership_set(parsed_cmd->vid, i,
1854a2477924SCodrin Ciubotariu 							  add);
1855a2477924SCodrin Ciubotariu 	}
1856a2477924SCodrin Ciubotariu 
1857a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1858a2477924SCodrin Ciubotariu }
1859a2477924SCodrin Ciubotariu static int vsc9953_port_untag_show_key_func(
1860a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
1861a2477924SCodrin Ciubotariu {
1862a2477924SCodrin Ciubotariu 	int i;
1863a2477924SCodrin Ciubotariu 
1864a2477924SCodrin Ciubotariu 	printf("%7s\t%17s\n", "Port", "Untag");
1865a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1866a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1867a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1868a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1869a2477924SCodrin Ciubotariu 		}
1870a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_show(parsed_cmd->port);
1871a2477924SCodrin Ciubotariu 	} else {
1872a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1873a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_show(i);
1874a2477924SCodrin Ciubotariu 	}
1875a2477924SCodrin Ciubotariu 
1876a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1877a2477924SCodrin Ciubotariu }
1878a2477924SCodrin Ciubotariu 
1879a2477924SCodrin Ciubotariu static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd)
1880a2477924SCodrin Ciubotariu {
1881a2477924SCodrin Ciubotariu 	int i;
1882a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
1883a2477924SCodrin Ciubotariu 
1884a2477924SCodrin Ciubotariu 	/* keywords for the untagged mode are the last in the array */
1885a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1886a2477924SCodrin Ciubotariu 	    ethsw_id_all)
1887a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_ALL;
1888a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1889a2477924SCodrin Ciubotariu 		 ethsw_id_none)
1890a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_NONE;
1891a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1892a2477924SCodrin Ciubotariu 		 ethsw_id_pvid)
1893a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_PVID_AND_ZERO;
1894a2477924SCodrin Ciubotariu 	else
1895a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
1896a2477924SCodrin Ciubotariu 
1897a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1898a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1899a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1900a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1901a2477924SCodrin Ciubotariu 		}
1902a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode);
1903a2477924SCodrin Ciubotariu 	} else {
1904a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1905a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_set(i, mode);
1906a2477924SCodrin Ciubotariu 	}
1907a2477924SCodrin Ciubotariu 
1908a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1909a2477924SCodrin Ciubotariu }
1910a2477924SCodrin Ciubotariu 
1911a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_show_key_func(
1912a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
1913a2477924SCodrin Ciubotariu {
1914a2477924SCodrin Ciubotariu 	int i;
1915a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
1916a2477924SCodrin Ciubotariu 
1917a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1918a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1919a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1920a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1921a2477924SCodrin Ciubotariu 		}
1922a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode);
1923a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
1924a2477924SCodrin Ciubotariu 		printf("%7d\t", parsed_cmd->port);
1925a2477924SCodrin Ciubotariu 		switch (mode) {
1926a2477924SCodrin Ciubotariu 		case EGR_TAG_CLASS:
1927a2477924SCodrin Ciubotariu 			printf("%12s\n", "classified");
1928a2477924SCodrin Ciubotariu 			break;
1929a2477924SCodrin Ciubotariu 		case EGR_TAG_PVID:
1930a2477924SCodrin Ciubotariu 			printf("%12s\n", "pvid");
1931a2477924SCodrin Ciubotariu 			break;
1932a2477924SCodrin Ciubotariu 		default:
1933a2477924SCodrin Ciubotariu 			printf("%12s\n", "-");
1934a2477924SCodrin Ciubotariu 		}
1935a2477924SCodrin Ciubotariu 	} else {
1936a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
1937a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1938a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_get(i, &mode);
1939a2477924SCodrin Ciubotariu 			switch (mode) {
1940a2477924SCodrin Ciubotariu 			case EGR_TAG_CLASS:
1941a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "classified");
1942a2477924SCodrin Ciubotariu 				break;
1943a2477924SCodrin Ciubotariu 			case EGR_TAG_PVID:
1944a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "pvid");
1945a2477924SCodrin Ciubotariu 				break;
1946a2477924SCodrin Ciubotariu 			default:
1947a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "-");
1948a2477924SCodrin Ciubotariu 			}
1949a2477924SCodrin Ciubotariu 		}
1950a2477924SCodrin Ciubotariu 	}
1951a2477924SCodrin Ciubotariu 
1952a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1953a2477924SCodrin Ciubotariu }
1954a2477924SCodrin Ciubotariu 
1955a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_set_key_func(
1956a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
1957a2477924SCodrin Ciubotariu {
1958a2477924SCodrin Ciubotariu 	int i;
1959a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
1960a2477924SCodrin Ciubotariu 
1961a2477924SCodrin Ciubotariu 	/* keywords for the egress vlan tag mode are the last in the array */
1962a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1963a2477924SCodrin Ciubotariu 	    ethsw_id_pvid)
1964a2477924SCodrin Ciubotariu 		mode = EGR_TAG_PVID;
1965a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1966a2477924SCodrin Ciubotariu 		 ethsw_id_classified)
1967a2477924SCodrin Ciubotariu 		mode = EGR_TAG_CLASS;
1968a2477924SCodrin Ciubotariu 	else
1969a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
1970a2477924SCodrin Ciubotariu 
1971a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1972a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1973a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
1974a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
1975a2477924SCodrin Ciubotariu 		}
1976a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode);
1977a2477924SCodrin Ciubotariu 	} else {
1978a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1979a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_set(i, mode);
1980a2477924SCodrin Ciubotariu 	}
1981a2477924SCodrin Ciubotariu 
1982a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
1983a2477924SCodrin Ciubotariu }
1984a2477924SCodrin Ciubotariu 
198521d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_show_key_func(
198621d214fcSCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
198721d214fcSCodrin Ciubotariu {
198821d214fcSCodrin Ciubotariu 	int rc;
198921d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
199021d214fcSCodrin Ciubotariu 
199121d214fcSCodrin Ciubotariu 	rc = vsc9953_vlan_learning_get(&mode);
199221d214fcSCodrin Ciubotariu 	if (rc)
199321d214fcSCodrin Ciubotariu 		return CMD_RET_FAILURE;
199421d214fcSCodrin Ciubotariu 
199521d214fcSCodrin Ciubotariu 	switch (mode) {
199621d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
199721d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: shared\n");
199821d214fcSCodrin Ciubotariu 		break;
199921d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
200021d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: private\n");
200121d214fcSCodrin Ciubotariu 		break;
200221d214fcSCodrin Ciubotariu 	default:
200321d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
200421d214fcSCodrin Ciubotariu 		rc = CMD_RET_FAILURE;
200521d214fcSCodrin Ciubotariu 	}
200621d214fcSCodrin Ciubotariu 
200721d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
200821d214fcSCodrin Ciubotariu }
200921d214fcSCodrin Ciubotariu 
201021d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
201121d214fcSCodrin Ciubotariu {
201221d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
201321d214fcSCodrin Ciubotariu 
201421d214fcSCodrin Ciubotariu 	/* keywords for shared/private are the last in the array */
201521d214fcSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
201621d214fcSCodrin Ciubotariu 	    ethsw_id_shared)
201721d214fcSCodrin Ciubotariu 		mode = SHARED_VLAN_LEARNING;
201821d214fcSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
201921d214fcSCodrin Ciubotariu 		 ethsw_id_private)
202021d214fcSCodrin Ciubotariu 		mode = PRIVATE_VLAN_LEARNING;
202121d214fcSCodrin Ciubotariu 	else
202221d214fcSCodrin Ciubotariu 		return CMD_RET_USAGE;
202321d214fcSCodrin Ciubotariu 
202421d214fcSCodrin Ciubotariu 	vsc9953_vlan_learning_set(mode);
202521d214fcSCodrin Ciubotariu 
202621d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
202721d214fcSCodrin Ciubotariu }
202821d214fcSCodrin Ciubotariu 
20295ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd)
20305ed1bacdSCodrin Ciubotariu {
20315ed1bacdSCodrin Ciubotariu 	int i;
20325ed1bacdSCodrin Ciubotariu 	int enabled;
20335ed1bacdSCodrin Ciubotariu 
20345ed1bacdSCodrin Ciubotariu 	printf("%7s\t%18s\n", "Port", "Ingress filtering");
20355ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
20365ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
20375ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
20385ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
20395ed1bacdSCodrin Ciubotariu 		}
20405ed1bacdSCodrin Ciubotariu 		enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port);
20415ed1bacdSCodrin Ciubotariu 		printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" :
20425ed1bacdSCodrin Ciubotariu 								  "disable");
20435ed1bacdSCodrin Ciubotariu 	} else {
20445ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
20455ed1bacdSCodrin Ciubotariu 			enabled = vsc9953_port_ingress_filtering_get(i);
20465ed1bacdSCodrin Ciubotariu 			printf("%7d\t%18s\n", parsed_cmd->port, enabled ?
20475ed1bacdSCodrin Ciubotariu 								"enable" :
20485ed1bacdSCodrin Ciubotariu 								"disable");
20495ed1bacdSCodrin Ciubotariu 		}
20505ed1bacdSCodrin Ciubotariu 	}
20515ed1bacdSCodrin Ciubotariu 
20525ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
20535ed1bacdSCodrin Ciubotariu }
20545ed1bacdSCodrin Ciubotariu 
20555ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
20565ed1bacdSCodrin Ciubotariu {
20575ed1bacdSCodrin Ciubotariu 	int i;
20585ed1bacdSCodrin Ciubotariu 	int enable;
20595ed1bacdSCodrin Ciubotariu 
20605ed1bacdSCodrin Ciubotariu 	/* keywords for enabling/disabling ingress filtering
20615ed1bacdSCodrin Ciubotariu 	 * are the last in the array
20625ed1bacdSCodrin Ciubotariu 	 */
20635ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
20645ed1bacdSCodrin Ciubotariu 	    ethsw_id_enable)
20655ed1bacdSCodrin Ciubotariu 		enable = 1;
20665ed1bacdSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
20675ed1bacdSCodrin Ciubotariu 		 ethsw_id_disable)
20685ed1bacdSCodrin Ciubotariu 		enable = 0;
20695ed1bacdSCodrin Ciubotariu 	else
20705ed1bacdSCodrin Ciubotariu 		return CMD_RET_USAGE;
20715ed1bacdSCodrin Ciubotariu 
20725ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
20735ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
20745ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
20755ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
20765ed1bacdSCodrin Ciubotariu 		}
20775ed1bacdSCodrin Ciubotariu 		vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable);
20785ed1bacdSCodrin Ciubotariu 	} else {
20795ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
20805ed1bacdSCodrin Ciubotariu 			vsc9953_port_ingress_filtering_set(i, enable);
20815ed1bacdSCodrin Ciubotariu 	}
20825ed1bacdSCodrin Ciubotariu 
20835ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
20845ed1bacdSCodrin Ciubotariu }
20855ed1bacdSCodrin Ciubotariu 
208624a23debSCodrin Ciubotariu static struct ethsw_command_func vsc9953_cmd_func = {
208724a23debSCodrin Ciubotariu 		.ethsw_name = "L2 Switch VSC9953",
208824a23debSCodrin Ciubotariu 		.port_enable = &vsc9953_port_status_key_func,
208924a23debSCodrin Ciubotariu 		.port_disable = &vsc9953_port_status_key_func,
209024a23debSCodrin Ciubotariu 		.port_show = &vsc9953_port_config_key_func,
209186719f0cSCodrin Ciubotariu 		.port_stats = &vsc9953_port_stats_key_func,
209286719f0cSCodrin Ciubotariu 		.port_stats_clear = &vsc9953_port_stats_clear_key_func,
209368c929daSCodrin Ciubotariu 		.port_learn = &vsc9953_learn_set_key_func,
209468c929daSCodrin Ciubotariu 		.port_learn_show = &vsc9953_learn_show_key_func,
209522449858SCodrin Ciubotariu 		.fdb_show = &vsc9953_fdb_show_key_func,
209622449858SCodrin Ciubotariu 		.fdb_flush = &vsc9953_fdb_flush_key_func,
209722449858SCodrin Ciubotariu 		.fdb_entry_add = &vsc9953_fdb_entry_add_key_func,
209822449858SCodrin Ciubotariu 		.fdb_entry_del = &vsc9953_fdb_entry_del_key_func,
2099a2477924SCodrin Ciubotariu 		.pvid_show = &vsc9953_pvid_show_key_func,
2100a2477924SCodrin Ciubotariu 		.pvid_set = &vsc9953_pvid_set_key_func,
2101a2477924SCodrin Ciubotariu 		.vlan_show = &vsc9953_vlan_show_key_func,
2102a2477924SCodrin Ciubotariu 		.vlan_set = &vsc9953_vlan_set_key_func,
2103a2477924SCodrin Ciubotariu 		.port_untag_show = &vsc9953_port_untag_show_key_func,
2104a2477924SCodrin Ciubotariu 		.port_untag_set = &vsc9953_port_untag_set_key_func,
2105a2477924SCodrin Ciubotariu 		.port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func,
2106a2477924SCodrin Ciubotariu 		.port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func,
210721d214fcSCodrin Ciubotariu 		.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
210821d214fcSCodrin Ciubotariu 		.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
21095ed1bacdSCodrin Ciubotariu 		.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
21105ed1bacdSCodrin Ciubotariu 		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
211124a23debSCodrin Ciubotariu };
211224a23debSCodrin Ciubotariu 
211324a23debSCodrin Ciubotariu #endif /* CONFIG_CMD_ETHSW */
211424a23debSCodrin Ciubotariu 
21159de05987SCodrin Ciubotariu /*****************************************************************************
21169de05987SCodrin Ciubotariu At startup, the default configuration would be:
21179de05987SCodrin Ciubotariu 	- HW learning enabled on all ports; (HW default)
21189de05987SCodrin Ciubotariu 	- All ports are in VLAN 1;
21199de05987SCodrin Ciubotariu 	- All ports are VLAN aware;
21209de05987SCodrin Ciubotariu 	- All ports have POP_COUNT 1;
21219de05987SCodrin Ciubotariu 	- All ports have PVID 1;
21229de05987SCodrin Ciubotariu 	- All ports have TPID 0x8100; (HW default)
21239de05987SCodrin Ciubotariu 	- All ports tag frames classified to all VLANs that are not PVID;
21249de05987SCodrin Ciubotariu *****************************************************************************/
21259de05987SCodrin Ciubotariu void vsc9953_default_configuration(void)
21269de05987SCodrin Ciubotariu {
21279de05987SCodrin Ciubotariu 	int i;
21289de05987SCodrin Ciubotariu 
2129*ba389e65SCodrin Ciubotariu 	if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
2130*ba389e65SCodrin Ciubotariu 		debug("VSC9953: failed to set AGE time to %d\n",
2131*ba389e65SCodrin Ciubotariu 		      VSC9953_DEFAULT_AGE_TIME);
2132*ba389e65SCodrin Ciubotariu 
21339de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_VLAN; i++)
21349de05987SCodrin Ciubotariu 		vsc9953_vlan_table_membership_all_set(i, 0);
21359de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_aware_set(1);
21369de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_pvid_set(1);
21379de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_poncnt_set(1);
21389de05987SCodrin Ciubotariu 	vsc9953_vlan_table_membership_all_set(1, 1);
21399de05987SCodrin Ciubotariu 	vsc9953_vlan_ingr_fltr_learn_drop(1);
21409de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
21419de05987SCodrin Ciubotariu }
21429de05987SCodrin Ciubotariu 
21436706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis)
21446706b115SCodrin Ciubotariu {
21453cc8cfffSCodrin Ciubotariu 	u32 i;
21463cc8cfffSCodrin Ciubotariu 	u32 hdx_cfg = 0;
21473cc8cfffSCodrin Ciubotariu 	u32 phy_addr = 0;
21486706b115SCodrin Ciubotariu 	int timeout;
21496706b115SCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
21506706b115SCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
21516706b115SCodrin Ciubotariu 	struct vsc9953_dev_gmii *l2dev_gmii_reg;
21526706b115SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
21536706b115SCodrin Ciubotariu 	struct vsc9953_devcpu_gcb *l2dev_gcb;
21546706b115SCodrin Ciubotariu 
21556706b115SCodrin Ciubotariu 	l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
21566706b115SCodrin Ciubotariu 			VSC9953_DEV_GMII_OFFSET);
21576706b115SCodrin Ciubotariu 
21586706b115SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
21596706b115SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
21606706b115SCodrin Ciubotariu 
21616706b115SCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
21626706b115SCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
21636706b115SCodrin Ciubotariu 
21646706b115SCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
21656706b115SCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
21666706b115SCodrin Ciubotariu 
21676706b115SCodrin Ciubotariu 	l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
21686706b115SCodrin Ciubotariu 			VSC9953_DEVCPU_GCB);
21696706b115SCodrin Ciubotariu 
21706706b115SCodrin Ciubotariu 	out_le32(&l2dev_gcb->chip_regs.soft_rst,
2171c4390486SCodrin Ciubotariu 		 VSC9953_SOFT_SWC_RST_ENA);
21726706b115SCodrin Ciubotariu 	timeout = 50000;
21736706b115SCodrin Ciubotariu 	while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
2174c4390486SCodrin Ciubotariu 			VSC9953_SOFT_SWC_RST_ENA) && --timeout)
21756706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 soft reset */
21766706b115SCodrin Ciubotariu 	if (timeout == 0)
21776706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 to reset\n");
21786706b115SCodrin Ciubotariu 
2179c4390486SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE |
2180c4390486SCodrin Ciubotariu 		 VSC9953_MEM_INIT);
21816706b115SCodrin Ciubotariu 
21826706b115SCodrin Ciubotariu 	timeout = 50000;
21836706b115SCodrin Ciubotariu 	while ((in_le32(&l2sys_reg->sys.reset_cfg) &
2184c4390486SCodrin Ciubotariu 		VSC9953_MEM_INIT) && --timeout)
21856706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 memory init */
21866706b115SCodrin Ciubotariu 	if (timeout == 0)
21876706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 memory to initialize\n");
21886706b115SCodrin Ciubotariu 
21896706b115SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
2190c4390486SCodrin Ciubotariu 			| VSC9953_CORE_ENABLE));
21916706b115SCodrin Ciubotariu 
21926706b115SCodrin Ciubotariu 	/* VSC9953 Setting to be done once only */
21936706b115SCodrin Ciubotariu 	out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
21946706b115SCodrin Ciubotariu 
21956706b115SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
21966706b115SCodrin Ciubotariu 		if (vsc9953_port_init(i))
21976706b115SCodrin Ciubotariu 			printf("Failed to initialize l2switch port %d\n", i);
21986706b115SCodrin Ciubotariu 
21996706b115SCodrin Ciubotariu 		/* Enable VSC9953 GMII Ports Port ID 0 - 7 */
22006706b115SCodrin Ciubotariu 		if (VSC9953_INTERNAL_PORT_CHECK(i)) {
22016706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2202c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC_QSGMII);
22036706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2204c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG_QSGMII);
22056706b115SCodrin Ciubotariu 		} else {
22066706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2207c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC);
22086706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2209c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG);
22106706b115SCodrin Ciubotariu 		}
22116706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
2212c4390486SCodrin Ciubotariu 			 VSC9953_CLOCK_CFG);
22136706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
2214c4390486SCodrin Ciubotariu 			 VSC9953_MAC_ENA_CFG);
22156706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
2216c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MODE_CFG);
22176706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
2218c4390486SCodrin Ciubotariu 			 VSC9953_MAC_IFG_CFG);
22196706b115SCodrin Ciubotariu 		/* mac_hdx_cfg varies with port id*/
2220c4390486SCodrin Ciubotariu 		hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16);
22216706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
22226706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->sys.front_port_mode[i],
2223c4390486SCodrin Ciubotariu 			 VSC9953_FRONT_PORT_MODE);
2224fe91095bSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[i],
2225c4390486SCodrin Ciubotariu 			     VSC9953_PORT_ENA);
22266706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
2227c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MAX_LEN);
22286706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
2229c4390486SCodrin Ciubotariu 			 VSC9953_PAUSE_CFG);
22306706b115SCodrin Ciubotariu 		/* WAIT FOR 2 us*/
22316706b115SCodrin Ciubotariu 		udelay(2);
22326706b115SCodrin Ciubotariu 
22336706b115SCodrin Ciubotariu 		l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(
22346706b115SCodrin Ciubotariu 				(char *)l2dev_gmii_reg
22356706b115SCodrin Ciubotariu 				+ T1040_SWITCH_GMII_DEV_OFFSET);
22366706b115SCodrin Ciubotariu 
22376706b115SCodrin Ciubotariu 		/* Initialize Lynx PHY Wrappers */
22386706b115SCodrin Ciubotariu 		phy_addr = 0;
22396706b115SCodrin Ciubotariu 		if (vsc9953_l2sw.port[i].enet_if ==
22406706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_QSGMII)
22416706b115SCodrin Ciubotariu 			phy_addr = (i + 0x4) & 0x1F;
22426706b115SCodrin Ciubotariu 		else if (vsc9953_l2sw.port[i].enet_if ==
22436706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_SGMII)
22446706b115SCodrin Ciubotariu 			phy_addr = (i + 1) & 0x1F;
22456706b115SCodrin Ciubotariu 
22466706b115SCodrin Ciubotariu 		if (phy_addr) {
22476706b115SCodrin Ciubotariu 			/* SGMII IF mode + AN enable */
22486706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
22496706b115SCodrin Ciubotariu 					   0x14, PHY_SGMII_IF_MODE_AN |
22506706b115SCodrin Ciubotariu 					   PHY_SGMII_IF_MODE_SGMII);
22516706b115SCodrin Ciubotariu 			/* Dev ability according to SGMII specification */
22526706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
22536706b115SCodrin Ciubotariu 					   0x4, PHY_SGMII_DEV_ABILITY_SGMII);
22546706b115SCodrin Ciubotariu 			/* Adjust link timer for SGMII
22556706b115SCodrin Ciubotariu 			 * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
22566706b115SCodrin Ciubotariu 			 */
22576706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
22586706b115SCodrin Ciubotariu 					   0x13, 0x0003);
22596706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
22606706b115SCodrin Ciubotariu 					   0x12, 0x0d40);
22616706b115SCodrin Ciubotariu 			/* Restart AN */
22626706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
22636706b115SCodrin Ciubotariu 					   0x0, PHY_SGMII_CR_DEF_VAL |
22646706b115SCodrin Ciubotariu 					   PHY_SGMII_CR_RESET_AN);
22656706b115SCodrin Ciubotariu 
22666706b115SCodrin Ciubotariu 			timeout = 50000;
22676706b115SCodrin Ciubotariu 			while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
22686706b115SCodrin Ciubotariu 					phy_addr, 0x01) & 0x0020) && --timeout)
22696706b115SCodrin Ciubotariu 				udelay(1); /* wait for AN to complete */
22706706b115SCodrin Ciubotariu 			if (timeout == 0)
22716706b115SCodrin Ciubotariu 				debug("Timeout waiting for AN to complete\n");
22726706b115SCodrin Ciubotariu 		}
22736706b115SCodrin Ciubotariu 	}
22746706b115SCodrin Ciubotariu 
22759de05987SCodrin Ciubotariu 	vsc9953_default_configuration();
22769de05987SCodrin Ciubotariu 
227724a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
227824a23debSCodrin Ciubotariu 	if (ethsw_define_functions(&vsc9953_cmd_func) < 0)
227924a23debSCodrin Ciubotariu 		debug("Unable to use \"ethsw\" commands\n");
228024a23debSCodrin Ciubotariu #endif
228124a23debSCodrin Ciubotariu 
22826706b115SCodrin Ciubotariu 	printf("VSC9953 L2 switch initialized\n");
22836706b115SCodrin Ciubotariu 	return;
22846706b115SCodrin Ciubotariu }
2285