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