xref: /OK3568_Linux_fs/u-boot/drivers/net/vsc9953.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  Copyright 2014 - 2015 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  SPDX-License-Identifier:      GPL-2.0+
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Driver for the Vitesse VSC9953 L2 Switch
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <asm/io.h>
10*4882a593Smuzhiyun #include <asm/fsl_serdes.h>
11*4882a593Smuzhiyun #include <fm_eth.h>
12*4882a593Smuzhiyun #include <fsl_memac.h>
13*4882a593Smuzhiyun #include <bitfield.h>
14*4882a593Smuzhiyun #include <errno.h>
15*4882a593Smuzhiyun #include <malloc.h>
16*4882a593Smuzhiyun #include <vsc9953.h>
17*4882a593Smuzhiyun #include <ethsw.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static struct vsc9953_info vsc9953_l2sw = {
20*4882a593Smuzhiyun 		.port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
21*4882a593Smuzhiyun 		.port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
22*4882a593Smuzhiyun 		.port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
23*4882a593Smuzhiyun 		.port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
24*4882a593Smuzhiyun 		.port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
25*4882a593Smuzhiyun 		.port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
26*4882a593Smuzhiyun 		.port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
27*4882a593Smuzhiyun 		.port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
28*4882a593Smuzhiyun 		.port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
29*4882a593Smuzhiyun 		.port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
vsc9953_port_info_set_mdio(int port_no,struct mii_dev * bus)32*4882a593Smuzhiyun void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
35*4882a593Smuzhiyun 		return;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	vsc9953_l2sw.port[port_no].bus = bus;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
vsc9953_port_info_set_phy_address(int port_no,int address)40*4882a593Smuzhiyun void vsc9953_port_info_set_phy_address(int port_no, int address)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
43*4882a593Smuzhiyun 		return;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	vsc9953_l2sw.port[port_no].phyaddr = address;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
vsc9953_port_info_set_phy_int(int port_no,phy_interface_t phy_int)48*4882a593Smuzhiyun void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	vsc9953_l2sw.port[port_no].enet_if = phy_int;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
vsc9953_port_enable(int port_no)56*4882a593Smuzhiyun void vsc9953_port_enable(int port_no)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
59*4882a593Smuzhiyun 		return;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	vsc9953_l2sw.port[port_no].enabled = 1;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
vsc9953_port_disable(int port_no)64*4882a593Smuzhiyun void vsc9953_port_disable(int port_no)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
67*4882a593Smuzhiyun 		return;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	vsc9953_l2sw.port[port_no].enabled = 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
vsc9953_mdio_write(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum,int value)72*4882a593Smuzhiyun static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
73*4882a593Smuzhiyun 		int regnum, int value)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	int timeout = 50000;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
78*4882a593Smuzhiyun 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
79*4882a593Smuzhiyun 			(0x1 << 1));
80*4882a593Smuzhiyun 	asm("sync");
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
83*4882a593Smuzhiyun 		udelay(1);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (timeout == 0)
86*4882a593Smuzhiyun 		debug("Timeout waiting for MDIO write\n");
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
vsc9953_mdio_read(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum)89*4882a593Smuzhiyun static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
90*4882a593Smuzhiyun 		int regnum)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	int value = 0xFFFF;
93*4882a593Smuzhiyun 	int timeout = 50000;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
96*4882a593Smuzhiyun 		udelay(1);
97*4882a593Smuzhiyun 	if (timeout == 0) {
98*4882a593Smuzhiyun 		debug("Timeout waiting for MDIO operation to finish\n");
99*4882a593Smuzhiyun 		return value;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/* Put the address of the phy, and the register
103*4882a593Smuzhiyun 	 * number into MIICMD
104*4882a593Smuzhiyun 	 */
105*4882a593Smuzhiyun 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
106*4882a593Smuzhiyun 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
107*4882a593Smuzhiyun 			(0x2 << 1));
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	timeout = 50000;
110*4882a593Smuzhiyun 	/* Wait for the the indication that the read is done */
111*4882a593Smuzhiyun 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
112*4882a593Smuzhiyun 		udelay(1);
113*4882a593Smuzhiyun 	if (timeout == 0)
114*4882a593Smuzhiyun 		debug("Timeout waiting for MDIO read\n");
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/* Grab the value read from the PHY */
117*4882a593Smuzhiyun 	value = in_le32(&phyregs->miimdata);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if ((value & 0x00030000) == 0)
120*4882a593Smuzhiyun 		return value & 0x0000ffff;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return value;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
init_phy(struct eth_device * dev)125*4882a593Smuzhiyun static int init_phy(struct eth_device *dev)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct vsc9953_port_info *l2sw_port = dev->priv;
128*4882a593Smuzhiyun 	struct phy_device *phydev = NULL;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun #ifdef CONFIG_PHYLIB
131*4882a593Smuzhiyun 	if (!l2sw_port->bus)
132*4882a593Smuzhiyun 		return 0;
133*4882a593Smuzhiyun 	phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
134*4882a593Smuzhiyun 			l2sw_port->enet_if);
135*4882a593Smuzhiyun 	if (!phydev) {
136*4882a593Smuzhiyun 		printf("Failed to connect\n");
137*4882a593Smuzhiyun 		return -1;
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	phydev->supported &= SUPPORTED_10baseT_Half |
141*4882a593Smuzhiyun 			SUPPORTED_10baseT_Full |
142*4882a593Smuzhiyun 			SUPPORTED_100baseT_Half |
143*4882a593Smuzhiyun 			SUPPORTED_100baseT_Full |
144*4882a593Smuzhiyun 			SUPPORTED_1000baseT_Full;
145*4882a593Smuzhiyun 	phydev->advertising = phydev->supported;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	l2sw_port->phydev = phydev;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	phy_config(phydev);
150*4882a593Smuzhiyun #endif
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
vsc9953_port_init(int port_no)155*4882a593Smuzhiyun static int vsc9953_port_init(int port_no)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct eth_device *dev;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* Internal ports never have a PHY */
160*4882a593Smuzhiyun 	if (VSC9953_INTERNAL_PORT_CHECK(port_no))
161*4882a593Smuzhiyun 		return 0;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	/* alloc eth device */
164*4882a593Smuzhiyun 	dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
165*4882a593Smuzhiyun 	if (!dev)
166*4882a593Smuzhiyun 		return -ENOMEM;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	sprintf(dev->name, "SW@PORT%d", port_no);
169*4882a593Smuzhiyun 	dev->priv = &vsc9953_l2sw.port[port_no];
170*4882a593Smuzhiyun 	dev->init = NULL;
171*4882a593Smuzhiyun 	dev->halt = NULL;
172*4882a593Smuzhiyun 	dev->send = NULL;
173*4882a593Smuzhiyun 	dev->recv = NULL;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (init_phy(dev)) {
176*4882a593Smuzhiyun 		free(dev);
177*4882a593Smuzhiyun 		return -ENODEV;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
vsc9953_vlan_table_poll_idle(void)183*4882a593Smuzhiyun static int vsc9953_vlan_table_poll_idle(void)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
186*4882a593Smuzhiyun 	int timeout;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
189*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	timeout = 50000;
192*4882a593Smuzhiyun 	while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
193*4882a593Smuzhiyun 		 VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
194*4882a593Smuzhiyun 		udelay(1);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return timeout ? 0 : -EBUSY;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun #ifdef CONFIG_CMD_ETHSW
200*4882a593Smuzhiyun /* Add/remove a port to/from a VLAN */
vsc9953_vlan_table_membership_set(int vid,u32 port_no,u8 add)201*4882a593Smuzhiyun static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	u32 val;
204*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
207*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (vsc9953_vlan_table_poll_idle() < 0) {
210*4882a593Smuzhiyun 		debug("VLAN table timeout\n");
211*4882a593Smuzhiyun 		return;
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
215*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
216*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
219*4882a593Smuzhiyun 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (vsc9953_vlan_table_poll_idle() < 0) {
222*4882a593Smuzhiyun 		debug("VLAN table timeout\n");
223*4882a593Smuzhiyun 		return;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
227*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
228*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.vlan_access);
231*4882a593Smuzhiyun 	if (!add) {
232*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
233*4882a593Smuzhiyun 						VSC9953_VLAN_CMD_WRITE) &
234*4882a593Smuzhiyun 		      ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
235*4882a593Smuzhiyun 						 (1 << port_no)));
236*4882a593Smuzhiyun 		 ;
237*4882a593Smuzhiyun 	} else {
238*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
239*4882a593Smuzhiyun 						VSC9953_VLAN_CMD_WRITE) |
240*4882a593Smuzhiyun 		      bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
241*4882a593Smuzhiyun 					       (1 << port_no));
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.vlan_access, val);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* wait for VLAN table command to flush */
246*4882a593Smuzhiyun 	if (vsc9953_vlan_table_poll_idle() < 0) {
247*4882a593Smuzhiyun 		debug("VLAN table timeout\n");
248*4882a593Smuzhiyun 		return;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /* show VLAN membership for a port */
vsc9953_vlan_membership_show(int port_no)253*4882a593Smuzhiyun static void vsc9953_vlan_membership_show(int port_no)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	u32 val;
256*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
257*4882a593Smuzhiyun 	u32 vid;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
260*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	printf("Port %d VLAN membership: ", port_no);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) {
265*4882a593Smuzhiyun 		if (vsc9953_vlan_table_poll_idle() < 0) {
266*4882a593Smuzhiyun 			debug("VLAN table timeout\n");
267*4882a593Smuzhiyun 			return;
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
271*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK,
272*4882a593Smuzhiyun 					       vid);
273*4882a593Smuzhiyun 		out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
276*4882a593Smuzhiyun 				VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		if (vsc9953_vlan_table_poll_idle() < 0) {
279*4882a593Smuzhiyun 			debug("VLAN table timeout\n");
280*4882a593Smuzhiyun 			return;
281*4882a593Smuzhiyun 		}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		val = in_le32(&l2ana_reg->ana_tables.vlan_access);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 		if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) &
286*4882a593Smuzhiyun 		    (1 << port_no))
287*4882a593Smuzhiyun 			printf("%d ", vid);
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	printf("\n");
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun #endif
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /* vlan table set/clear all membership of vid */
vsc9953_vlan_table_membership_all_set(int vid,int set_member)294*4882a593Smuzhiyun static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	uint val;
297*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
300*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (vsc9953_vlan_table_poll_idle() < 0) {
303*4882a593Smuzhiyun 		debug("VLAN table timeout\n");
304*4882a593Smuzhiyun 		return;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	/* read current vlan configuration */
308*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
309*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
310*4882a593Smuzhiyun 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
313*4882a593Smuzhiyun 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	if (vsc9953_vlan_table_poll_idle() < 0) {
316*4882a593Smuzhiyun 		debug("VLAN table timeout\n");
317*4882a593Smuzhiyun 		return;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
321*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
322*4882a593Smuzhiyun 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
325*4882a593Smuzhiyun 			VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
326*4882a593Smuzhiyun 			VSC9953_VLAN_CMD_WRITE |
327*4882a593Smuzhiyun 			(set_member ? VSC9953_VLAN_PORT_MASK : 0));
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun #ifdef CONFIG_CMD_ETHSW
331*4882a593Smuzhiyun /* Get PVID of a VSC9953 port */
vsc9953_port_vlan_pvid_get(int port_nr,int * pvid)332*4882a593Smuzhiyun static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	u32 val;
335*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	/* Administrative down */
338*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_nr].enabled) {
339*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_nr);
340*4882a593Smuzhiyun 		return -1;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
344*4882a593Smuzhiyun 				VSC9953_ANA_OFFSET);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/* Get ingress PVID */
347*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg);
348*4882a593Smuzhiyun 	*pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun #endif
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun /* Set PVID for a VSC9953 port */
vsc9953_port_vlan_pvid_set(int port_no,int pvid)355*4882a593Smuzhiyun static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	uint val;
358*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
359*4882a593Smuzhiyun 	struct vsc9953_rew_reg *l2rew_reg;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	/* Administrative down */
362*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
363*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
364*4882a593Smuzhiyun 		return;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
368*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
369*4882a593Smuzhiyun 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
370*4882a593Smuzhiyun 			VSC9953_REW_OFFSET);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	/* Set PVID on ingress */
373*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
374*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
375*4882a593Smuzhiyun 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/* Set PVID on egress */
378*4882a593Smuzhiyun 	val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
379*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
380*4882a593Smuzhiyun 				       pvid);
381*4882a593Smuzhiyun 	out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
vsc9953_port_all_vlan_pvid_set(int pvid)384*4882a593Smuzhiyun static void vsc9953_port_all_vlan_pvid_set(int pvid)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	int i;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
389*4882a593Smuzhiyun 		vsc9953_port_vlan_pvid_set(i, pvid);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun /* Enable/disable vlan aware of a VSC9953 port */
vsc9953_port_vlan_aware_set(int port_no,int enabled)393*4882a593Smuzhiyun static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/* Administrative down */
398*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
399*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
400*4882a593Smuzhiyun 		return;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
404*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	if (enabled)
407*4882a593Smuzhiyun 		setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
408*4882a593Smuzhiyun 			     VSC9953_VLAN_CFG_AWARE_ENA);
409*4882a593Smuzhiyun 	else
410*4882a593Smuzhiyun 		clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
411*4882a593Smuzhiyun 			     VSC9953_VLAN_CFG_AWARE_ENA);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun /* Set all VSC9953 ports' vlan aware  */
vsc9953_port_all_vlan_aware_set(int enabled)415*4882a593Smuzhiyun static void vsc9953_port_all_vlan_aware_set(int enabled)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	int i;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
420*4882a593Smuzhiyun 		vsc9953_port_vlan_aware_set(i, enabled);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /* Enable/disable vlan pop count of a VSC9953 port */
vsc9953_port_vlan_popcnt_set(int port_no,int popcnt)424*4882a593Smuzhiyun static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	uint val;
427*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	/* Administrative down */
430*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
431*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
432*4882a593Smuzhiyun 		return;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (popcnt > 3 || popcnt < 0) {
436*4882a593Smuzhiyun 		printf("Invalid pop count value: %d\n", port_no);
437*4882a593Smuzhiyun 		return;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
441*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
444*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
445*4882a593Smuzhiyun 				       popcnt);
446*4882a593Smuzhiyun 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /* Set all VSC9953 ports' pop count  */
vsc9953_port_all_vlan_poncnt_set(int popcnt)450*4882a593Smuzhiyun static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	int i;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
455*4882a593Smuzhiyun 		vsc9953_port_vlan_popcnt_set(i, popcnt);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun /* Enable/disable learning for frames dropped due to ingress filtering */
vsc9953_vlan_ingr_fltr_learn_drop(int enable)459*4882a593Smuzhiyun static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
464*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	if (enable)
467*4882a593Smuzhiyun 		setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
468*4882a593Smuzhiyun 	else
469*4882a593Smuzhiyun 		clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun enum aggr_code_mode {
473*4882a593Smuzhiyun 	AGGR_CODE_RAND = 0,
474*4882a593Smuzhiyun 	AGGR_CODE_ALL,	/* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
475*4882a593Smuzhiyun };
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun /* Set aggregation code generation mode */
vsc9953_aggr_code_set(enum aggr_code_mode ac)478*4882a593Smuzhiyun static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	int rc;
481*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
484*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	switch (ac) {
487*4882a593Smuzhiyun 	case AGGR_CODE_RAND:
488*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
489*4882a593Smuzhiyun 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
490*4882a593Smuzhiyun 				VSC9953_AC_IP6_LBL_ENA |
491*4882a593Smuzhiyun 				VSC9953_AC_IP6_TCPUDP_ENA |
492*4882a593Smuzhiyun 				VSC9953_AC_IP4_SIPDIP_ENA |
493*4882a593Smuzhiyun 				VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
494*4882a593Smuzhiyun 		rc = 0;
495*4882a593Smuzhiyun 		break;
496*4882a593Smuzhiyun 	case AGGR_CODE_ALL:
497*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
498*4882a593Smuzhiyun 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
499*4882a593Smuzhiyun 				VSC9953_AC_IP6_LBL_ENA |
500*4882a593Smuzhiyun 				VSC9953_AC_IP6_TCPUDP_ENA |
501*4882a593Smuzhiyun 				VSC9953_AC_IP4_SIPDIP_ENA |
502*4882a593Smuzhiyun 				VSC9953_AC_IP4_TCPUDP_ENA);
503*4882a593Smuzhiyun 		rc = 0;
504*4882a593Smuzhiyun 		break;
505*4882a593Smuzhiyun 	default:
506*4882a593Smuzhiyun 		/* unknown mode for aggregation code */
507*4882a593Smuzhiyun 		rc = -EINVAL;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	return rc;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun /* Egress untag modes of a VSC9953 port */
514*4882a593Smuzhiyun enum egress_untag_mode {
515*4882a593Smuzhiyun 	EGRESS_UNTAG_ALL = 0,
516*4882a593Smuzhiyun 	EGRESS_UNTAG_PVID_AND_ZERO,
517*4882a593Smuzhiyun 	EGRESS_UNTAG_ZERO,
518*4882a593Smuzhiyun 	EGRESS_UNTAG_NONE,
519*4882a593Smuzhiyun };
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun #ifdef CONFIG_CMD_ETHSW
522*4882a593Smuzhiyun /* Get egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_get(int port_no,enum egress_untag_mode * mode)523*4882a593Smuzhiyun static int vsc9953_port_vlan_egr_untag_get(int port_no,
524*4882a593Smuzhiyun 					   enum egress_untag_mode *mode)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	u32 val;
527*4882a593Smuzhiyun 	struct vsc9953_rew_reg *l2rew_reg;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	/* Administrative down */
530*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
531*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
532*4882a593Smuzhiyun 		return -1;
533*4882a593Smuzhiyun 	}
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
536*4882a593Smuzhiyun 			VSC9953_REW_OFFSET);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	switch (val & VSC9953_TAG_CFG_MASK) {
541*4882a593Smuzhiyun 	case VSC9953_TAG_CFG_NONE:
542*4882a593Smuzhiyun 		*mode = EGRESS_UNTAG_ALL;
543*4882a593Smuzhiyun 		return 0;
544*4882a593Smuzhiyun 	case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO:
545*4882a593Smuzhiyun 		*mode = EGRESS_UNTAG_PVID_AND_ZERO;
546*4882a593Smuzhiyun 		return 0;
547*4882a593Smuzhiyun 	case VSC9953_TAG_CFG_ALL_BUT_ZERO:
548*4882a593Smuzhiyun 		*mode = EGRESS_UNTAG_ZERO;
549*4882a593Smuzhiyun 		return 0;
550*4882a593Smuzhiyun 	case VSC9953_TAG_CFG_ALL:
551*4882a593Smuzhiyun 		*mode = EGRESS_UNTAG_NONE;
552*4882a593Smuzhiyun 		return 0;
553*4882a593Smuzhiyun 	default:
554*4882a593Smuzhiyun 		printf("Unknown egress tagging configuration for port %d\n",
555*4882a593Smuzhiyun 		       port_no);
556*4882a593Smuzhiyun 		return -1;
557*4882a593Smuzhiyun 	}
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun /* Show egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_show(int port_no)561*4882a593Smuzhiyun static void vsc9953_port_vlan_egr_untag_show(int port_no)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	enum egress_untag_mode mode;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) {
566*4882a593Smuzhiyun 		printf("%7d\t%17s\n", port_no, "-");
567*4882a593Smuzhiyun 		return;
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	printf("%7d\t", port_no);
571*4882a593Smuzhiyun 	switch (mode) {
572*4882a593Smuzhiyun 	case EGRESS_UNTAG_ALL:
573*4882a593Smuzhiyun 		printf("%17s\n", "all");
574*4882a593Smuzhiyun 		break;
575*4882a593Smuzhiyun 	case EGRESS_UNTAG_NONE:
576*4882a593Smuzhiyun 		printf("%17s\n", "none");
577*4882a593Smuzhiyun 		break;
578*4882a593Smuzhiyun 	case EGRESS_UNTAG_PVID_AND_ZERO:
579*4882a593Smuzhiyun 		printf("%17s\n", "PVID and 0");
580*4882a593Smuzhiyun 		break;
581*4882a593Smuzhiyun 	case EGRESS_UNTAG_ZERO:
582*4882a593Smuzhiyun 		printf("%17s\n", "0");
583*4882a593Smuzhiyun 		break;
584*4882a593Smuzhiyun 	default:
585*4882a593Smuzhiyun 		printf("%17s\n", "-");
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun #endif
589*4882a593Smuzhiyun 
vsc9953_port_vlan_egr_untag_set(int port_no,enum egress_untag_mode mode)590*4882a593Smuzhiyun static void vsc9953_port_vlan_egr_untag_set(int port_no,
591*4882a593Smuzhiyun 					    enum egress_untag_mode mode)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun 	struct vsc9953_rew_reg *l2rew_reg;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	/* Administrative down */
596*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
597*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
598*4882a593Smuzhiyun 		return;
599*4882a593Smuzhiyun 	}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
602*4882a593Smuzhiyun 			VSC9953_REW_OFFSET);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	switch (mode) {
605*4882a593Smuzhiyun 	case EGRESS_UNTAG_ALL:
606*4882a593Smuzhiyun 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
607*4882a593Smuzhiyun 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
608*4882a593Smuzhiyun 		break;
609*4882a593Smuzhiyun 	case EGRESS_UNTAG_PVID_AND_ZERO:
610*4882a593Smuzhiyun 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
611*4882a593Smuzhiyun 				VSC9953_TAG_CFG_MASK,
612*4882a593Smuzhiyun 				VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
613*4882a593Smuzhiyun 		break;
614*4882a593Smuzhiyun 	case EGRESS_UNTAG_ZERO:
615*4882a593Smuzhiyun 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
616*4882a593Smuzhiyun 				VSC9953_TAG_CFG_MASK,
617*4882a593Smuzhiyun 				VSC9953_TAG_CFG_ALL_BUT_ZERO);
618*4882a593Smuzhiyun 		break;
619*4882a593Smuzhiyun 	case EGRESS_UNTAG_NONE:
620*4882a593Smuzhiyun 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
621*4882a593Smuzhiyun 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
622*4882a593Smuzhiyun 		break;
623*4882a593Smuzhiyun 	default:
624*4882a593Smuzhiyun 		printf("Unknown untag mode for port %d\n", port_no);
625*4882a593Smuzhiyun 	}
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun 
vsc9953_port_all_vlan_egress_untagged_set(enum egress_untag_mode mode)628*4882a593Smuzhiyun static void vsc9953_port_all_vlan_egress_untagged_set(
629*4882a593Smuzhiyun 		enum egress_untag_mode mode)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	int i;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
634*4882a593Smuzhiyun 		vsc9953_port_vlan_egr_untag_set(i, mode);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
vsc9953_autoage_time_set(int age_period)637*4882a593Smuzhiyun static int vsc9953_autoage_time_set(int age_period)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	u32 autoage;
640*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
643*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
646*4882a593Smuzhiyun 		return -EINVAL;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
649*4882a593Smuzhiyun 					   VSC9953_AUTOAGE_PERIOD_MASK,
650*4882a593Smuzhiyun 					   age_period);
651*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana.auto_age, autoage);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	return 0;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun #ifdef CONFIG_CMD_ETHSW
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun /* Enable/disable status of a VSC9953 port */
vsc9953_port_status_set(int port_no,u8 enabled)659*4882a593Smuzhiyun static void vsc9953_port_status_set(int port_no, u8 enabled)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun 	struct vsc9953_qsys_reg *l2qsys_reg;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	/* Administrative down */
664*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled)
665*4882a593Smuzhiyun 		return;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
668*4882a593Smuzhiyun 			VSC9953_QSYS_OFFSET);
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	if (enabled)
671*4882a593Smuzhiyun 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
672*4882a593Smuzhiyun 			     VSC9953_PORT_ENA);
673*4882a593Smuzhiyun 	else
674*4882a593Smuzhiyun 		clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
675*4882a593Smuzhiyun 			     VSC9953_PORT_ENA);
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun /* Start autonegotiation for a VSC9953 PHY */
vsc9953_phy_autoneg(int port_no)679*4882a593Smuzhiyun static void vsc9953_phy_autoneg(int port_no)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].phydev)
682*4882a593Smuzhiyun 		return;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	if (vsc9953_l2sw.port[port_no].phydev->drv->startup(
685*4882a593Smuzhiyun 			vsc9953_l2sw.port[port_no].phydev))
686*4882a593Smuzhiyun 		printf("Failed to start PHY for port %d\n", port_no);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun /* Print a VSC9953 port's configuration */
vsc9953_port_config_show(int port_no)690*4882a593Smuzhiyun static void vsc9953_port_config_show(int port_no)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	int speed;
693*4882a593Smuzhiyun 	int duplex;
694*4882a593Smuzhiyun 	int link;
695*4882a593Smuzhiyun 	u8 enabled;
696*4882a593Smuzhiyun 	u32 val;
697*4882a593Smuzhiyun 	struct vsc9953_qsys_reg *l2qsys_reg;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
700*4882a593Smuzhiyun 			VSC9953_QSYS_OFFSET);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]);
703*4882a593Smuzhiyun 	enabled = vsc9953_l2sw.port[port_no].enabled &&
704*4882a593Smuzhiyun 		  (val & VSC9953_PORT_ENA);
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	/* internal ports (8 and 9) are fixed */
707*4882a593Smuzhiyun 	if (VSC9953_INTERNAL_PORT_CHECK(port_no)) {
708*4882a593Smuzhiyun 		link = 1;
709*4882a593Smuzhiyun 		speed = SPEED_2500;
710*4882a593Smuzhiyun 		duplex = DUPLEX_FULL;
711*4882a593Smuzhiyun 	} else {
712*4882a593Smuzhiyun 		if (vsc9953_l2sw.port[port_no].phydev) {
713*4882a593Smuzhiyun 			link = vsc9953_l2sw.port[port_no].phydev->link;
714*4882a593Smuzhiyun 			speed = vsc9953_l2sw.port[port_no].phydev->speed;
715*4882a593Smuzhiyun 			duplex = vsc9953_l2sw.port[port_no].phydev->duplex;
716*4882a593Smuzhiyun 		} else {
717*4882a593Smuzhiyun 			link = -1;
718*4882a593Smuzhiyun 			speed = -1;
719*4882a593Smuzhiyun 			duplex = -1;
720*4882a593Smuzhiyun 		}
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	printf("%8d ", port_no);
724*4882a593Smuzhiyun 	printf("%8s ", enabled == 1 ? "enabled" : "disabled");
725*4882a593Smuzhiyun 	printf("%8s ", link == 1 ? "up" : "down");
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	switch (speed) {
728*4882a593Smuzhiyun 	case SPEED_10:
729*4882a593Smuzhiyun 		printf("%8d ", 10);
730*4882a593Smuzhiyun 		break;
731*4882a593Smuzhiyun 	case SPEED_100:
732*4882a593Smuzhiyun 		printf("%8d ", 100);
733*4882a593Smuzhiyun 		break;
734*4882a593Smuzhiyun 	case SPEED_1000:
735*4882a593Smuzhiyun 		printf("%8d ", 1000);
736*4882a593Smuzhiyun 		break;
737*4882a593Smuzhiyun 	case SPEED_2500:
738*4882a593Smuzhiyun 		printf("%8d ", 2500);
739*4882a593Smuzhiyun 		break;
740*4882a593Smuzhiyun 	case SPEED_10000:
741*4882a593Smuzhiyun 		printf("%8d ", 10000);
742*4882a593Smuzhiyun 		break;
743*4882a593Smuzhiyun 	default:
744*4882a593Smuzhiyun 		printf("%8s ", "-");
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun /* Show VSC9953 ports' statistics */
vsc9953_port_statistics_show(int port_no)751*4882a593Smuzhiyun static void vsc9953_port_statistics_show(int port_no)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun 	u32 rx_val;
754*4882a593Smuzhiyun 	u32 tx_val;
755*4882a593Smuzhiyun 	struct vsc9953_system_reg *l2sys_reg;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	/* Administrative down */
758*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
759*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
760*4882a593Smuzhiyun 		return;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
764*4882a593Smuzhiyun 			VSC9953_SYS_OFFSET);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	printf("Statistics for L2 Switch port %d:\n", port_no);
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	/* Set counter view for our port */
769*4882a593Smuzhiyun 	out_le32(&l2sys_reg->sys.stat_cfg, port_no);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun #define VSC9953_STATS_PRINTF "%-15s %10u"
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames */
774*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) +
775*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) +
776*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) +
777*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) +
778*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) +
779*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) +
780*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) +
781*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) +
782*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) +
783*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) +
784*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
785*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
786*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
787*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
788*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
789*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
790*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
791*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
792*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
793*4882a593Smuzhiyun 	       "Rx frames:", rx_val, "Tx frames:", tx_val);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	/* Get number of Rx and Tx bytes */
796*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct);
797*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct);
798*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
799*4882a593Smuzhiyun 	       "Rx bytes:", rx_val, "Tx bytes:", tx_val);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	/* Get number of Rx frames received ok and Tx frames sent ok */
802*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) +
803*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) +
804*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) +
805*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) +
806*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) +
807*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) +
808*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) +
809*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) +
810*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) +
811*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) +
812*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) +
813*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) +
814*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) +
815*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) +
816*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) +
817*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7);
818*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
819*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
820*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
821*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
822*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
823*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
824*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
825*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
826*4882a593Smuzhiyun 	       "Rx frames ok:", rx_val, "Tx frames ok:", tx_val);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	/* Get number of Rx and Tx unicast frames */
829*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc);
830*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc);
831*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
832*4882a593Smuzhiyun 	       "Rx unicast:", rx_val, "Tx unicast:", tx_val);
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	/* Get number of Rx and Tx broadcast frames */
835*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc);
836*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc);
837*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
838*4882a593Smuzhiyun 	       "Rx broadcast:", rx_val, "Tx broadcast:", tx_val);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames of 64B */
841*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64);
842*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64);
843*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
844*4882a593Smuzhiyun 	       "Rx 64B:", rx_val, "Tx 64B:", tx_val);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames with sizes between 65B and 127B */
847*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127);
848*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127);
849*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
850*4882a593Smuzhiyun 	       "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val);
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames with sizes between 128B and 255B */
853*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255);
854*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255);
855*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
856*4882a593Smuzhiyun 	       "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames with sizes between 256B and 511B */
859*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511);
860*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511);
861*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
862*4882a593Smuzhiyun 	       "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val);
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames with sizes between 512B and 1023B */
865*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023);
866*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023);
867*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
868*4882a593Smuzhiyun 	       "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val);
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	/* Get number of Rx and Tx frames with sizes between 1024B and 1526B */
871*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526);
872*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526);
873*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
874*4882a593Smuzhiyun 	       "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val);
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	/* Get number of Rx and Tx jumbo frames */
877*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
878*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
879*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
880*4882a593Smuzhiyun 	       "Rx jumbo:", rx_val, "Tx jumbo:", tx_val);
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	/* Get number of Rx and Tx dropped frames */
883*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
884*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) +
885*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) +
886*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) +
887*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) +
888*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) +
889*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) +
890*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) +
891*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) +
892*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) +
893*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) +
894*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) +
895*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) +
896*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) +
897*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) +
898*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) +
899*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) +
900*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7);
901*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) +
902*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
903*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
904*4882a593Smuzhiyun 	       "Rx drops:", rx_val, "Tx drops:", tx_val);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	/*
907*4882a593Smuzhiyun 	 * Get number of Rx frames with CRC or alignment errors
908*4882a593Smuzhiyun 	 * and number of detected Tx collisions
909*4882a593Smuzhiyun 	 */
910*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc);
911*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col);
912*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
913*4882a593Smuzhiyun 	       "Rx CRC&align:", rx_val, "Tx coll:", tx_val);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	/*
916*4882a593Smuzhiyun 	 * Get number of Rx undersized frames and
917*4882a593Smuzhiyun 	 * number of Tx aged frames
918*4882a593Smuzhiyun 	 */
919*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short);
920*4882a593Smuzhiyun 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
921*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
922*4882a593Smuzhiyun 	       "Rx undersize:", rx_val, "Tx aged:", tx_val);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	/* Get number of Rx oversized frames */
925*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long);
926*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val);
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	/* Get number of Rx fragmented frames */
929*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag);
930*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	/* Get number of Rx jabber errors */
933*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber);
934*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val);
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	/*
937*4882a593Smuzhiyun 	 * Get number of Rx frames filtered due to classification rules or
938*4882a593Smuzhiyun 	 * no destination ports
939*4882a593Smuzhiyun 	 */
940*4882a593Smuzhiyun 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
941*4882a593Smuzhiyun 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local);
942*4882a593Smuzhiyun 	printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val);
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	printf("\n");
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun /* Clear statistics for a VSC9953 port */
vsc9953_port_statistics_clear(int port_no)948*4882a593Smuzhiyun static void vsc9953_port_statistics_clear(int port_no)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun 	struct vsc9953_system_reg *l2sys_reg;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	/* Administrative down */
953*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
954*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
955*4882a593Smuzhiyun 		return;
956*4882a593Smuzhiyun 	}
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
959*4882a593Smuzhiyun 			VSC9953_SYS_OFFSET);
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	/* Clear all counter groups for our ports */
962*4882a593Smuzhiyun 	out_le32(&l2sys_reg->sys.stat_cfg, port_no |
963*4882a593Smuzhiyun 		 VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX |
964*4882a593Smuzhiyun 		 VSC9953_STAT_CLEAR_DR);
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun enum port_learn_mode {
968*4882a593Smuzhiyun 	PORT_LEARN_NONE,
969*4882a593Smuzhiyun 	PORT_LEARN_AUTO
970*4882a593Smuzhiyun };
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun /* Set learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_set(int port_no,enum port_learn_mode mode)973*4882a593Smuzhiyun static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	/* Administrative down */
978*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
979*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
980*4882a593Smuzhiyun 		return;
981*4882a593Smuzhiyun 	}
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
984*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	switch (mode) {
987*4882a593Smuzhiyun 	case PORT_LEARN_NONE:
988*4882a593Smuzhiyun 		clrbits_le32(&l2ana_reg->port[port_no].port_cfg,
989*4882a593Smuzhiyun 			     VSC9953_PORT_CFG_LEARN_DROP |
990*4882a593Smuzhiyun 			     VSC9953_PORT_CFG_LEARN_CPU |
991*4882a593Smuzhiyun 			     VSC9953_PORT_CFG_LEARN_AUTO |
992*4882a593Smuzhiyun 			     VSC9953_PORT_CFG_LEARN_ENA);
993*4882a593Smuzhiyun 		break;
994*4882a593Smuzhiyun 	case PORT_LEARN_AUTO:
995*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg,
996*4882a593Smuzhiyun 				VSC9953_PORT_CFG_LEARN_DROP |
997*4882a593Smuzhiyun 				VSC9953_PORT_CFG_LEARN_CPU,
998*4882a593Smuzhiyun 				VSC9953_PORT_CFG_LEARN_ENA |
999*4882a593Smuzhiyun 				VSC9953_PORT_CFG_LEARN_AUTO);
1000*4882a593Smuzhiyun 		break;
1001*4882a593Smuzhiyun 	default:
1002*4882a593Smuzhiyun 		printf("Unknown learn mode for port %d\n", port_no);
1003*4882a593Smuzhiyun 	}
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun /* Get learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_get(int port_no,enum port_learn_mode * mode)1007*4882a593Smuzhiyun static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun 	u32 val;
1010*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	/* Administrative down */
1013*4882a593Smuzhiyun 	if (!vsc9953_l2sw.port[port_no].enabled) {
1014*4882a593Smuzhiyun 		printf("Port %d is administrative down\n", port_no);
1015*4882a593Smuzhiyun 		return -1;
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1019*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	/* For now we only support HW learning (auto) and no learning */
1022*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1023*4882a593Smuzhiyun 	if ((val & (VSC9953_PORT_CFG_LEARN_ENA |
1024*4882a593Smuzhiyun 		    VSC9953_PORT_CFG_LEARN_AUTO)) ==
1025*4882a593Smuzhiyun 	    (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO))
1026*4882a593Smuzhiyun 		*mode = PORT_LEARN_AUTO;
1027*4882a593Smuzhiyun 	else
1028*4882a593Smuzhiyun 		*mode = PORT_LEARN_NONE;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	return 0;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun /* wait for FDB to become available */
vsc9953_mac_table_poll_idle(void)1034*4882a593Smuzhiyun static int vsc9953_mac_table_poll_idle(void)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1037*4882a593Smuzhiyun 	u32 timeout;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1040*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	timeout = 50000;
1043*4882a593Smuzhiyun 	while (((in_le32(&l2ana_reg->ana_tables.mac_access) &
1044*4882a593Smuzhiyun 			 VSC9953_MAC_CMD_MASK) !=
1045*4882a593Smuzhiyun 		VSC9953_MAC_CMD_IDLE) && --timeout)
1046*4882a593Smuzhiyun 		udelay(1);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	return timeout ? 0 : -EBUSY;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun /* enum describing available commands for the MAC table */
1052*4882a593Smuzhiyun enum mac_table_cmd {
1053*4882a593Smuzhiyun 	MAC_TABLE_READ,
1054*4882a593Smuzhiyun 	MAC_TABLE_LOOKUP,
1055*4882a593Smuzhiyun 	MAC_TABLE_WRITE,
1056*4882a593Smuzhiyun 	MAC_TABLE_LEARN,
1057*4882a593Smuzhiyun 	MAC_TABLE_FORGET,
1058*4882a593Smuzhiyun 	MAC_TABLE_GET_NEXT,
1059*4882a593Smuzhiyun 	MAC_TABLE_AGE,
1060*4882a593Smuzhiyun };
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun /* Issues a command to the FDB table */
vsc9953_mac_table_cmd(enum mac_table_cmd cmd)1063*4882a593Smuzhiyun static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd)
1064*4882a593Smuzhiyun {
1065*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1068*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	switch (cmd) {
1071*4882a593Smuzhiyun 	case MAC_TABLE_READ:
1072*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1073*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID,
1074*4882a593Smuzhiyun 				VSC9953_MAC_CMD_READ);
1075*4882a593Smuzhiyun 		break;
1076*4882a593Smuzhiyun 	case MAC_TABLE_LOOKUP:
1077*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1078*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ |
1079*4882a593Smuzhiyun 				VSC9953_MAC_CMD_VALID);
1080*4882a593Smuzhiyun 		break;
1081*4882a593Smuzhiyun 	case MAC_TABLE_WRITE:
1082*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1083*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK |
1084*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_MASK,
1085*4882a593Smuzhiyun 				VSC9953_MAC_CMD_WRITE |
1086*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_LOCKED);
1087*4882a593Smuzhiyun 		break;
1088*4882a593Smuzhiyun 	case MAC_TABLE_LEARN:
1089*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1090*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK |
1091*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_MASK,
1092*4882a593Smuzhiyun 				VSC9953_MAC_CMD_LEARN |
1093*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_LOCKED |
1094*4882a593Smuzhiyun 				VSC9953_MAC_CMD_VALID);
1095*4882a593Smuzhiyun 		break;
1096*4882a593Smuzhiyun 	case MAC_TABLE_FORGET:
1097*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1098*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK |
1099*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_MASK,
1100*4882a593Smuzhiyun 				VSC9953_MAC_CMD_FORGET);
1101*4882a593Smuzhiyun 		break;
1102*4882a593Smuzhiyun 	case MAC_TABLE_GET_NEXT:
1103*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1104*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK |
1105*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_MASK,
1106*4882a593Smuzhiyun 				VSC9953_MAC_CMD_NEXT);
1107*4882a593Smuzhiyun 		break;
1108*4882a593Smuzhiyun 	case MAC_TABLE_AGE:
1109*4882a593Smuzhiyun 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
1110*4882a593Smuzhiyun 				VSC9953_MAC_CMD_MASK |
1111*4882a593Smuzhiyun 				VSC9953_MAC_ENTRYTYPE_MASK,
1112*4882a593Smuzhiyun 				VSC9953_MAC_CMD_AGE);
1113*4882a593Smuzhiyun 		break;
1114*4882a593Smuzhiyun 	default:
1115*4882a593Smuzhiyun 		printf("Unknown MAC table command\n");
1116*4882a593Smuzhiyun 	}
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	if (vsc9953_mac_table_poll_idle() < 0) {
1119*4882a593Smuzhiyun 		debug("MAC table timeout\n");
1120*4882a593Smuzhiyun 		return -1;
1121*4882a593Smuzhiyun 	}
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	return 0;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun /* show the FDB entries that correspond to a port and a VLAN */
vsc9953_mac_table_show(int port_no,int vid)1127*4882a593Smuzhiyun static void vsc9953_mac_table_show(int port_no, int vid)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun 	int rc[VSC9953_MAX_PORTS];
1130*4882a593Smuzhiyun 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
1131*4882a593Smuzhiyun 	int i;
1132*4882a593Smuzhiyun 	u32 val;
1133*4882a593Smuzhiyun 	u32 vlan;
1134*4882a593Smuzhiyun 	u32 mach;
1135*4882a593Smuzhiyun 	u32 macl;
1136*4882a593Smuzhiyun 	u32 dest_indx;
1137*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1140*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	/* disable auto learning */
1143*4882a593Smuzhiyun 	if (port_no == ETHSW_CMD_PORT_ALL) {
1144*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1145*4882a593Smuzhiyun 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
1146*4882a593Smuzhiyun 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
1147*4882a593Smuzhiyun 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
1148*4882a593Smuzhiyun 		}
1149*4882a593Smuzhiyun 	} else {
1150*4882a593Smuzhiyun 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
1151*4882a593Smuzhiyun 							  &mode[port_no]);
1152*4882a593Smuzhiyun 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
1153*4882a593Smuzhiyun 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
1154*4882a593Smuzhiyun 	}
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	/* write port and vid to get selected FDB entries */
1157*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana.anag_efil);
1158*4882a593Smuzhiyun 	if (port_no != ETHSW_CMD_PORT_ALL) {
1159*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
1160*4882a593Smuzhiyun 					       port_no) | VSC9953_AGE_PORT_EN;
1161*4882a593Smuzhiyun 	}
1162*4882a593Smuzhiyun 	if (vid != ETHSW_CMD_VLAN_ALL) {
1163*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK,
1164*4882a593Smuzhiyun 					       vid) | VSC9953_AGE_VID_EN;
1165*4882a593Smuzhiyun 	}
1166*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana.anag_efil, val);
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	/* set MAC and VLAN to 0 to look from beginning */
1169*4882a593Smuzhiyun 	clrbits_le32(&l2ana_reg->ana_tables.mach_data,
1170*4882a593Smuzhiyun 		     VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK);
1171*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data, 0);
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	/* get entries */
1174*4882a593Smuzhiyun 	printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID");
1175*4882a593Smuzhiyun 	do {
1176*4882a593Smuzhiyun 		if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) {
1177*4882a593Smuzhiyun 			debug("GET NEXT MAC table command failed\n");
1178*4882a593Smuzhiyun 			break;
1179*4882a593Smuzhiyun 		}
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 		val = in_le32(&l2ana_reg->ana_tables.mac_access);
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 		/* get out when an invalid entry is found */
1184*4882a593Smuzhiyun 		if (!(val & VSC9953_MAC_CMD_VALID))
1185*4882a593Smuzhiyun 			break;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 		switch (val & VSC9953_MAC_ENTRYTYPE_MASK) {
1188*4882a593Smuzhiyun 		case VSC9953_MAC_ENTRYTYPE_NORMAL:
1189*4882a593Smuzhiyun 			printf("%10s ", "Dynamic");
1190*4882a593Smuzhiyun 			break;
1191*4882a593Smuzhiyun 		case VSC9953_MAC_ENTRYTYPE_LOCKED:
1192*4882a593Smuzhiyun 			printf("%10s ", "Static");
1193*4882a593Smuzhiyun 			break;
1194*4882a593Smuzhiyun 		case VSC9953_MAC_ENTRYTYPE_IPV4MCAST:
1195*4882a593Smuzhiyun 			printf("%10s ", "IPv4 Mcast");
1196*4882a593Smuzhiyun 			break;
1197*4882a593Smuzhiyun 		case VSC9953_MAC_ENTRYTYPE_IPV6MCAST:
1198*4882a593Smuzhiyun 			printf("%10s ", "IPv6 Mcast");
1199*4882a593Smuzhiyun 			break;
1200*4882a593Smuzhiyun 		default:
1201*4882a593Smuzhiyun 			printf("%10s ", "Unknown");
1202*4882a593Smuzhiyun 		}
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 		dest_indx = bitfield_extract_by_mask(val,
1205*4882a593Smuzhiyun 						     VSC9953_MAC_DESTIDX_MASK);
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 		val = in_le32(&l2ana_reg->ana_tables.mach_data);
1208*4882a593Smuzhiyun 		vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK);
1209*4882a593Smuzhiyun 		mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK);
1210*4882a593Smuzhiyun 		macl = in_le32(&l2ana_reg->ana_tables.macl_data);
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 		printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff,
1213*4882a593Smuzhiyun 		       mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff,
1214*4882a593Smuzhiyun 		       (macl >> 8) & 0xff, macl & 0xff);
1215*4882a593Smuzhiyun 		printf("%5d ", dest_indx);
1216*4882a593Smuzhiyun 		printf("%4d\n", vlan);
1217*4882a593Smuzhiyun 	} while (1);
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	/* set learning mode to previous value */
1220*4882a593Smuzhiyun 	if (port_no == ETHSW_CMD_PORT_ALL) {
1221*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1222*4882a593Smuzhiyun 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
1223*4882a593Smuzhiyun 				vsc9953_port_learn_mode_set(i, mode[i]);
1224*4882a593Smuzhiyun 		}
1225*4882a593Smuzhiyun 	} else {
1226*4882a593Smuzhiyun 		/* If administrative down, skip */
1227*4882a593Smuzhiyun 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
1228*4882a593Smuzhiyun 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
1229*4882a593Smuzhiyun 	}
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	/* reset FDB port and VLAN FDB selection */
1232*4882a593Smuzhiyun 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
1233*4882a593Smuzhiyun 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
1234*4882a593Smuzhiyun 		     VSC9953_AGE_VID_MASK);
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun /* Add a static FDB entry */
vsc9953_mac_table_add(u8 port_no,uchar mac[6],int vid)1238*4882a593Smuzhiyun static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun 	u32 val;
1241*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1244*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
1247*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
1248*4882a593Smuzhiyun 	      (mac[0] << 8) | (mac[1] << 0);
1249*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data,
1252*4882a593Smuzhiyun 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
1253*4882a593Smuzhiyun 		 (mac[5] << 0));
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	/* set on which port is the MAC address added */
1256*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
1257*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no);
1258*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mac_access, val);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0)
1261*4882a593Smuzhiyun 		return -1;
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 	/* check if the MAC address was indeed added */
1264*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
1265*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
1266*4882a593Smuzhiyun 	      (mac[0] << 8) | (mac[1] << 0);
1267*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data,
1270*4882a593Smuzhiyun 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
1271*4882a593Smuzhiyun 		 (mac[5] << 0));
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0)
1274*4882a593Smuzhiyun 		return -1;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	if ((port_no != bitfield_extract_by_mask(val,
1279*4882a593Smuzhiyun 						 VSC9953_MAC_DESTIDX_MASK))) {
1280*4882a593Smuzhiyun 		printf("Failed to add MAC address\n");
1281*4882a593Smuzhiyun 		return -1;
1282*4882a593Smuzhiyun 	}
1283*4882a593Smuzhiyun 	return 0;
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun /* Delete a FDB entry */
vsc9953_mac_table_del(uchar mac[6],u16 vid)1287*4882a593Smuzhiyun static int vsc9953_mac_table_del(uchar mac[6], u16 vid)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun 	u32 val;
1290*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1293*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	/* check first if MAC entry is present */
1296*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
1297*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
1298*4882a593Smuzhiyun 	      (mac[0] << 8) | (mac[1] << 0);
1299*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data,
1302*4882a593Smuzhiyun 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
1303*4882a593Smuzhiyun 		 (mac[5] << 0));
1304*4882a593Smuzhiyun 
1305*4882a593Smuzhiyun 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
1306*4882a593Smuzhiyun 		debug("Lookup in the MAC table failed\n");
1307*4882a593Smuzhiyun 		return -1;
1308*4882a593Smuzhiyun 	}
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	if (!(in_le32(&l2ana_reg->ana_tables.mac_access) &
1311*4882a593Smuzhiyun 	      VSC9953_MAC_CMD_VALID)) {
1312*4882a593Smuzhiyun 		printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ",
1313*4882a593Smuzhiyun 		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1314*4882a593Smuzhiyun 		printf("VLAN: %d does not exist.\n", vid);
1315*4882a593Smuzhiyun 		return -1;
1316*4882a593Smuzhiyun 	}
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	/* FDB entry found, proceed to delete */
1319*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
1320*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
1321*4882a593Smuzhiyun 	      (mac[0] << 8) | (mac[1] << 0);
1322*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
1325*4882a593Smuzhiyun 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0)
1328*4882a593Smuzhiyun 		return -1;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	/* check if the MAC entry is still in FDB */
1331*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
1332*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
1333*4882a593Smuzhiyun 	      (mac[0] << 8) | (mac[1] << 0);
1334*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
1337*4882a593Smuzhiyun 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
1340*4882a593Smuzhiyun 		debug("Lookup in the MAC table failed\n");
1341*4882a593Smuzhiyun 		return -1;
1342*4882a593Smuzhiyun 	}
1343*4882a593Smuzhiyun 	if (in_le32(&l2ana_reg->ana_tables.mac_access) &
1344*4882a593Smuzhiyun 	    VSC9953_MAC_CMD_VALID) {
1345*4882a593Smuzhiyun 		printf("Failed to delete MAC address\n");
1346*4882a593Smuzhiyun 		return -1;
1347*4882a593Smuzhiyun 	}
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	return 0;
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun /* age the unlocked entries in FDB */
vsc9953_mac_table_age(int port_no,int vid)1353*4882a593Smuzhiyun static void vsc9953_mac_table_age(int port_no, int vid)
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun 	int rc[VSC9953_MAX_PORTS];
1356*4882a593Smuzhiyun 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
1357*4882a593Smuzhiyun 	u32 val;
1358*4882a593Smuzhiyun 	int i;
1359*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1362*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	/* set port and VID for selective aging */
1365*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana.anag_efil);
1366*4882a593Smuzhiyun 	if (port_no != ETHSW_CMD_PORT_ALL) {
1367*4882a593Smuzhiyun 		/* disable auto learning */
1368*4882a593Smuzhiyun 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
1369*4882a593Smuzhiyun 							  &mode[port_no]);
1370*4882a593Smuzhiyun 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
1371*4882a593Smuzhiyun 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
1374*4882a593Smuzhiyun 					       port_no) | VSC9953_AGE_PORT_EN;
1375*4882a593Smuzhiyun 	} else {
1376*4882a593Smuzhiyun 		/* disable auto learning on all ports */
1377*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1378*4882a593Smuzhiyun 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
1379*4882a593Smuzhiyun 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
1380*4882a593Smuzhiyun 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
1381*4882a593Smuzhiyun 		}
1382*4882a593Smuzhiyun 	}
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	if (vid != ETHSW_CMD_VLAN_ALL) {
1385*4882a593Smuzhiyun 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) |
1386*4882a593Smuzhiyun 		      VSC9953_AGE_VID_EN;
1387*4882a593Smuzhiyun 	}
1388*4882a593Smuzhiyun 	out_le32(&l2ana_reg->ana.anag_efil, val);
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	/* age the dynamic FDB entries */
1391*4882a593Smuzhiyun 	vsc9953_mac_table_cmd(MAC_TABLE_AGE);
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	/* clear previously set port and VID */
1394*4882a593Smuzhiyun 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
1395*4882a593Smuzhiyun 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
1396*4882a593Smuzhiyun 		     VSC9953_AGE_VID_MASK);
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	if (port_no != ETHSW_CMD_PORT_ALL) {
1399*4882a593Smuzhiyun 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
1400*4882a593Smuzhiyun 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
1401*4882a593Smuzhiyun 	} else {
1402*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1403*4882a593Smuzhiyun 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
1404*4882a593Smuzhiyun 				vsc9953_port_learn_mode_set(i, mode[i]);
1405*4882a593Smuzhiyun 		}
1406*4882a593Smuzhiyun 	}
1407*4882a593Smuzhiyun }
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun /* Delete all the dynamic FDB entries */
vsc9953_mac_table_flush(int port,int vid)1410*4882a593Smuzhiyun static void vsc9953_mac_table_flush(int port, int vid)
1411*4882a593Smuzhiyun {
1412*4882a593Smuzhiyun 	vsc9953_mac_table_age(port, vid);
1413*4882a593Smuzhiyun 	vsc9953_mac_table_age(port, vid);
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun enum egress_vlan_tag {
1417*4882a593Smuzhiyun 	EGR_TAG_CLASS = 0,
1418*4882a593Smuzhiyun 	EGR_TAG_PVID,
1419*4882a593Smuzhiyun };
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun /* Set egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_set(int port_no,enum egress_vlan_tag mode)1422*4882a593Smuzhiyun static void vsc9953_port_vlan_egress_tag_set(int port_no,
1423*4882a593Smuzhiyun 					     enum egress_vlan_tag mode)
1424*4882a593Smuzhiyun {
1425*4882a593Smuzhiyun 	struct vsc9953_rew_reg *l2rew_reg;
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1428*4882a593Smuzhiyun 			VSC9953_REW_OFFSET);
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 	switch (mode) {
1431*4882a593Smuzhiyun 	case EGR_TAG_CLASS:
1432*4882a593Smuzhiyun 		clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1433*4882a593Smuzhiyun 			     VSC9953_TAG_VID_PVID);
1434*4882a593Smuzhiyun 		break;
1435*4882a593Smuzhiyun 	case EGR_TAG_PVID:
1436*4882a593Smuzhiyun 		setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1437*4882a593Smuzhiyun 			     VSC9953_TAG_VID_PVID);
1438*4882a593Smuzhiyun 		break;
1439*4882a593Smuzhiyun 	default:
1440*4882a593Smuzhiyun 		printf("Unknown egress VLAN tag mode for port %d\n", port_no);
1441*4882a593Smuzhiyun 	}
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun /* Get egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_get(int port_no,enum egress_vlan_tag * mode)1445*4882a593Smuzhiyun static void vsc9953_port_vlan_egress_tag_get(int port_no,
1446*4882a593Smuzhiyun 					     enum egress_vlan_tag *mode)
1447*4882a593Smuzhiyun {
1448*4882a593Smuzhiyun 	u32 val;
1449*4882a593Smuzhiyun 	struct vsc9953_rew_reg *l2rew_reg;
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1452*4882a593Smuzhiyun 			VSC9953_REW_OFFSET);
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
1455*4882a593Smuzhiyun 	if (val & VSC9953_TAG_VID_PVID)
1456*4882a593Smuzhiyun 		*mode = EGR_TAG_PVID;
1457*4882a593Smuzhiyun 	else
1458*4882a593Smuzhiyun 		*mode = EGR_TAG_CLASS;
1459*4882a593Smuzhiyun }
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun /* VSC9953 VLAN learning modes */
1462*4882a593Smuzhiyun enum vlan_learning_mode {
1463*4882a593Smuzhiyun 	SHARED_VLAN_LEARNING,
1464*4882a593Smuzhiyun 	PRIVATE_VLAN_LEARNING,
1465*4882a593Smuzhiyun };
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun /* Set VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)1468*4882a593Smuzhiyun static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)
1469*4882a593Smuzhiyun {
1470*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1473*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	switch (lrn_mode) {
1476*4882a593Smuzhiyun 	case SHARED_VLAN_LEARNING:
1477*4882a593Smuzhiyun 		setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
1478*4882a593Smuzhiyun 		break;
1479*4882a593Smuzhiyun 	case PRIVATE_VLAN_LEARNING:
1480*4882a593Smuzhiyun 		clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
1481*4882a593Smuzhiyun 		break;
1482*4882a593Smuzhiyun 	default:
1483*4882a593Smuzhiyun 		printf("Unknown VLAN learn mode\n");
1484*4882a593Smuzhiyun 	}
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun /* Get VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_get(enum vlan_learning_mode * lrn_mode)1488*4882a593Smuzhiyun static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun 	u32 val;
1491*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1494*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana.agen_ctrl);
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	if (!(val & VSC9953_FID_MASK_ALL)) {
1499*4882a593Smuzhiyun 		*lrn_mode = PRIVATE_VLAN_LEARNING;
1500*4882a593Smuzhiyun 	} else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) {
1501*4882a593Smuzhiyun 		*lrn_mode = SHARED_VLAN_LEARNING;
1502*4882a593Smuzhiyun 	} else {
1503*4882a593Smuzhiyun 		printf("Unknown VLAN learning mode\n");
1504*4882a593Smuzhiyun 		return -EINVAL;
1505*4882a593Smuzhiyun 	}
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	return 0;
1508*4882a593Smuzhiyun }
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun /* Enable/disable VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_set(int port_no,int enabled)1511*4882a593Smuzhiyun static void vsc9953_port_ingress_filtering_set(int port_no, int enabled)
1512*4882a593Smuzhiyun {
1513*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1516*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	if (enabled)
1519*4882a593Smuzhiyun 		setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
1520*4882a593Smuzhiyun 	else
1521*4882a593Smuzhiyun 		clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
1522*4882a593Smuzhiyun }
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun /* Return VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_get(int port_no)1525*4882a593Smuzhiyun static int vsc9953_port_ingress_filtering_get(int port_no)
1526*4882a593Smuzhiyun {
1527*4882a593Smuzhiyun 	u32 val;
1528*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1531*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->ana.vlan_mask);
1534*4882a593Smuzhiyun 	return !!(val & (1 << port_no));
1535*4882a593Smuzhiyun }
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun /* Get the aggregation group of a port */
vsc9953_port_aggr_grp_get(int port_no,int * aggr_grp)1538*4882a593Smuzhiyun static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
1539*4882a593Smuzhiyun {
1540*4882a593Smuzhiyun 	u32 val;
1541*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no))
1544*4882a593Smuzhiyun 		return -EINVAL;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1547*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1550*4882a593Smuzhiyun 	*aggr_grp = bitfield_extract_by_mask(val,
1551*4882a593Smuzhiyun 					     VSC9953_PORT_CFG_PORTID_MASK);
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 	return 0;
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun 
vsc9953_aggr_grp_members_get(int aggr_grp,u8 aggr_membr[VSC9953_MAX_PORTS])1556*4882a593Smuzhiyun static void vsc9953_aggr_grp_members_get(int aggr_grp,
1557*4882a593Smuzhiyun 					 u8 aggr_membr[VSC9953_MAX_PORTS])
1558*4882a593Smuzhiyun {
1559*4882a593Smuzhiyun 	int port_no;
1560*4882a593Smuzhiyun 	int aggr_membr_grp;
1561*4882a593Smuzhiyun 
1562*4882a593Smuzhiyun 	for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
1563*4882a593Smuzhiyun 		aggr_membr[port_no] = 0;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 		if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
1566*4882a593Smuzhiyun 			continue;
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 		if (aggr_grp == aggr_membr_grp)
1569*4882a593Smuzhiyun 			aggr_membr[port_no] = 1;
1570*4882a593Smuzhiyun 	}
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun 
vsc9953_update_dest_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1573*4882a593Smuzhiyun static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
1574*4882a593Smuzhiyun 					      u32 membr_bitfld_new)
1575*4882a593Smuzhiyun {
1576*4882a593Smuzhiyun 	int i;
1577*4882a593Smuzhiyun 	u32 pgid;
1578*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1581*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	/*
1584*4882a593Smuzhiyun 	 * NOTE: Only the unicast destination masks are updated, since
1585*4882a593Smuzhiyun 	 * we do not support for now Layer-2 multicast entries
1586*4882a593Smuzhiyun 	 */
1587*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1588*4882a593Smuzhiyun 		if (i == port_no) {
1589*4882a593Smuzhiyun 			clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
1590*4882a593Smuzhiyun 					VSC9953_PGID_PORT_MASK,
1591*4882a593Smuzhiyun 					membr_bitfld_new);
1592*4882a593Smuzhiyun 			continue;
1593*4882a593Smuzhiyun 		}
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1596*4882a593Smuzhiyun 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1597*4882a593Smuzhiyun 			pgid &= ~((u32)(1 << port_no));
1598*4882a593Smuzhiyun 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1599*4882a593Smuzhiyun 			pgid |= ((u32)(1 << port_no));
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1602*4882a593Smuzhiyun 	}
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun 
vsc9953_update_source_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1605*4882a593Smuzhiyun static void vsc9953_update_source_members_masks(int port_no,
1606*4882a593Smuzhiyun 						u32 membr_bitfld_old,
1607*4882a593Smuzhiyun 						u32 membr_bitfld_new)
1608*4882a593Smuzhiyun {
1609*4882a593Smuzhiyun 	int i;
1610*4882a593Smuzhiyun 	int index;
1611*4882a593Smuzhiyun 	u32 pgid;
1612*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1615*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
1618*4882a593Smuzhiyun 		index = PGID_SRC_START + i;
1619*4882a593Smuzhiyun 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
1620*4882a593Smuzhiyun 		if (i == port_no) {
1621*4882a593Smuzhiyun 			pgid = (pgid | VSC9953_PGID_PORT_MASK) &
1622*4882a593Smuzhiyun 			       ~membr_bitfld_new;
1623*4882a593Smuzhiyun 			out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
1624*4882a593Smuzhiyun 				 pgid);
1625*4882a593Smuzhiyun 			continue;
1626*4882a593Smuzhiyun 		}
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1629*4882a593Smuzhiyun 			pgid |= (u32)(1 << port_no);
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1632*4882a593Smuzhiyun 			pgid &= ~(u32)(1 << port_no);
1633*4882a593Smuzhiyun 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
1634*4882a593Smuzhiyun 	}
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun 
vsc9953_aggr_mask_get_next(u32 aggr_mask,u32 member_bitfield)1637*4882a593Smuzhiyun static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
1638*4882a593Smuzhiyun {
1639*4882a593Smuzhiyun 	if (!member_bitfield)
1640*4882a593Smuzhiyun 		return 0;
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun 	if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1643*4882a593Smuzhiyun 		aggr_mask = 1;
1644*4882a593Smuzhiyun 	else
1645*4882a593Smuzhiyun 		aggr_mask <<= 1;
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	while (!(aggr_mask & member_bitfield)) {
1648*4882a593Smuzhiyun 		aggr_mask <<= 1;
1649*4882a593Smuzhiyun 		if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1650*4882a593Smuzhiyun 			aggr_mask = 1;
1651*4882a593Smuzhiyun 	}
1652*4882a593Smuzhiyun 
1653*4882a593Smuzhiyun 	return aggr_mask;
1654*4882a593Smuzhiyun }
1655*4882a593Smuzhiyun 
vsc9953_update_aggr_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1656*4882a593Smuzhiyun static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
1657*4882a593Smuzhiyun 					      u32 membr_bitfld_new)
1658*4882a593Smuzhiyun {
1659*4882a593Smuzhiyun 	int i;
1660*4882a593Smuzhiyun 	u32 pgid;
1661*4882a593Smuzhiyun 	u32 aggr_mask_old = 0;
1662*4882a593Smuzhiyun 	u32 aggr_mask_new = 0;
1663*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1666*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	/* Update all the PGID aggregation masks */
1669*4882a593Smuzhiyun 	for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
1670*4882a593Smuzhiyun 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 		aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
1673*4882a593Smuzhiyun 							   membr_bitfld_old);
1674*4882a593Smuzhiyun 		pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 		aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
1677*4882a593Smuzhiyun 							   membr_bitfld_new);
1678*4882a593Smuzhiyun 		pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1681*4882a593Smuzhiyun 	}
1682*4882a593Smuzhiyun }
1683*4882a593Smuzhiyun 
vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])1684*4882a593Smuzhiyun static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
1685*4882a593Smuzhiyun {
1686*4882a593Smuzhiyun 	int i;
1687*4882a593Smuzhiyun 	u32 member_bitfield = 0;
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1690*4882a593Smuzhiyun 		if (member[i])
1691*4882a593Smuzhiyun 			member_bitfield |= 1 << i;
1692*4882a593Smuzhiyun 	}
1693*4882a593Smuzhiyun 	member_bitfield &= VSC9953_PGID_PORT_MASK;
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 	return member_bitfield;
1696*4882a593Smuzhiyun }
1697*4882a593Smuzhiyun 
vsc9953_update_members_masks(int port_no,u8 member_old[VSC9953_MAX_PORTS],u8 member_new[VSC9953_MAX_PORTS])1698*4882a593Smuzhiyun static void vsc9953_update_members_masks(int port_no,
1699*4882a593Smuzhiyun 					 u8 member_old[VSC9953_MAX_PORTS],
1700*4882a593Smuzhiyun 					 u8 member_new[VSC9953_MAX_PORTS])
1701*4882a593Smuzhiyun {
1702*4882a593Smuzhiyun 	u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
1703*4882a593Smuzhiyun 	u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 	vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
1706*4882a593Smuzhiyun 					  membr_bitfld_new);
1707*4882a593Smuzhiyun 	vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
1708*4882a593Smuzhiyun 					    membr_bitfld_new);
1709*4882a593Smuzhiyun 	vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
1710*4882a593Smuzhiyun 					  membr_bitfld_new);
1711*4882a593Smuzhiyun }
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun /* Set the aggregation group of a port */
vsc9953_port_aggr_grp_set(int port_no,int aggr_grp)1714*4882a593Smuzhiyun static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun 	u8 aggr_membr_old[VSC9953_MAX_PORTS];
1717*4882a593Smuzhiyun 	u8 aggr_membr_new[VSC9953_MAX_PORTS];
1718*4882a593Smuzhiyun 	int rc;
1719*4882a593Smuzhiyun 	int aggr_grp_old;
1720*4882a593Smuzhiyun 	u32 val;
1721*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
1722*4882a593Smuzhiyun 
1723*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
1724*4882a593Smuzhiyun 		return -EINVAL;
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1727*4882a593Smuzhiyun 						VSC9953_ANA_OFFSET);
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
1730*4882a593Smuzhiyun 	if (rc)
1731*4882a593Smuzhiyun 		return rc;
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun 	/* get all the members of the old aggregation group */
1734*4882a593Smuzhiyun 	vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
1735*4882a593Smuzhiyun 
1736*4882a593Smuzhiyun 	/* get all the members of the same aggregation group */
1737*4882a593Smuzhiyun 	vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	/* add current port as member to the new aggregation group */
1740*4882a593Smuzhiyun 	aggr_membr_old[port_no] = 0;
1741*4882a593Smuzhiyun 	aggr_membr_new[port_no] = 1;
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 	/* update masks */
1744*4882a593Smuzhiyun 	vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	/* Change logical port number */
1747*4882a593Smuzhiyun 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1748*4882a593Smuzhiyun 	val = bitfield_replace_by_mask(val,
1749*4882a593Smuzhiyun 				       VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
1750*4882a593Smuzhiyun 	out_le32(&l2ana_reg->port[port_no].port_cfg, val);
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	return 0;
1753*4882a593Smuzhiyun }
1754*4882a593Smuzhiyun 
vsc9953_port_status_key_func(struct ethsw_command_def * parsed_cmd)1755*4882a593Smuzhiyun static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
1756*4882a593Smuzhiyun {
1757*4882a593Smuzhiyun 	int i;
1758*4882a593Smuzhiyun 	u8 enabled;
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 	/* Last keyword should tell us if we should enable/disable the port */
1761*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1762*4882a593Smuzhiyun 	    ethsw_id_enable)
1763*4882a593Smuzhiyun 		enabled = 1;
1764*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1765*4882a593Smuzhiyun 		 ethsw_id_disable)
1766*4882a593Smuzhiyun 		enabled = 0;
1767*4882a593Smuzhiyun 	else
1768*4882a593Smuzhiyun 		return CMD_RET_USAGE;
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1771*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1772*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1773*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1774*4882a593Smuzhiyun 		}
1775*4882a593Smuzhiyun 		vsc9953_port_status_set(parsed_cmd->port, enabled);
1776*4882a593Smuzhiyun 	} else {
1777*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1778*4882a593Smuzhiyun 			vsc9953_port_status_set(i, enabled);
1779*4882a593Smuzhiyun 	}
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1782*4882a593Smuzhiyun }
1783*4882a593Smuzhiyun 
vsc9953_port_config_key_func(struct ethsw_command_def * parsed_cmd)1784*4882a593Smuzhiyun static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun 	int i;
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1789*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1790*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1791*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1792*4882a593Smuzhiyun 		}
1793*4882a593Smuzhiyun 		vsc9953_phy_autoneg(parsed_cmd->port);
1794*4882a593Smuzhiyun 		printf("%8s %8s %8s %8s %8s\n",
1795*4882a593Smuzhiyun 		       "Port", "Status", "Link", "Speed",
1796*4882a593Smuzhiyun 		       "Duplex");
1797*4882a593Smuzhiyun 		vsc9953_port_config_show(parsed_cmd->port);
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	} else {
1800*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1801*4882a593Smuzhiyun 			vsc9953_phy_autoneg(i);
1802*4882a593Smuzhiyun 		printf("%8s %8s %8s %8s %8s\n",
1803*4882a593Smuzhiyun 		       "Port", "Status", "Link", "Speed", "Duplex");
1804*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1805*4882a593Smuzhiyun 			vsc9953_port_config_show(i);
1806*4882a593Smuzhiyun 	}
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun 
vsc9953_port_stats_key_func(struct ethsw_command_def * parsed_cmd)1811*4882a593Smuzhiyun static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd)
1812*4882a593Smuzhiyun {
1813*4882a593Smuzhiyun 	int i;
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1816*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1817*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1818*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1819*4882a593Smuzhiyun 		}
1820*4882a593Smuzhiyun 		vsc9953_port_statistics_show(parsed_cmd->port);
1821*4882a593Smuzhiyun 	} else {
1822*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1823*4882a593Smuzhiyun 			vsc9953_port_statistics_show(i);
1824*4882a593Smuzhiyun 	}
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1827*4882a593Smuzhiyun }
1828*4882a593Smuzhiyun 
vsc9953_port_stats_clear_key_func(struct ethsw_command_def * parsed_cmd)1829*4882a593Smuzhiyun static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def
1830*4882a593Smuzhiyun 					     *parsed_cmd)
1831*4882a593Smuzhiyun {
1832*4882a593Smuzhiyun 	int i;
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1835*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1836*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1837*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1838*4882a593Smuzhiyun 		}
1839*4882a593Smuzhiyun 		vsc9953_port_statistics_clear(parsed_cmd->port);
1840*4882a593Smuzhiyun 	} else {
1841*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1842*4882a593Smuzhiyun 			vsc9953_port_statistics_clear(i);
1843*4882a593Smuzhiyun 	}
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1846*4882a593Smuzhiyun }
1847*4882a593Smuzhiyun 
vsc9953_learn_show_key_func(struct ethsw_command_def * parsed_cmd)1848*4882a593Smuzhiyun static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd)
1849*4882a593Smuzhiyun {
1850*4882a593Smuzhiyun 	int i;
1851*4882a593Smuzhiyun 	enum port_learn_mode mode;
1852*4882a593Smuzhiyun 
1853*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1854*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1855*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1856*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1857*4882a593Smuzhiyun 		}
1858*4882a593Smuzhiyun 		if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode))
1859*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1860*4882a593Smuzhiyun 		printf("%7s %11s\n", "Port", "Learn mode");
1861*4882a593Smuzhiyun 		switch (mode) {
1862*4882a593Smuzhiyun 		case PORT_LEARN_NONE:
1863*4882a593Smuzhiyun 			printf("%7d %11s\n", parsed_cmd->port, "disable");
1864*4882a593Smuzhiyun 			break;
1865*4882a593Smuzhiyun 		case PORT_LEARN_AUTO:
1866*4882a593Smuzhiyun 			printf("%7d %11s\n", parsed_cmd->port, "auto");
1867*4882a593Smuzhiyun 			break;
1868*4882a593Smuzhiyun 		default:
1869*4882a593Smuzhiyun 			printf("%7d %11s\n", parsed_cmd->port, "-");
1870*4882a593Smuzhiyun 		}
1871*4882a593Smuzhiyun 	} else {
1872*4882a593Smuzhiyun 		printf("%7s %11s\n", "Port", "Learn mode");
1873*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1874*4882a593Smuzhiyun 			if (vsc9953_port_learn_mode_get(i, &mode))
1875*4882a593Smuzhiyun 				continue;
1876*4882a593Smuzhiyun 			switch (mode) {
1877*4882a593Smuzhiyun 			case PORT_LEARN_NONE:
1878*4882a593Smuzhiyun 				printf("%7d %11s\n", i, "disable");
1879*4882a593Smuzhiyun 				break;
1880*4882a593Smuzhiyun 			case PORT_LEARN_AUTO:
1881*4882a593Smuzhiyun 				printf("%7d %11s\n", i, "auto");
1882*4882a593Smuzhiyun 				break;
1883*4882a593Smuzhiyun 			default:
1884*4882a593Smuzhiyun 				printf("%7d %11s\n", i, "-");
1885*4882a593Smuzhiyun 			}
1886*4882a593Smuzhiyun 		}
1887*4882a593Smuzhiyun 	}
1888*4882a593Smuzhiyun 
1889*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1890*4882a593Smuzhiyun }
1891*4882a593Smuzhiyun 
vsc9953_learn_set_key_func(struct ethsw_command_def * parsed_cmd)1892*4882a593Smuzhiyun static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
1893*4882a593Smuzhiyun {
1894*4882a593Smuzhiyun 	int i;
1895*4882a593Smuzhiyun 	enum port_learn_mode mode;
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun 	/* Last keyword should tell us the learn mode */
1898*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1899*4882a593Smuzhiyun 	    ethsw_id_auto)
1900*4882a593Smuzhiyun 		mode = PORT_LEARN_AUTO;
1901*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
1902*4882a593Smuzhiyun 		 ethsw_id_disable)
1903*4882a593Smuzhiyun 		mode = PORT_LEARN_NONE;
1904*4882a593Smuzhiyun 	else
1905*4882a593Smuzhiyun 		return CMD_RET_USAGE;
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
1908*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1909*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
1910*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
1911*4882a593Smuzhiyun 		}
1912*4882a593Smuzhiyun 		vsc9953_port_learn_mode_set(parsed_cmd->port, mode);
1913*4882a593Smuzhiyun 	} else {
1914*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
1915*4882a593Smuzhiyun 			vsc9953_port_learn_mode_set(i, mode);
1916*4882a593Smuzhiyun 	}
1917*4882a593Smuzhiyun 
1918*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1919*4882a593Smuzhiyun }
1920*4882a593Smuzhiyun 
vsc9953_fdb_show_key_func(struct ethsw_command_def * parsed_cmd)1921*4882a593Smuzhiyun static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd)
1922*4882a593Smuzhiyun {
1923*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
1924*4882a593Smuzhiyun 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
1925*4882a593Smuzhiyun 		printf("Invalid port number: %d\n", parsed_cmd->port);
1926*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1927*4882a593Smuzhiyun 	}
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
1930*4882a593Smuzhiyun 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
1931*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
1932*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1933*4882a593Smuzhiyun 	}
1934*4882a593Smuzhiyun 
1935*4882a593Smuzhiyun 	vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid);
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun 
vsc9953_fdb_flush_key_func(struct ethsw_command_def * parsed_cmd)1940*4882a593Smuzhiyun static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd)
1941*4882a593Smuzhiyun {
1942*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
1943*4882a593Smuzhiyun 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
1944*4882a593Smuzhiyun 		printf("Invalid port number: %d\n", parsed_cmd->port);
1945*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1946*4882a593Smuzhiyun 	}
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
1949*4882a593Smuzhiyun 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
1950*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
1951*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1952*4882a593Smuzhiyun 	}
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun 	vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid);
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1957*4882a593Smuzhiyun }
1958*4882a593Smuzhiyun 
vsc9953_fdb_entry_add_key_func(struct ethsw_command_def * parsed_cmd)1959*4882a593Smuzhiyun static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd)
1960*4882a593Smuzhiyun {
1961*4882a593Smuzhiyun 	int vid;
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 	/* a port number must be present */
1964*4882a593Smuzhiyun 	if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) {
1965*4882a593Smuzhiyun 		printf("Please specify a port\n");
1966*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1967*4882a593Smuzhiyun 	}
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
1970*4882a593Smuzhiyun 		printf("Invalid port number: %d\n", parsed_cmd->port);
1971*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1972*4882a593Smuzhiyun 	}
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 	/* Use VLAN 1 if VID is not set */
1975*4882a593Smuzhiyun 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	if (!VSC9953_VLAN_CHECK(vid)) {
1978*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", vid);
1979*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1980*4882a593Smuzhiyun 	}
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun 	if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid))
1983*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
1986*4882a593Smuzhiyun }
1987*4882a593Smuzhiyun 
vsc9953_fdb_entry_del_key_func(struct ethsw_command_def * parsed_cmd)1988*4882a593Smuzhiyun static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd)
1989*4882a593Smuzhiyun {
1990*4882a593Smuzhiyun 	int vid;
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	/* Use VLAN 1 if VID is not set */
1993*4882a593Smuzhiyun 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	if (!VSC9953_VLAN_CHECK(vid)) {
1996*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", vid);
1997*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
1998*4882a593Smuzhiyun 	}
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid))
2001*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2002*4882a593Smuzhiyun 
2003*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2004*4882a593Smuzhiyun }
2005*4882a593Smuzhiyun 
vsc9953_pvid_show_key_func(struct ethsw_command_def * parsed_cmd)2006*4882a593Smuzhiyun static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd)
2007*4882a593Smuzhiyun {
2008*4882a593Smuzhiyun 	int i;
2009*4882a593Smuzhiyun 	int pvid;
2010*4882a593Smuzhiyun 
2011*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2012*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2013*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2014*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2015*4882a593Smuzhiyun 		}
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 		if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid))
2018*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2019*4882a593Smuzhiyun 		printf("%7s %7s\n", "Port", "PVID");
2020*4882a593Smuzhiyun 		printf("%7d %7d\n", parsed_cmd->port, pvid);
2021*4882a593Smuzhiyun 	} else {
2022*4882a593Smuzhiyun 		printf("%7s %7s\n", "Port", "PVID");
2023*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2024*4882a593Smuzhiyun 			if (vsc9953_port_vlan_pvid_get(i, &pvid))
2025*4882a593Smuzhiyun 				continue;
2026*4882a593Smuzhiyun 			printf("%7d %7d\n", i, pvid);
2027*4882a593Smuzhiyun 		}
2028*4882a593Smuzhiyun 	}
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2031*4882a593Smuzhiyun }
2032*4882a593Smuzhiyun 
vsc9953_pvid_set_key_func(struct ethsw_command_def * parsed_cmd)2033*4882a593Smuzhiyun static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd)
2034*4882a593Smuzhiyun {
2035*4882a593Smuzhiyun 	/* PVID number should be set in parsed_cmd->vid */
2036*4882a593Smuzhiyun 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2037*4882a593Smuzhiyun 		printf("Please set a pvid value\n");
2038*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2039*4882a593Smuzhiyun 	}
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2042*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2043*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2044*4882a593Smuzhiyun 	}
2045*4882a593Smuzhiyun 
2046*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2047*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2048*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2049*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2050*4882a593Smuzhiyun 		}
2051*4882a593Smuzhiyun 		vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid);
2052*4882a593Smuzhiyun 	} else {
2053*4882a593Smuzhiyun 		vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid);
2054*4882a593Smuzhiyun 	}
2055*4882a593Smuzhiyun 
2056*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2057*4882a593Smuzhiyun }
2058*4882a593Smuzhiyun 
vsc9953_vlan_show_key_func(struct ethsw_command_def * parsed_cmd)2059*4882a593Smuzhiyun static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd)
2060*4882a593Smuzhiyun {
2061*4882a593Smuzhiyun 	int i;
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2064*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2065*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2066*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2067*4882a593Smuzhiyun 		}
2068*4882a593Smuzhiyun 		vsc9953_vlan_membership_show(parsed_cmd->port);
2069*4882a593Smuzhiyun 	} else {
2070*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2071*4882a593Smuzhiyun 			vsc9953_vlan_membership_show(i);
2072*4882a593Smuzhiyun 	}
2073*4882a593Smuzhiyun 
2074*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2075*4882a593Smuzhiyun }
2076*4882a593Smuzhiyun 
vsc9953_vlan_set_key_func(struct ethsw_command_def * parsed_cmd)2077*4882a593Smuzhiyun static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd)
2078*4882a593Smuzhiyun {
2079*4882a593Smuzhiyun 	int i;
2080*4882a593Smuzhiyun 	int add;
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	/* VLAN should be set in parsed_cmd->vid */
2083*4882a593Smuzhiyun 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2084*4882a593Smuzhiyun 		printf("Please set a vlan value\n");
2085*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2086*4882a593Smuzhiyun 	}
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2089*4882a593Smuzhiyun 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2090*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2091*4882a593Smuzhiyun 	}
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	/* keywords add/delete should be the last but one in array */
2094*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2095*4882a593Smuzhiyun 	    ethsw_id_add)
2096*4882a593Smuzhiyun 		add = 1;
2097*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2098*4882a593Smuzhiyun 		 ethsw_id_del)
2099*4882a593Smuzhiyun 		add = 0;
2100*4882a593Smuzhiyun 	else
2101*4882a593Smuzhiyun 		return CMD_RET_USAGE;
2102*4882a593Smuzhiyun 
2103*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2104*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2105*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2106*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2107*4882a593Smuzhiyun 		}
2108*4882a593Smuzhiyun 		vsc9953_vlan_table_membership_set(parsed_cmd->vid,
2109*4882a593Smuzhiyun 						  parsed_cmd->port, add);
2110*4882a593Smuzhiyun 	} else {
2111*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2112*4882a593Smuzhiyun 			vsc9953_vlan_table_membership_set(parsed_cmd->vid, i,
2113*4882a593Smuzhiyun 							  add);
2114*4882a593Smuzhiyun 	}
2115*4882a593Smuzhiyun 
2116*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2117*4882a593Smuzhiyun }
vsc9953_port_untag_show_key_func(struct ethsw_command_def * parsed_cmd)2118*4882a593Smuzhiyun static int vsc9953_port_untag_show_key_func(
2119*4882a593Smuzhiyun 		struct ethsw_command_def *parsed_cmd)
2120*4882a593Smuzhiyun {
2121*4882a593Smuzhiyun 	int i;
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 	printf("%7s\t%17s\n", "Port", "Untag");
2124*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2125*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2126*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2127*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2128*4882a593Smuzhiyun 		}
2129*4882a593Smuzhiyun 		vsc9953_port_vlan_egr_untag_show(parsed_cmd->port);
2130*4882a593Smuzhiyun 	} else {
2131*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2132*4882a593Smuzhiyun 			vsc9953_port_vlan_egr_untag_show(i);
2133*4882a593Smuzhiyun 	}
2134*4882a593Smuzhiyun 
2135*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2136*4882a593Smuzhiyun }
2137*4882a593Smuzhiyun 
vsc9953_port_untag_set_key_func(struct ethsw_command_def * parsed_cmd)2138*4882a593Smuzhiyun static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd)
2139*4882a593Smuzhiyun {
2140*4882a593Smuzhiyun 	int i;
2141*4882a593Smuzhiyun 	enum egress_untag_mode mode;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	/* keywords for the untagged mode are the last in the array */
2144*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2145*4882a593Smuzhiyun 	    ethsw_id_all)
2146*4882a593Smuzhiyun 		mode = EGRESS_UNTAG_ALL;
2147*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2148*4882a593Smuzhiyun 		 ethsw_id_none)
2149*4882a593Smuzhiyun 		mode = EGRESS_UNTAG_NONE;
2150*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2151*4882a593Smuzhiyun 		 ethsw_id_pvid)
2152*4882a593Smuzhiyun 		mode = EGRESS_UNTAG_PVID_AND_ZERO;
2153*4882a593Smuzhiyun 	else
2154*4882a593Smuzhiyun 		return CMD_RET_USAGE;
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2157*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2158*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2159*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2160*4882a593Smuzhiyun 		}
2161*4882a593Smuzhiyun 		vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode);
2162*4882a593Smuzhiyun 	} else {
2163*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2164*4882a593Smuzhiyun 			vsc9953_port_vlan_egr_untag_set(i, mode);
2165*4882a593Smuzhiyun 	}
2166*4882a593Smuzhiyun 
2167*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2168*4882a593Smuzhiyun }
2169*4882a593Smuzhiyun 
vsc9953_egr_vlan_tag_show_key_func(struct ethsw_command_def * parsed_cmd)2170*4882a593Smuzhiyun static int vsc9953_egr_vlan_tag_show_key_func(
2171*4882a593Smuzhiyun 		struct ethsw_command_def *parsed_cmd)
2172*4882a593Smuzhiyun {
2173*4882a593Smuzhiyun 	int i;
2174*4882a593Smuzhiyun 	enum egress_vlan_tag mode;
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2177*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2178*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2179*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2180*4882a593Smuzhiyun 		}
2181*4882a593Smuzhiyun 		vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode);
2182*4882a593Smuzhiyun 		printf("%7s\t%12s\n", "Port", "Egress VID");
2183*4882a593Smuzhiyun 		printf("%7d\t", parsed_cmd->port);
2184*4882a593Smuzhiyun 		switch (mode) {
2185*4882a593Smuzhiyun 		case EGR_TAG_CLASS:
2186*4882a593Smuzhiyun 			printf("%12s\n", "classified");
2187*4882a593Smuzhiyun 			break;
2188*4882a593Smuzhiyun 		case EGR_TAG_PVID:
2189*4882a593Smuzhiyun 			printf("%12s\n", "pvid");
2190*4882a593Smuzhiyun 			break;
2191*4882a593Smuzhiyun 		default:
2192*4882a593Smuzhiyun 			printf("%12s\n", "-");
2193*4882a593Smuzhiyun 		}
2194*4882a593Smuzhiyun 	} else {
2195*4882a593Smuzhiyun 		printf("%7s\t%12s\n", "Port", "Egress VID");
2196*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2197*4882a593Smuzhiyun 			vsc9953_port_vlan_egress_tag_get(i, &mode);
2198*4882a593Smuzhiyun 			switch (mode) {
2199*4882a593Smuzhiyun 			case EGR_TAG_CLASS:
2200*4882a593Smuzhiyun 				printf("%7d\t%12s\n", i, "classified");
2201*4882a593Smuzhiyun 				break;
2202*4882a593Smuzhiyun 			case EGR_TAG_PVID:
2203*4882a593Smuzhiyun 				printf("%7d\t%12s\n", i, "pvid");
2204*4882a593Smuzhiyun 				break;
2205*4882a593Smuzhiyun 			default:
2206*4882a593Smuzhiyun 				printf("%7d\t%12s\n", i, "-");
2207*4882a593Smuzhiyun 			}
2208*4882a593Smuzhiyun 		}
2209*4882a593Smuzhiyun 	}
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun 
vsc9953_egr_vlan_tag_set_key_func(struct ethsw_command_def * parsed_cmd)2214*4882a593Smuzhiyun static int vsc9953_egr_vlan_tag_set_key_func(
2215*4882a593Smuzhiyun 		struct ethsw_command_def *parsed_cmd)
2216*4882a593Smuzhiyun {
2217*4882a593Smuzhiyun 	int i;
2218*4882a593Smuzhiyun 	enum egress_vlan_tag mode;
2219*4882a593Smuzhiyun 
2220*4882a593Smuzhiyun 	/* keywords for the egress vlan tag mode are the last in the array */
2221*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2222*4882a593Smuzhiyun 	    ethsw_id_pvid)
2223*4882a593Smuzhiyun 		mode = EGR_TAG_PVID;
2224*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2225*4882a593Smuzhiyun 		 ethsw_id_classified)
2226*4882a593Smuzhiyun 		mode = EGR_TAG_CLASS;
2227*4882a593Smuzhiyun 	else
2228*4882a593Smuzhiyun 		return CMD_RET_USAGE;
2229*4882a593Smuzhiyun 
2230*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2231*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2232*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2233*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2234*4882a593Smuzhiyun 		}
2235*4882a593Smuzhiyun 		vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode);
2236*4882a593Smuzhiyun 	} else {
2237*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2238*4882a593Smuzhiyun 			vsc9953_port_vlan_egress_tag_set(i, mode);
2239*4882a593Smuzhiyun 	}
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2242*4882a593Smuzhiyun }
2243*4882a593Smuzhiyun 
vsc9953_vlan_learn_show_key_func(struct ethsw_command_def * parsed_cmd)2244*4882a593Smuzhiyun static int vsc9953_vlan_learn_show_key_func(
2245*4882a593Smuzhiyun 		struct ethsw_command_def *parsed_cmd)
2246*4882a593Smuzhiyun {
2247*4882a593Smuzhiyun 	int rc;
2248*4882a593Smuzhiyun 	enum vlan_learning_mode mode;
2249*4882a593Smuzhiyun 
2250*4882a593Smuzhiyun 	rc = vsc9953_vlan_learning_get(&mode);
2251*4882a593Smuzhiyun 	if (rc)
2252*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 	switch (mode) {
2255*4882a593Smuzhiyun 	case SHARED_VLAN_LEARNING:
2256*4882a593Smuzhiyun 		printf("VLAN learning mode: shared\n");
2257*4882a593Smuzhiyun 		break;
2258*4882a593Smuzhiyun 	case PRIVATE_VLAN_LEARNING:
2259*4882a593Smuzhiyun 		printf("VLAN learning mode: private\n");
2260*4882a593Smuzhiyun 		break;
2261*4882a593Smuzhiyun 	default:
2262*4882a593Smuzhiyun 		printf("Unknown VLAN learning mode\n");
2263*4882a593Smuzhiyun 		rc = CMD_RET_FAILURE;
2264*4882a593Smuzhiyun 	}
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun 
vsc9953_vlan_learn_set_key_func(struct ethsw_command_def * parsed_cmd)2269*4882a593Smuzhiyun static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
2270*4882a593Smuzhiyun {
2271*4882a593Smuzhiyun 	enum vlan_learning_mode mode;
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun 	/* keywords for shared/private are the last in the array */
2274*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2275*4882a593Smuzhiyun 	    ethsw_id_shared)
2276*4882a593Smuzhiyun 		mode = SHARED_VLAN_LEARNING;
2277*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2278*4882a593Smuzhiyun 		 ethsw_id_private)
2279*4882a593Smuzhiyun 		mode = PRIVATE_VLAN_LEARNING;
2280*4882a593Smuzhiyun 	else
2281*4882a593Smuzhiyun 		return CMD_RET_USAGE;
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun 	vsc9953_vlan_learning_set(mode);
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2286*4882a593Smuzhiyun }
2287*4882a593Smuzhiyun 
vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def * parsed_cmd)2288*4882a593Smuzhiyun static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd)
2289*4882a593Smuzhiyun {
2290*4882a593Smuzhiyun 	int i;
2291*4882a593Smuzhiyun 	int enabled;
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun 	printf("%7s\t%18s\n", "Port", "Ingress filtering");
2294*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2295*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2296*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2297*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2298*4882a593Smuzhiyun 		}
2299*4882a593Smuzhiyun 		enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port);
2300*4882a593Smuzhiyun 		printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" :
2301*4882a593Smuzhiyun 								  "disable");
2302*4882a593Smuzhiyun 	} else {
2303*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2304*4882a593Smuzhiyun 			enabled = vsc9953_port_ingress_filtering_get(i);
2305*4882a593Smuzhiyun 			printf("%7d\t%18s\n", parsed_cmd->port, enabled ?
2306*4882a593Smuzhiyun 								"enable" :
2307*4882a593Smuzhiyun 								"disable");
2308*4882a593Smuzhiyun 		}
2309*4882a593Smuzhiyun 	}
2310*4882a593Smuzhiyun 
2311*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2312*4882a593Smuzhiyun }
2313*4882a593Smuzhiyun 
vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def * parsed_cmd)2314*4882a593Smuzhiyun static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
2315*4882a593Smuzhiyun {
2316*4882a593Smuzhiyun 	int i;
2317*4882a593Smuzhiyun 	int enable;
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 	/* keywords for enabling/disabling ingress filtering
2320*4882a593Smuzhiyun 	 * are the last in the array
2321*4882a593Smuzhiyun 	 */
2322*4882a593Smuzhiyun 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2323*4882a593Smuzhiyun 	    ethsw_id_enable)
2324*4882a593Smuzhiyun 		enable = 1;
2325*4882a593Smuzhiyun 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2326*4882a593Smuzhiyun 		 ethsw_id_disable)
2327*4882a593Smuzhiyun 		enable = 0;
2328*4882a593Smuzhiyun 	else
2329*4882a593Smuzhiyun 		return CMD_RET_USAGE;
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2332*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2333*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2334*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2335*4882a593Smuzhiyun 		}
2336*4882a593Smuzhiyun 		vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable);
2337*4882a593Smuzhiyun 	} else {
2338*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2339*4882a593Smuzhiyun 			vsc9953_port_ingress_filtering_set(i, enable);
2340*4882a593Smuzhiyun 	}
2341*4882a593Smuzhiyun 
2342*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2343*4882a593Smuzhiyun }
2344*4882a593Smuzhiyun 
vsc9953_port_aggr_show_key_func(struct ethsw_command_def * parsed_cmd)2345*4882a593Smuzhiyun static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
2346*4882a593Smuzhiyun {
2347*4882a593Smuzhiyun 	int i;
2348*4882a593Smuzhiyun 	int aggr_grp;
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2351*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2352*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2353*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2354*4882a593Smuzhiyun 		}
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun 		if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
2357*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2358*4882a593Smuzhiyun 		printf("%7s %10s\n", "Port", "Aggr grp");
2359*4882a593Smuzhiyun 		printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
2360*4882a593Smuzhiyun 	} else {
2361*4882a593Smuzhiyun 		printf("%7s %10s\n", "Port", "Aggr grp");
2362*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2363*4882a593Smuzhiyun 			if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
2364*4882a593Smuzhiyun 				continue;
2365*4882a593Smuzhiyun 			printf("%7d %10d\n", i, aggr_grp);
2366*4882a593Smuzhiyun 		}
2367*4882a593Smuzhiyun 	}
2368*4882a593Smuzhiyun 
2369*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2370*4882a593Smuzhiyun }
2371*4882a593Smuzhiyun 
vsc9953_port_aggr_set_key_func(struct ethsw_command_def * parsed_cmd)2372*4882a593Smuzhiyun static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
2373*4882a593Smuzhiyun {
2374*4882a593Smuzhiyun 	int i;
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	/* Aggregation group number should be set in parsed_cmd->aggr_grp */
2377*4882a593Smuzhiyun 	if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
2378*4882a593Smuzhiyun 		printf("Please set an aggregation group value\n");
2379*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2380*4882a593Smuzhiyun 	}
2381*4882a593Smuzhiyun 
2382*4882a593Smuzhiyun 	if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
2383*4882a593Smuzhiyun 		printf("Invalid aggregation group number: %d\n",
2384*4882a593Smuzhiyun 		       parsed_cmd->aggr_grp);
2385*4882a593Smuzhiyun 		return CMD_RET_FAILURE;
2386*4882a593Smuzhiyun 	}
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2389*4882a593Smuzhiyun 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2390*4882a593Smuzhiyun 			printf("Invalid port number: %d\n", parsed_cmd->port);
2391*4882a593Smuzhiyun 			return CMD_RET_FAILURE;
2392*4882a593Smuzhiyun 		}
2393*4882a593Smuzhiyun 		if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
2394*4882a593Smuzhiyun 					      parsed_cmd->aggr_grp)) {
2395*4882a593Smuzhiyun 			printf("Port %d: failed to set aggr group %d\n",
2396*4882a593Smuzhiyun 			       parsed_cmd->port, parsed_cmd->aggr_grp);
2397*4882a593Smuzhiyun 		}
2398*4882a593Smuzhiyun 	} else {
2399*4882a593Smuzhiyun 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2400*4882a593Smuzhiyun 			if (vsc9953_port_aggr_grp_set(i,
2401*4882a593Smuzhiyun 						      parsed_cmd->aggr_grp)) {
2402*4882a593Smuzhiyun 				printf("Port %d: failed to set aggr group %d\n",
2403*4882a593Smuzhiyun 				       i, parsed_cmd->aggr_grp);
2404*4882a593Smuzhiyun 			}
2405*4882a593Smuzhiyun 		}
2406*4882a593Smuzhiyun 	}
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	return CMD_RET_SUCCESS;
2409*4882a593Smuzhiyun }
2410*4882a593Smuzhiyun 
2411*4882a593Smuzhiyun static struct ethsw_command_func vsc9953_cmd_func = {
2412*4882a593Smuzhiyun 		.ethsw_name = "L2 Switch VSC9953",
2413*4882a593Smuzhiyun 		.port_enable = &vsc9953_port_status_key_func,
2414*4882a593Smuzhiyun 		.port_disable = &vsc9953_port_status_key_func,
2415*4882a593Smuzhiyun 		.port_show = &vsc9953_port_config_key_func,
2416*4882a593Smuzhiyun 		.port_stats = &vsc9953_port_stats_key_func,
2417*4882a593Smuzhiyun 		.port_stats_clear = &vsc9953_port_stats_clear_key_func,
2418*4882a593Smuzhiyun 		.port_learn = &vsc9953_learn_set_key_func,
2419*4882a593Smuzhiyun 		.port_learn_show = &vsc9953_learn_show_key_func,
2420*4882a593Smuzhiyun 		.fdb_show = &vsc9953_fdb_show_key_func,
2421*4882a593Smuzhiyun 		.fdb_flush = &vsc9953_fdb_flush_key_func,
2422*4882a593Smuzhiyun 		.fdb_entry_add = &vsc9953_fdb_entry_add_key_func,
2423*4882a593Smuzhiyun 		.fdb_entry_del = &vsc9953_fdb_entry_del_key_func,
2424*4882a593Smuzhiyun 		.pvid_show = &vsc9953_pvid_show_key_func,
2425*4882a593Smuzhiyun 		.pvid_set = &vsc9953_pvid_set_key_func,
2426*4882a593Smuzhiyun 		.vlan_show = &vsc9953_vlan_show_key_func,
2427*4882a593Smuzhiyun 		.vlan_set = &vsc9953_vlan_set_key_func,
2428*4882a593Smuzhiyun 		.port_untag_show = &vsc9953_port_untag_show_key_func,
2429*4882a593Smuzhiyun 		.port_untag_set = &vsc9953_port_untag_set_key_func,
2430*4882a593Smuzhiyun 		.port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func,
2431*4882a593Smuzhiyun 		.port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func,
2432*4882a593Smuzhiyun 		.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
2433*4882a593Smuzhiyun 		.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
2434*4882a593Smuzhiyun 		.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
2435*4882a593Smuzhiyun 		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
2436*4882a593Smuzhiyun 		.port_aggr_show = &vsc9953_port_aggr_show_key_func,
2437*4882a593Smuzhiyun 		.port_aggr_set = &vsc9953_port_aggr_set_key_func,
2438*4882a593Smuzhiyun };
2439*4882a593Smuzhiyun 
2440*4882a593Smuzhiyun #endif /* CONFIG_CMD_ETHSW */
2441*4882a593Smuzhiyun 
2442*4882a593Smuzhiyun /*****************************************************************************
2443*4882a593Smuzhiyun At startup, the default configuration would be:
2444*4882a593Smuzhiyun 	- HW learning enabled on all ports; (HW default)
2445*4882a593Smuzhiyun 	- All ports are in VLAN 1;
2446*4882a593Smuzhiyun 	- All ports are VLAN aware;
2447*4882a593Smuzhiyun 	- All ports have POP_COUNT 1;
2448*4882a593Smuzhiyun 	- All ports have PVID 1;
2449*4882a593Smuzhiyun 	- All ports have TPID 0x8100; (HW default)
2450*4882a593Smuzhiyun 	- All ports tag frames classified to all VLANs that are not PVID;
2451*4882a593Smuzhiyun *****************************************************************************/
vsc9953_default_configuration(void)2452*4882a593Smuzhiyun void vsc9953_default_configuration(void)
2453*4882a593Smuzhiyun {
2454*4882a593Smuzhiyun 	int i;
2455*4882a593Smuzhiyun 
2456*4882a593Smuzhiyun 	if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
2457*4882a593Smuzhiyun 		debug("VSC9953: failed to set AGE time to %d\n",
2458*4882a593Smuzhiyun 		      VSC9953_DEFAULT_AGE_TIME);
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_VLAN; i++)
2461*4882a593Smuzhiyun 		vsc9953_vlan_table_membership_all_set(i, 0);
2462*4882a593Smuzhiyun 	vsc9953_port_all_vlan_aware_set(1);
2463*4882a593Smuzhiyun 	vsc9953_port_all_vlan_pvid_set(1);
2464*4882a593Smuzhiyun 	vsc9953_port_all_vlan_poncnt_set(1);
2465*4882a593Smuzhiyun 	vsc9953_vlan_table_membership_all_set(1, 1);
2466*4882a593Smuzhiyun 	vsc9953_vlan_ingr_fltr_learn_drop(1);
2467*4882a593Smuzhiyun 	vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
2468*4882a593Smuzhiyun 	if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
2469*4882a593Smuzhiyun 		debug("VSC9953: failed to set default aggregation code mode\n");
2470*4882a593Smuzhiyun }
2471*4882a593Smuzhiyun 
vsc9953_init(bd_t * bis)2472*4882a593Smuzhiyun void vsc9953_init(bd_t *bis)
2473*4882a593Smuzhiyun {
2474*4882a593Smuzhiyun 	u32 i;
2475*4882a593Smuzhiyun 	u32 hdx_cfg = 0;
2476*4882a593Smuzhiyun 	u32 phy_addr = 0;
2477*4882a593Smuzhiyun 	int timeout;
2478*4882a593Smuzhiyun 	struct vsc9953_system_reg *l2sys_reg;
2479*4882a593Smuzhiyun 	struct vsc9953_qsys_reg *l2qsys_reg;
2480*4882a593Smuzhiyun 	struct vsc9953_dev_gmii *l2dev_gmii_reg;
2481*4882a593Smuzhiyun 	struct vsc9953_analyzer *l2ana_reg;
2482*4882a593Smuzhiyun 	struct vsc9953_devcpu_gcb *l2dev_gcb;
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
2485*4882a593Smuzhiyun 			VSC9953_DEV_GMII_OFFSET);
2486*4882a593Smuzhiyun 
2487*4882a593Smuzhiyun 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
2488*4882a593Smuzhiyun 			VSC9953_ANA_OFFSET);
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
2491*4882a593Smuzhiyun 			VSC9953_SYS_OFFSET);
2492*4882a593Smuzhiyun 
2493*4882a593Smuzhiyun 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
2494*4882a593Smuzhiyun 			VSC9953_QSYS_OFFSET);
2495*4882a593Smuzhiyun 
2496*4882a593Smuzhiyun 	l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
2497*4882a593Smuzhiyun 			VSC9953_DEVCPU_GCB);
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun 	out_le32(&l2dev_gcb->chip_regs.soft_rst,
2500*4882a593Smuzhiyun 		 VSC9953_SOFT_SWC_RST_ENA);
2501*4882a593Smuzhiyun 	timeout = 50000;
2502*4882a593Smuzhiyun 	while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
2503*4882a593Smuzhiyun 			VSC9953_SOFT_SWC_RST_ENA) && --timeout)
2504*4882a593Smuzhiyun 		udelay(1); /* busy wait for vsc9953 soft reset */
2505*4882a593Smuzhiyun 	if (timeout == 0)
2506*4882a593Smuzhiyun 		debug("Timeout waiting for VSC9953 to reset\n");
2507*4882a593Smuzhiyun 
2508*4882a593Smuzhiyun 	out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE |
2509*4882a593Smuzhiyun 		 VSC9953_MEM_INIT);
2510*4882a593Smuzhiyun 
2511*4882a593Smuzhiyun 	timeout = 50000;
2512*4882a593Smuzhiyun 	while ((in_le32(&l2sys_reg->sys.reset_cfg) &
2513*4882a593Smuzhiyun 		VSC9953_MEM_INIT) && --timeout)
2514*4882a593Smuzhiyun 		udelay(1); /* busy wait for vsc9953 memory init */
2515*4882a593Smuzhiyun 	if (timeout == 0)
2516*4882a593Smuzhiyun 		debug("Timeout waiting for VSC9953 memory to initialize\n");
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun 	out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
2519*4882a593Smuzhiyun 			| VSC9953_CORE_ENABLE));
2520*4882a593Smuzhiyun 
2521*4882a593Smuzhiyun 	/* VSC9953 Setting to be done once only */
2522*4882a593Smuzhiyun 	out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
2523*4882a593Smuzhiyun 
2524*4882a593Smuzhiyun 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2525*4882a593Smuzhiyun 		if (vsc9953_port_init(i))
2526*4882a593Smuzhiyun 			printf("Failed to initialize l2switch port %d\n", i);
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun 		if (!vsc9953_l2sw.port[i].enabled)
2529*4882a593Smuzhiyun 			continue;
2530*4882a593Smuzhiyun 
2531*4882a593Smuzhiyun 		/* Enable VSC9953 GMII Ports Port ID 0 - 7 */
2532*4882a593Smuzhiyun 		if (VSC9953_INTERNAL_PORT_CHECK(i)) {
2533*4882a593Smuzhiyun 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2534*4882a593Smuzhiyun 				 VSC9953_PFC_FC_QSGMII);
2535*4882a593Smuzhiyun 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2536*4882a593Smuzhiyun 				 VSC9953_MAC_FC_CFG_QSGMII);
2537*4882a593Smuzhiyun 		} else {
2538*4882a593Smuzhiyun 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2539*4882a593Smuzhiyun 				 VSC9953_PFC_FC);
2540*4882a593Smuzhiyun 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2541*4882a593Smuzhiyun 				 VSC9953_MAC_FC_CFG);
2542*4882a593Smuzhiyun 		}
2543*4882a593Smuzhiyun 
2544*4882a593Smuzhiyun 		l2dev_gmii_reg = (struct vsc9953_dev_gmii *)
2545*4882a593Smuzhiyun 				 (VSC9953_OFFSET + VSC9953_DEV_GMII_OFFSET +
2546*4882a593Smuzhiyun 				 T1040_SWITCH_GMII_DEV_OFFSET * i);
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
2549*4882a593Smuzhiyun 			 VSC9953_CLOCK_CFG);
2550*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
2551*4882a593Smuzhiyun 			 VSC9953_MAC_ENA_CFG);
2552*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
2553*4882a593Smuzhiyun 			 VSC9953_MAC_MODE_CFG);
2554*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
2555*4882a593Smuzhiyun 			 VSC9953_MAC_IFG_CFG);
2556*4882a593Smuzhiyun 		/* mac_hdx_cfg varies with port id*/
2557*4882a593Smuzhiyun 		hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16);
2558*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
2559*4882a593Smuzhiyun 		out_le32(&l2sys_reg->sys.front_port_mode[i],
2560*4882a593Smuzhiyun 			 VSC9953_FRONT_PORT_MODE);
2561*4882a593Smuzhiyun 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[i],
2562*4882a593Smuzhiyun 			     VSC9953_PORT_ENA);
2563*4882a593Smuzhiyun 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
2564*4882a593Smuzhiyun 			 VSC9953_MAC_MAX_LEN);
2565*4882a593Smuzhiyun 		out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
2566*4882a593Smuzhiyun 			 VSC9953_PAUSE_CFG);
2567*4882a593Smuzhiyun 		/* WAIT FOR 2 us*/
2568*4882a593Smuzhiyun 		udelay(2);
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun 		/* Initialize Lynx PHY Wrappers */
2571*4882a593Smuzhiyun 		phy_addr = 0;
2572*4882a593Smuzhiyun 		if (vsc9953_l2sw.port[i].enet_if ==
2573*4882a593Smuzhiyun 				PHY_INTERFACE_MODE_QSGMII)
2574*4882a593Smuzhiyun 			phy_addr = (i + 0x4) & 0x1F;
2575*4882a593Smuzhiyun 		else if (vsc9953_l2sw.port[i].enet_if ==
2576*4882a593Smuzhiyun 				PHY_INTERFACE_MODE_SGMII)
2577*4882a593Smuzhiyun 			phy_addr = (i + 1) & 0x1F;
2578*4882a593Smuzhiyun 
2579*4882a593Smuzhiyun 		if (phy_addr) {
2580*4882a593Smuzhiyun 			/* SGMII IF mode + AN enable */
2581*4882a593Smuzhiyun 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
2582*4882a593Smuzhiyun 					   0x14, PHY_SGMII_IF_MODE_AN |
2583*4882a593Smuzhiyun 					   PHY_SGMII_IF_MODE_SGMII);
2584*4882a593Smuzhiyun 			/* Dev ability according to SGMII specification */
2585*4882a593Smuzhiyun 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
2586*4882a593Smuzhiyun 					   0x4, PHY_SGMII_DEV_ABILITY_SGMII);
2587*4882a593Smuzhiyun 			/* Adjust link timer for SGMII
2588*4882a593Smuzhiyun 			 * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
2589*4882a593Smuzhiyun 			 */
2590*4882a593Smuzhiyun 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
2591*4882a593Smuzhiyun 					   0x13, 0x0003);
2592*4882a593Smuzhiyun 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
2593*4882a593Smuzhiyun 					   0x12, 0x0d40);
2594*4882a593Smuzhiyun 			/* Restart AN */
2595*4882a593Smuzhiyun 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
2596*4882a593Smuzhiyun 					   0x0, PHY_SGMII_CR_DEF_VAL |
2597*4882a593Smuzhiyun 					   PHY_SGMII_CR_RESET_AN);
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun 			timeout = 50000;
2600*4882a593Smuzhiyun 			while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
2601*4882a593Smuzhiyun 					phy_addr, 0x01) & 0x0020) && --timeout)
2602*4882a593Smuzhiyun 				udelay(1); /* wait for AN to complete */
2603*4882a593Smuzhiyun 			if (timeout == 0)
2604*4882a593Smuzhiyun 				debug("Timeout waiting for AN to complete\n");
2605*4882a593Smuzhiyun 		}
2606*4882a593Smuzhiyun 	}
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun 	vsc9953_default_configuration();
2609*4882a593Smuzhiyun 
2610*4882a593Smuzhiyun #ifdef CONFIG_CMD_ETHSW
2611*4882a593Smuzhiyun 	if (ethsw_define_functions(&vsc9953_cmd_func) < 0)
2612*4882a593Smuzhiyun 		debug("Unable to use \"ethsw\" commands\n");
2613*4882a593Smuzhiyun #endif
2614*4882a593Smuzhiyun 
2615*4882a593Smuzhiyun 	printf("VSC9953 L2 switch initialized\n");
2616*4882a593Smuzhiyun 	return;
2617*4882a593Smuzhiyun }
2618