xref: /openbmc/u-boot/drivers/net/vsc9953.c (revision 606fddd76c7a045c09d544357806b0b4de4845c7)
1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+
26706b115SCodrin Ciubotariu /*
3a857d5f8SCodrin Ciubotariu  *  Copyright 2014 - 2015 Freescale Semiconductor, Inc.
46706b115SCodrin Ciubotariu  *
56706b115SCodrin Ciubotariu  *  Driver for the Vitesse VSC9953 L2 Switch
66706b115SCodrin Ciubotariu  */
76706b115SCodrin Ciubotariu 
86706b115SCodrin Ciubotariu #include <asm/io.h>
96706b115SCodrin Ciubotariu #include <asm/fsl_serdes.h>
106706b115SCodrin Ciubotariu #include <fm_eth.h>
11cd348efaSShaohui Xie #include <fsl_memac.h>
129de05987SCodrin Ciubotariu #include <bitfield.h>
133cc8cfffSCodrin Ciubotariu #include <errno.h>
143cc8cfffSCodrin Ciubotariu #include <malloc.h>
156706b115SCodrin Ciubotariu #include <vsc9953.h>
1624a23debSCodrin Ciubotariu #include <ethsw.h>
176706b115SCodrin Ciubotariu 
186706b115SCodrin Ciubotariu static struct vsc9953_info vsc9953_l2sw = {
196706b115SCodrin Ciubotariu 		.port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
206706b115SCodrin Ciubotariu 		.port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
216706b115SCodrin Ciubotariu 		.port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
226706b115SCodrin Ciubotariu 		.port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
236706b115SCodrin Ciubotariu 		.port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
246706b115SCodrin Ciubotariu 		.port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
256706b115SCodrin Ciubotariu 		.port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
266706b115SCodrin Ciubotariu 		.port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
276706b115SCodrin Ciubotariu 		.port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
286706b115SCodrin Ciubotariu 		.port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
296706b115SCodrin Ciubotariu };
306706b115SCodrin Ciubotariu 
vsc9953_port_info_set_mdio(int port_no,struct mii_dev * bus)313cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus)
326706b115SCodrin Ciubotariu {
333cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
346706b115SCodrin Ciubotariu 		return;
356706b115SCodrin Ciubotariu 
363cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].bus = bus;
376706b115SCodrin Ciubotariu }
386706b115SCodrin Ciubotariu 
vsc9953_port_info_set_phy_address(int port_no,int address)393cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_address(int port_no, int address)
406706b115SCodrin Ciubotariu {
413cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
426706b115SCodrin Ciubotariu 		return;
436706b115SCodrin Ciubotariu 
443cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].phyaddr = address;
456706b115SCodrin Ciubotariu }
466706b115SCodrin Ciubotariu 
vsc9953_port_info_set_phy_int(int port_no,phy_interface_t phy_int)473cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int)
486706b115SCodrin Ciubotariu {
493cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
506706b115SCodrin Ciubotariu 		return;
516706b115SCodrin Ciubotariu 
523cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enet_if = phy_int;
536706b115SCodrin Ciubotariu }
546706b115SCodrin Ciubotariu 
vsc9953_port_enable(int port_no)553cc8cfffSCodrin Ciubotariu void vsc9953_port_enable(int port_no)
566706b115SCodrin Ciubotariu {
573cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
586706b115SCodrin Ciubotariu 		return;
596706b115SCodrin Ciubotariu 
603cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 1;
616706b115SCodrin Ciubotariu }
626706b115SCodrin Ciubotariu 
vsc9953_port_disable(int port_no)633cc8cfffSCodrin Ciubotariu void vsc9953_port_disable(int port_no)
646706b115SCodrin Ciubotariu {
653cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
666706b115SCodrin Ciubotariu 		return;
676706b115SCodrin Ciubotariu 
683cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 0;
696706b115SCodrin Ciubotariu }
706706b115SCodrin Ciubotariu 
vsc9953_mdio_write(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum,int value)716706b115SCodrin Ciubotariu static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
726706b115SCodrin Ciubotariu 		int regnum, int value)
736706b115SCodrin Ciubotariu {
746706b115SCodrin Ciubotariu 	int timeout = 50000;
756706b115SCodrin Ciubotariu 
766706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
776706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
786706b115SCodrin Ciubotariu 			(0x1 << 1));
796706b115SCodrin Ciubotariu 	asm("sync");
806706b115SCodrin Ciubotariu 
816706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
826706b115SCodrin Ciubotariu 		udelay(1);
836706b115SCodrin Ciubotariu 
846706b115SCodrin Ciubotariu 	if (timeout == 0)
856706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO write\n");
866706b115SCodrin Ciubotariu }
876706b115SCodrin Ciubotariu 
vsc9953_mdio_read(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum)886706b115SCodrin Ciubotariu static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
896706b115SCodrin Ciubotariu 		int regnum)
906706b115SCodrin Ciubotariu {
916706b115SCodrin Ciubotariu 	int value = 0xFFFF;
926706b115SCodrin Ciubotariu 	int timeout = 50000;
936706b115SCodrin Ciubotariu 
946706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
956706b115SCodrin Ciubotariu 		udelay(1);
966706b115SCodrin Ciubotariu 	if (timeout == 0) {
976706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO operation to finish\n");
986706b115SCodrin Ciubotariu 		return value;
996706b115SCodrin Ciubotariu 	}
1006706b115SCodrin Ciubotariu 
1016706b115SCodrin Ciubotariu 	/* Put the address of the phy, and the register
1026706b115SCodrin Ciubotariu 	 * number into MIICMD
1036706b115SCodrin Ciubotariu 	 */
1046706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
1056706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
1066706b115SCodrin Ciubotariu 			(0x2 << 1));
1076706b115SCodrin Ciubotariu 
1086706b115SCodrin Ciubotariu 	timeout = 50000;
1096706b115SCodrin Ciubotariu 	/* Wait for the the indication that the read is done */
1106706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
1116706b115SCodrin Ciubotariu 		udelay(1);
1126706b115SCodrin Ciubotariu 	if (timeout == 0)
1136706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO read\n");
1146706b115SCodrin Ciubotariu 
1156706b115SCodrin Ciubotariu 	/* Grab the value read from the PHY */
1166706b115SCodrin Ciubotariu 	value = in_le32(&phyregs->miimdata);
1176706b115SCodrin Ciubotariu 
1186706b115SCodrin Ciubotariu 	if ((value & 0x00030000) == 0)
1196706b115SCodrin Ciubotariu 		return value & 0x0000ffff;
1206706b115SCodrin Ciubotariu 
1216706b115SCodrin Ciubotariu 	return value;
1226706b115SCodrin Ciubotariu }
1236706b115SCodrin Ciubotariu 
init_phy(struct eth_device * dev)1246706b115SCodrin Ciubotariu static int init_phy(struct eth_device *dev)
1256706b115SCodrin Ciubotariu {
1266706b115SCodrin Ciubotariu 	struct vsc9953_port_info *l2sw_port = dev->priv;
1276706b115SCodrin Ciubotariu 	struct phy_device *phydev = NULL;
1286706b115SCodrin Ciubotariu 
1296706b115SCodrin Ciubotariu #ifdef CONFIG_PHYLIB
1306706b115SCodrin Ciubotariu 	if (!l2sw_port->bus)
1316706b115SCodrin Ciubotariu 		return 0;
1326706b115SCodrin Ciubotariu 	phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
1336706b115SCodrin Ciubotariu 			l2sw_port->enet_if);
1346706b115SCodrin Ciubotariu 	if (!phydev) {
1356706b115SCodrin Ciubotariu 		printf("Failed to connect\n");
1366706b115SCodrin Ciubotariu 		return -1;
1376706b115SCodrin Ciubotariu 	}
1386706b115SCodrin Ciubotariu 
1396706b115SCodrin Ciubotariu 	phydev->supported &= SUPPORTED_10baseT_Half |
1406706b115SCodrin Ciubotariu 			SUPPORTED_10baseT_Full |
1416706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Half |
1426706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Full |
1436706b115SCodrin Ciubotariu 			SUPPORTED_1000baseT_Full;
1446706b115SCodrin Ciubotariu 	phydev->advertising = phydev->supported;
1456706b115SCodrin Ciubotariu 
1466706b115SCodrin Ciubotariu 	l2sw_port->phydev = phydev;
1476706b115SCodrin Ciubotariu 
1486706b115SCodrin Ciubotariu 	phy_config(phydev);
1496706b115SCodrin Ciubotariu #endif
1506706b115SCodrin Ciubotariu 
1516706b115SCodrin Ciubotariu 	return 0;
1526706b115SCodrin Ciubotariu }
1536706b115SCodrin Ciubotariu 
vsc9953_port_init(int port_no)1543cc8cfffSCodrin Ciubotariu static int vsc9953_port_init(int port_no)
1556706b115SCodrin Ciubotariu {
1566706b115SCodrin Ciubotariu 	struct eth_device *dev;
1576706b115SCodrin Ciubotariu 
1586706b115SCodrin Ciubotariu 	/* Internal ports never have a PHY */
1593cc8cfffSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no))
1606706b115SCodrin Ciubotariu 		return 0;
1616706b115SCodrin Ciubotariu 
1626706b115SCodrin Ciubotariu 	/* alloc eth device */
1636706b115SCodrin Ciubotariu 	dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
1646706b115SCodrin Ciubotariu 	if (!dev)
1653cc8cfffSCodrin Ciubotariu 		return -ENOMEM;
1666706b115SCodrin Ciubotariu 
1673cc8cfffSCodrin Ciubotariu 	sprintf(dev->name, "SW@PORT%d", port_no);
1683cc8cfffSCodrin Ciubotariu 	dev->priv = &vsc9953_l2sw.port[port_no];
1696706b115SCodrin Ciubotariu 	dev->init = NULL;
1706706b115SCodrin Ciubotariu 	dev->halt = NULL;
1716706b115SCodrin Ciubotariu 	dev->send = NULL;
1726706b115SCodrin Ciubotariu 	dev->recv = NULL;
1736706b115SCodrin Ciubotariu 
1746706b115SCodrin Ciubotariu 	if (init_phy(dev)) {
1756706b115SCodrin Ciubotariu 		free(dev);
1763cc8cfffSCodrin Ciubotariu 		return -ENODEV;
1776706b115SCodrin Ciubotariu 	}
1786706b115SCodrin Ciubotariu 
1796706b115SCodrin Ciubotariu 	return 0;
1806706b115SCodrin Ciubotariu }
1816706b115SCodrin Ciubotariu 
vsc9953_vlan_table_poll_idle(void)1829de05987SCodrin Ciubotariu static int vsc9953_vlan_table_poll_idle(void)
1839de05987SCodrin Ciubotariu {
1849de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1859de05987SCodrin Ciubotariu 	int timeout;
1869de05987SCodrin Ciubotariu 
1879de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1889de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
1899de05987SCodrin Ciubotariu 
1909de05987SCodrin Ciubotariu 	timeout = 50000;
1919de05987SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
1929de05987SCodrin Ciubotariu 		 VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
1939de05987SCodrin Ciubotariu 		udelay(1);
1949de05987SCodrin Ciubotariu 
1959de05987SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
1969de05987SCodrin Ciubotariu }
1979de05987SCodrin Ciubotariu 
198a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
199a2477924SCodrin Ciubotariu /* Add/remove a port to/from a VLAN */
vsc9953_vlan_table_membership_set(int vid,u32 port_no,u8 add)200a2477924SCodrin Ciubotariu static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add)
201a2477924SCodrin Ciubotariu {
202a2477924SCodrin Ciubotariu 	u32 val;
203a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
204a2477924SCodrin Ciubotariu 
205a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
206a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
207a2477924SCodrin Ciubotariu 
208a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
209a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
210a2477924SCodrin Ciubotariu 		return;
211a2477924SCodrin Ciubotariu 	}
212a2477924SCodrin Ciubotariu 
213a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
214a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
215a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
216a2477924SCodrin Ciubotariu 
217a2477924SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
218a2477924SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
219a2477924SCodrin Ciubotariu 
220a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
221a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
222a2477924SCodrin Ciubotariu 		return;
223a2477924SCodrin Ciubotariu 	}
224a2477924SCodrin Ciubotariu 
225a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
226a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
227a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
228a2477924SCodrin Ciubotariu 
229a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_access);
230a2477924SCodrin Ciubotariu 	if (!add) {
231a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
232a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) &
233a2477924SCodrin Ciubotariu 		      ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
234a2477924SCodrin Ciubotariu 						 (1 << port_no)));
235a2477924SCodrin Ciubotariu 		 ;
236a2477924SCodrin Ciubotariu 	} else {
237a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
238a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) |
239a2477924SCodrin Ciubotariu 		      bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
240a2477924SCodrin Ciubotariu 					       (1 << port_no));
241a2477924SCodrin Ciubotariu 	}
242a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_access, val);
243a2477924SCodrin Ciubotariu 
244a2477924SCodrin Ciubotariu 	/* wait for VLAN table command to flush */
245a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
246a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
247a2477924SCodrin Ciubotariu 		return;
248a2477924SCodrin Ciubotariu 	}
249a2477924SCodrin Ciubotariu }
250a2477924SCodrin Ciubotariu 
251a2477924SCodrin Ciubotariu /* show VLAN membership for a port */
vsc9953_vlan_membership_show(int port_no)252a2477924SCodrin Ciubotariu static void vsc9953_vlan_membership_show(int port_no)
253a2477924SCodrin Ciubotariu {
254a2477924SCodrin Ciubotariu 	u32 val;
255a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
256a2477924SCodrin Ciubotariu 	u32 vid;
257a2477924SCodrin Ciubotariu 
258a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
259a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
260a2477924SCodrin Ciubotariu 
261a2477924SCodrin Ciubotariu 	printf("Port %d VLAN membership: ", port_no);
262a2477924SCodrin Ciubotariu 
263a2477924SCodrin Ciubotariu 	for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) {
264a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
265a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
266a2477924SCodrin Ciubotariu 			return;
267a2477924SCodrin Ciubotariu 		}
268a2477924SCodrin Ciubotariu 
269a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
270a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK,
271a2477924SCodrin Ciubotariu 					       vid);
272a2477924SCodrin Ciubotariu 		out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
273a2477924SCodrin Ciubotariu 
274a2477924SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
275a2477924SCodrin Ciubotariu 				VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
276a2477924SCodrin Ciubotariu 
277a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
278a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
279a2477924SCodrin Ciubotariu 			return;
280a2477924SCodrin Ciubotariu 		}
281a2477924SCodrin Ciubotariu 
282a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_access);
283a2477924SCodrin Ciubotariu 
284a2477924SCodrin Ciubotariu 		if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) &
285a2477924SCodrin Ciubotariu 		    (1 << port_no))
286a2477924SCodrin Ciubotariu 			printf("%d ", vid);
287a2477924SCodrin Ciubotariu 	}
288a2477924SCodrin Ciubotariu 	printf("\n");
289a2477924SCodrin Ciubotariu }
290a2477924SCodrin Ciubotariu #endif
291a2477924SCodrin Ciubotariu 
2929de05987SCodrin Ciubotariu /* vlan table set/clear all membership of vid */
vsc9953_vlan_table_membership_all_set(int vid,int set_member)2939de05987SCodrin Ciubotariu static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
2949de05987SCodrin Ciubotariu {
2959de05987SCodrin Ciubotariu 	uint val;
2969de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
2979de05987SCodrin Ciubotariu 
2989de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
2999de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3009de05987SCodrin Ciubotariu 
3019de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3029de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3039de05987SCodrin Ciubotariu 		return;
3049de05987SCodrin Ciubotariu 	}
3059de05987SCodrin Ciubotariu 
3069de05987SCodrin Ciubotariu 	/* read current vlan configuration */
3079de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3089de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3099de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3109de05987SCodrin Ciubotariu 
3119de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3129de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
3139de05987SCodrin Ciubotariu 
3149de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3159de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3169de05987SCodrin Ciubotariu 		return;
3179de05987SCodrin Ciubotariu 	}
3189de05987SCodrin Ciubotariu 
3199de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3209de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3219de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3229de05987SCodrin Ciubotariu 
3239de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3249de05987SCodrin Ciubotariu 			VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
3259de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_WRITE |
3269de05987SCodrin Ciubotariu 			(set_member ? VSC9953_VLAN_PORT_MASK : 0));
3279de05987SCodrin Ciubotariu }
3289de05987SCodrin Ciubotariu 
329a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
330a2477924SCodrin Ciubotariu /* Get PVID of a VSC9953 port */
vsc9953_port_vlan_pvid_get(int port_nr,int * pvid)331a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid)
332a2477924SCodrin Ciubotariu {
333a2477924SCodrin Ciubotariu 	u32 val;
334a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
335a2477924SCodrin Ciubotariu 
336a2477924SCodrin Ciubotariu 	/* Administrative down */
3379101a68cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_nr].enabled) {
338a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_nr);
339a2477924SCodrin Ciubotariu 		return -1;
340a2477924SCodrin Ciubotariu 	}
341a2477924SCodrin Ciubotariu 
342a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
343a2477924SCodrin Ciubotariu 				VSC9953_ANA_OFFSET);
344a2477924SCodrin Ciubotariu 
345a2477924SCodrin Ciubotariu 	/* Get ingress PVID */
346a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg);
347a2477924SCodrin Ciubotariu 	*pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK);
348a2477924SCodrin Ciubotariu 
349a2477924SCodrin Ciubotariu 	return 0;
350a2477924SCodrin Ciubotariu }
351a2477924SCodrin Ciubotariu #endif
352a2477924SCodrin Ciubotariu 
3539de05987SCodrin Ciubotariu /* Set PVID for a VSC9953 port */
vsc9953_port_vlan_pvid_set(int port_no,int pvid)3549de05987SCodrin Ciubotariu static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
3559de05987SCodrin Ciubotariu {
3569de05987SCodrin Ciubotariu 	uint val;
3579de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3589de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
3599de05987SCodrin Ciubotariu 
3609de05987SCodrin Ciubotariu 	/* Administrative down */
3619de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3629de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
3639de05987SCodrin Ciubotariu 		return;
3649de05987SCodrin Ciubotariu 	}
3659de05987SCodrin Ciubotariu 
3669de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
3679de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3689de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
3699de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
3709de05987SCodrin Ciubotariu 
3719de05987SCodrin Ciubotariu 	/* Set PVID on ingress */
3729de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
3739de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
3749de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
3759de05987SCodrin Ciubotariu 
3769de05987SCodrin Ciubotariu 	/* Set PVID on egress */
3779de05987SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
3789de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
3799de05987SCodrin Ciubotariu 				       pvid);
3809de05987SCodrin Ciubotariu 	out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
3819de05987SCodrin Ciubotariu }
3829de05987SCodrin Ciubotariu 
vsc9953_port_all_vlan_pvid_set(int pvid)3839de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_pvid_set(int pvid)
3849de05987SCodrin Ciubotariu {
3859de05987SCodrin Ciubotariu 	int i;
3869de05987SCodrin Ciubotariu 
3879de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
3889de05987SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(i, pvid);
3899de05987SCodrin Ciubotariu }
3909de05987SCodrin Ciubotariu 
3919de05987SCodrin Ciubotariu /* Enable/disable vlan aware of a VSC9953 port */
vsc9953_port_vlan_aware_set(int port_no,int enabled)3929de05987SCodrin Ciubotariu static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
3939de05987SCodrin Ciubotariu {
3949de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3959de05987SCodrin Ciubotariu 
3969de05987SCodrin Ciubotariu 	/* Administrative down */
3979de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3989de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
3999de05987SCodrin Ciubotariu 		return;
4009de05987SCodrin Ciubotariu 	}
4019de05987SCodrin Ciubotariu 
4029de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4039de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4049de05987SCodrin Ciubotariu 
4059de05987SCodrin Ciubotariu 	if (enabled)
4069de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4079de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4089de05987SCodrin Ciubotariu 	else
4099de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4109de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4119de05987SCodrin Ciubotariu }
4129de05987SCodrin Ciubotariu 
4139de05987SCodrin Ciubotariu /* Set all VSC9953 ports' vlan aware  */
vsc9953_port_all_vlan_aware_set(int enabled)4149de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_aware_set(int enabled)
4159de05987SCodrin Ciubotariu {
4169de05987SCodrin Ciubotariu 	int i;
4179de05987SCodrin Ciubotariu 
4189de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4199de05987SCodrin Ciubotariu 		vsc9953_port_vlan_aware_set(i, enabled);
4209de05987SCodrin Ciubotariu }
4219de05987SCodrin Ciubotariu 
4229de05987SCodrin Ciubotariu /* Enable/disable vlan pop count of a VSC9953 port */
vsc9953_port_vlan_popcnt_set(int port_no,int popcnt)4239de05987SCodrin Ciubotariu static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
4249de05987SCodrin Ciubotariu {
4259de05987SCodrin Ciubotariu 	uint val;
4269de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4279de05987SCodrin Ciubotariu 
4289de05987SCodrin Ciubotariu 	/* Administrative down */
4299de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
4309de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
4319de05987SCodrin Ciubotariu 		return;
4329de05987SCodrin Ciubotariu 	}
4339de05987SCodrin Ciubotariu 
4349de05987SCodrin Ciubotariu 	if (popcnt > 3 || popcnt < 0) {
4359de05987SCodrin Ciubotariu 		printf("Invalid pop count value: %d\n", port_no);
4369de05987SCodrin Ciubotariu 		return;
4379de05987SCodrin Ciubotariu 	}
4389de05987SCodrin Ciubotariu 
4399de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4409de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4419de05987SCodrin Ciubotariu 
4429de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
4439de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
4449de05987SCodrin Ciubotariu 				       popcnt);
4459de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
4469de05987SCodrin Ciubotariu }
4479de05987SCodrin Ciubotariu 
4489de05987SCodrin Ciubotariu /* Set all VSC9953 ports' pop count  */
vsc9953_port_all_vlan_poncnt_set(int popcnt)4499de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
4509de05987SCodrin Ciubotariu {
4519de05987SCodrin Ciubotariu 	int i;
4529de05987SCodrin Ciubotariu 
4539de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4549de05987SCodrin Ciubotariu 		vsc9953_port_vlan_popcnt_set(i, popcnt);
4559de05987SCodrin Ciubotariu }
4569de05987SCodrin Ciubotariu 
4579de05987SCodrin Ciubotariu /* Enable/disable learning for frames dropped due to ingress filtering */
vsc9953_vlan_ingr_fltr_learn_drop(int enable)4589de05987SCodrin Ciubotariu static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
4599de05987SCodrin Ciubotariu {
4609de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4619de05987SCodrin Ciubotariu 
4629de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4639de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4649de05987SCodrin Ciubotariu 
4659de05987SCodrin Ciubotariu 	if (enable)
4669de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4679de05987SCodrin Ciubotariu 	else
4689de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4699de05987SCodrin Ciubotariu }
4709de05987SCodrin Ciubotariu 
471aae0e689SCodrin Ciubotariu enum aggr_code_mode {
472aae0e689SCodrin Ciubotariu 	AGGR_CODE_RAND = 0,
473aae0e689SCodrin Ciubotariu 	AGGR_CODE_ALL,	/* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
474aae0e689SCodrin Ciubotariu };
475aae0e689SCodrin Ciubotariu 
476aae0e689SCodrin Ciubotariu /* Set aggregation code generation mode */
vsc9953_aggr_code_set(enum aggr_code_mode ac)477aae0e689SCodrin Ciubotariu static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
478aae0e689SCodrin Ciubotariu {
479aae0e689SCodrin Ciubotariu 	int rc;
480aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
481aae0e689SCodrin Ciubotariu 
482aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
483aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
484aae0e689SCodrin Ciubotariu 
485aae0e689SCodrin Ciubotariu 	switch (ac) {
486aae0e689SCodrin Ciubotariu 	case AGGR_CODE_RAND:
487aae0e689SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
488aae0e689SCodrin Ciubotariu 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
489aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_LBL_ENA |
490aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_TCPUDP_ENA |
491aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_SIPDIP_ENA |
492aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
493aae0e689SCodrin Ciubotariu 		rc = 0;
494aae0e689SCodrin Ciubotariu 		break;
495aae0e689SCodrin Ciubotariu 	case AGGR_CODE_ALL:
496aae0e689SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
497aae0e689SCodrin Ciubotariu 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
498aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_LBL_ENA |
499aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_TCPUDP_ENA |
500aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_SIPDIP_ENA |
501aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_TCPUDP_ENA);
502aae0e689SCodrin Ciubotariu 		rc = 0;
503aae0e689SCodrin Ciubotariu 		break;
504aae0e689SCodrin Ciubotariu 	default:
505aae0e689SCodrin Ciubotariu 		/* unknown mode for aggregation code */
506aae0e689SCodrin Ciubotariu 		rc = -EINVAL;
507aae0e689SCodrin Ciubotariu 	}
508aae0e689SCodrin Ciubotariu 
509aae0e689SCodrin Ciubotariu 	return rc;
510aae0e689SCodrin Ciubotariu }
511aae0e689SCodrin Ciubotariu 
5129de05987SCodrin Ciubotariu /* Egress untag modes of a VSC9953 port */
5139de05987SCodrin Ciubotariu enum egress_untag_mode {
5149de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ALL = 0,
5159de05987SCodrin Ciubotariu 	EGRESS_UNTAG_PVID_AND_ZERO,
5169de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ZERO,
5179de05987SCodrin Ciubotariu 	EGRESS_UNTAG_NONE,
5189de05987SCodrin Ciubotariu };
5199de05987SCodrin Ciubotariu 
520a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
521a2477924SCodrin Ciubotariu /* Get egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_get(int port_no,enum egress_untag_mode * mode)522a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_egr_untag_get(int port_no,
523a2477924SCodrin Ciubotariu 					   enum egress_untag_mode *mode)
524a2477924SCodrin Ciubotariu {
525a2477924SCodrin Ciubotariu 	u32 val;
526a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
527a2477924SCodrin Ciubotariu 
528a2477924SCodrin Ciubotariu 	/* Administrative down */
529a2477924SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
530a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
531a2477924SCodrin Ciubotariu 		return -1;
532a2477924SCodrin Ciubotariu 	}
533a2477924SCodrin Ciubotariu 
534a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
535a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
536a2477924SCodrin Ciubotariu 
537a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
538a2477924SCodrin Ciubotariu 
539a2477924SCodrin Ciubotariu 	switch (val & VSC9953_TAG_CFG_MASK) {
540a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_NONE:
541a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ALL;
542a2477924SCodrin Ciubotariu 		return 0;
543a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO:
544a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_PVID_AND_ZERO;
545a2477924SCodrin Ciubotariu 		return 0;
546a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_ZERO:
547a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ZERO;
548a2477924SCodrin Ciubotariu 		return 0;
549a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL:
550a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_NONE;
551a2477924SCodrin Ciubotariu 		return 0;
552a2477924SCodrin Ciubotariu 	default:
553a2477924SCodrin Ciubotariu 		printf("Unknown egress tagging configuration for port %d\n",
554a2477924SCodrin Ciubotariu 		       port_no);
555a2477924SCodrin Ciubotariu 		return -1;
556a2477924SCodrin Ciubotariu 	}
557a2477924SCodrin Ciubotariu }
558a2477924SCodrin Ciubotariu 
559a2477924SCodrin Ciubotariu /* Show egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_show(int port_no)560a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_show(int port_no)
561a2477924SCodrin Ciubotariu {
562a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
563a2477924SCodrin Ciubotariu 
564a2477924SCodrin Ciubotariu 	if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) {
565a2477924SCodrin Ciubotariu 		printf("%7d\t%17s\n", port_no, "-");
566a2477924SCodrin Ciubotariu 		return;
567a2477924SCodrin Ciubotariu 	}
568a2477924SCodrin Ciubotariu 
569a2477924SCodrin Ciubotariu 	printf("%7d\t", port_no);
570a2477924SCodrin Ciubotariu 	switch (mode) {
571a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
572a2477924SCodrin Ciubotariu 		printf("%17s\n", "all");
573a2477924SCodrin Ciubotariu 		break;
574a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
575a2477924SCodrin Ciubotariu 		printf("%17s\n", "none");
576a2477924SCodrin Ciubotariu 		break;
577a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
578a2477924SCodrin Ciubotariu 		printf("%17s\n", "PVID and 0");
579a2477924SCodrin Ciubotariu 		break;
580a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
581a2477924SCodrin Ciubotariu 		printf("%17s\n", "0");
582a2477924SCodrin Ciubotariu 		break;
583a2477924SCodrin Ciubotariu 	default:
584a2477924SCodrin Ciubotariu 		printf("%17s\n", "-");
585a2477924SCodrin Ciubotariu 	}
586a2477924SCodrin Ciubotariu }
587a2477924SCodrin Ciubotariu #endif
588a2477924SCodrin Ciubotariu 
vsc9953_port_vlan_egr_untag_set(int port_no,enum egress_untag_mode mode)5899de05987SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_set(int port_no,
5909de05987SCodrin Ciubotariu 					    enum egress_untag_mode mode)
5919de05987SCodrin Ciubotariu {
5929de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
5939de05987SCodrin Ciubotariu 
5949de05987SCodrin Ciubotariu 	/* Administrative down */
5959de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
5969de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
5979de05987SCodrin Ciubotariu 		return;
5989de05987SCodrin Ciubotariu 	}
5999de05987SCodrin Ciubotariu 
6009de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
6019de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
6029de05987SCodrin Ciubotariu 
6039de05987SCodrin Ciubotariu 	switch (mode) {
6049de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
6059de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6069de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
6079de05987SCodrin Ciubotariu 		break;
6089de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
6099de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6109de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
6119de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
6129de05987SCodrin Ciubotariu 		break;
6139de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
6149de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6159de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
6169de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_ZERO);
6179de05987SCodrin Ciubotariu 		break;
6189de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
6199de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6209de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
6219de05987SCodrin Ciubotariu 		break;
6229de05987SCodrin Ciubotariu 	default:
6239de05987SCodrin Ciubotariu 		printf("Unknown untag mode for port %d\n", port_no);
6249de05987SCodrin Ciubotariu 	}
6259de05987SCodrin Ciubotariu }
6269de05987SCodrin Ciubotariu 
vsc9953_port_all_vlan_egress_untagged_set(enum egress_untag_mode mode)6279de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_egress_untagged_set(
6289de05987SCodrin Ciubotariu 		enum egress_untag_mode mode)
6299de05987SCodrin Ciubotariu {
6309de05987SCodrin Ciubotariu 	int i;
6319de05987SCodrin Ciubotariu 
6329de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
6339de05987SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(i, mode);
6349de05987SCodrin Ciubotariu }
6359de05987SCodrin Ciubotariu 
vsc9953_autoage_time_set(int age_period)636ba389e65SCodrin Ciubotariu static int vsc9953_autoage_time_set(int age_period)
637ba389e65SCodrin Ciubotariu {
638ba389e65SCodrin Ciubotariu 	u32 autoage;
639ba389e65SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
640ba389e65SCodrin Ciubotariu 
641ba389e65SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
642ba389e65SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
643ba389e65SCodrin Ciubotariu 
644ba389e65SCodrin Ciubotariu 	if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
645ba389e65SCodrin Ciubotariu 		return -EINVAL;
646ba389e65SCodrin Ciubotariu 
647ba389e65SCodrin Ciubotariu 	autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
648ba389e65SCodrin Ciubotariu 					   VSC9953_AUTOAGE_PERIOD_MASK,
649ba389e65SCodrin Ciubotariu 					   age_period);
650ba389e65SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.auto_age, autoage);
651ba389e65SCodrin Ciubotariu 
652ba389e65SCodrin Ciubotariu 	return 0;
653ba389e65SCodrin Ciubotariu }
654ba389e65SCodrin Ciubotariu 
65524a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
65624a23debSCodrin Ciubotariu 
65724a23debSCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */
vsc9953_port_status_set(int port_no,u8 enabled)65824a23debSCodrin Ciubotariu static void vsc9953_port_status_set(int port_no, u8 enabled)
65924a23debSCodrin Ciubotariu {
66024a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
66124a23debSCodrin Ciubotariu 
66224a23debSCodrin Ciubotariu 	/* Administrative down */
66324a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled)
66424a23debSCodrin Ciubotariu 		return;
66524a23debSCodrin Ciubotariu 
66624a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
66724a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
66824a23debSCodrin Ciubotariu 
66924a23debSCodrin Ciubotariu 	if (enabled)
67024a23debSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
67124a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
67224a23debSCodrin Ciubotariu 	else
67324a23debSCodrin Ciubotariu 		clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
67424a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
67524a23debSCodrin Ciubotariu }
67624a23debSCodrin Ciubotariu 
67724a23debSCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */
vsc9953_phy_autoneg(int port_no)67824a23debSCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_no)
67924a23debSCodrin Ciubotariu {
68024a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].phydev)
68124a23debSCodrin Ciubotariu 		return;
68224a23debSCodrin Ciubotariu 
68324a23debSCodrin Ciubotariu 	if (vsc9953_l2sw.port[port_no].phydev->drv->startup(
68424a23debSCodrin Ciubotariu 			vsc9953_l2sw.port[port_no].phydev))
68524a23debSCodrin Ciubotariu 		printf("Failed to start PHY for port %d\n", port_no);
68624a23debSCodrin Ciubotariu }
68724a23debSCodrin Ciubotariu 
68824a23debSCodrin Ciubotariu /* Print a VSC9953 port's configuration */
vsc9953_port_config_show(int port_no)68924a23debSCodrin Ciubotariu static void vsc9953_port_config_show(int port_no)
69024a23debSCodrin Ciubotariu {
69124a23debSCodrin Ciubotariu 	int speed;
69224a23debSCodrin Ciubotariu 	int duplex;
69324a23debSCodrin Ciubotariu 	int link;
69424a23debSCodrin Ciubotariu 	u8 enabled;
69524a23debSCodrin Ciubotariu 	u32 val;
69624a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
69724a23debSCodrin Ciubotariu 
69824a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
69924a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
70024a23debSCodrin Ciubotariu 
70124a23debSCodrin Ciubotariu 	val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]);
70224a23debSCodrin Ciubotariu 	enabled = vsc9953_l2sw.port[port_no].enabled &&
70324a23debSCodrin Ciubotariu 		  (val & VSC9953_PORT_ENA);
70424a23debSCodrin Ciubotariu 
70524a23debSCodrin Ciubotariu 	/* internal ports (8 and 9) are fixed */
70624a23debSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no)) {
70724a23debSCodrin Ciubotariu 		link = 1;
70824a23debSCodrin Ciubotariu 		speed = SPEED_2500;
70924a23debSCodrin Ciubotariu 		duplex = DUPLEX_FULL;
71024a23debSCodrin Ciubotariu 	} else {
71124a23debSCodrin Ciubotariu 		if (vsc9953_l2sw.port[port_no].phydev) {
71224a23debSCodrin Ciubotariu 			link = vsc9953_l2sw.port[port_no].phydev->link;
71324a23debSCodrin Ciubotariu 			speed = vsc9953_l2sw.port[port_no].phydev->speed;
71424a23debSCodrin Ciubotariu 			duplex = vsc9953_l2sw.port[port_no].phydev->duplex;
71524a23debSCodrin Ciubotariu 		} else {
71624a23debSCodrin Ciubotariu 			link = -1;
71724a23debSCodrin Ciubotariu 			speed = -1;
71824a23debSCodrin Ciubotariu 			duplex = -1;
71924a23debSCodrin Ciubotariu 		}
72024a23debSCodrin Ciubotariu 	}
72124a23debSCodrin Ciubotariu 
72224a23debSCodrin Ciubotariu 	printf("%8d ", port_no);
72324a23debSCodrin Ciubotariu 	printf("%8s ", enabled == 1 ? "enabled" : "disabled");
72424a23debSCodrin Ciubotariu 	printf("%8s ", link == 1 ? "up" : "down");
72524a23debSCodrin Ciubotariu 
72624a23debSCodrin Ciubotariu 	switch (speed) {
72724a23debSCodrin Ciubotariu 	case SPEED_10:
72824a23debSCodrin Ciubotariu 		printf("%8d ", 10);
72924a23debSCodrin Ciubotariu 		break;
73024a23debSCodrin Ciubotariu 	case SPEED_100:
73124a23debSCodrin Ciubotariu 		printf("%8d ", 100);
73224a23debSCodrin Ciubotariu 		break;
73324a23debSCodrin Ciubotariu 	case SPEED_1000:
73424a23debSCodrin Ciubotariu 		printf("%8d ", 1000);
73524a23debSCodrin Ciubotariu 		break;
73624a23debSCodrin Ciubotariu 	case SPEED_2500:
73724a23debSCodrin Ciubotariu 		printf("%8d ", 2500);
73824a23debSCodrin Ciubotariu 		break;
73924a23debSCodrin Ciubotariu 	case SPEED_10000:
74024a23debSCodrin Ciubotariu 		printf("%8d ", 10000);
74124a23debSCodrin Ciubotariu 		break;
74224a23debSCodrin Ciubotariu 	default:
74324a23debSCodrin Ciubotariu 		printf("%8s ", "-");
74424a23debSCodrin Ciubotariu 	}
74524a23debSCodrin Ciubotariu 
74624a23debSCodrin Ciubotariu 	printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
74724a23debSCodrin Ciubotariu }
74824a23debSCodrin Ciubotariu 
74986719f0cSCodrin Ciubotariu /* Show VSC9953 ports' statistics */
vsc9953_port_statistics_show(int port_no)75086719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_show(int port_no)
75186719f0cSCodrin Ciubotariu {
75286719f0cSCodrin Ciubotariu 	u32 rx_val;
75386719f0cSCodrin Ciubotariu 	u32 tx_val;
75486719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
75586719f0cSCodrin Ciubotariu 
75686719f0cSCodrin Ciubotariu 	/* Administrative down */
75786719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
75886719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
75986719f0cSCodrin Ciubotariu 		return;
76086719f0cSCodrin Ciubotariu 	}
76186719f0cSCodrin Ciubotariu 
76286719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
76386719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
76486719f0cSCodrin Ciubotariu 
76586719f0cSCodrin Ciubotariu 	printf("Statistics for L2 Switch port %d:\n", port_no);
76686719f0cSCodrin Ciubotariu 
76786719f0cSCodrin Ciubotariu 	/* Set counter view for our port */
76886719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no);
76986719f0cSCodrin Ciubotariu 
77086719f0cSCodrin Ciubotariu #define VSC9953_STATS_PRINTF "%-15s %10u"
77186719f0cSCodrin Ciubotariu 
77286719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames */
77386719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) +
77486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) +
77586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) +
77686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) +
77786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) +
77886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) +
77986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) +
78086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) +
78186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) +
78286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) +
78386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
78486719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
78586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
78686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
78786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
78886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
78986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
79086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
79186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79286719f0cSCodrin Ciubotariu 	       "Rx frames:", rx_val, "Tx frames:", tx_val);
79386719f0cSCodrin Ciubotariu 
79486719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx bytes */
79586719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct);
79686719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct);
79786719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79886719f0cSCodrin Ciubotariu 	       "Rx bytes:", rx_val, "Tx bytes:", tx_val);
79986719f0cSCodrin Ciubotariu 
80086719f0cSCodrin Ciubotariu 	/* Get number of Rx frames received ok and Tx frames sent ok */
80186719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) +
80286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) +
80386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) +
80486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) +
80586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) +
80686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) +
80786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) +
80886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) +
80986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) +
81086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) +
81186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) +
81286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) +
81386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) +
81486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) +
81586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) +
81686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7);
81786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
81886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
81986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
82086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
82186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
82286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
82386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
82486719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
82586719f0cSCodrin Ciubotariu 	       "Rx frames ok:", rx_val, "Tx frames ok:", tx_val);
82686719f0cSCodrin Ciubotariu 
82786719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx unicast frames */
82886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc);
82986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc);
83086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83186719f0cSCodrin Ciubotariu 	       "Rx unicast:", rx_val, "Tx unicast:", tx_val);
83286719f0cSCodrin Ciubotariu 
83386719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx broadcast frames */
83486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc);
83586719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc);
83686719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83786719f0cSCodrin Ciubotariu 	       "Rx broadcast:", rx_val, "Tx broadcast:", tx_val);
83886719f0cSCodrin Ciubotariu 
83986719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames of 64B */
84086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64);
84186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64);
84286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
84386719f0cSCodrin Ciubotariu 	       "Rx 64B:", rx_val, "Tx 64B:", tx_val);
84486719f0cSCodrin Ciubotariu 
84586719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 65B and 127B */
84686719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127);
84786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127);
84886719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
84986719f0cSCodrin Ciubotariu 	       "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val);
85086719f0cSCodrin Ciubotariu 
85186719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 128B and 255B */
85286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255);
85386719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255);
85486719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
85586719f0cSCodrin Ciubotariu 	       "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val);
85686719f0cSCodrin Ciubotariu 
85786719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 256B and 511B */
85886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511);
85986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511);
86086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
86186719f0cSCodrin Ciubotariu 	       "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val);
86286719f0cSCodrin Ciubotariu 
86386719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 512B and 1023B */
86486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023);
86586719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023);
86686719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
86786719f0cSCodrin Ciubotariu 	       "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val);
86886719f0cSCodrin Ciubotariu 
86986719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 1024B and 1526B */
87086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526);
87186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526);
87286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
87386719f0cSCodrin Ciubotariu 	       "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val);
87486719f0cSCodrin Ciubotariu 
87586719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx jumbo frames */
87686719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
87786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
87886719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
87986719f0cSCodrin Ciubotariu 	       "Rx jumbo:", rx_val, "Tx jumbo:", tx_val);
88086719f0cSCodrin Ciubotariu 
88186719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx dropped frames */
88286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
88386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) +
88486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) +
88586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) +
88686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) +
88786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) +
88886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) +
88986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) +
89086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) +
89186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) +
89286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) +
89386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) +
89486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) +
89586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) +
89686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) +
89786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) +
89886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) +
89986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7);
90086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) +
90186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
90286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
90386719f0cSCodrin Ciubotariu 	       "Rx drops:", rx_val, "Tx drops:", tx_val);
90486719f0cSCodrin Ciubotariu 
90586719f0cSCodrin Ciubotariu 	/*
90686719f0cSCodrin Ciubotariu 	 * Get number of Rx frames with CRC or alignment errors
90786719f0cSCodrin Ciubotariu 	 * and number of detected Tx collisions
90886719f0cSCodrin Ciubotariu 	 */
90986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc);
91086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col);
91186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
91286719f0cSCodrin Ciubotariu 	       "Rx CRC&align:", rx_val, "Tx coll:", tx_val);
91386719f0cSCodrin Ciubotariu 
91486719f0cSCodrin Ciubotariu 	/*
91586719f0cSCodrin Ciubotariu 	 * Get number of Rx undersized frames and
91686719f0cSCodrin Ciubotariu 	 * number of Tx aged frames
91786719f0cSCodrin Ciubotariu 	 */
91886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short);
91986719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
92086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
92186719f0cSCodrin Ciubotariu 	       "Rx undersize:", rx_val, "Tx aged:", tx_val);
92286719f0cSCodrin Ciubotariu 
92386719f0cSCodrin Ciubotariu 	/* Get number of Rx oversized frames */
92486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long);
92586719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val);
92686719f0cSCodrin Ciubotariu 
92786719f0cSCodrin Ciubotariu 	/* Get number of Rx fragmented frames */
92886719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag);
92986719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val);
93086719f0cSCodrin Ciubotariu 
93186719f0cSCodrin Ciubotariu 	/* Get number of Rx jabber errors */
93286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber);
93386719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val);
93486719f0cSCodrin Ciubotariu 
93586719f0cSCodrin Ciubotariu 	/*
93686719f0cSCodrin Ciubotariu 	 * Get number of Rx frames filtered due to classification rules or
93786719f0cSCodrin Ciubotariu 	 * no destination ports
93886719f0cSCodrin Ciubotariu 	 */
93986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
94086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local);
94186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val);
94286719f0cSCodrin Ciubotariu 
94386719f0cSCodrin Ciubotariu 	printf("\n");
94486719f0cSCodrin Ciubotariu }
94586719f0cSCodrin Ciubotariu 
94686719f0cSCodrin Ciubotariu /* Clear statistics for a VSC9953 port */
vsc9953_port_statistics_clear(int port_no)94786719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_clear(int port_no)
94886719f0cSCodrin Ciubotariu {
94986719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
95086719f0cSCodrin Ciubotariu 
95186719f0cSCodrin Ciubotariu 	/* Administrative down */
95286719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
95386719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
95486719f0cSCodrin Ciubotariu 		return;
95586719f0cSCodrin Ciubotariu 	}
95686719f0cSCodrin Ciubotariu 
95786719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
95886719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
95986719f0cSCodrin Ciubotariu 
96086719f0cSCodrin Ciubotariu 	/* Clear all counter groups for our ports */
96186719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no |
96286719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX |
96386719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_DR);
96486719f0cSCodrin Ciubotariu }
96586719f0cSCodrin Ciubotariu 
96668c929daSCodrin Ciubotariu enum port_learn_mode {
96768c929daSCodrin Ciubotariu 	PORT_LEARN_NONE,
96868c929daSCodrin Ciubotariu 	PORT_LEARN_AUTO
96968c929daSCodrin Ciubotariu };
97068c929daSCodrin Ciubotariu 
97168c929daSCodrin Ciubotariu /* Set learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_set(int port_no,enum port_learn_mode mode)97268c929daSCodrin Ciubotariu static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode)
97368c929daSCodrin Ciubotariu {
97468c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
97568c929daSCodrin Ciubotariu 
97668c929daSCodrin Ciubotariu 	/* Administrative down */
97768c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
97868c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
97968c929daSCodrin Ciubotariu 		return;
98068c929daSCodrin Ciubotariu 	}
98168c929daSCodrin Ciubotariu 
98268c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
98368c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
98468c929daSCodrin Ciubotariu 
98568c929daSCodrin Ciubotariu 	switch (mode) {
98668c929daSCodrin Ciubotariu 	case PORT_LEARN_NONE:
98768c929daSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].port_cfg,
98868c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_DROP |
98968c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_CPU |
99068c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_AUTO |
99168c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_ENA);
99268c929daSCodrin Ciubotariu 		break;
99368c929daSCodrin Ciubotariu 	case PORT_LEARN_AUTO:
99468c929daSCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg,
99568c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_DROP |
99668c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_CPU,
99768c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_ENA |
99868c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_AUTO);
99968c929daSCodrin Ciubotariu 		break;
100068c929daSCodrin Ciubotariu 	default:
100168c929daSCodrin Ciubotariu 		printf("Unknown learn mode for port %d\n", port_no);
100268c929daSCodrin Ciubotariu 	}
100368c929daSCodrin Ciubotariu }
100468c929daSCodrin Ciubotariu 
100568c929daSCodrin Ciubotariu /* Get learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_get(int port_no,enum port_learn_mode * mode)100668c929daSCodrin Ciubotariu static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode)
100768c929daSCodrin Ciubotariu {
100868c929daSCodrin Ciubotariu 	u32 val;
100968c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
101068c929daSCodrin Ciubotariu 
101168c929daSCodrin Ciubotariu 	/* Administrative down */
101268c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
101368c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
101468c929daSCodrin Ciubotariu 		return -1;
101568c929daSCodrin Ciubotariu 	}
101668c929daSCodrin Ciubotariu 
101768c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
101868c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
101968c929daSCodrin Ciubotariu 
102068c929daSCodrin Ciubotariu 	/* For now we only support HW learning (auto) and no learning */
102168c929daSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
102268c929daSCodrin Ciubotariu 	if ((val & (VSC9953_PORT_CFG_LEARN_ENA |
102368c929daSCodrin Ciubotariu 		    VSC9953_PORT_CFG_LEARN_AUTO)) ==
102468c929daSCodrin Ciubotariu 	    (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO))
102568c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_AUTO;
102668c929daSCodrin Ciubotariu 	else
102768c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_NONE;
102868c929daSCodrin Ciubotariu 
102968c929daSCodrin Ciubotariu 	return 0;
103068c929daSCodrin Ciubotariu }
103168c929daSCodrin Ciubotariu 
103222449858SCodrin Ciubotariu /* wait for FDB to become available */
vsc9953_mac_table_poll_idle(void)103322449858SCodrin Ciubotariu static int vsc9953_mac_table_poll_idle(void)
103422449858SCodrin Ciubotariu {
103522449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
103622449858SCodrin Ciubotariu 	u32 timeout;
103722449858SCodrin Ciubotariu 
103822449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
103922449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
104022449858SCodrin Ciubotariu 
104122449858SCodrin Ciubotariu 	timeout = 50000;
104222449858SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.mac_access) &
104322449858SCodrin Ciubotariu 			 VSC9953_MAC_CMD_MASK) !=
104422449858SCodrin Ciubotariu 		VSC9953_MAC_CMD_IDLE) && --timeout)
104522449858SCodrin Ciubotariu 		udelay(1);
104622449858SCodrin Ciubotariu 
104722449858SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
104822449858SCodrin Ciubotariu }
104922449858SCodrin Ciubotariu 
105022449858SCodrin Ciubotariu /* enum describing available commands for the MAC table */
105122449858SCodrin Ciubotariu enum mac_table_cmd {
105222449858SCodrin Ciubotariu 	MAC_TABLE_READ,
105322449858SCodrin Ciubotariu 	MAC_TABLE_LOOKUP,
105422449858SCodrin Ciubotariu 	MAC_TABLE_WRITE,
105522449858SCodrin Ciubotariu 	MAC_TABLE_LEARN,
105622449858SCodrin Ciubotariu 	MAC_TABLE_FORGET,
105722449858SCodrin Ciubotariu 	MAC_TABLE_GET_NEXT,
105822449858SCodrin Ciubotariu 	MAC_TABLE_AGE,
105922449858SCodrin Ciubotariu };
106022449858SCodrin Ciubotariu 
106122449858SCodrin Ciubotariu /* Issues a command to the FDB table */
vsc9953_mac_table_cmd(enum mac_table_cmd cmd)106222449858SCodrin Ciubotariu static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd)
106322449858SCodrin Ciubotariu {
106422449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
106522449858SCodrin Ciubotariu 
106622449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
106722449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
106822449858SCodrin Ciubotariu 
106922449858SCodrin Ciubotariu 	switch (cmd) {
107022449858SCodrin Ciubotariu 	case MAC_TABLE_READ:
107122449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
107222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID,
107322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_READ);
107422449858SCodrin Ciubotariu 		break;
107522449858SCodrin Ciubotariu 	case MAC_TABLE_LOOKUP:
107622449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
107722449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ |
107822449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
107922449858SCodrin Ciubotariu 		break;
108022449858SCodrin Ciubotariu 	case MAC_TABLE_WRITE:
108122449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
108222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
108322449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
108422449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_WRITE |
108522449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED);
108622449858SCodrin Ciubotariu 		break;
108722449858SCodrin Ciubotariu 	case MAC_TABLE_LEARN:
108822449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
108922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
109022449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
109122449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_LEARN |
109222449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED |
109322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
109422449858SCodrin Ciubotariu 		break;
109522449858SCodrin Ciubotariu 	case MAC_TABLE_FORGET:
109622449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
109722449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
109822449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
109922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_FORGET);
110022449858SCodrin Ciubotariu 		break;
110122449858SCodrin Ciubotariu 	case MAC_TABLE_GET_NEXT:
110222449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
110322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
110422449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
110522449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_NEXT);
110622449858SCodrin Ciubotariu 		break;
110722449858SCodrin Ciubotariu 	case MAC_TABLE_AGE:
110822449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
110922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
111022449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
111122449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_AGE);
111222449858SCodrin Ciubotariu 		break;
111322449858SCodrin Ciubotariu 	default:
111422449858SCodrin Ciubotariu 		printf("Unknown MAC table command\n");
111522449858SCodrin Ciubotariu 	}
111622449858SCodrin Ciubotariu 
111722449858SCodrin Ciubotariu 	if (vsc9953_mac_table_poll_idle() < 0) {
111822449858SCodrin Ciubotariu 		debug("MAC table timeout\n");
111922449858SCodrin Ciubotariu 		return -1;
112022449858SCodrin Ciubotariu 	}
112122449858SCodrin Ciubotariu 
112222449858SCodrin Ciubotariu 	return 0;
112322449858SCodrin Ciubotariu }
112422449858SCodrin Ciubotariu 
112522449858SCodrin Ciubotariu /* show the FDB entries that correspond to a port and a VLAN */
vsc9953_mac_table_show(int port_no,int vid)112622449858SCodrin Ciubotariu static void vsc9953_mac_table_show(int port_no, int vid)
112722449858SCodrin Ciubotariu {
112822449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
112922449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
113022449858SCodrin Ciubotariu 	int i;
113122449858SCodrin Ciubotariu 	u32 val;
113222449858SCodrin Ciubotariu 	u32 vlan;
113322449858SCodrin Ciubotariu 	u32 mach;
113422449858SCodrin Ciubotariu 	u32 macl;
113522449858SCodrin Ciubotariu 	u32 dest_indx;
113622449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
113722449858SCodrin Ciubotariu 
113822449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
113922449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
114022449858SCodrin Ciubotariu 
114122449858SCodrin Ciubotariu 	/* disable auto learning */
114222449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
114322449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
114422449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
114522449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
114622449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
114722449858SCodrin Ciubotariu 		}
114822449858SCodrin Ciubotariu 	} else {
114922449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
115022449858SCodrin Ciubotariu 							  &mode[port_no]);
115122449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
115222449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
115322449858SCodrin Ciubotariu 	}
115422449858SCodrin Ciubotariu 
115522449858SCodrin Ciubotariu 	/* write port and vid to get selected FDB entries */
115622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
115722449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
115822449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
115922449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
116022449858SCodrin Ciubotariu 	}
116122449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
116222449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK,
116322449858SCodrin Ciubotariu 					       vid) | VSC9953_AGE_VID_EN;
116422449858SCodrin Ciubotariu 	}
116522449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
116622449858SCodrin Ciubotariu 
116722449858SCodrin Ciubotariu 	/* set MAC and VLAN to 0 to look from beginning */
116822449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana_tables.mach_data,
116922449858SCodrin Ciubotariu 		     VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK);
117022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, 0);
117122449858SCodrin Ciubotariu 
117222449858SCodrin Ciubotariu 	/* get entries */
117322449858SCodrin Ciubotariu 	printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID");
117422449858SCodrin Ciubotariu 	do {
117522449858SCodrin Ciubotariu 		if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) {
117622449858SCodrin Ciubotariu 			debug("GET NEXT MAC table command failed\n");
117722449858SCodrin Ciubotariu 			break;
117822449858SCodrin Ciubotariu 		}
117922449858SCodrin Ciubotariu 
118022449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mac_access);
118122449858SCodrin Ciubotariu 
118222449858SCodrin Ciubotariu 		/* get out when an invalid entry is found */
118322449858SCodrin Ciubotariu 		if (!(val & VSC9953_MAC_CMD_VALID))
118422449858SCodrin Ciubotariu 			break;
118522449858SCodrin Ciubotariu 
118622449858SCodrin Ciubotariu 		switch (val & VSC9953_MAC_ENTRYTYPE_MASK) {
118722449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_NORMAL:
118822449858SCodrin Ciubotariu 			printf("%10s ", "Dynamic");
118922449858SCodrin Ciubotariu 			break;
119022449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_LOCKED:
119122449858SCodrin Ciubotariu 			printf("%10s ", "Static");
119222449858SCodrin Ciubotariu 			break;
119322449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV4MCAST:
119422449858SCodrin Ciubotariu 			printf("%10s ", "IPv4 Mcast");
119522449858SCodrin Ciubotariu 			break;
119622449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV6MCAST:
119722449858SCodrin Ciubotariu 			printf("%10s ", "IPv6 Mcast");
119822449858SCodrin Ciubotariu 			break;
119922449858SCodrin Ciubotariu 		default:
120022449858SCodrin Ciubotariu 			printf("%10s ", "Unknown");
120122449858SCodrin Ciubotariu 		}
120222449858SCodrin Ciubotariu 
120322449858SCodrin Ciubotariu 		dest_indx = bitfield_extract_by_mask(val,
120422449858SCodrin Ciubotariu 						     VSC9953_MAC_DESTIDX_MASK);
120522449858SCodrin Ciubotariu 
120622449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mach_data);
120722449858SCodrin Ciubotariu 		vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK);
120822449858SCodrin Ciubotariu 		mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK);
120922449858SCodrin Ciubotariu 		macl = in_le32(&l2ana_reg->ana_tables.macl_data);
121022449858SCodrin Ciubotariu 
121122449858SCodrin Ciubotariu 		printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff,
121222449858SCodrin Ciubotariu 		       mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff,
121322449858SCodrin Ciubotariu 		       (macl >> 8) & 0xff, macl & 0xff);
121422449858SCodrin Ciubotariu 		printf("%5d ", dest_indx);
121522449858SCodrin Ciubotariu 		printf("%4d\n", vlan);
121622449858SCodrin Ciubotariu 	} while (1);
121722449858SCodrin Ciubotariu 
121822449858SCodrin Ciubotariu 	/* set learning mode to previous value */
121922449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
122022449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
122122449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
122222449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
122322449858SCodrin Ciubotariu 		}
122422449858SCodrin Ciubotariu 	} else {
122522449858SCodrin Ciubotariu 		/* If administrative down, skip */
122622449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
122722449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
122822449858SCodrin Ciubotariu 	}
122922449858SCodrin Ciubotariu 
123022449858SCodrin Ciubotariu 	/* reset FDB port and VLAN FDB selection */
123122449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
123222449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
123322449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
123422449858SCodrin Ciubotariu }
123522449858SCodrin Ciubotariu 
123622449858SCodrin Ciubotariu /* Add a static FDB entry */
vsc9953_mac_table_add(u8 port_no,uchar mac[6],int vid)123722449858SCodrin Ciubotariu static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid)
123822449858SCodrin Ciubotariu {
123922449858SCodrin Ciubotariu 	u32 val;
124022449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
124122449858SCodrin Ciubotariu 
124222449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
124322449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
124422449858SCodrin Ciubotariu 
124522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
124622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
124722449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
124822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
124922449858SCodrin Ciubotariu 
125022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
125122449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
125222449858SCodrin Ciubotariu 		 (mac[5] << 0));
125322449858SCodrin Ciubotariu 
125422449858SCodrin Ciubotariu 	/* set on which port is the MAC address added */
125522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
125622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no);
125722449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mac_access, val);
125822449858SCodrin Ciubotariu 
125922449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0)
126022449858SCodrin Ciubotariu 		return -1;
126122449858SCodrin Ciubotariu 
126222449858SCodrin Ciubotariu 	/* check if the MAC address was indeed added */
126322449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
126422449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
126522449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
126622449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
126722449858SCodrin Ciubotariu 
126822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
126922449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
127022449858SCodrin Ciubotariu 		 (mac[5] << 0));
127122449858SCodrin Ciubotariu 
127222449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0)
127322449858SCodrin Ciubotariu 		return -1;
127422449858SCodrin Ciubotariu 
127522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
127622449858SCodrin Ciubotariu 
127722449858SCodrin Ciubotariu 	if ((port_no != bitfield_extract_by_mask(val,
127822449858SCodrin Ciubotariu 						 VSC9953_MAC_DESTIDX_MASK))) {
127922449858SCodrin Ciubotariu 		printf("Failed to add MAC address\n");
128022449858SCodrin Ciubotariu 		return -1;
128122449858SCodrin Ciubotariu 	}
128222449858SCodrin Ciubotariu 	return 0;
128322449858SCodrin Ciubotariu }
128422449858SCodrin Ciubotariu 
128522449858SCodrin Ciubotariu /* Delete a FDB entry */
vsc9953_mac_table_del(uchar mac[6],u16 vid)128622449858SCodrin Ciubotariu static int vsc9953_mac_table_del(uchar mac[6], u16 vid)
128722449858SCodrin Ciubotariu {
128822449858SCodrin Ciubotariu 	u32 val;
128922449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
129022449858SCodrin Ciubotariu 
129122449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
129222449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
129322449858SCodrin Ciubotariu 
129422449858SCodrin Ciubotariu 	/* check first if MAC entry is present */
129522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
129622449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
129722449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
129822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
129922449858SCodrin Ciubotariu 
130022449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
130122449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
130222449858SCodrin Ciubotariu 		 (mac[5] << 0));
130322449858SCodrin Ciubotariu 
130422449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
130522449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
130622449858SCodrin Ciubotariu 		return -1;
130722449858SCodrin Ciubotariu 	}
130822449858SCodrin Ciubotariu 
130922449858SCodrin Ciubotariu 	if (!(in_le32(&l2ana_reg->ana_tables.mac_access) &
131022449858SCodrin Ciubotariu 	      VSC9953_MAC_CMD_VALID)) {
131122449858SCodrin Ciubotariu 		printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ",
131222449858SCodrin Ciubotariu 		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
131322449858SCodrin Ciubotariu 		printf("VLAN: %d does not exist.\n", vid);
131422449858SCodrin Ciubotariu 		return -1;
131522449858SCodrin Ciubotariu 	}
131622449858SCodrin Ciubotariu 
131722449858SCodrin Ciubotariu 	/* FDB entry found, proceed to delete */
131822449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
131922449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
132022449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
132122449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
132222449858SCodrin Ciubotariu 
132322449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
132422449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
132522449858SCodrin Ciubotariu 
132622449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0)
132722449858SCodrin Ciubotariu 		return -1;
132822449858SCodrin Ciubotariu 
132922449858SCodrin Ciubotariu 	/* check if the MAC entry is still in FDB */
133022449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
133122449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
133222449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
133322449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
133422449858SCodrin Ciubotariu 
133522449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
133622449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
133722449858SCodrin Ciubotariu 
133822449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
133922449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
134022449858SCodrin Ciubotariu 		return -1;
134122449858SCodrin Ciubotariu 	}
134222449858SCodrin Ciubotariu 	if (in_le32(&l2ana_reg->ana_tables.mac_access) &
134322449858SCodrin Ciubotariu 	    VSC9953_MAC_CMD_VALID) {
134422449858SCodrin Ciubotariu 		printf("Failed to delete MAC address\n");
134522449858SCodrin Ciubotariu 		return -1;
134622449858SCodrin Ciubotariu 	}
134722449858SCodrin Ciubotariu 
134822449858SCodrin Ciubotariu 	return 0;
134922449858SCodrin Ciubotariu }
135022449858SCodrin Ciubotariu 
135122449858SCodrin Ciubotariu /* age the unlocked entries in FDB */
vsc9953_mac_table_age(int port_no,int vid)135222449858SCodrin Ciubotariu static void vsc9953_mac_table_age(int port_no, int vid)
135322449858SCodrin Ciubotariu {
135422449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
135522449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
135622449858SCodrin Ciubotariu 	u32 val;
135722449858SCodrin Ciubotariu 	int i;
135822449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
135922449858SCodrin Ciubotariu 
136022449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
136122449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
136222449858SCodrin Ciubotariu 
136322449858SCodrin Ciubotariu 	/* set port and VID for selective aging */
136422449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
136522449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
136622449858SCodrin Ciubotariu 		/* disable auto learning */
136722449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
136822449858SCodrin Ciubotariu 							  &mode[port_no]);
136922449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
137022449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
137122449858SCodrin Ciubotariu 
137222449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
137322449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
137422449858SCodrin Ciubotariu 	} else {
137522449858SCodrin Ciubotariu 		/* disable auto learning on all ports */
137622449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
137722449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
137822449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
137922449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
138022449858SCodrin Ciubotariu 		}
138122449858SCodrin Ciubotariu 	}
138222449858SCodrin Ciubotariu 
138322449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
138422449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) |
138522449858SCodrin Ciubotariu 		      VSC9953_AGE_VID_EN;
138622449858SCodrin Ciubotariu 	}
138722449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
138822449858SCodrin Ciubotariu 
138922449858SCodrin Ciubotariu 	/* age the dynamic FDB entries */
139022449858SCodrin Ciubotariu 	vsc9953_mac_table_cmd(MAC_TABLE_AGE);
139122449858SCodrin Ciubotariu 
139222449858SCodrin Ciubotariu 	/* clear previously set port and VID */
139322449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
139422449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
139522449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
139622449858SCodrin Ciubotariu 
139722449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
139822449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
139922449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
140022449858SCodrin Ciubotariu 	} else {
140122449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
140222449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
140322449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
140422449858SCodrin Ciubotariu 		}
140522449858SCodrin Ciubotariu 	}
140622449858SCodrin Ciubotariu }
140722449858SCodrin Ciubotariu 
140822449858SCodrin Ciubotariu /* Delete all the dynamic FDB entries */
vsc9953_mac_table_flush(int port,int vid)140922449858SCodrin Ciubotariu static void vsc9953_mac_table_flush(int port, int vid)
141022449858SCodrin Ciubotariu {
141122449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
141222449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
141322449858SCodrin Ciubotariu }
141422449858SCodrin Ciubotariu 
1415a2477924SCodrin Ciubotariu enum egress_vlan_tag {
1416a2477924SCodrin Ciubotariu 	EGR_TAG_CLASS = 0,
1417a2477924SCodrin Ciubotariu 	EGR_TAG_PVID,
1418a2477924SCodrin Ciubotariu };
1419a2477924SCodrin Ciubotariu 
1420a2477924SCodrin Ciubotariu /* Set egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_set(int port_no,enum egress_vlan_tag mode)1421a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_set(int port_no,
1422a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag mode)
1423a2477924SCodrin Ciubotariu {
1424a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1425a2477924SCodrin Ciubotariu 
1426a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1427a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1428a2477924SCodrin Ciubotariu 
1429a2477924SCodrin Ciubotariu 	switch (mode) {
1430a2477924SCodrin Ciubotariu 	case EGR_TAG_CLASS:
1431a2477924SCodrin Ciubotariu 		clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1432a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1433a2477924SCodrin Ciubotariu 		break;
1434a2477924SCodrin Ciubotariu 	case EGR_TAG_PVID:
1435a2477924SCodrin Ciubotariu 		setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1436a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1437a2477924SCodrin Ciubotariu 		break;
1438a2477924SCodrin Ciubotariu 	default:
1439a2477924SCodrin Ciubotariu 		printf("Unknown egress VLAN tag mode for port %d\n", port_no);
1440a2477924SCodrin Ciubotariu 	}
1441a2477924SCodrin Ciubotariu }
1442a2477924SCodrin Ciubotariu 
1443a2477924SCodrin Ciubotariu /* Get egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_get(int port_no,enum egress_vlan_tag * mode)1444a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_get(int port_no,
1445a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag *mode)
1446a2477924SCodrin Ciubotariu {
1447a2477924SCodrin Ciubotariu 	u32 val;
1448a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1449a2477924SCodrin Ciubotariu 
1450a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1451a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1452a2477924SCodrin Ciubotariu 
1453a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
1454a2477924SCodrin Ciubotariu 	if (val & VSC9953_TAG_VID_PVID)
1455a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_PVID;
1456a2477924SCodrin Ciubotariu 	else
1457a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_CLASS;
1458a2477924SCodrin Ciubotariu }
1459a2477924SCodrin Ciubotariu 
146021d214fcSCodrin Ciubotariu /* VSC9953 VLAN learning modes */
146121d214fcSCodrin Ciubotariu enum vlan_learning_mode {
146221d214fcSCodrin Ciubotariu 	SHARED_VLAN_LEARNING,
146321d214fcSCodrin Ciubotariu 	PRIVATE_VLAN_LEARNING,
146421d214fcSCodrin Ciubotariu };
146521d214fcSCodrin Ciubotariu 
146621d214fcSCodrin Ciubotariu /* Set VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)146721d214fcSCodrin Ciubotariu static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)
146821d214fcSCodrin Ciubotariu {
146921d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
147021d214fcSCodrin Ciubotariu 
147121d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
147221d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
147321d214fcSCodrin Ciubotariu 
147421d214fcSCodrin Ciubotariu 	switch (lrn_mode) {
147521d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
147621d214fcSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
147721d214fcSCodrin Ciubotariu 		break;
147821d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
147921d214fcSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
148021d214fcSCodrin Ciubotariu 		break;
148121d214fcSCodrin Ciubotariu 	default:
148221d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learn mode\n");
148321d214fcSCodrin Ciubotariu 	}
148421d214fcSCodrin Ciubotariu }
148521d214fcSCodrin Ciubotariu 
148621d214fcSCodrin Ciubotariu /* Get VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_get(enum vlan_learning_mode * lrn_mode)148721d214fcSCodrin Ciubotariu static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode)
148821d214fcSCodrin Ciubotariu {
148921d214fcSCodrin Ciubotariu 	u32 val;
149021d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
149121d214fcSCodrin Ciubotariu 
149221d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
149321d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
149421d214fcSCodrin Ciubotariu 
149521d214fcSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.agen_ctrl);
149621d214fcSCodrin Ciubotariu 
149721d214fcSCodrin Ciubotariu 	if (!(val & VSC9953_FID_MASK_ALL)) {
149821d214fcSCodrin Ciubotariu 		*lrn_mode = PRIVATE_VLAN_LEARNING;
149921d214fcSCodrin Ciubotariu 	} else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) {
150021d214fcSCodrin Ciubotariu 		*lrn_mode = SHARED_VLAN_LEARNING;
150121d214fcSCodrin Ciubotariu 	} else {
150221d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
150321d214fcSCodrin Ciubotariu 		return -EINVAL;
150421d214fcSCodrin Ciubotariu 	}
150521d214fcSCodrin Ciubotariu 
150621d214fcSCodrin Ciubotariu 	return 0;
150721d214fcSCodrin Ciubotariu }
150821d214fcSCodrin Ciubotariu 
15095ed1bacdSCodrin Ciubotariu /* Enable/disable VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_set(int port_no,int enabled)15105ed1bacdSCodrin Ciubotariu static void vsc9953_port_ingress_filtering_set(int port_no, int enabled)
15115ed1bacdSCodrin Ciubotariu {
15125ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
15135ed1bacdSCodrin Ciubotariu 
15145ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
15155ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
15165ed1bacdSCodrin Ciubotariu 
15175ed1bacdSCodrin Ciubotariu 	if (enabled)
15185ed1bacdSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
15195ed1bacdSCodrin Ciubotariu 	else
15205ed1bacdSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
15215ed1bacdSCodrin Ciubotariu }
15225ed1bacdSCodrin Ciubotariu 
15235ed1bacdSCodrin Ciubotariu /* Return VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_get(int port_no)15245ed1bacdSCodrin Ciubotariu static int vsc9953_port_ingress_filtering_get(int port_no)
15255ed1bacdSCodrin Ciubotariu {
15265ed1bacdSCodrin Ciubotariu 	u32 val;
15275ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
15285ed1bacdSCodrin Ciubotariu 
15295ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
15305ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
15315ed1bacdSCodrin Ciubotariu 
15325ed1bacdSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.vlan_mask);
15335ed1bacdSCodrin Ciubotariu 	return !!(val & (1 << port_no));
15345ed1bacdSCodrin Ciubotariu }
15355ed1bacdSCodrin Ciubotariu 
1536aae0e689SCodrin Ciubotariu /* Get the aggregation group of a port */
vsc9953_port_aggr_grp_get(int port_no,int * aggr_grp)1537aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
1538aae0e689SCodrin Ciubotariu {
1539aae0e689SCodrin Ciubotariu 	u32 val;
1540aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1541aae0e689SCodrin Ciubotariu 
1542aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
1543aae0e689SCodrin Ciubotariu 		return -EINVAL;
1544aae0e689SCodrin Ciubotariu 
1545aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1546aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1547aae0e689SCodrin Ciubotariu 
1548aae0e689SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1549aae0e689SCodrin Ciubotariu 	*aggr_grp = bitfield_extract_by_mask(val,
1550aae0e689SCodrin Ciubotariu 					     VSC9953_PORT_CFG_PORTID_MASK);
1551aae0e689SCodrin Ciubotariu 
1552aae0e689SCodrin Ciubotariu 	return 0;
1553aae0e689SCodrin Ciubotariu }
1554aae0e689SCodrin Ciubotariu 
vsc9953_aggr_grp_members_get(int aggr_grp,u8 aggr_membr[VSC9953_MAX_PORTS])1555aae0e689SCodrin Ciubotariu static void vsc9953_aggr_grp_members_get(int aggr_grp,
1556aae0e689SCodrin Ciubotariu 					 u8 aggr_membr[VSC9953_MAX_PORTS])
1557aae0e689SCodrin Ciubotariu {
1558aae0e689SCodrin Ciubotariu 	int port_no;
1559aae0e689SCodrin Ciubotariu 	int aggr_membr_grp;
1560aae0e689SCodrin Ciubotariu 
1561aae0e689SCodrin Ciubotariu 	for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
1562aae0e689SCodrin Ciubotariu 		aggr_membr[port_no] = 0;
1563aae0e689SCodrin Ciubotariu 
1564aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
1565aae0e689SCodrin Ciubotariu 			continue;
1566aae0e689SCodrin Ciubotariu 
1567aae0e689SCodrin Ciubotariu 		if (aggr_grp == aggr_membr_grp)
1568aae0e689SCodrin Ciubotariu 			aggr_membr[port_no] = 1;
1569aae0e689SCodrin Ciubotariu 	}
1570aae0e689SCodrin Ciubotariu }
1571aae0e689SCodrin Ciubotariu 
vsc9953_update_dest_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1572aae0e689SCodrin Ciubotariu static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
1573aae0e689SCodrin Ciubotariu 					      u32 membr_bitfld_new)
1574aae0e689SCodrin Ciubotariu {
1575aae0e689SCodrin Ciubotariu 	int i;
1576aae0e689SCodrin Ciubotariu 	u32 pgid;
1577aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1578aae0e689SCodrin Ciubotariu 
1579aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1580aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1581aae0e689SCodrin Ciubotariu 
1582aae0e689SCodrin Ciubotariu 	/*
1583aae0e689SCodrin Ciubotariu 	 * NOTE: Only the unicast destination masks are updated, since
1584aae0e689SCodrin Ciubotariu 	 * we do not support for now Layer-2 multicast entries
1585aae0e689SCodrin Ciubotariu 	 */
1586aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1587aae0e689SCodrin Ciubotariu 		if (i == port_no) {
1588aae0e689SCodrin Ciubotariu 			clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
1589aae0e689SCodrin Ciubotariu 					VSC9953_PGID_PORT_MASK,
1590aae0e689SCodrin Ciubotariu 					membr_bitfld_new);
1591aae0e689SCodrin Ciubotariu 			continue;
1592aae0e689SCodrin Ciubotariu 		}
1593aae0e689SCodrin Ciubotariu 
1594aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1595aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1596aae0e689SCodrin Ciubotariu 			pgid &= ~((u32)(1 << port_no));
1597aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1598aae0e689SCodrin Ciubotariu 			pgid |= ((u32)(1 << port_no));
1599aae0e689SCodrin Ciubotariu 
1600aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1601aae0e689SCodrin Ciubotariu 	}
1602aae0e689SCodrin Ciubotariu }
1603aae0e689SCodrin Ciubotariu 
vsc9953_update_source_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1604aae0e689SCodrin Ciubotariu static void vsc9953_update_source_members_masks(int port_no,
1605aae0e689SCodrin Ciubotariu 						u32 membr_bitfld_old,
1606aae0e689SCodrin Ciubotariu 						u32 membr_bitfld_new)
1607aae0e689SCodrin Ciubotariu {
1608aae0e689SCodrin Ciubotariu 	int i;
1609aae0e689SCodrin Ciubotariu 	int index;
1610aae0e689SCodrin Ciubotariu 	u32 pgid;
1611aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1612aae0e689SCodrin Ciubotariu 
1613aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1614aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1615aae0e689SCodrin Ciubotariu 
1616aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
1617aae0e689SCodrin Ciubotariu 		index = PGID_SRC_START + i;
1618aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
1619aae0e689SCodrin Ciubotariu 		if (i == port_no) {
1620aae0e689SCodrin Ciubotariu 			pgid = (pgid | VSC9953_PGID_PORT_MASK) &
1621aae0e689SCodrin Ciubotariu 			       ~membr_bitfld_new;
1622aae0e689SCodrin Ciubotariu 			out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
1623aae0e689SCodrin Ciubotariu 				 pgid);
1624aae0e689SCodrin Ciubotariu 			continue;
1625aae0e689SCodrin Ciubotariu 		}
1626aae0e689SCodrin Ciubotariu 
1627aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1628aae0e689SCodrin Ciubotariu 			pgid |= (u32)(1 << port_no);
1629aae0e689SCodrin Ciubotariu 
1630aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1631aae0e689SCodrin Ciubotariu 			pgid &= ~(u32)(1 << port_no);
1632aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
1633aae0e689SCodrin Ciubotariu 	}
1634aae0e689SCodrin Ciubotariu }
1635aae0e689SCodrin Ciubotariu 
vsc9953_aggr_mask_get_next(u32 aggr_mask,u32 member_bitfield)1636aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
1637aae0e689SCodrin Ciubotariu {
1638aae0e689SCodrin Ciubotariu 	if (!member_bitfield)
1639aae0e689SCodrin Ciubotariu 		return 0;
1640aae0e689SCodrin Ciubotariu 
1641aae0e689SCodrin Ciubotariu 	if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1642aae0e689SCodrin Ciubotariu 		aggr_mask = 1;
1643aae0e689SCodrin Ciubotariu 	else
1644aae0e689SCodrin Ciubotariu 		aggr_mask <<= 1;
1645aae0e689SCodrin Ciubotariu 
1646aae0e689SCodrin Ciubotariu 	while (!(aggr_mask & member_bitfield)) {
1647aae0e689SCodrin Ciubotariu 		aggr_mask <<= 1;
1648aae0e689SCodrin Ciubotariu 		if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1649aae0e689SCodrin Ciubotariu 			aggr_mask = 1;
1650aae0e689SCodrin Ciubotariu 	}
1651aae0e689SCodrin Ciubotariu 
1652aae0e689SCodrin Ciubotariu 	return aggr_mask;
1653aae0e689SCodrin Ciubotariu }
1654aae0e689SCodrin Ciubotariu 
vsc9953_update_aggr_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1655aae0e689SCodrin Ciubotariu static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
1656aae0e689SCodrin Ciubotariu 					      u32 membr_bitfld_new)
1657aae0e689SCodrin Ciubotariu {
1658aae0e689SCodrin Ciubotariu 	int i;
1659aae0e689SCodrin Ciubotariu 	u32 pgid;
1660aae0e689SCodrin Ciubotariu 	u32 aggr_mask_old = 0;
1661aae0e689SCodrin Ciubotariu 	u32 aggr_mask_new = 0;
1662aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1663aae0e689SCodrin Ciubotariu 
1664aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1665aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1666aae0e689SCodrin Ciubotariu 
1667aae0e689SCodrin Ciubotariu 	/* Update all the PGID aggregation masks */
1668aae0e689SCodrin Ciubotariu 	for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
1669aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1670aae0e689SCodrin Ciubotariu 
1671aae0e689SCodrin Ciubotariu 		aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
1672aae0e689SCodrin Ciubotariu 							   membr_bitfld_old);
1673aae0e689SCodrin Ciubotariu 		pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
1674aae0e689SCodrin Ciubotariu 
1675aae0e689SCodrin Ciubotariu 		aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
1676aae0e689SCodrin Ciubotariu 							   membr_bitfld_new);
1677aae0e689SCodrin Ciubotariu 		pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
1678aae0e689SCodrin Ciubotariu 
1679aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1680aae0e689SCodrin Ciubotariu 	}
1681aae0e689SCodrin Ciubotariu }
1682aae0e689SCodrin Ciubotariu 
vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])1683aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
1684aae0e689SCodrin Ciubotariu {
1685aae0e689SCodrin Ciubotariu 	int i;
1686aae0e689SCodrin Ciubotariu 	u32 member_bitfield = 0;
1687aae0e689SCodrin Ciubotariu 
1688aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1689aae0e689SCodrin Ciubotariu 		if (member[i])
1690aae0e689SCodrin Ciubotariu 			member_bitfield |= 1 << i;
1691aae0e689SCodrin Ciubotariu 	}
1692aae0e689SCodrin Ciubotariu 	member_bitfield &= VSC9953_PGID_PORT_MASK;
1693aae0e689SCodrin Ciubotariu 
1694aae0e689SCodrin Ciubotariu 	return member_bitfield;
1695aae0e689SCodrin Ciubotariu }
1696aae0e689SCodrin Ciubotariu 
vsc9953_update_members_masks(int port_no,u8 member_old[VSC9953_MAX_PORTS],u8 member_new[VSC9953_MAX_PORTS])1697aae0e689SCodrin Ciubotariu static void vsc9953_update_members_masks(int port_no,
1698aae0e689SCodrin Ciubotariu 					 u8 member_old[VSC9953_MAX_PORTS],
1699aae0e689SCodrin Ciubotariu 					 u8 member_new[VSC9953_MAX_PORTS])
1700aae0e689SCodrin Ciubotariu {
1701aae0e689SCodrin Ciubotariu 	u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
1702aae0e689SCodrin Ciubotariu 	u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
1703aae0e689SCodrin Ciubotariu 
1704aae0e689SCodrin Ciubotariu 	vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
1705aae0e689SCodrin Ciubotariu 					  membr_bitfld_new);
1706aae0e689SCodrin Ciubotariu 	vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
1707aae0e689SCodrin Ciubotariu 					    membr_bitfld_new);
1708aae0e689SCodrin Ciubotariu 	vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
1709aae0e689SCodrin Ciubotariu 					  membr_bitfld_new);
1710aae0e689SCodrin Ciubotariu }
1711aae0e689SCodrin Ciubotariu 
1712aae0e689SCodrin Ciubotariu /* Set the aggregation group of a port */
vsc9953_port_aggr_grp_set(int port_no,int aggr_grp)1713aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
1714aae0e689SCodrin Ciubotariu {
1715aae0e689SCodrin Ciubotariu 	u8 aggr_membr_old[VSC9953_MAX_PORTS];
1716aae0e689SCodrin Ciubotariu 	u8 aggr_membr_new[VSC9953_MAX_PORTS];
1717aae0e689SCodrin Ciubotariu 	int rc;
1718aae0e689SCodrin Ciubotariu 	int aggr_grp_old;
1719aae0e689SCodrin Ciubotariu 	u32 val;
1720aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1721aae0e689SCodrin Ciubotariu 
1722aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
1723aae0e689SCodrin Ciubotariu 		return -EINVAL;
1724aae0e689SCodrin Ciubotariu 
1725aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1726aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1727aae0e689SCodrin Ciubotariu 
1728aae0e689SCodrin Ciubotariu 	rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
1729aae0e689SCodrin Ciubotariu 	if (rc)
1730aae0e689SCodrin Ciubotariu 		return rc;
1731aae0e689SCodrin Ciubotariu 
1732aae0e689SCodrin Ciubotariu 	/* get all the members of the old aggregation group */
1733aae0e689SCodrin Ciubotariu 	vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
1734aae0e689SCodrin Ciubotariu 
1735aae0e689SCodrin Ciubotariu 	/* get all the members of the same aggregation group */
1736aae0e689SCodrin Ciubotariu 	vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
1737aae0e689SCodrin Ciubotariu 
1738aae0e689SCodrin Ciubotariu 	/* add current port as member to the new aggregation group */
1739aae0e689SCodrin Ciubotariu 	aggr_membr_old[port_no] = 0;
1740aae0e689SCodrin Ciubotariu 	aggr_membr_new[port_no] = 1;
1741aae0e689SCodrin Ciubotariu 
1742aae0e689SCodrin Ciubotariu 	/* update masks */
1743aae0e689SCodrin Ciubotariu 	vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
1744aae0e689SCodrin Ciubotariu 
1745aae0e689SCodrin Ciubotariu 	/* Change logical port number */
1746aae0e689SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1747aae0e689SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val,
1748aae0e689SCodrin Ciubotariu 				       VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
1749aae0e689SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].port_cfg, val);
1750aae0e689SCodrin Ciubotariu 
1751aae0e689SCodrin Ciubotariu 	return 0;
1752aae0e689SCodrin Ciubotariu }
1753aae0e689SCodrin Ciubotariu 
vsc9953_port_status_key_func(struct ethsw_command_def * parsed_cmd)175424a23debSCodrin Ciubotariu static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
175524a23debSCodrin Ciubotariu {
175624a23debSCodrin Ciubotariu 	int i;
175724a23debSCodrin Ciubotariu 	u8 enabled;
175824a23debSCodrin Ciubotariu 
175924a23debSCodrin Ciubotariu 	/* Last keyword should tell us if we should enable/disable the port */
176024a23debSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
176124a23debSCodrin Ciubotariu 	    ethsw_id_enable)
176224a23debSCodrin Ciubotariu 		enabled = 1;
176324a23debSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
176424a23debSCodrin Ciubotariu 		 ethsw_id_disable)
176524a23debSCodrin Ciubotariu 		enabled = 0;
176624a23debSCodrin Ciubotariu 	else
176724a23debSCodrin Ciubotariu 		return CMD_RET_USAGE;
176824a23debSCodrin Ciubotariu 
176924a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
177024a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
177124a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
177224a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
177324a23debSCodrin Ciubotariu 		}
177424a23debSCodrin Ciubotariu 		vsc9953_port_status_set(parsed_cmd->port, enabled);
177524a23debSCodrin Ciubotariu 	} else {
177624a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
177724a23debSCodrin Ciubotariu 			vsc9953_port_status_set(i, enabled);
177824a23debSCodrin Ciubotariu 	}
177924a23debSCodrin Ciubotariu 
178024a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
178124a23debSCodrin Ciubotariu }
178224a23debSCodrin Ciubotariu 
vsc9953_port_config_key_func(struct ethsw_command_def * parsed_cmd)178324a23debSCodrin Ciubotariu static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd)
178424a23debSCodrin Ciubotariu {
178524a23debSCodrin Ciubotariu 	int i;
178624a23debSCodrin Ciubotariu 
178724a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
178824a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
178924a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
179024a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
179124a23debSCodrin Ciubotariu 		}
179224a23debSCodrin Ciubotariu 		vsc9953_phy_autoneg(parsed_cmd->port);
179324a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
179424a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed",
179524a23debSCodrin Ciubotariu 		       "Duplex");
179624a23debSCodrin Ciubotariu 		vsc9953_port_config_show(parsed_cmd->port);
179724a23debSCodrin Ciubotariu 
179824a23debSCodrin Ciubotariu 	} else {
179924a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
180024a23debSCodrin Ciubotariu 			vsc9953_phy_autoneg(i);
180124a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
180224a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed", "Duplex");
180324a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
180424a23debSCodrin Ciubotariu 			vsc9953_port_config_show(i);
180524a23debSCodrin Ciubotariu 	}
180624a23debSCodrin Ciubotariu 
180724a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
180824a23debSCodrin Ciubotariu }
180924a23debSCodrin Ciubotariu 
vsc9953_port_stats_key_func(struct ethsw_command_def * parsed_cmd)181086719f0cSCodrin Ciubotariu static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd)
181186719f0cSCodrin Ciubotariu {
181286719f0cSCodrin Ciubotariu 	int i;
181386719f0cSCodrin Ciubotariu 
181486719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
181586719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
181686719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
181786719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
181886719f0cSCodrin Ciubotariu 		}
181986719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_show(parsed_cmd->port);
182086719f0cSCodrin Ciubotariu 	} else {
182186719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
182286719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_show(i);
182386719f0cSCodrin Ciubotariu 	}
182486719f0cSCodrin Ciubotariu 
182586719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
182686719f0cSCodrin Ciubotariu }
182786719f0cSCodrin Ciubotariu 
vsc9953_port_stats_clear_key_func(struct ethsw_command_def * parsed_cmd)182886719f0cSCodrin Ciubotariu static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def
182986719f0cSCodrin Ciubotariu 					     *parsed_cmd)
183086719f0cSCodrin Ciubotariu {
183186719f0cSCodrin Ciubotariu 	int i;
183286719f0cSCodrin Ciubotariu 
183386719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
183486719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
183586719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
183686719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
183786719f0cSCodrin Ciubotariu 		}
183886719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_clear(parsed_cmd->port);
183986719f0cSCodrin Ciubotariu 	} else {
184086719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
184186719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_clear(i);
184286719f0cSCodrin Ciubotariu 	}
184386719f0cSCodrin Ciubotariu 
184486719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
184586719f0cSCodrin Ciubotariu }
184686719f0cSCodrin Ciubotariu 
vsc9953_learn_show_key_func(struct ethsw_command_def * parsed_cmd)184768c929daSCodrin Ciubotariu static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd)
184868c929daSCodrin Ciubotariu {
184968c929daSCodrin Ciubotariu 	int i;
185068c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
185168c929daSCodrin Ciubotariu 
185268c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
185368c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
185468c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
185568c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
185668c929daSCodrin Ciubotariu 		}
185768c929daSCodrin Ciubotariu 		if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode))
185868c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
185968c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
186068c929daSCodrin Ciubotariu 		switch (mode) {
186168c929daSCodrin Ciubotariu 		case PORT_LEARN_NONE:
186268c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "disable");
186368c929daSCodrin Ciubotariu 			break;
186468c929daSCodrin Ciubotariu 		case PORT_LEARN_AUTO:
186568c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "auto");
186668c929daSCodrin Ciubotariu 			break;
186768c929daSCodrin Ciubotariu 		default:
186868c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "-");
186968c929daSCodrin Ciubotariu 		}
187068c929daSCodrin Ciubotariu 	} else {
187168c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
187268c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
187368c929daSCodrin Ciubotariu 			if (vsc9953_port_learn_mode_get(i, &mode))
187468c929daSCodrin Ciubotariu 				continue;
187568c929daSCodrin Ciubotariu 			switch (mode) {
187668c929daSCodrin Ciubotariu 			case PORT_LEARN_NONE:
187768c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "disable");
187868c929daSCodrin Ciubotariu 				break;
187968c929daSCodrin Ciubotariu 			case PORT_LEARN_AUTO:
188068c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "auto");
188168c929daSCodrin Ciubotariu 				break;
188268c929daSCodrin Ciubotariu 			default:
188368c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "-");
188468c929daSCodrin Ciubotariu 			}
188568c929daSCodrin Ciubotariu 		}
188668c929daSCodrin Ciubotariu 	}
188768c929daSCodrin Ciubotariu 
188868c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
188968c929daSCodrin Ciubotariu }
189068c929daSCodrin Ciubotariu 
vsc9953_learn_set_key_func(struct ethsw_command_def * parsed_cmd)189168c929daSCodrin Ciubotariu static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
189268c929daSCodrin Ciubotariu {
189368c929daSCodrin Ciubotariu 	int i;
189468c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
189568c929daSCodrin Ciubotariu 
189668c929daSCodrin Ciubotariu 	/* Last keyword should tell us the learn mode */
189768c929daSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
189868c929daSCodrin Ciubotariu 	    ethsw_id_auto)
189968c929daSCodrin Ciubotariu 		mode = PORT_LEARN_AUTO;
190068c929daSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
190168c929daSCodrin Ciubotariu 		 ethsw_id_disable)
190268c929daSCodrin Ciubotariu 		mode = PORT_LEARN_NONE;
190368c929daSCodrin Ciubotariu 	else
190468c929daSCodrin Ciubotariu 		return CMD_RET_USAGE;
190568c929daSCodrin Ciubotariu 
190668c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
190768c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
190868c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
190968c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
191068c929daSCodrin Ciubotariu 		}
191168c929daSCodrin Ciubotariu 		vsc9953_port_learn_mode_set(parsed_cmd->port, mode);
191268c929daSCodrin Ciubotariu 	} else {
191368c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
191468c929daSCodrin Ciubotariu 			vsc9953_port_learn_mode_set(i, mode);
191568c929daSCodrin Ciubotariu 	}
191668c929daSCodrin Ciubotariu 
191768c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
191868c929daSCodrin Ciubotariu }
191968c929daSCodrin Ciubotariu 
vsc9953_fdb_show_key_func(struct ethsw_command_def * parsed_cmd)192022449858SCodrin Ciubotariu static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd)
192122449858SCodrin Ciubotariu {
192222449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
192322449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
192422449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
192522449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
192622449858SCodrin Ciubotariu 	}
192722449858SCodrin Ciubotariu 
192822449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
192922449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
193022449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
193122449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
193222449858SCodrin Ciubotariu 	}
193322449858SCodrin Ciubotariu 
193422449858SCodrin Ciubotariu 	vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid);
193522449858SCodrin Ciubotariu 
193622449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
193722449858SCodrin Ciubotariu }
193822449858SCodrin Ciubotariu 
vsc9953_fdb_flush_key_func(struct ethsw_command_def * parsed_cmd)193922449858SCodrin Ciubotariu static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd)
194022449858SCodrin Ciubotariu {
194122449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
194222449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
194322449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
194422449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
194522449858SCodrin Ciubotariu 	}
194622449858SCodrin Ciubotariu 
194722449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
194822449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
194922449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
195022449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
195122449858SCodrin Ciubotariu 	}
195222449858SCodrin Ciubotariu 
195322449858SCodrin Ciubotariu 	vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid);
195422449858SCodrin Ciubotariu 
195522449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
195622449858SCodrin Ciubotariu }
195722449858SCodrin Ciubotariu 
vsc9953_fdb_entry_add_key_func(struct ethsw_command_def * parsed_cmd)195822449858SCodrin Ciubotariu static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd)
195922449858SCodrin Ciubotariu {
196022449858SCodrin Ciubotariu 	int vid;
196122449858SCodrin Ciubotariu 
196222449858SCodrin Ciubotariu 	/* a port number must be present */
196322449858SCodrin Ciubotariu 	if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) {
196422449858SCodrin Ciubotariu 		printf("Please specify a port\n");
196522449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
196622449858SCodrin Ciubotariu 	}
196722449858SCodrin Ciubotariu 
196822449858SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
196922449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
197022449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
197122449858SCodrin Ciubotariu 	}
197222449858SCodrin Ciubotariu 
197322449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
197422449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
197522449858SCodrin Ciubotariu 
197622449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
197722449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
197822449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
197922449858SCodrin Ciubotariu 	}
198022449858SCodrin Ciubotariu 
198122449858SCodrin Ciubotariu 	if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid))
198222449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
198322449858SCodrin Ciubotariu 
198422449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
198522449858SCodrin Ciubotariu }
198622449858SCodrin Ciubotariu 
vsc9953_fdb_entry_del_key_func(struct ethsw_command_def * parsed_cmd)198722449858SCodrin Ciubotariu static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd)
198822449858SCodrin Ciubotariu {
198922449858SCodrin Ciubotariu 	int vid;
199022449858SCodrin Ciubotariu 
199122449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
199222449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
199322449858SCodrin Ciubotariu 
199422449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
199522449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
199622449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
199722449858SCodrin Ciubotariu 	}
199822449858SCodrin Ciubotariu 
199922449858SCodrin Ciubotariu 	if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid))
200022449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
200122449858SCodrin Ciubotariu 
200222449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
200322449858SCodrin Ciubotariu }
200422449858SCodrin Ciubotariu 
vsc9953_pvid_show_key_func(struct ethsw_command_def * parsed_cmd)2005a2477924SCodrin Ciubotariu static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd)
2006a2477924SCodrin Ciubotariu {
2007a2477924SCodrin Ciubotariu 	int i;
2008a2477924SCodrin Ciubotariu 	int pvid;
2009a2477924SCodrin Ciubotariu 
2010a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2011a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2012a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2013a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2014a2477924SCodrin Ciubotariu 		}
2015a2477924SCodrin Ciubotariu 
2016a2477924SCodrin Ciubotariu 		if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid))
2017a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2018a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
2019a2477924SCodrin Ciubotariu 		printf("%7d %7d\n", parsed_cmd->port, pvid);
2020a2477924SCodrin Ciubotariu 	} else {
2021a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
2022a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2023a2477924SCodrin Ciubotariu 			if (vsc9953_port_vlan_pvid_get(i, &pvid))
2024a2477924SCodrin Ciubotariu 				continue;
2025a2477924SCodrin Ciubotariu 			printf("%7d %7d\n", i, pvid);
2026a2477924SCodrin Ciubotariu 		}
2027a2477924SCodrin Ciubotariu 	}
2028a2477924SCodrin Ciubotariu 
2029a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2030a2477924SCodrin Ciubotariu }
2031a2477924SCodrin Ciubotariu 
vsc9953_pvid_set_key_func(struct ethsw_command_def * parsed_cmd)2032a2477924SCodrin Ciubotariu static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd)
2033a2477924SCodrin Ciubotariu {
2034a2477924SCodrin Ciubotariu 	/* PVID number should be set in parsed_cmd->vid */
2035a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2036a2477924SCodrin Ciubotariu 		printf("Please set a pvid value\n");
2037a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2038a2477924SCodrin Ciubotariu 	}
2039a2477924SCodrin Ciubotariu 
2040a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2041a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2042a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2043a2477924SCodrin Ciubotariu 	}
2044a2477924SCodrin Ciubotariu 
2045a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2046a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2047a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2048a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2049a2477924SCodrin Ciubotariu 		}
2050a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid);
2051a2477924SCodrin Ciubotariu 	} else {
2052a2477924SCodrin Ciubotariu 		vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid);
2053a2477924SCodrin Ciubotariu 	}
2054a2477924SCodrin Ciubotariu 
2055a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2056a2477924SCodrin Ciubotariu }
2057a2477924SCodrin Ciubotariu 
vsc9953_vlan_show_key_func(struct ethsw_command_def * parsed_cmd)2058a2477924SCodrin Ciubotariu static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd)
2059a2477924SCodrin Ciubotariu {
2060a2477924SCodrin Ciubotariu 	int i;
2061a2477924SCodrin Ciubotariu 
2062a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2063a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2064a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2065a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2066a2477924SCodrin Ciubotariu 		}
2067a2477924SCodrin Ciubotariu 		vsc9953_vlan_membership_show(parsed_cmd->port);
2068a2477924SCodrin Ciubotariu 	} else {
2069a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2070a2477924SCodrin Ciubotariu 			vsc9953_vlan_membership_show(i);
2071a2477924SCodrin Ciubotariu 	}
2072a2477924SCodrin Ciubotariu 
2073a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2074a2477924SCodrin Ciubotariu }
2075a2477924SCodrin Ciubotariu 
vsc9953_vlan_set_key_func(struct ethsw_command_def * parsed_cmd)2076a2477924SCodrin Ciubotariu static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd)
2077a2477924SCodrin Ciubotariu {
2078a2477924SCodrin Ciubotariu 	int i;
2079a2477924SCodrin Ciubotariu 	int add;
2080a2477924SCodrin Ciubotariu 
2081a2477924SCodrin Ciubotariu 	/* VLAN should be set in parsed_cmd->vid */
2082a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2083a2477924SCodrin Ciubotariu 		printf("Please set a vlan value\n");
2084a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2085a2477924SCodrin Ciubotariu 	}
2086a2477924SCodrin Ciubotariu 
2087a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2088a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2089a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2090a2477924SCodrin Ciubotariu 	}
2091a2477924SCodrin Ciubotariu 
2092a2477924SCodrin Ciubotariu 	/* keywords add/delete should be the last but one in array */
2093a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2094a2477924SCodrin Ciubotariu 	    ethsw_id_add)
2095a2477924SCodrin Ciubotariu 		add = 1;
2096a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2097a2477924SCodrin Ciubotariu 		 ethsw_id_del)
2098a2477924SCodrin Ciubotariu 		add = 0;
2099a2477924SCodrin Ciubotariu 	else
2100a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2101a2477924SCodrin Ciubotariu 
2102a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2103a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2104a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2105a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2106a2477924SCodrin Ciubotariu 		}
2107a2477924SCodrin Ciubotariu 		vsc9953_vlan_table_membership_set(parsed_cmd->vid,
2108a2477924SCodrin Ciubotariu 						  parsed_cmd->port, add);
2109a2477924SCodrin Ciubotariu 	} else {
2110a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2111a2477924SCodrin Ciubotariu 			vsc9953_vlan_table_membership_set(parsed_cmd->vid, i,
2112a2477924SCodrin Ciubotariu 							  add);
2113a2477924SCodrin Ciubotariu 	}
2114a2477924SCodrin Ciubotariu 
2115a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2116a2477924SCodrin Ciubotariu }
vsc9953_port_untag_show_key_func(struct ethsw_command_def * parsed_cmd)2117a2477924SCodrin Ciubotariu static int vsc9953_port_untag_show_key_func(
2118a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2119a2477924SCodrin Ciubotariu {
2120a2477924SCodrin Ciubotariu 	int i;
2121a2477924SCodrin Ciubotariu 
2122a2477924SCodrin Ciubotariu 	printf("%7s\t%17s\n", "Port", "Untag");
2123a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2124a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2125a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2126a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2127a2477924SCodrin Ciubotariu 		}
2128a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_show(parsed_cmd->port);
2129a2477924SCodrin Ciubotariu 	} else {
2130a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2131a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_show(i);
2132a2477924SCodrin Ciubotariu 	}
2133a2477924SCodrin Ciubotariu 
2134a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2135a2477924SCodrin Ciubotariu }
2136a2477924SCodrin Ciubotariu 
vsc9953_port_untag_set_key_func(struct ethsw_command_def * parsed_cmd)2137a2477924SCodrin Ciubotariu static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd)
2138a2477924SCodrin Ciubotariu {
2139a2477924SCodrin Ciubotariu 	int i;
2140a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
2141a2477924SCodrin Ciubotariu 
2142a2477924SCodrin Ciubotariu 	/* keywords for the untagged mode are the last in the array */
2143a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2144a2477924SCodrin Ciubotariu 	    ethsw_id_all)
2145a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_ALL;
2146a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2147a2477924SCodrin Ciubotariu 		 ethsw_id_none)
2148a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_NONE;
2149a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2150a2477924SCodrin Ciubotariu 		 ethsw_id_pvid)
2151a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_PVID_AND_ZERO;
2152a2477924SCodrin Ciubotariu 	else
2153a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2154a2477924SCodrin Ciubotariu 
2155a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2156a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2157a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2158a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2159a2477924SCodrin Ciubotariu 		}
2160a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode);
2161a2477924SCodrin Ciubotariu 	} else {
2162a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2163a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_set(i, mode);
2164a2477924SCodrin Ciubotariu 	}
2165a2477924SCodrin Ciubotariu 
2166a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2167a2477924SCodrin Ciubotariu }
2168a2477924SCodrin Ciubotariu 
vsc9953_egr_vlan_tag_show_key_func(struct ethsw_command_def * parsed_cmd)2169a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_show_key_func(
2170a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2171a2477924SCodrin Ciubotariu {
2172a2477924SCodrin Ciubotariu 	int i;
2173a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
2174a2477924SCodrin Ciubotariu 
2175a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2176a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2177a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2178a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2179a2477924SCodrin Ciubotariu 		}
2180a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode);
2181a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
2182a2477924SCodrin Ciubotariu 		printf("%7d\t", parsed_cmd->port);
2183a2477924SCodrin Ciubotariu 		switch (mode) {
2184a2477924SCodrin Ciubotariu 		case EGR_TAG_CLASS:
2185a2477924SCodrin Ciubotariu 			printf("%12s\n", "classified");
2186a2477924SCodrin Ciubotariu 			break;
2187a2477924SCodrin Ciubotariu 		case EGR_TAG_PVID:
2188a2477924SCodrin Ciubotariu 			printf("%12s\n", "pvid");
2189a2477924SCodrin Ciubotariu 			break;
2190a2477924SCodrin Ciubotariu 		default:
2191a2477924SCodrin Ciubotariu 			printf("%12s\n", "-");
2192a2477924SCodrin Ciubotariu 		}
2193a2477924SCodrin Ciubotariu 	} else {
2194a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
2195a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2196a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_get(i, &mode);
2197a2477924SCodrin Ciubotariu 			switch (mode) {
2198a2477924SCodrin Ciubotariu 			case EGR_TAG_CLASS:
2199a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "classified");
2200a2477924SCodrin Ciubotariu 				break;
2201a2477924SCodrin Ciubotariu 			case EGR_TAG_PVID:
2202a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "pvid");
2203a2477924SCodrin Ciubotariu 				break;
2204a2477924SCodrin Ciubotariu 			default:
2205a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "-");
2206a2477924SCodrin Ciubotariu 			}
2207a2477924SCodrin Ciubotariu 		}
2208a2477924SCodrin Ciubotariu 	}
2209a2477924SCodrin Ciubotariu 
2210a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2211a2477924SCodrin Ciubotariu }
2212a2477924SCodrin Ciubotariu 
vsc9953_egr_vlan_tag_set_key_func(struct ethsw_command_def * parsed_cmd)2213a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_set_key_func(
2214a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2215a2477924SCodrin Ciubotariu {
2216a2477924SCodrin Ciubotariu 	int i;
2217a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
2218a2477924SCodrin Ciubotariu 
2219a2477924SCodrin Ciubotariu 	/* keywords for the egress vlan tag mode are the last in the array */
2220a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2221a2477924SCodrin Ciubotariu 	    ethsw_id_pvid)
2222a2477924SCodrin Ciubotariu 		mode = EGR_TAG_PVID;
2223a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2224a2477924SCodrin Ciubotariu 		 ethsw_id_classified)
2225a2477924SCodrin Ciubotariu 		mode = EGR_TAG_CLASS;
2226a2477924SCodrin Ciubotariu 	else
2227a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2228a2477924SCodrin Ciubotariu 
2229a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2230a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2231a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2232a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2233a2477924SCodrin Ciubotariu 		}
2234a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode);
2235a2477924SCodrin Ciubotariu 	} else {
2236a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2237a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_set(i, mode);
2238a2477924SCodrin Ciubotariu 	}
2239a2477924SCodrin Ciubotariu 
2240a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2241a2477924SCodrin Ciubotariu }
2242a2477924SCodrin Ciubotariu 
vsc9953_vlan_learn_show_key_func(struct ethsw_command_def * parsed_cmd)224321d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_show_key_func(
224421d214fcSCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
224521d214fcSCodrin Ciubotariu {
224621d214fcSCodrin Ciubotariu 	int rc;
224721d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
224821d214fcSCodrin Ciubotariu 
224921d214fcSCodrin Ciubotariu 	rc = vsc9953_vlan_learning_get(&mode);
225021d214fcSCodrin Ciubotariu 	if (rc)
225121d214fcSCodrin Ciubotariu 		return CMD_RET_FAILURE;
225221d214fcSCodrin Ciubotariu 
225321d214fcSCodrin Ciubotariu 	switch (mode) {
225421d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
225521d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: shared\n");
225621d214fcSCodrin Ciubotariu 		break;
225721d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
225821d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: private\n");
225921d214fcSCodrin Ciubotariu 		break;
226021d214fcSCodrin Ciubotariu 	default:
226121d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
226221d214fcSCodrin Ciubotariu 		rc = CMD_RET_FAILURE;
226321d214fcSCodrin Ciubotariu 	}
226421d214fcSCodrin Ciubotariu 
226521d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
226621d214fcSCodrin Ciubotariu }
226721d214fcSCodrin Ciubotariu 
vsc9953_vlan_learn_set_key_func(struct ethsw_command_def * parsed_cmd)226821d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
226921d214fcSCodrin Ciubotariu {
227021d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
227121d214fcSCodrin Ciubotariu 
227221d214fcSCodrin Ciubotariu 	/* keywords for shared/private are the last in the array */
227321d214fcSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
227421d214fcSCodrin Ciubotariu 	    ethsw_id_shared)
227521d214fcSCodrin Ciubotariu 		mode = SHARED_VLAN_LEARNING;
227621d214fcSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
227721d214fcSCodrin Ciubotariu 		 ethsw_id_private)
227821d214fcSCodrin Ciubotariu 		mode = PRIVATE_VLAN_LEARNING;
227921d214fcSCodrin Ciubotariu 	else
228021d214fcSCodrin Ciubotariu 		return CMD_RET_USAGE;
228121d214fcSCodrin Ciubotariu 
228221d214fcSCodrin Ciubotariu 	vsc9953_vlan_learning_set(mode);
228321d214fcSCodrin Ciubotariu 
228421d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
228521d214fcSCodrin Ciubotariu }
228621d214fcSCodrin Ciubotariu 
vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def * parsed_cmd)22875ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd)
22885ed1bacdSCodrin Ciubotariu {
22895ed1bacdSCodrin Ciubotariu 	int i;
22905ed1bacdSCodrin Ciubotariu 	int enabled;
22915ed1bacdSCodrin Ciubotariu 
22925ed1bacdSCodrin Ciubotariu 	printf("%7s\t%18s\n", "Port", "Ingress filtering");
22935ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
22945ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
22955ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
22965ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
22975ed1bacdSCodrin Ciubotariu 		}
22985ed1bacdSCodrin Ciubotariu 		enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port);
22995ed1bacdSCodrin Ciubotariu 		printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" :
23005ed1bacdSCodrin Ciubotariu 								  "disable");
23015ed1bacdSCodrin Ciubotariu 	} else {
23025ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
23035ed1bacdSCodrin Ciubotariu 			enabled = vsc9953_port_ingress_filtering_get(i);
23045ed1bacdSCodrin Ciubotariu 			printf("%7d\t%18s\n", parsed_cmd->port, enabled ?
23055ed1bacdSCodrin Ciubotariu 								"enable" :
23065ed1bacdSCodrin Ciubotariu 								"disable");
23075ed1bacdSCodrin Ciubotariu 		}
23085ed1bacdSCodrin Ciubotariu 	}
23095ed1bacdSCodrin Ciubotariu 
23105ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
23115ed1bacdSCodrin Ciubotariu }
23125ed1bacdSCodrin Ciubotariu 
vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def * parsed_cmd)23135ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
23145ed1bacdSCodrin Ciubotariu {
23155ed1bacdSCodrin Ciubotariu 	int i;
23165ed1bacdSCodrin Ciubotariu 	int enable;
23175ed1bacdSCodrin Ciubotariu 
23185ed1bacdSCodrin Ciubotariu 	/* keywords for enabling/disabling ingress filtering
23195ed1bacdSCodrin Ciubotariu 	 * are the last in the array
23205ed1bacdSCodrin Ciubotariu 	 */
23215ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
23225ed1bacdSCodrin Ciubotariu 	    ethsw_id_enable)
23235ed1bacdSCodrin Ciubotariu 		enable = 1;
23245ed1bacdSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
23255ed1bacdSCodrin Ciubotariu 		 ethsw_id_disable)
23265ed1bacdSCodrin Ciubotariu 		enable = 0;
23275ed1bacdSCodrin Ciubotariu 	else
23285ed1bacdSCodrin Ciubotariu 		return CMD_RET_USAGE;
23295ed1bacdSCodrin Ciubotariu 
23305ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
23315ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
23325ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
23335ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
23345ed1bacdSCodrin Ciubotariu 		}
23355ed1bacdSCodrin Ciubotariu 		vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable);
23365ed1bacdSCodrin Ciubotariu 	} else {
23375ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
23385ed1bacdSCodrin Ciubotariu 			vsc9953_port_ingress_filtering_set(i, enable);
23395ed1bacdSCodrin Ciubotariu 	}
23405ed1bacdSCodrin Ciubotariu 
23415ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
23425ed1bacdSCodrin Ciubotariu }
23435ed1bacdSCodrin Ciubotariu 
vsc9953_port_aggr_show_key_func(struct ethsw_command_def * parsed_cmd)2344aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
2345aae0e689SCodrin Ciubotariu {
2346aae0e689SCodrin Ciubotariu 	int i;
2347aae0e689SCodrin Ciubotariu 	int aggr_grp;
2348aae0e689SCodrin Ciubotariu 
2349aae0e689SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2350aae0e689SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2351aae0e689SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2352aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2353aae0e689SCodrin Ciubotariu 		}
2354aae0e689SCodrin Ciubotariu 
2355aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
2356aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2357aae0e689SCodrin Ciubotariu 		printf("%7s %10s\n", "Port", "Aggr grp");
2358aae0e689SCodrin Ciubotariu 		printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
2359aae0e689SCodrin Ciubotariu 	} else {
2360aae0e689SCodrin Ciubotariu 		printf("%7s %10s\n", "Port", "Aggr grp");
2361aae0e689SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2362aae0e689SCodrin Ciubotariu 			if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
2363aae0e689SCodrin Ciubotariu 				continue;
2364aae0e689SCodrin Ciubotariu 			printf("%7d %10d\n", i, aggr_grp);
2365aae0e689SCodrin Ciubotariu 		}
2366aae0e689SCodrin Ciubotariu 	}
2367aae0e689SCodrin Ciubotariu 
2368aae0e689SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2369aae0e689SCodrin Ciubotariu }
2370aae0e689SCodrin Ciubotariu 
vsc9953_port_aggr_set_key_func(struct ethsw_command_def * parsed_cmd)2371aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
2372aae0e689SCodrin Ciubotariu {
2373aae0e689SCodrin Ciubotariu 	int i;
2374aae0e689SCodrin Ciubotariu 
2375aae0e689SCodrin Ciubotariu 	/* Aggregation group number should be set in parsed_cmd->aggr_grp */
2376aae0e689SCodrin Ciubotariu 	if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
2377aae0e689SCodrin Ciubotariu 		printf("Please set an aggregation group value\n");
2378aae0e689SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2379aae0e689SCodrin Ciubotariu 	}
2380aae0e689SCodrin Ciubotariu 
2381aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
2382aae0e689SCodrin Ciubotariu 		printf("Invalid aggregation group number: %d\n",
2383aae0e689SCodrin Ciubotariu 		       parsed_cmd->aggr_grp);
2384aae0e689SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2385aae0e689SCodrin Ciubotariu 	}
2386aae0e689SCodrin Ciubotariu 
2387aae0e689SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2388aae0e689SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2389aae0e689SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2390aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2391aae0e689SCodrin Ciubotariu 		}
2392aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
2393aae0e689SCodrin Ciubotariu 					      parsed_cmd->aggr_grp)) {
2394aae0e689SCodrin Ciubotariu 			printf("Port %d: failed to set aggr group %d\n",
2395aae0e689SCodrin Ciubotariu 			       parsed_cmd->port, parsed_cmd->aggr_grp);
2396aae0e689SCodrin Ciubotariu 		}
2397aae0e689SCodrin Ciubotariu 	} else {
2398aae0e689SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2399aae0e689SCodrin Ciubotariu 			if (vsc9953_port_aggr_grp_set(i,
2400aae0e689SCodrin Ciubotariu 						      parsed_cmd->aggr_grp)) {
2401aae0e689SCodrin Ciubotariu 				printf("Port %d: failed to set aggr group %d\n",
2402aae0e689SCodrin Ciubotariu 				       i, parsed_cmd->aggr_grp);
2403aae0e689SCodrin Ciubotariu 			}
2404aae0e689SCodrin Ciubotariu 		}
2405aae0e689SCodrin Ciubotariu 	}
2406aae0e689SCodrin Ciubotariu 
2407aae0e689SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2408aae0e689SCodrin Ciubotariu }
2409aae0e689SCodrin Ciubotariu 
241024a23debSCodrin Ciubotariu static struct ethsw_command_func vsc9953_cmd_func = {
241124a23debSCodrin Ciubotariu 		.ethsw_name = "L2 Switch VSC9953",
241224a23debSCodrin Ciubotariu 		.port_enable = &vsc9953_port_status_key_func,
241324a23debSCodrin Ciubotariu 		.port_disable = &vsc9953_port_status_key_func,
241424a23debSCodrin Ciubotariu 		.port_show = &vsc9953_port_config_key_func,
241586719f0cSCodrin Ciubotariu 		.port_stats = &vsc9953_port_stats_key_func,
241686719f0cSCodrin Ciubotariu 		.port_stats_clear = &vsc9953_port_stats_clear_key_func,
241768c929daSCodrin Ciubotariu 		.port_learn = &vsc9953_learn_set_key_func,
241868c929daSCodrin Ciubotariu 		.port_learn_show = &vsc9953_learn_show_key_func,
241922449858SCodrin Ciubotariu 		.fdb_show = &vsc9953_fdb_show_key_func,
242022449858SCodrin Ciubotariu 		.fdb_flush = &vsc9953_fdb_flush_key_func,
242122449858SCodrin Ciubotariu 		.fdb_entry_add = &vsc9953_fdb_entry_add_key_func,
242222449858SCodrin Ciubotariu 		.fdb_entry_del = &vsc9953_fdb_entry_del_key_func,
2423a2477924SCodrin Ciubotariu 		.pvid_show = &vsc9953_pvid_show_key_func,
2424a2477924SCodrin Ciubotariu 		.pvid_set = &vsc9953_pvid_set_key_func,
2425a2477924SCodrin Ciubotariu 		.vlan_show = &vsc9953_vlan_show_key_func,
2426a2477924SCodrin Ciubotariu 		.vlan_set = &vsc9953_vlan_set_key_func,
2427a2477924SCodrin Ciubotariu 		.port_untag_show = &vsc9953_port_untag_show_key_func,
2428a2477924SCodrin Ciubotariu 		.port_untag_set = &vsc9953_port_untag_set_key_func,
2429a2477924SCodrin Ciubotariu 		.port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func,
2430a2477924SCodrin Ciubotariu 		.port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func,
243121d214fcSCodrin Ciubotariu 		.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
243221d214fcSCodrin Ciubotariu 		.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
24335ed1bacdSCodrin Ciubotariu 		.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
2434aae0e689SCodrin Ciubotariu 		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
2435aae0e689SCodrin Ciubotariu 		.port_aggr_show = &vsc9953_port_aggr_show_key_func,
2436aae0e689SCodrin Ciubotariu 		.port_aggr_set = &vsc9953_port_aggr_set_key_func,
243724a23debSCodrin Ciubotariu };
243824a23debSCodrin Ciubotariu 
243924a23debSCodrin Ciubotariu #endif /* CONFIG_CMD_ETHSW */
244024a23debSCodrin Ciubotariu 
24419de05987SCodrin Ciubotariu /*****************************************************************************
24429de05987SCodrin Ciubotariu At startup, the default configuration would be:
24439de05987SCodrin Ciubotariu 	- HW learning enabled on all ports; (HW default)
24449de05987SCodrin Ciubotariu 	- All ports are in VLAN 1;
24459de05987SCodrin Ciubotariu 	- All ports are VLAN aware;
24469de05987SCodrin Ciubotariu 	- All ports have POP_COUNT 1;
24479de05987SCodrin Ciubotariu 	- All ports have PVID 1;
24489de05987SCodrin Ciubotariu 	- All ports have TPID 0x8100; (HW default)
24499de05987SCodrin Ciubotariu 	- All ports tag frames classified to all VLANs that are not PVID;
24509de05987SCodrin Ciubotariu *****************************************************************************/
vsc9953_default_configuration(void)24519de05987SCodrin Ciubotariu void vsc9953_default_configuration(void)
24529de05987SCodrin Ciubotariu {
24539de05987SCodrin Ciubotariu 	int i;
24549de05987SCodrin Ciubotariu 
2455ba389e65SCodrin Ciubotariu 	if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
2456ba389e65SCodrin Ciubotariu 		debug("VSC9953: failed to set AGE time to %d\n",
2457ba389e65SCodrin Ciubotariu 		      VSC9953_DEFAULT_AGE_TIME);
2458ba389e65SCodrin Ciubotariu 
24599de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_VLAN; i++)
24609de05987SCodrin Ciubotariu 		vsc9953_vlan_table_membership_all_set(i, 0);
24619de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_aware_set(1);
24629de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_pvid_set(1);
24639de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_poncnt_set(1);
24649de05987SCodrin Ciubotariu 	vsc9953_vlan_table_membership_all_set(1, 1);
24659de05987SCodrin Ciubotariu 	vsc9953_vlan_ingr_fltr_learn_drop(1);
24669de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
2467aae0e689SCodrin Ciubotariu 	if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
2468aae0e689SCodrin Ciubotariu 		debug("VSC9953: failed to set default aggregation code mode\n");
24699de05987SCodrin Ciubotariu }
24709de05987SCodrin Ciubotariu 
vcap_entry2cache_init(u32 target,u32 entry_words)2471*98017a1fSRadu Bulie static void vcap_entry2cache_init(u32 target, u32 entry_words)
2472*98017a1fSRadu Bulie {
2473*98017a1fSRadu Bulie 	int i;
2474*98017a1fSRadu Bulie 
2475*98017a1fSRadu Bulie 	for (i = 0; i < entry_words; i++) {
2476*98017a1fSRadu Bulie 		out_le32((unsigned int *)(VSC9953_OFFSET +
2477*98017a1fSRadu Bulie 				VSC9953_VCAP_CACHE_ENTRY_DAT(target, i)), 0x00);
2478*98017a1fSRadu Bulie 		out_le32((unsigned int *)(VSC9953_OFFSET +
2479*98017a1fSRadu Bulie 				VSC9953_VCAP_CACHE_MASK_DAT(target, i)), 0xFF);
2480*98017a1fSRadu Bulie 	}
2481*98017a1fSRadu Bulie 
2482*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2483*98017a1fSRadu Bulie 				VSC9953_VCAP_CACHE_TG_DAT(target)), 0x00);
2484*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2485*98017a1fSRadu Bulie 				  VSC9953_VCAP_CFG_MV_CFG(target)),
2486*98017a1fSRadu Bulie 		 VSC9953_VCAP_CFG_MV_CFG_SIZE(entry_words));
2487*98017a1fSRadu Bulie }
2488*98017a1fSRadu Bulie 
vcap_action2cache_init(u32 target,u32 action_words,u32 counter_words)2489*98017a1fSRadu Bulie static void vcap_action2cache_init(u32 target, u32 action_words,
2490*98017a1fSRadu Bulie 				   u32 counter_words)
2491*98017a1fSRadu Bulie {
2492*98017a1fSRadu Bulie 	int i;
2493*98017a1fSRadu Bulie 
2494*98017a1fSRadu Bulie 	for (i = 0; i < action_words; i++)
2495*98017a1fSRadu Bulie 		out_le32((unsigned int *)(VSC9953_OFFSET +
2496*98017a1fSRadu Bulie 			       VSC9953_VCAP_CACHE_ACTION_DAT(target, i)), 0x00);
2497*98017a1fSRadu Bulie 
2498*98017a1fSRadu Bulie 	for (i = 0; i < counter_words; i++)
2499*98017a1fSRadu Bulie 		out_le32((unsigned int *)(VSC9953_OFFSET +
2500*98017a1fSRadu Bulie 				  VSC9953_VCAP_CACHE_CNT_DAT(target, i)), 0x00);
2501*98017a1fSRadu Bulie }
2502*98017a1fSRadu Bulie 
vcap_cmd(u32 target,u16 ix,int cmd,int sel,int entry_count)2503*98017a1fSRadu Bulie static int vcap_cmd(u32 target, u16 ix, int cmd, int sel, int entry_count)
2504*98017a1fSRadu Bulie {
2505*98017a1fSRadu Bulie 	u32 tgt = target;
2506*98017a1fSRadu Bulie 	u32 value = (VSC9953_VCAP_UPDATE_CTRL_UPDATE_CMD(cmd) |
2507*98017a1fSRadu Bulie 		     VSC9953_VCAP_UPDATE_CTRL_UPDATE_ADDR(ix) |
2508*98017a1fSRadu Bulie 		     VSC9953_VCAP_UPDATE_CTRL_UPDATE_SHOT);
2509*98017a1fSRadu Bulie 
2510*98017a1fSRadu Bulie 	if ((sel & TCAM_SEL_ENTRY) && ix >= entry_count)
2511*98017a1fSRadu Bulie 		return CMD_RET_FAILURE;
2512*98017a1fSRadu Bulie 
2513*98017a1fSRadu Bulie 	if (!(sel & TCAM_SEL_ENTRY))
2514*98017a1fSRadu Bulie 		value |= VSC9953_VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS;
2515*98017a1fSRadu Bulie 
2516*98017a1fSRadu Bulie 	if (!(sel & TCAM_SEL_ACTION))
2517*98017a1fSRadu Bulie 		value |= VSC9953_VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS;
2518*98017a1fSRadu Bulie 
2519*98017a1fSRadu Bulie 	if (!(sel & TCAM_SEL_COUNTER))
2520*98017a1fSRadu Bulie 		value |= VSC9953_VCAP_UPDATE_CTRL_UPDATE_CNT_DIS;
2521*98017a1fSRadu Bulie 
2522*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2523*98017a1fSRadu Bulie 				VSC9953_VCAP_CFG_UPDATE_CTRL(tgt)), value);
2524*98017a1fSRadu Bulie 
2525*98017a1fSRadu Bulie 	do {
2526*98017a1fSRadu Bulie 		value = in_le32((unsigned int *)(VSC9953_OFFSET +
2527*98017a1fSRadu Bulie 				VSC9953_VCAP_CFG_UPDATE_CTRL(tgt)));
2528*98017a1fSRadu Bulie 
2529*98017a1fSRadu Bulie 	} while (value & VSC9953_VCAP_UPDATE_CTRL_UPDATE_SHOT);
2530*98017a1fSRadu Bulie 
2531*98017a1fSRadu Bulie 	return CMD_RET_SUCCESS;
2532*98017a1fSRadu Bulie }
2533*98017a1fSRadu Bulie 
vsc9953_vcap_init(void)2534*98017a1fSRadu Bulie static void vsc9953_vcap_init(void)
2535*98017a1fSRadu Bulie {
2536*98017a1fSRadu Bulie 	u32 tgt = VSC9953_ES0;
2537*98017a1fSRadu Bulie 	int cmd_ret;
2538*98017a1fSRadu Bulie 
2539*98017a1fSRadu Bulie 	/* write entries */
2540*98017a1fSRadu Bulie 	vcap_entry2cache_init(tgt, ENTRY_WORDS_ES0);
2541*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE, TCAM_SEL_ENTRY,
2542*98017a1fSRadu Bulie 			   ENTRY_WORDS_ES0);
2543*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2544*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid TCAM_SEL_ENTRY\n",
2545*98017a1fSRadu Bulie 		      __LINE__);
2546*98017a1fSRadu Bulie 
2547*98017a1fSRadu Bulie 	/* write actions and counters */
2548*98017a1fSRadu Bulie 	vcap_action2cache_init(tgt, BITS_TO_DWORD(ES0_ACT_WIDTH),
2549*98017a1fSRadu Bulie 			       BITS_TO_DWORD(ES0_CNT_WIDTH));
2550*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2551*98017a1fSRadu Bulie 				  VSC9953_VCAP_CFG_MV_CFG(tgt)),
2552*98017a1fSRadu Bulie 		 VSC9953_VCAP_CFG_MV_CFG_SIZE(ES0_ACT_COUNT));
2553*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE,
2554*98017a1fSRadu Bulie 			   TCAM_SEL_ACTION | TCAM_SEL_COUNTER, ENTRY_WORDS_ES0);
2555*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2556*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid TCAM_SEL_ACTION | TCAM_SEL_COUNTER\n",
2557*98017a1fSRadu Bulie 		      __LINE__);
2558*98017a1fSRadu Bulie 
2559*98017a1fSRadu Bulie 	tgt = VSC9953_IS1;
2560*98017a1fSRadu Bulie 
2561*98017a1fSRadu Bulie 	/* write entries */
2562*98017a1fSRadu Bulie 	vcap_entry2cache_init(tgt, ENTRY_WORDS_IS1);
2563*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE, TCAM_SEL_ENTRY,
2564*98017a1fSRadu Bulie 			   ENTRY_WORDS_IS1);
2565*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2566*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid TCAM_SEL_ENTRY\n",
2567*98017a1fSRadu Bulie 		      __LINE__);
2568*98017a1fSRadu Bulie 
2569*98017a1fSRadu Bulie 	/* write actions and counters */
2570*98017a1fSRadu Bulie 	vcap_action2cache_init(tgt, BITS_TO_DWORD(IS1_ACT_WIDTH),
2571*98017a1fSRadu Bulie 			       BITS_TO_DWORD(IS1_CNT_WIDTH));
2572*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2573*98017a1fSRadu Bulie 				  VSC9953_VCAP_CFG_MV_CFG(tgt)),
2574*98017a1fSRadu Bulie 		 VSC9953_VCAP_CFG_MV_CFG_SIZE(IS1_ACT_COUNT));
2575*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE,
2576*98017a1fSRadu Bulie 			   TCAM_SEL_ACTION | TCAM_SEL_COUNTER, ENTRY_WORDS_IS1);
2577*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2578*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid TCAM_SEL_ACTION | TCAM_SEL_COUNTER\n",
2579*98017a1fSRadu Bulie 		      __LINE__);
2580*98017a1fSRadu Bulie 
2581*98017a1fSRadu Bulie 	tgt = VSC9953_IS2;
2582*98017a1fSRadu Bulie 
2583*98017a1fSRadu Bulie 	/* write entries */
2584*98017a1fSRadu Bulie 	vcap_entry2cache_init(tgt, ENTRY_WORDS_IS2);
2585*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE, TCAM_SEL_ENTRY,
2586*98017a1fSRadu Bulie 			   ENTRY_WORDS_IS2);
2587*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2588*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid selection: TCAM_SEL_ENTRY\n",
2589*98017a1fSRadu Bulie 		      __LINE__);
2590*98017a1fSRadu Bulie 
2591*98017a1fSRadu Bulie 	/* write actions and counters */
2592*98017a1fSRadu Bulie 	vcap_action2cache_init(tgt, BITS_TO_DWORD(IS2_ACT_WIDTH),
2593*98017a1fSRadu Bulie 			       BITS_TO_DWORD(IS2_CNT_WIDTH));
2594*98017a1fSRadu Bulie 	out_le32((unsigned int *)(VSC9953_OFFSET +
2595*98017a1fSRadu Bulie 				  VSC9953_VCAP_CFG_MV_CFG(tgt)),
2596*98017a1fSRadu Bulie 		 VSC9953_VCAP_CFG_MV_CFG_SIZE(IS2_ACT_COUNT));
2597*98017a1fSRadu Bulie 	cmd_ret = vcap_cmd(tgt, 0, TCAM_CMD_INITIALIZE,
2598*98017a1fSRadu Bulie 			   TCAM_SEL_ACTION | TCAM_SEL_COUNTER, ENTRY_WORDS_IS2);
2599*98017a1fSRadu Bulie 	if (cmd_ret != CMD_RET_SUCCESS)
2600*98017a1fSRadu Bulie 		debug("VSC9953:%d invalid TCAM_SEL_ACTION | TCAM_SEL_COUNTER\n",
2601*98017a1fSRadu Bulie 		      __LINE__);
2602*98017a1fSRadu Bulie }
2603*98017a1fSRadu Bulie 
vsc9953_init(bd_t * bis)26046706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis)
26056706b115SCodrin Ciubotariu {
26063cc8cfffSCodrin Ciubotariu 	u32 i;
26073cc8cfffSCodrin Ciubotariu 	u32 hdx_cfg = 0;
26083cc8cfffSCodrin Ciubotariu 	u32 phy_addr = 0;
26096706b115SCodrin Ciubotariu 	int timeout;
26106706b115SCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
26116706b115SCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
26126706b115SCodrin Ciubotariu 	struct vsc9953_dev_gmii *l2dev_gmii_reg;
26136706b115SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
26146706b115SCodrin Ciubotariu 	struct vsc9953_devcpu_gcb *l2dev_gcb;
26156706b115SCodrin Ciubotariu 
26166706b115SCodrin Ciubotariu 	l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
26176706b115SCodrin Ciubotariu 			VSC9953_DEV_GMII_OFFSET);
26186706b115SCodrin Ciubotariu 
26196706b115SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
26206706b115SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
26216706b115SCodrin Ciubotariu 
26226706b115SCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
26236706b115SCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
26246706b115SCodrin Ciubotariu 
26256706b115SCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
26266706b115SCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
26276706b115SCodrin Ciubotariu 
26286706b115SCodrin Ciubotariu 	l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
26296706b115SCodrin Ciubotariu 			VSC9953_DEVCPU_GCB);
26306706b115SCodrin Ciubotariu 
26316706b115SCodrin Ciubotariu 	out_le32(&l2dev_gcb->chip_regs.soft_rst,
2632c4390486SCodrin Ciubotariu 		 VSC9953_SOFT_SWC_RST_ENA);
26336706b115SCodrin Ciubotariu 	timeout = 50000;
26346706b115SCodrin Ciubotariu 	while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
2635c4390486SCodrin Ciubotariu 			VSC9953_SOFT_SWC_RST_ENA) && --timeout)
26366706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 soft reset */
26376706b115SCodrin Ciubotariu 	if (timeout == 0)
26386706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 to reset\n");
26396706b115SCodrin Ciubotariu 
2640c4390486SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE |
2641c4390486SCodrin Ciubotariu 		 VSC9953_MEM_INIT);
26426706b115SCodrin Ciubotariu 
26436706b115SCodrin Ciubotariu 	timeout = 50000;
26446706b115SCodrin Ciubotariu 	while ((in_le32(&l2sys_reg->sys.reset_cfg) &
2645c4390486SCodrin Ciubotariu 		VSC9953_MEM_INIT) && --timeout)
26466706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 memory init */
26476706b115SCodrin Ciubotariu 	if (timeout == 0)
26486706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 memory to initialize\n");
26496706b115SCodrin Ciubotariu 
26506706b115SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
2651c4390486SCodrin Ciubotariu 			| VSC9953_CORE_ENABLE));
26526706b115SCodrin Ciubotariu 
26536706b115SCodrin Ciubotariu 	/* VSC9953 Setting to be done once only */
26546706b115SCodrin Ciubotariu 	out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
26556706b115SCodrin Ciubotariu 
26566706b115SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
26576706b115SCodrin Ciubotariu 		if (vsc9953_port_init(i))
26586706b115SCodrin Ciubotariu 			printf("Failed to initialize l2switch port %d\n", i);
26596706b115SCodrin Ciubotariu 
266002c00f26SCodrin Ciubotariu 		if (!vsc9953_l2sw.port[i].enabled)
266102c00f26SCodrin Ciubotariu 			continue;
266202c00f26SCodrin Ciubotariu 
26636706b115SCodrin Ciubotariu 		/* Enable VSC9953 GMII Ports Port ID 0 - 7 */
26646706b115SCodrin Ciubotariu 		if (VSC9953_INTERNAL_PORT_CHECK(i)) {
26656706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2666c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC_QSGMII);
26676706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2668c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG_QSGMII);
26696706b115SCodrin Ciubotariu 		} else {
26706706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2671c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC);
26726706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2673c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG);
26746706b115SCodrin Ciubotariu 		}
267502c00f26SCodrin Ciubotariu 
267602c00f26SCodrin Ciubotariu 		l2dev_gmii_reg = (struct vsc9953_dev_gmii *)
267702c00f26SCodrin Ciubotariu 				 (VSC9953_OFFSET + VSC9953_DEV_GMII_OFFSET +
267802c00f26SCodrin Ciubotariu 				 T1040_SWITCH_GMII_DEV_OFFSET * i);
267902c00f26SCodrin Ciubotariu 
26806706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
2681c4390486SCodrin Ciubotariu 			 VSC9953_CLOCK_CFG);
26826706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
2683c4390486SCodrin Ciubotariu 			 VSC9953_MAC_ENA_CFG);
26846706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
2685c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MODE_CFG);
26866706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
2687c4390486SCodrin Ciubotariu 			 VSC9953_MAC_IFG_CFG);
26886706b115SCodrin Ciubotariu 		/* mac_hdx_cfg varies with port id*/
2689c4390486SCodrin Ciubotariu 		hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16);
26906706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
26916706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->sys.front_port_mode[i],
2692c4390486SCodrin Ciubotariu 			 VSC9953_FRONT_PORT_MODE);
2693fe91095bSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[i],
2694c4390486SCodrin Ciubotariu 			     VSC9953_PORT_ENA);
26956706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
2696c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MAX_LEN);
26976706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
2698c4390486SCodrin Ciubotariu 			 VSC9953_PAUSE_CFG);
26996706b115SCodrin Ciubotariu 		/* WAIT FOR 2 us*/
27006706b115SCodrin Ciubotariu 		udelay(2);
27016706b115SCodrin Ciubotariu 
27026706b115SCodrin Ciubotariu 		/* Initialize Lynx PHY Wrappers */
27036706b115SCodrin Ciubotariu 		phy_addr = 0;
27046706b115SCodrin Ciubotariu 		if (vsc9953_l2sw.port[i].enet_if ==
27056706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_QSGMII)
27066706b115SCodrin Ciubotariu 			phy_addr = (i + 0x4) & 0x1F;
27076706b115SCodrin Ciubotariu 		else if (vsc9953_l2sw.port[i].enet_if ==
27086706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_SGMII)
27096706b115SCodrin Ciubotariu 			phy_addr = (i + 1) & 0x1F;
27106706b115SCodrin Ciubotariu 
27116706b115SCodrin Ciubotariu 		if (phy_addr) {
27126706b115SCodrin Ciubotariu 			/* SGMII IF mode + AN enable */
27136706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
27146706b115SCodrin Ciubotariu 					   0x14, PHY_SGMII_IF_MODE_AN |
27156706b115SCodrin Ciubotariu 					   PHY_SGMII_IF_MODE_SGMII);
27166706b115SCodrin Ciubotariu 			/* Dev ability according to SGMII specification */
27176706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
27186706b115SCodrin Ciubotariu 					   0x4, PHY_SGMII_DEV_ABILITY_SGMII);
27196706b115SCodrin Ciubotariu 			/* Adjust link timer for SGMII
27206706b115SCodrin Ciubotariu 			 * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
27216706b115SCodrin Ciubotariu 			 */
27226706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
27236706b115SCodrin Ciubotariu 					   0x13, 0x0003);
27246706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
27256706b115SCodrin Ciubotariu 					   0x12, 0x0d40);
27266706b115SCodrin Ciubotariu 			/* Restart AN */
27276706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
27286706b115SCodrin Ciubotariu 					   0x0, PHY_SGMII_CR_DEF_VAL |
27296706b115SCodrin Ciubotariu 					   PHY_SGMII_CR_RESET_AN);
27306706b115SCodrin Ciubotariu 
27316706b115SCodrin Ciubotariu 			timeout = 50000;
27326706b115SCodrin Ciubotariu 			while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
27336706b115SCodrin Ciubotariu 					phy_addr, 0x01) & 0x0020) && --timeout)
27346706b115SCodrin Ciubotariu 				udelay(1); /* wait for AN to complete */
27356706b115SCodrin Ciubotariu 			if (timeout == 0)
27366706b115SCodrin Ciubotariu 				debug("Timeout waiting for AN to complete\n");
27376706b115SCodrin Ciubotariu 		}
27386706b115SCodrin Ciubotariu 	}
27396706b115SCodrin Ciubotariu 
2740*98017a1fSRadu Bulie 	vsc9953_vcap_init();
27419de05987SCodrin Ciubotariu 	vsc9953_default_configuration();
27429de05987SCodrin Ciubotariu 
274324a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
274424a23debSCodrin Ciubotariu 	if (ethsw_define_functions(&vsc9953_cmd_func) < 0)
274524a23debSCodrin Ciubotariu 		debug("Unable to use \"ethsw\" commands\n");
274624a23debSCodrin Ciubotariu #endif
274724a23debSCodrin Ciubotariu 
27486706b115SCodrin Ciubotariu 	printf("VSC9953 L2 switch initialized\n");
27496706b115SCodrin Ciubotariu 	return;
27506706b115SCodrin Ciubotariu }
2751