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 472*aae0e689SCodrin Ciubotariu enum aggr_code_mode { 473*aae0e689SCodrin Ciubotariu AGGR_CODE_RAND = 0, 474*aae0e689SCodrin Ciubotariu AGGR_CODE_ALL, /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */ 475*aae0e689SCodrin Ciubotariu }; 476*aae0e689SCodrin Ciubotariu 477*aae0e689SCodrin Ciubotariu /* Set aggregation code generation mode */ 478*aae0e689SCodrin Ciubotariu static int vsc9953_aggr_code_set(enum aggr_code_mode ac) 479*aae0e689SCodrin Ciubotariu { 480*aae0e689SCodrin Ciubotariu int rc; 481*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 482*aae0e689SCodrin Ciubotariu 483*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 484*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 485*aae0e689SCodrin Ciubotariu 486*aae0e689SCodrin Ciubotariu switch (ac) { 487*aae0e689SCodrin Ciubotariu case AGGR_CODE_RAND: 488*aae0e689SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->common.aggr_cfg, 489*aae0e689SCodrin Ciubotariu VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA | 490*aae0e689SCodrin Ciubotariu VSC9953_AC_IP6_LBL_ENA | 491*aae0e689SCodrin Ciubotariu VSC9953_AC_IP6_TCPUDP_ENA | 492*aae0e689SCodrin Ciubotariu VSC9953_AC_IP4_SIPDIP_ENA | 493*aae0e689SCodrin Ciubotariu VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA); 494*aae0e689SCodrin Ciubotariu rc = 0; 495*aae0e689SCodrin Ciubotariu break; 496*aae0e689SCodrin Ciubotariu case AGGR_CODE_ALL: 497*aae0e689SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA, 498*aae0e689SCodrin Ciubotariu VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA | 499*aae0e689SCodrin Ciubotariu VSC9953_AC_IP6_LBL_ENA | 500*aae0e689SCodrin Ciubotariu VSC9953_AC_IP6_TCPUDP_ENA | 501*aae0e689SCodrin Ciubotariu VSC9953_AC_IP4_SIPDIP_ENA | 502*aae0e689SCodrin Ciubotariu VSC9953_AC_IP4_TCPUDP_ENA); 503*aae0e689SCodrin Ciubotariu rc = 0; 504*aae0e689SCodrin Ciubotariu break; 505*aae0e689SCodrin Ciubotariu default: 506*aae0e689SCodrin Ciubotariu /* unknown mode for aggregation code */ 507*aae0e689SCodrin Ciubotariu rc = -EINVAL; 508*aae0e689SCodrin Ciubotariu } 509*aae0e689SCodrin Ciubotariu 510*aae0e689SCodrin Ciubotariu return rc; 511*aae0e689SCodrin Ciubotariu } 512*aae0e689SCodrin Ciubotariu 5139de05987SCodrin Ciubotariu /* Egress untag modes of a VSC9953 port */ 5149de05987SCodrin Ciubotariu enum egress_untag_mode { 5159de05987SCodrin Ciubotariu EGRESS_UNTAG_ALL = 0, 5169de05987SCodrin Ciubotariu EGRESS_UNTAG_PVID_AND_ZERO, 5179de05987SCodrin Ciubotariu EGRESS_UNTAG_ZERO, 5189de05987SCodrin Ciubotariu EGRESS_UNTAG_NONE, 5199de05987SCodrin Ciubotariu }; 5209de05987SCodrin Ciubotariu 521a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW 522a2477924SCodrin Ciubotariu /* Get egress tagging configuration for a VSC9953 port */ 523a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_egr_untag_get(int port_no, 524a2477924SCodrin Ciubotariu enum egress_untag_mode *mode) 525a2477924SCodrin Ciubotariu { 526a2477924SCodrin Ciubotariu u32 val; 527a2477924SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 528a2477924SCodrin Ciubotariu 529a2477924SCodrin Ciubotariu /* Administrative down */ 530a2477924SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 531a2477924SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 532a2477924SCodrin Ciubotariu return -1; 533a2477924SCodrin Ciubotariu } 534a2477924SCodrin Ciubotariu 535a2477924SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 536a2477924SCodrin Ciubotariu VSC9953_REW_OFFSET); 537a2477924SCodrin Ciubotariu 538a2477924SCodrin Ciubotariu val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg); 539a2477924SCodrin Ciubotariu 540a2477924SCodrin Ciubotariu switch (val & VSC9953_TAG_CFG_MASK) { 541a2477924SCodrin Ciubotariu case VSC9953_TAG_CFG_NONE: 542a2477924SCodrin Ciubotariu *mode = EGRESS_UNTAG_ALL; 543a2477924SCodrin Ciubotariu return 0; 544a2477924SCodrin Ciubotariu case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO: 545a2477924SCodrin Ciubotariu *mode = EGRESS_UNTAG_PVID_AND_ZERO; 546a2477924SCodrin Ciubotariu return 0; 547a2477924SCodrin Ciubotariu case VSC9953_TAG_CFG_ALL_BUT_ZERO: 548a2477924SCodrin Ciubotariu *mode = EGRESS_UNTAG_ZERO; 549a2477924SCodrin Ciubotariu return 0; 550a2477924SCodrin Ciubotariu case VSC9953_TAG_CFG_ALL: 551a2477924SCodrin Ciubotariu *mode = EGRESS_UNTAG_NONE; 552a2477924SCodrin Ciubotariu return 0; 553a2477924SCodrin Ciubotariu default: 554a2477924SCodrin Ciubotariu printf("Unknown egress tagging configuration for port %d\n", 555a2477924SCodrin Ciubotariu port_no); 556a2477924SCodrin Ciubotariu return -1; 557a2477924SCodrin Ciubotariu } 558a2477924SCodrin Ciubotariu } 559a2477924SCodrin Ciubotariu 560a2477924SCodrin Ciubotariu /* Show egress tagging configuration for a VSC9953 port */ 561a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_show(int port_no) 562a2477924SCodrin Ciubotariu { 563a2477924SCodrin Ciubotariu enum egress_untag_mode mode; 564a2477924SCodrin Ciubotariu 565a2477924SCodrin Ciubotariu if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) { 566a2477924SCodrin Ciubotariu printf("%7d\t%17s\n", port_no, "-"); 567a2477924SCodrin Ciubotariu return; 568a2477924SCodrin Ciubotariu } 569a2477924SCodrin Ciubotariu 570a2477924SCodrin Ciubotariu printf("%7d\t", port_no); 571a2477924SCodrin Ciubotariu switch (mode) { 572a2477924SCodrin Ciubotariu case EGRESS_UNTAG_ALL: 573a2477924SCodrin Ciubotariu printf("%17s\n", "all"); 574a2477924SCodrin Ciubotariu break; 575a2477924SCodrin Ciubotariu case EGRESS_UNTAG_NONE: 576a2477924SCodrin Ciubotariu printf("%17s\n", "none"); 577a2477924SCodrin Ciubotariu break; 578a2477924SCodrin Ciubotariu case EGRESS_UNTAG_PVID_AND_ZERO: 579a2477924SCodrin Ciubotariu printf("%17s\n", "PVID and 0"); 580a2477924SCodrin Ciubotariu break; 581a2477924SCodrin Ciubotariu case EGRESS_UNTAG_ZERO: 582a2477924SCodrin Ciubotariu printf("%17s\n", "0"); 583a2477924SCodrin Ciubotariu break; 584a2477924SCodrin Ciubotariu default: 585a2477924SCodrin Ciubotariu printf("%17s\n", "-"); 586a2477924SCodrin Ciubotariu } 587a2477924SCodrin Ciubotariu } 588a2477924SCodrin Ciubotariu #endif 589a2477924SCodrin Ciubotariu 5909de05987SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_set(int port_no, 5919de05987SCodrin Ciubotariu enum egress_untag_mode mode) 5929de05987SCodrin Ciubotariu { 5939de05987SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 5949de05987SCodrin Ciubotariu 5959de05987SCodrin Ciubotariu /* Administrative down */ 5969de05987SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 5979de05987SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 5989de05987SCodrin Ciubotariu return; 5999de05987SCodrin Ciubotariu } 6009de05987SCodrin Ciubotariu 6019de05987SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 6029de05987SCodrin Ciubotariu VSC9953_REW_OFFSET); 6039de05987SCodrin Ciubotariu 6049de05987SCodrin Ciubotariu switch (mode) { 6059de05987SCodrin Ciubotariu case EGRESS_UNTAG_ALL: 6069de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 6079de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE); 6089de05987SCodrin Ciubotariu break; 6099de05987SCodrin Ciubotariu case EGRESS_UNTAG_PVID_AND_ZERO: 6109de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 6119de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, 6129de05987SCodrin Ciubotariu VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO); 6139de05987SCodrin Ciubotariu break; 6149de05987SCodrin Ciubotariu case EGRESS_UNTAG_ZERO: 6159de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 6169de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, 6179de05987SCodrin Ciubotariu VSC9953_TAG_CFG_ALL_BUT_ZERO); 6189de05987SCodrin Ciubotariu break; 6199de05987SCodrin Ciubotariu case EGRESS_UNTAG_NONE: 6209de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 6219de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL); 6229de05987SCodrin Ciubotariu break; 6239de05987SCodrin Ciubotariu default: 6249de05987SCodrin Ciubotariu printf("Unknown untag mode for port %d\n", port_no); 6259de05987SCodrin Ciubotariu } 6269de05987SCodrin Ciubotariu } 6279de05987SCodrin Ciubotariu 6289de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_egress_untagged_set( 6299de05987SCodrin Ciubotariu enum egress_untag_mode mode) 6309de05987SCodrin Ciubotariu { 6319de05987SCodrin Ciubotariu int i; 6329de05987SCodrin Ciubotariu 6339de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 6349de05987SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_set(i, mode); 6359de05987SCodrin Ciubotariu } 6369de05987SCodrin Ciubotariu 637ba389e65SCodrin Ciubotariu static int vsc9953_autoage_time_set(int age_period) 638ba389e65SCodrin Ciubotariu { 639ba389e65SCodrin Ciubotariu u32 autoage; 640ba389e65SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 641ba389e65SCodrin Ciubotariu 642ba389e65SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 643ba389e65SCodrin Ciubotariu VSC9953_ANA_OFFSET); 644ba389e65SCodrin Ciubotariu 645ba389e65SCodrin Ciubotariu if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK) 646ba389e65SCodrin Ciubotariu return -EINVAL; 647ba389e65SCodrin Ciubotariu 648ba389e65SCodrin Ciubotariu autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age), 649ba389e65SCodrin Ciubotariu VSC9953_AUTOAGE_PERIOD_MASK, 650ba389e65SCodrin Ciubotariu age_period); 651ba389e65SCodrin Ciubotariu out_le32(&l2ana_reg->ana.auto_age, autoage); 652ba389e65SCodrin Ciubotariu 653ba389e65SCodrin Ciubotariu return 0; 654ba389e65SCodrin Ciubotariu } 655ba389e65SCodrin Ciubotariu 65624a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW 65724a23debSCodrin Ciubotariu 65824a23debSCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */ 65924a23debSCodrin Ciubotariu static void vsc9953_port_status_set(int port_no, u8 enabled) 66024a23debSCodrin Ciubotariu { 66124a23debSCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 66224a23debSCodrin Ciubotariu 66324a23debSCodrin Ciubotariu /* Administrative down */ 66424a23debSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) 66524a23debSCodrin Ciubotariu return; 66624a23debSCodrin Ciubotariu 66724a23debSCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 66824a23debSCodrin Ciubotariu VSC9953_QSYS_OFFSET); 66924a23debSCodrin Ciubotariu 67024a23debSCodrin Ciubotariu if (enabled) 67124a23debSCodrin Ciubotariu setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], 67224a23debSCodrin Ciubotariu VSC9953_PORT_ENA); 67324a23debSCodrin Ciubotariu else 67424a23debSCodrin Ciubotariu clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], 67524a23debSCodrin Ciubotariu VSC9953_PORT_ENA); 67624a23debSCodrin Ciubotariu } 67724a23debSCodrin Ciubotariu 67824a23debSCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */ 67924a23debSCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_no) 68024a23debSCodrin Ciubotariu { 68124a23debSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].phydev) 68224a23debSCodrin Ciubotariu return; 68324a23debSCodrin Ciubotariu 68424a23debSCodrin Ciubotariu if (vsc9953_l2sw.port[port_no].phydev->drv->startup( 68524a23debSCodrin Ciubotariu vsc9953_l2sw.port[port_no].phydev)) 68624a23debSCodrin Ciubotariu printf("Failed to start PHY for port %d\n", port_no); 68724a23debSCodrin Ciubotariu } 68824a23debSCodrin Ciubotariu 68924a23debSCodrin Ciubotariu /* Print a VSC9953 port's configuration */ 69024a23debSCodrin Ciubotariu static void vsc9953_port_config_show(int port_no) 69124a23debSCodrin Ciubotariu { 69224a23debSCodrin Ciubotariu int speed; 69324a23debSCodrin Ciubotariu int duplex; 69424a23debSCodrin Ciubotariu int link; 69524a23debSCodrin Ciubotariu u8 enabled; 69624a23debSCodrin Ciubotariu u32 val; 69724a23debSCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 69824a23debSCodrin Ciubotariu 69924a23debSCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 70024a23debSCodrin Ciubotariu VSC9953_QSYS_OFFSET); 70124a23debSCodrin Ciubotariu 70224a23debSCodrin Ciubotariu val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]); 70324a23debSCodrin Ciubotariu enabled = vsc9953_l2sw.port[port_no].enabled && 70424a23debSCodrin Ciubotariu (val & VSC9953_PORT_ENA); 70524a23debSCodrin Ciubotariu 70624a23debSCodrin Ciubotariu /* internal ports (8 and 9) are fixed */ 70724a23debSCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(port_no)) { 70824a23debSCodrin Ciubotariu link = 1; 70924a23debSCodrin Ciubotariu speed = SPEED_2500; 71024a23debSCodrin Ciubotariu duplex = DUPLEX_FULL; 71124a23debSCodrin Ciubotariu } else { 71224a23debSCodrin Ciubotariu if (vsc9953_l2sw.port[port_no].phydev) { 71324a23debSCodrin Ciubotariu link = vsc9953_l2sw.port[port_no].phydev->link; 71424a23debSCodrin Ciubotariu speed = vsc9953_l2sw.port[port_no].phydev->speed; 71524a23debSCodrin Ciubotariu duplex = vsc9953_l2sw.port[port_no].phydev->duplex; 71624a23debSCodrin Ciubotariu } else { 71724a23debSCodrin Ciubotariu link = -1; 71824a23debSCodrin Ciubotariu speed = -1; 71924a23debSCodrin Ciubotariu duplex = -1; 72024a23debSCodrin Ciubotariu } 72124a23debSCodrin Ciubotariu } 72224a23debSCodrin Ciubotariu 72324a23debSCodrin Ciubotariu printf("%8d ", port_no); 72424a23debSCodrin Ciubotariu printf("%8s ", enabled == 1 ? "enabled" : "disabled"); 72524a23debSCodrin Ciubotariu printf("%8s ", link == 1 ? "up" : "down"); 72624a23debSCodrin Ciubotariu 72724a23debSCodrin Ciubotariu switch (speed) { 72824a23debSCodrin Ciubotariu case SPEED_10: 72924a23debSCodrin Ciubotariu printf("%8d ", 10); 73024a23debSCodrin Ciubotariu break; 73124a23debSCodrin Ciubotariu case SPEED_100: 73224a23debSCodrin Ciubotariu printf("%8d ", 100); 73324a23debSCodrin Ciubotariu break; 73424a23debSCodrin Ciubotariu case SPEED_1000: 73524a23debSCodrin Ciubotariu printf("%8d ", 1000); 73624a23debSCodrin Ciubotariu break; 73724a23debSCodrin Ciubotariu case SPEED_2500: 73824a23debSCodrin Ciubotariu printf("%8d ", 2500); 73924a23debSCodrin Ciubotariu break; 74024a23debSCodrin Ciubotariu case SPEED_10000: 74124a23debSCodrin Ciubotariu printf("%8d ", 10000); 74224a23debSCodrin Ciubotariu break; 74324a23debSCodrin Ciubotariu default: 74424a23debSCodrin Ciubotariu printf("%8s ", "-"); 74524a23debSCodrin Ciubotariu } 74624a23debSCodrin Ciubotariu 74724a23debSCodrin Ciubotariu printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half"); 74824a23debSCodrin Ciubotariu } 74924a23debSCodrin Ciubotariu 75086719f0cSCodrin Ciubotariu /* Show VSC9953 ports' statistics */ 75186719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_show(int port_no) 75286719f0cSCodrin Ciubotariu { 75386719f0cSCodrin Ciubotariu u32 rx_val; 75486719f0cSCodrin Ciubotariu u32 tx_val; 75586719f0cSCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 75686719f0cSCodrin Ciubotariu 75786719f0cSCodrin Ciubotariu /* Administrative down */ 75886719f0cSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 75986719f0cSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 76086719f0cSCodrin Ciubotariu return; 76186719f0cSCodrin Ciubotariu } 76286719f0cSCodrin Ciubotariu 76386719f0cSCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 76486719f0cSCodrin Ciubotariu VSC9953_SYS_OFFSET); 76586719f0cSCodrin Ciubotariu 76686719f0cSCodrin Ciubotariu printf("Statistics for L2 Switch port %d:\n", port_no); 76786719f0cSCodrin Ciubotariu 76886719f0cSCodrin Ciubotariu /* Set counter view for our port */ 76986719f0cSCodrin Ciubotariu out_le32(&l2sys_reg->sys.stat_cfg, port_no); 77086719f0cSCodrin Ciubotariu 77186719f0cSCodrin Ciubotariu #define VSC9953_STATS_PRINTF "%-15s %10u" 77286719f0cSCodrin Ciubotariu 77386719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames */ 77486719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) + 77586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) + 77686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) + 77786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) + 77886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) + 77986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) + 78086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) + 78186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) + 78286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) + 78386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) + 78486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); 78586719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + 78686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + 78786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + 78886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + 78986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + 79086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + 79186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 79286719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 79386719f0cSCodrin Ciubotariu "Rx frames:", rx_val, "Tx frames:", tx_val); 79486719f0cSCodrin Ciubotariu 79586719f0cSCodrin Ciubotariu /* Get number of Rx and Tx bytes */ 79686719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct); 79786719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct); 79886719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 79986719f0cSCodrin Ciubotariu "Rx bytes:", rx_val, "Tx bytes:", tx_val); 80086719f0cSCodrin Ciubotariu 80186719f0cSCodrin Ciubotariu /* Get number of Rx frames received ok and Tx frames sent ok */ 80286719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) + 80386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) + 80486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) + 80586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) + 80686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) + 80786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) + 80886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) + 80986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) + 81086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) + 81186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) + 81286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) + 81386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) + 81486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) + 81586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) + 81686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) + 81786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7); 81886719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + 81986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + 82086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + 82186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + 82286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + 82386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + 82486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 82586719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 82686719f0cSCodrin Ciubotariu "Rx frames ok:", rx_val, "Tx frames ok:", tx_val); 82786719f0cSCodrin Ciubotariu 82886719f0cSCodrin Ciubotariu /* Get number of Rx and Tx unicast frames */ 82986719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc); 83086719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc); 83186719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 83286719f0cSCodrin Ciubotariu "Rx unicast:", rx_val, "Tx unicast:", tx_val); 83386719f0cSCodrin Ciubotariu 83486719f0cSCodrin Ciubotariu /* Get number of Rx and Tx broadcast frames */ 83586719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc); 83686719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc); 83786719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 83886719f0cSCodrin Ciubotariu "Rx broadcast:", rx_val, "Tx broadcast:", tx_val); 83986719f0cSCodrin Ciubotariu 84086719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames of 64B */ 84186719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64); 84286719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64); 84386719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 84486719f0cSCodrin Ciubotariu "Rx 64B:", rx_val, "Tx 64B:", tx_val); 84586719f0cSCodrin Ciubotariu 84686719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 65B and 127B */ 84786719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127); 84886719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127); 84986719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 85086719f0cSCodrin Ciubotariu "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val); 85186719f0cSCodrin Ciubotariu 85286719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 128B and 255B */ 85386719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255); 85486719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255); 85586719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 85686719f0cSCodrin Ciubotariu "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val); 85786719f0cSCodrin Ciubotariu 85886719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 256B and 511B */ 85986719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511); 86086719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511); 86186719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 86286719f0cSCodrin Ciubotariu "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val); 86386719f0cSCodrin Ciubotariu 86486719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 512B and 1023B */ 86586719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023); 86686719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023); 86786719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 86886719f0cSCodrin Ciubotariu "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val); 86986719f0cSCodrin Ciubotariu 87086719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 1024B and 1526B */ 87186719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526); 87286719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526); 87386719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 87486719f0cSCodrin Ciubotariu "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val); 87586719f0cSCodrin Ciubotariu 87686719f0cSCodrin Ciubotariu /* Get number of Rx and Tx jumbo frames */ 87786719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); 87886719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 87986719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 88086719f0cSCodrin Ciubotariu "Rx jumbo:", rx_val, "Tx jumbo:", tx_val); 88186719f0cSCodrin Ciubotariu 88286719f0cSCodrin Ciubotariu /* Get number of Rx and Tx dropped frames */ 88386719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + 88486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) + 88586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) + 88686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) + 88786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) + 88886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) + 88986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) + 89086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) + 89186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) + 89286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) + 89386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) + 89486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) + 89586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) + 89686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) + 89786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) + 89886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) + 89986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) + 90086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7); 90186719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) + 90286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); 90386719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 90486719f0cSCodrin Ciubotariu "Rx drops:", rx_val, "Tx drops:", tx_val); 90586719f0cSCodrin Ciubotariu 90686719f0cSCodrin Ciubotariu /* 90786719f0cSCodrin Ciubotariu * Get number of Rx frames with CRC or alignment errors 90886719f0cSCodrin Ciubotariu * and number of detected Tx collisions 90986719f0cSCodrin Ciubotariu */ 91086719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc); 91186719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col); 91286719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 91386719f0cSCodrin Ciubotariu "Rx CRC&align:", rx_val, "Tx coll:", tx_val); 91486719f0cSCodrin Ciubotariu 91586719f0cSCodrin Ciubotariu /* 91686719f0cSCodrin Ciubotariu * Get number of Rx undersized frames and 91786719f0cSCodrin Ciubotariu * number of Tx aged frames 91886719f0cSCodrin Ciubotariu */ 91986719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short); 92086719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); 92186719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 92286719f0cSCodrin Ciubotariu "Rx undersize:", rx_val, "Tx aged:", tx_val); 92386719f0cSCodrin Ciubotariu 92486719f0cSCodrin Ciubotariu /* Get number of Rx oversized frames */ 92586719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long); 92686719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val); 92786719f0cSCodrin Ciubotariu 92886719f0cSCodrin Ciubotariu /* Get number of Rx fragmented frames */ 92986719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag); 93086719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val); 93186719f0cSCodrin Ciubotariu 93286719f0cSCodrin Ciubotariu /* Get number of Rx jabber errors */ 93386719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber); 93486719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val); 93586719f0cSCodrin Ciubotariu 93686719f0cSCodrin Ciubotariu /* 93786719f0cSCodrin Ciubotariu * Get number of Rx frames filtered due to classification rules or 93886719f0cSCodrin Ciubotariu * no destination ports 93986719f0cSCodrin Ciubotariu */ 94086719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + 94186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local); 94286719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val); 94386719f0cSCodrin Ciubotariu 94486719f0cSCodrin Ciubotariu printf("\n"); 94586719f0cSCodrin Ciubotariu } 94686719f0cSCodrin Ciubotariu 94786719f0cSCodrin Ciubotariu /* Clear statistics for a VSC9953 port */ 94886719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_clear(int port_no) 94986719f0cSCodrin Ciubotariu { 95086719f0cSCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 95186719f0cSCodrin Ciubotariu 95286719f0cSCodrin Ciubotariu /* Administrative down */ 95386719f0cSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 95486719f0cSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 95586719f0cSCodrin Ciubotariu return; 95686719f0cSCodrin Ciubotariu } 95786719f0cSCodrin Ciubotariu 95886719f0cSCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 95986719f0cSCodrin Ciubotariu VSC9953_SYS_OFFSET); 96086719f0cSCodrin Ciubotariu 96186719f0cSCodrin Ciubotariu /* Clear all counter groups for our ports */ 96286719f0cSCodrin Ciubotariu out_le32(&l2sys_reg->sys.stat_cfg, port_no | 96386719f0cSCodrin Ciubotariu VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX | 96486719f0cSCodrin Ciubotariu VSC9953_STAT_CLEAR_DR); 96586719f0cSCodrin Ciubotariu } 96686719f0cSCodrin Ciubotariu 96768c929daSCodrin Ciubotariu enum port_learn_mode { 96868c929daSCodrin Ciubotariu PORT_LEARN_NONE, 96968c929daSCodrin Ciubotariu PORT_LEARN_AUTO 97068c929daSCodrin Ciubotariu }; 97168c929daSCodrin Ciubotariu 97268c929daSCodrin Ciubotariu /* Set learning configuration for a VSC9953 port */ 97368c929daSCodrin Ciubotariu static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode) 97468c929daSCodrin Ciubotariu { 97568c929daSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 97668c929daSCodrin Ciubotariu 97768c929daSCodrin Ciubotariu /* Administrative down */ 97868c929daSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 97968c929daSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 98068c929daSCodrin Ciubotariu return; 98168c929daSCodrin Ciubotariu } 98268c929daSCodrin Ciubotariu 98368c929daSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 98468c929daSCodrin Ciubotariu VSC9953_ANA_OFFSET); 98568c929daSCodrin Ciubotariu 98668c929daSCodrin Ciubotariu switch (mode) { 98768c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 98868c929daSCodrin Ciubotariu clrbits_le32(&l2ana_reg->port[port_no].port_cfg, 98968c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_DROP | 99068c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_CPU | 99168c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO | 99268c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_ENA); 99368c929daSCodrin Ciubotariu break; 99468c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 99568c929daSCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg, 99668c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_DROP | 99768c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_CPU, 99868c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_ENA | 99968c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO); 100068c929daSCodrin Ciubotariu break; 100168c929daSCodrin Ciubotariu default: 100268c929daSCodrin Ciubotariu printf("Unknown learn mode for port %d\n", port_no); 100368c929daSCodrin Ciubotariu } 100468c929daSCodrin Ciubotariu } 100568c929daSCodrin Ciubotariu 100668c929daSCodrin Ciubotariu /* Get learning configuration for a VSC9953 port */ 100768c929daSCodrin Ciubotariu static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode) 100868c929daSCodrin Ciubotariu { 100968c929daSCodrin Ciubotariu u32 val; 101068c929daSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 101168c929daSCodrin Ciubotariu 101268c929daSCodrin Ciubotariu /* Administrative down */ 101368c929daSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 101468c929daSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 101568c929daSCodrin Ciubotariu return -1; 101668c929daSCodrin Ciubotariu } 101768c929daSCodrin Ciubotariu 101868c929daSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 101968c929daSCodrin Ciubotariu VSC9953_ANA_OFFSET); 102068c929daSCodrin Ciubotariu 102168c929daSCodrin Ciubotariu /* For now we only support HW learning (auto) and no learning */ 102268c929daSCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].port_cfg); 102368c929daSCodrin Ciubotariu if ((val & (VSC9953_PORT_CFG_LEARN_ENA | 102468c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO)) == 102568c929daSCodrin Ciubotariu (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO)) 102668c929daSCodrin Ciubotariu *mode = PORT_LEARN_AUTO; 102768c929daSCodrin Ciubotariu else 102868c929daSCodrin Ciubotariu *mode = PORT_LEARN_NONE; 102968c929daSCodrin Ciubotariu 103068c929daSCodrin Ciubotariu return 0; 103168c929daSCodrin Ciubotariu } 103268c929daSCodrin Ciubotariu 103322449858SCodrin Ciubotariu /* wait for FDB to become available */ 103422449858SCodrin Ciubotariu static int vsc9953_mac_table_poll_idle(void) 103522449858SCodrin Ciubotariu { 103622449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 103722449858SCodrin Ciubotariu u32 timeout; 103822449858SCodrin Ciubotariu 103922449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 104022449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 104122449858SCodrin Ciubotariu 104222449858SCodrin Ciubotariu timeout = 50000; 104322449858SCodrin Ciubotariu while (((in_le32(&l2ana_reg->ana_tables.mac_access) & 104422449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK) != 104522449858SCodrin Ciubotariu VSC9953_MAC_CMD_IDLE) && --timeout) 104622449858SCodrin Ciubotariu udelay(1); 104722449858SCodrin Ciubotariu 104822449858SCodrin Ciubotariu return timeout ? 0 : -EBUSY; 104922449858SCodrin Ciubotariu } 105022449858SCodrin Ciubotariu 105122449858SCodrin Ciubotariu /* enum describing available commands for the MAC table */ 105222449858SCodrin Ciubotariu enum mac_table_cmd { 105322449858SCodrin Ciubotariu MAC_TABLE_READ, 105422449858SCodrin Ciubotariu MAC_TABLE_LOOKUP, 105522449858SCodrin Ciubotariu MAC_TABLE_WRITE, 105622449858SCodrin Ciubotariu MAC_TABLE_LEARN, 105722449858SCodrin Ciubotariu MAC_TABLE_FORGET, 105822449858SCodrin Ciubotariu MAC_TABLE_GET_NEXT, 105922449858SCodrin Ciubotariu MAC_TABLE_AGE, 106022449858SCodrin Ciubotariu }; 106122449858SCodrin Ciubotariu 106222449858SCodrin Ciubotariu /* Issues a command to the FDB table */ 106322449858SCodrin Ciubotariu static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd) 106422449858SCodrin Ciubotariu { 106522449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 106622449858SCodrin Ciubotariu 106722449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 106822449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 106922449858SCodrin Ciubotariu 107022449858SCodrin Ciubotariu switch (cmd) { 107122449858SCodrin Ciubotariu case MAC_TABLE_READ: 107222449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 107322449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID, 107422449858SCodrin Ciubotariu VSC9953_MAC_CMD_READ); 107522449858SCodrin Ciubotariu break; 107622449858SCodrin Ciubotariu case MAC_TABLE_LOOKUP: 107722449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 107822449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ | 107922449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID); 108022449858SCodrin Ciubotariu break; 108122449858SCodrin Ciubotariu case MAC_TABLE_WRITE: 108222449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 108322449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 108422449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 108522449858SCodrin Ciubotariu VSC9953_MAC_CMD_WRITE | 108622449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_LOCKED); 108722449858SCodrin Ciubotariu break; 108822449858SCodrin Ciubotariu case MAC_TABLE_LEARN: 108922449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 109022449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 109122449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 109222449858SCodrin Ciubotariu VSC9953_MAC_CMD_LEARN | 109322449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_LOCKED | 109422449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID); 109522449858SCodrin Ciubotariu break; 109622449858SCodrin Ciubotariu case MAC_TABLE_FORGET: 109722449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 109822449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 109922449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 110022449858SCodrin Ciubotariu VSC9953_MAC_CMD_FORGET); 110122449858SCodrin Ciubotariu break; 110222449858SCodrin Ciubotariu case MAC_TABLE_GET_NEXT: 110322449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 110422449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 110522449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 110622449858SCodrin Ciubotariu VSC9953_MAC_CMD_NEXT); 110722449858SCodrin Ciubotariu break; 110822449858SCodrin Ciubotariu case MAC_TABLE_AGE: 110922449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 111022449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 111122449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 111222449858SCodrin Ciubotariu VSC9953_MAC_CMD_AGE); 111322449858SCodrin Ciubotariu break; 111422449858SCodrin Ciubotariu default: 111522449858SCodrin Ciubotariu printf("Unknown MAC table command\n"); 111622449858SCodrin Ciubotariu } 111722449858SCodrin Ciubotariu 111822449858SCodrin Ciubotariu if (vsc9953_mac_table_poll_idle() < 0) { 111922449858SCodrin Ciubotariu debug("MAC table timeout\n"); 112022449858SCodrin Ciubotariu return -1; 112122449858SCodrin Ciubotariu } 112222449858SCodrin Ciubotariu 112322449858SCodrin Ciubotariu return 0; 112422449858SCodrin Ciubotariu } 112522449858SCodrin Ciubotariu 112622449858SCodrin Ciubotariu /* show the FDB entries that correspond to a port and a VLAN */ 112722449858SCodrin Ciubotariu static void vsc9953_mac_table_show(int port_no, int vid) 112822449858SCodrin Ciubotariu { 112922449858SCodrin Ciubotariu int rc[VSC9953_MAX_PORTS]; 113022449858SCodrin Ciubotariu enum port_learn_mode mode[VSC9953_MAX_PORTS]; 113122449858SCodrin Ciubotariu int i; 113222449858SCodrin Ciubotariu u32 val; 113322449858SCodrin Ciubotariu u32 vlan; 113422449858SCodrin Ciubotariu u32 mach; 113522449858SCodrin Ciubotariu u32 macl; 113622449858SCodrin Ciubotariu u32 dest_indx; 113722449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 113822449858SCodrin Ciubotariu 113922449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 114022449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 114122449858SCodrin Ciubotariu 114222449858SCodrin Ciubotariu /* disable auto learning */ 114322449858SCodrin Ciubotariu if (port_no == ETHSW_CMD_PORT_ALL) { 114422449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 114522449858SCodrin Ciubotariu rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); 114622449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 114722449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); 114822449858SCodrin Ciubotariu } 114922449858SCodrin Ciubotariu } else { 115022449858SCodrin Ciubotariu rc[port_no] = vsc9953_port_learn_mode_get(port_no, 115122449858SCodrin Ciubotariu &mode[port_no]); 115222449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 115322449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); 115422449858SCodrin Ciubotariu } 115522449858SCodrin Ciubotariu 115622449858SCodrin Ciubotariu /* write port and vid to get selected FDB entries */ 115722449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.anag_efil); 115822449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 115922449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, 116022449858SCodrin Ciubotariu port_no) | VSC9953_AGE_PORT_EN; 116122449858SCodrin Ciubotariu } 116222449858SCodrin Ciubotariu if (vid != ETHSW_CMD_VLAN_ALL) { 116322449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, 116422449858SCodrin Ciubotariu vid) | VSC9953_AGE_VID_EN; 116522449858SCodrin Ciubotariu } 116622449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana.anag_efil, val); 116722449858SCodrin Ciubotariu 116822449858SCodrin Ciubotariu /* set MAC and VLAN to 0 to look from beginning */ 116922449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana_tables.mach_data, 117022449858SCodrin Ciubotariu VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK); 117122449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 0); 117222449858SCodrin Ciubotariu 117322449858SCodrin Ciubotariu /* get entries */ 117422449858SCodrin Ciubotariu printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID"); 117522449858SCodrin Ciubotariu do { 117622449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) { 117722449858SCodrin Ciubotariu debug("GET NEXT MAC table command failed\n"); 117822449858SCodrin Ciubotariu break; 117922449858SCodrin Ciubotariu } 118022449858SCodrin Ciubotariu 118122449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 118222449858SCodrin Ciubotariu 118322449858SCodrin Ciubotariu /* get out when an invalid entry is found */ 118422449858SCodrin Ciubotariu if (!(val & VSC9953_MAC_CMD_VALID)) 118522449858SCodrin Ciubotariu break; 118622449858SCodrin Ciubotariu 118722449858SCodrin Ciubotariu switch (val & VSC9953_MAC_ENTRYTYPE_MASK) { 118822449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_NORMAL: 118922449858SCodrin Ciubotariu printf("%10s ", "Dynamic"); 119022449858SCodrin Ciubotariu break; 119122449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_LOCKED: 119222449858SCodrin Ciubotariu printf("%10s ", "Static"); 119322449858SCodrin Ciubotariu break; 119422449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_IPV4MCAST: 119522449858SCodrin Ciubotariu printf("%10s ", "IPv4 Mcast"); 119622449858SCodrin Ciubotariu break; 119722449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_IPV6MCAST: 119822449858SCodrin Ciubotariu printf("%10s ", "IPv6 Mcast"); 119922449858SCodrin Ciubotariu break; 120022449858SCodrin Ciubotariu default: 120122449858SCodrin Ciubotariu printf("%10s ", "Unknown"); 120222449858SCodrin Ciubotariu } 120322449858SCodrin Ciubotariu 120422449858SCodrin Ciubotariu dest_indx = bitfield_extract_by_mask(val, 120522449858SCodrin Ciubotariu VSC9953_MAC_DESTIDX_MASK); 120622449858SCodrin Ciubotariu 120722449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 120822449858SCodrin Ciubotariu vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK); 120922449858SCodrin Ciubotariu mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK); 121022449858SCodrin Ciubotariu macl = in_le32(&l2ana_reg->ana_tables.macl_data); 121122449858SCodrin Ciubotariu 121222449858SCodrin Ciubotariu printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff, 121322449858SCodrin Ciubotariu mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff, 121422449858SCodrin Ciubotariu (macl >> 8) & 0xff, macl & 0xff); 121522449858SCodrin Ciubotariu printf("%5d ", dest_indx); 121622449858SCodrin Ciubotariu printf("%4d\n", vlan); 121722449858SCodrin Ciubotariu } while (1); 121822449858SCodrin Ciubotariu 121922449858SCodrin Ciubotariu /* set learning mode to previous value */ 122022449858SCodrin Ciubotariu if (port_no == ETHSW_CMD_PORT_ALL) { 122122449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 122222449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 122322449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode[i]); 122422449858SCodrin Ciubotariu } 122522449858SCodrin Ciubotariu } else { 122622449858SCodrin Ciubotariu /* If administrative down, skip */ 122722449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 122822449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, mode[port_no]); 122922449858SCodrin Ciubotariu } 123022449858SCodrin Ciubotariu 123122449858SCodrin Ciubotariu /* reset FDB port and VLAN FDB selection */ 123222449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | 123322449858SCodrin Ciubotariu VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | 123422449858SCodrin Ciubotariu VSC9953_AGE_VID_MASK); 123522449858SCodrin Ciubotariu } 123622449858SCodrin Ciubotariu 123722449858SCodrin Ciubotariu /* Add a static FDB entry */ 123822449858SCodrin Ciubotariu static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid) 123922449858SCodrin Ciubotariu { 124022449858SCodrin Ciubotariu u32 val; 124122449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 124222449858SCodrin Ciubotariu 124322449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 124422449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 124522449858SCodrin Ciubotariu 124622449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 124722449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 124822449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 124922449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 125022449858SCodrin Ciubotariu 125122449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 125222449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 125322449858SCodrin Ciubotariu (mac[5] << 0)); 125422449858SCodrin Ciubotariu 125522449858SCodrin Ciubotariu /* set on which port is the MAC address added */ 125622449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 125722449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no); 125822449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mac_access, val); 125922449858SCodrin Ciubotariu 126022449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0) 126122449858SCodrin Ciubotariu return -1; 126222449858SCodrin Ciubotariu 126322449858SCodrin Ciubotariu /* check if the MAC address was indeed added */ 126422449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 126522449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 126622449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 126722449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 126822449858SCodrin Ciubotariu 126922449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 127022449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 127122449858SCodrin Ciubotariu (mac[5] << 0)); 127222449858SCodrin Ciubotariu 127322449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0) 127422449858SCodrin Ciubotariu return -1; 127522449858SCodrin Ciubotariu 127622449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 127722449858SCodrin Ciubotariu 127822449858SCodrin Ciubotariu if ((port_no != bitfield_extract_by_mask(val, 127922449858SCodrin Ciubotariu VSC9953_MAC_DESTIDX_MASK))) { 128022449858SCodrin Ciubotariu printf("Failed to add MAC address\n"); 128122449858SCodrin Ciubotariu return -1; 128222449858SCodrin Ciubotariu } 128322449858SCodrin Ciubotariu return 0; 128422449858SCodrin Ciubotariu } 128522449858SCodrin Ciubotariu 128622449858SCodrin Ciubotariu /* Delete a FDB entry */ 128722449858SCodrin Ciubotariu static int vsc9953_mac_table_del(uchar mac[6], u16 vid) 128822449858SCodrin Ciubotariu { 128922449858SCodrin Ciubotariu u32 val; 129022449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 129122449858SCodrin Ciubotariu 129222449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 129322449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 129422449858SCodrin Ciubotariu 129522449858SCodrin Ciubotariu /* check first if MAC entry is present */ 129622449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 129722449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 129822449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 129922449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 130022449858SCodrin Ciubotariu 130122449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 130222449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 130322449858SCodrin Ciubotariu (mac[5] << 0)); 130422449858SCodrin Ciubotariu 130522449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { 130622449858SCodrin Ciubotariu debug("Lookup in the MAC table failed\n"); 130722449858SCodrin Ciubotariu return -1; 130822449858SCodrin Ciubotariu } 130922449858SCodrin Ciubotariu 131022449858SCodrin Ciubotariu if (!(in_le32(&l2ana_reg->ana_tables.mac_access) & 131122449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID)) { 131222449858SCodrin Ciubotariu printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ", 131322449858SCodrin Ciubotariu mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 131422449858SCodrin Ciubotariu printf("VLAN: %d does not exist.\n", vid); 131522449858SCodrin Ciubotariu return -1; 131622449858SCodrin Ciubotariu } 131722449858SCodrin Ciubotariu 131822449858SCodrin Ciubotariu /* FDB entry found, proceed to delete */ 131922449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 132022449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 132122449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 132222449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 132322449858SCodrin Ciubotariu 132422449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | 132522449858SCodrin Ciubotariu (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); 132622449858SCodrin Ciubotariu 132722449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0) 132822449858SCodrin Ciubotariu return -1; 132922449858SCodrin Ciubotariu 133022449858SCodrin Ciubotariu /* check if the MAC entry is still in FDB */ 133122449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 133222449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 133322449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 133422449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 133522449858SCodrin Ciubotariu 133622449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | 133722449858SCodrin Ciubotariu (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); 133822449858SCodrin Ciubotariu 133922449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { 134022449858SCodrin Ciubotariu debug("Lookup in the MAC table failed\n"); 134122449858SCodrin Ciubotariu return -1; 134222449858SCodrin Ciubotariu } 134322449858SCodrin Ciubotariu if (in_le32(&l2ana_reg->ana_tables.mac_access) & 134422449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID) { 134522449858SCodrin Ciubotariu printf("Failed to delete MAC address\n"); 134622449858SCodrin Ciubotariu return -1; 134722449858SCodrin Ciubotariu } 134822449858SCodrin Ciubotariu 134922449858SCodrin Ciubotariu return 0; 135022449858SCodrin Ciubotariu } 135122449858SCodrin Ciubotariu 135222449858SCodrin Ciubotariu /* age the unlocked entries in FDB */ 135322449858SCodrin Ciubotariu static void vsc9953_mac_table_age(int port_no, int vid) 135422449858SCodrin Ciubotariu { 135522449858SCodrin Ciubotariu int rc[VSC9953_MAX_PORTS]; 135622449858SCodrin Ciubotariu enum port_learn_mode mode[VSC9953_MAX_PORTS]; 135722449858SCodrin Ciubotariu u32 val; 135822449858SCodrin Ciubotariu int i; 135922449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 136022449858SCodrin Ciubotariu 136122449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 136222449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 136322449858SCodrin Ciubotariu 136422449858SCodrin Ciubotariu /* set port and VID for selective aging */ 136522449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.anag_efil); 136622449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 136722449858SCodrin Ciubotariu /* disable auto learning */ 136822449858SCodrin Ciubotariu rc[port_no] = vsc9953_port_learn_mode_get(port_no, 136922449858SCodrin Ciubotariu &mode[port_no]); 137022449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 137122449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); 137222449858SCodrin Ciubotariu 137322449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, 137422449858SCodrin Ciubotariu port_no) | VSC9953_AGE_PORT_EN; 137522449858SCodrin Ciubotariu } else { 137622449858SCodrin Ciubotariu /* disable auto learning on all ports */ 137722449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 137822449858SCodrin Ciubotariu rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); 137922449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 138022449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); 138122449858SCodrin Ciubotariu } 138222449858SCodrin Ciubotariu } 138322449858SCodrin Ciubotariu 138422449858SCodrin Ciubotariu if (vid != ETHSW_CMD_VLAN_ALL) { 138522449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) | 138622449858SCodrin Ciubotariu VSC9953_AGE_VID_EN; 138722449858SCodrin Ciubotariu } 138822449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana.anag_efil, val); 138922449858SCodrin Ciubotariu 139022449858SCodrin Ciubotariu /* age the dynamic FDB entries */ 139122449858SCodrin Ciubotariu vsc9953_mac_table_cmd(MAC_TABLE_AGE); 139222449858SCodrin Ciubotariu 139322449858SCodrin Ciubotariu /* clear previously set port and VID */ 139422449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | 139522449858SCodrin Ciubotariu VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | 139622449858SCodrin Ciubotariu VSC9953_AGE_VID_MASK); 139722449858SCodrin Ciubotariu 139822449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 139922449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 140022449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, mode[port_no]); 140122449858SCodrin Ciubotariu } else { 140222449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 140322449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 140422449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode[i]); 140522449858SCodrin Ciubotariu } 140622449858SCodrin Ciubotariu } 140722449858SCodrin Ciubotariu } 140822449858SCodrin Ciubotariu 140922449858SCodrin Ciubotariu /* Delete all the dynamic FDB entries */ 141022449858SCodrin Ciubotariu static void vsc9953_mac_table_flush(int port, int vid) 141122449858SCodrin Ciubotariu { 141222449858SCodrin Ciubotariu vsc9953_mac_table_age(port, vid); 141322449858SCodrin Ciubotariu vsc9953_mac_table_age(port, vid); 141422449858SCodrin Ciubotariu } 141522449858SCodrin Ciubotariu 1416a2477924SCodrin Ciubotariu enum egress_vlan_tag { 1417a2477924SCodrin Ciubotariu EGR_TAG_CLASS = 0, 1418a2477924SCodrin Ciubotariu EGR_TAG_PVID, 1419a2477924SCodrin Ciubotariu }; 1420a2477924SCodrin Ciubotariu 1421a2477924SCodrin Ciubotariu /* Set egress tag mode for a VSC9953 port */ 1422a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_set(int port_no, 1423a2477924SCodrin Ciubotariu enum egress_vlan_tag mode) 1424a2477924SCodrin Ciubotariu { 1425a2477924SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 1426a2477924SCodrin Ciubotariu 1427a2477924SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 1428a2477924SCodrin Ciubotariu VSC9953_REW_OFFSET); 1429a2477924SCodrin Ciubotariu 1430a2477924SCodrin Ciubotariu switch (mode) { 1431a2477924SCodrin Ciubotariu case EGR_TAG_CLASS: 1432a2477924SCodrin Ciubotariu clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 1433a2477924SCodrin Ciubotariu VSC9953_TAG_VID_PVID); 1434a2477924SCodrin Ciubotariu break; 1435a2477924SCodrin Ciubotariu case EGR_TAG_PVID: 1436a2477924SCodrin Ciubotariu setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 1437a2477924SCodrin Ciubotariu VSC9953_TAG_VID_PVID); 1438a2477924SCodrin Ciubotariu break; 1439a2477924SCodrin Ciubotariu default: 1440a2477924SCodrin Ciubotariu printf("Unknown egress VLAN tag mode for port %d\n", port_no); 1441a2477924SCodrin Ciubotariu } 1442a2477924SCodrin Ciubotariu } 1443a2477924SCodrin Ciubotariu 1444a2477924SCodrin Ciubotariu /* Get egress tag mode for a VSC9953 port */ 1445a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_get(int port_no, 1446a2477924SCodrin Ciubotariu enum egress_vlan_tag *mode) 1447a2477924SCodrin Ciubotariu { 1448a2477924SCodrin Ciubotariu u32 val; 1449a2477924SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 1450a2477924SCodrin Ciubotariu 1451a2477924SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 1452a2477924SCodrin Ciubotariu VSC9953_REW_OFFSET); 1453a2477924SCodrin Ciubotariu 1454a2477924SCodrin Ciubotariu val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg); 1455a2477924SCodrin Ciubotariu if (val & VSC9953_TAG_VID_PVID) 1456a2477924SCodrin Ciubotariu *mode = EGR_TAG_PVID; 1457a2477924SCodrin Ciubotariu else 1458a2477924SCodrin Ciubotariu *mode = EGR_TAG_CLASS; 1459a2477924SCodrin Ciubotariu } 1460a2477924SCodrin Ciubotariu 146121d214fcSCodrin Ciubotariu /* VSC9953 VLAN learning modes */ 146221d214fcSCodrin Ciubotariu enum vlan_learning_mode { 146321d214fcSCodrin Ciubotariu SHARED_VLAN_LEARNING, 146421d214fcSCodrin Ciubotariu PRIVATE_VLAN_LEARNING, 146521d214fcSCodrin Ciubotariu }; 146621d214fcSCodrin Ciubotariu 146721d214fcSCodrin Ciubotariu /* Set VLAN learning mode for VSC9953 */ 146821d214fcSCodrin Ciubotariu static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode) 146921d214fcSCodrin Ciubotariu { 147021d214fcSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 147121d214fcSCodrin Ciubotariu 147221d214fcSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 147321d214fcSCodrin Ciubotariu VSC9953_ANA_OFFSET); 147421d214fcSCodrin Ciubotariu 147521d214fcSCodrin Ciubotariu switch (lrn_mode) { 147621d214fcSCodrin Ciubotariu case SHARED_VLAN_LEARNING: 147721d214fcSCodrin Ciubotariu setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL); 147821d214fcSCodrin Ciubotariu break; 147921d214fcSCodrin Ciubotariu case PRIVATE_VLAN_LEARNING: 148021d214fcSCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL); 148121d214fcSCodrin Ciubotariu break; 148221d214fcSCodrin Ciubotariu default: 148321d214fcSCodrin Ciubotariu printf("Unknown VLAN learn mode\n"); 148421d214fcSCodrin Ciubotariu } 148521d214fcSCodrin Ciubotariu } 148621d214fcSCodrin Ciubotariu 148721d214fcSCodrin Ciubotariu /* Get VLAN learning mode for VSC9953 */ 148821d214fcSCodrin Ciubotariu static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode) 148921d214fcSCodrin Ciubotariu { 149021d214fcSCodrin Ciubotariu u32 val; 149121d214fcSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 149221d214fcSCodrin Ciubotariu 149321d214fcSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 149421d214fcSCodrin Ciubotariu VSC9953_ANA_OFFSET); 149521d214fcSCodrin Ciubotariu 149621d214fcSCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.agen_ctrl); 149721d214fcSCodrin Ciubotariu 149821d214fcSCodrin Ciubotariu if (!(val & VSC9953_FID_MASK_ALL)) { 149921d214fcSCodrin Ciubotariu *lrn_mode = PRIVATE_VLAN_LEARNING; 150021d214fcSCodrin Ciubotariu } else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) { 150121d214fcSCodrin Ciubotariu *lrn_mode = SHARED_VLAN_LEARNING; 150221d214fcSCodrin Ciubotariu } else { 150321d214fcSCodrin Ciubotariu printf("Unknown VLAN learning mode\n"); 150421d214fcSCodrin Ciubotariu return -EINVAL; 150521d214fcSCodrin Ciubotariu } 150621d214fcSCodrin Ciubotariu 150721d214fcSCodrin Ciubotariu return 0; 150821d214fcSCodrin Ciubotariu } 150921d214fcSCodrin Ciubotariu 15105ed1bacdSCodrin Ciubotariu /* Enable/disable VLAN ingress filtering on a VSC9953 port */ 15115ed1bacdSCodrin Ciubotariu static void vsc9953_port_ingress_filtering_set(int port_no, int enabled) 15125ed1bacdSCodrin Ciubotariu { 15135ed1bacdSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 15145ed1bacdSCodrin Ciubotariu 15155ed1bacdSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 15165ed1bacdSCodrin Ciubotariu VSC9953_ANA_OFFSET); 15175ed1bacdSCodrin Ciubotariu 15185ed1bacdSCodrin Ciubotariu if (enabled) 15195ed1bacdSCodrin Ciubotariu setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no); 15205ed1bacdSCodrin Ciubotariu else 15215ed1bacdSCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no); 15225ed1bacdSCodrin Ciubotariu } 15235ed1bacdSCodrin Ciubotariu 15245ed1bacdSCodrin Ciubotariu /* Return VLAN ingress filtering on a VSC9953 port */ 15255ed1bacdSCodrin Ciubotariu static int vsc9953_port_ingress_filtering_get(int port_no) 15265ed1bacdSCodrin Ciubotariu { 15275ed1bacdSCodrin Ciubotariu u32 val; 15285ed1bacdSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 15295ed1bacdSCodrin Ciubotariu 15305ed1bacdSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 15315ed1bacdSCodrin Ciubotariu VSC9953_ANA_OFFSET); 15325ed1bacdSCodrin Ciubotariu 15335ed1bacdSCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.vlan_mask); 15345ed1bacdSCodrin Ciubotariu return !!(val & (1 << port_no)); 15355ed1bacdSCodrin Ciubotariu } 15365ed1bacdSCodrin Ciubotariu 1537*aae0e689SCodrin Ciubotariu /* Get the aggregation group of a port */ 1538*aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp) 1539*aae0e689SCodrin Ciubotariu { 1540*aae0e689SCodrin Ciubotariu u32 val; 1541*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1542*aae0e689SCodrin Ciubotariu 1543*aae0e689SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port_no)) 1544*aae0e689SCodrin Ciubotariu return -EINVAL; 1545*aae0e689SCodrin Ciubotariu 1546*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1547*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1548*aae0e689SCodrin Ciubotariu 1549*aae0e689SCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].port_cfg); 1550*aae0e689SCodrin Ciubotariu *aggr_grp = bitfield_extract_by_mask(val, 1551*aae0e689SCodrin Ciubotariu VSC9953_PORT_CFG_PORTID_MASK); 1552*aae0e689SCodrin Ciubotariu 1553*aae0e689SCodrin Ciubotariu return 0; 1554*aae0e689SCodrin Ciubotariu } 1555*aae0e689SCodrin Ciubotariu 1556*aae0e689SCodrin Ciubotariu static void vsc9953_aggr_grp_members_get(int aggr_grp, 1557*aae0e689SCodrin Ciubotariu u8 aggr_membr[VSC9953_MAX_PORTS]) 1558*aae0e689SCodrin Ciubotariu { 1559*aae0e689SCodrin Ciubotariu int port_no; 1560*aae0e689SCodrin Ciubotariu int aggr_membr_grp; 1561*aae0e689SCodrin Ciubotariu 1562*aae0e689SCodrin Ciubotariu for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) { 1563*aae0e689SCodrin Ciubotariu aggr_membr[port_no] = 0; 1564*aae0e689SCodrin Ciubotariu 1565*aae0e689SCodrin Ciubotariu if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp)) 1566*aae0e689SCodrin Ciubotariu continue; 1567*aae0e689SCodrin Ciubotariu 1568*aae0e689SCodrin Ciubotariu if (aggr_grp == aggr_membr_grp) 1569*aae0e689SCodrin Ciubotariu aggr_membr[port_no] = 1; 1570*aae0e689SCodrin Ciubotariu } 1571*aae0e689SCodrin Ciubotariu } 1572*aae0e689SCodrin Ciubotariu 1573*aae0e689SCodrin Ciubotariu static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old, 1574*aae0e689SCodrin Ciubotariu u32 membr_bitfld_new) 1575*aae0e689SCodrin Ciubotariu { 1576*aae0e689SCodrin Ciubotariu int i; 1577*aae0e689SCodrin Ciubotariu u32 pgid; 1578*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1579*aae0e689SCodrin Ciubotariu 1580*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1581*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1582*aae0e689SCodrin Ciubotariu 1583*aae0e689SCodrin Ciubotariu /* 1584*aae0e689SCodrin Ciubotariu * NOTE: Only the unicast destination masks are updated, since 1585*aae0e689SCodrin Ciubotariu * we do not support for now Layer-2 multicast entries 1586*aae0e689SCodrin Ciubotariu */ 1587*aae0e689SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 1588*aae0e689SCodrin Ciubotariu if (i == port_no) { 1589*aae0e689SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], 1590*aae0e689SCodrin Ciubotariu VSC9953_PGID_PORT_MASK, 1591*aae0e689SCodrin Ciubotariu membr_bitfld_new); 1592*aae0e689SCodrin Ciubotariu continue; 1593*aae0e689SCodrin Ciubotariu } 1594*aae0e689SCodrin Ciubotariu 1595*aae0e689SCodrin Ciubotariu pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]); 1596*aae0e689SCodrin Ciubotariu if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK) 1597*aae0e689SCodrin Ciubotariu pgid &= ~((u32)(1 << port_no)); 1598*aae0e689SCodrin Ciubotariu if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK) 1599*aae0e689SCodrin Ciubotariu pgid |= ((u32)(1 << port_no)); 1600*aae0e689SCodrin Ciubotariu 1601*aae0e689SCodrin Ciubotariu out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid); 1602*aae0e689SCodrin Ciubotariu } 1603*aae0e689SCodrin Ciubotariu } 1604*aae0e689SCodrin Ciubotariu 1605*aae0e689SCodrin Ciubotariu static void vsc9953_update_source_members_masks(int port_no, 1606*aae0e689SCodrin Ciubotariu u32 membr_bitfld_old, 1607*aae0e689SCodrin Ciubotariu u32 membr_bitfld_new) 1608*aae0e689SCodrin Ciubotariu { 1609*aae0e689SCodrin Ciubotariu int i; 1610*aae0e689SCodrin Ciubotariu int index; 1611*aae0e689SCodrin Ciubotariu u32 pgid; 1612*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1613*aae0e689SCodrin Ciubotariu 1614*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1615*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1616*aae0e689SCodrin Ciubotariu 1617*aae0e689SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) { 1618*aae0e689SCodrin Ciubotariu index = PGID_SRC_START + i; 1619*aae0e689SCodrin Ciubotariu pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]); 1620*aae0e689SCodrin Ciubotariu if (i == port_no) { 1621*aae0e689SCodrin Ciubotariu pgid = (pgid | VSC9953_PGID_PORT_MASK) & 1622*aae0e689SCodrin Ciubotariu ~membr_bitfld_new; 1623*aae0e689SCodrin Ciubotariu out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], 1624*aae0e689SCodrin Ciubotariu pgid); 1625*aae0e689SCodrin Ciubotariu continue; 1626*aae0e689SCodrin Ciubotariu } 1627*aae0e689SCodrin Ciubotariu 1628*aae0e689SCodrin Ciubotariu if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK) 1629*aae0e689SCodrin Ciubotariu pgid |= (u32)(1 << port_no); 1630*aae0e689SCodrin Ciubotariu 1631*aae0e689SCodrin Ciubotariu if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK) 1632*aae0e689SCodrin Ciubotariu pgid &= ~(u32)(1 << port_no); 1633*aae0e689SCodrin Ciubotariu out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid); 1634*aae0e689SCodrin Ciubotariu } 1635*aae0e689SCodrin Ciubotariu } 1636*aae0e689SCodrin Ciubotariu 1637*aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield) 1638*aae0e689SCodrin Ciubotariu { 1639*aae0e689SCodrin Ciubotariu if (!member_bitfield) 1640*aae0e689SCodrin Ciubotariu return 0; 1641*aae0e689SCodrin Ciubotariu 1642*aae0e689SCodrin Ciubotariu if (!(aggr_mask & VSC9953_PGID_PORT_MASK)) 1643*aae0e689SCodrin Ciubotariu aggr_mask = 1; 1644*aae0e689SCodrin Ciubotariu else 1645*aae0e689SCodrin Ciubotariu aggr_mask <<= 1; 1646*aae0e689SCodrin Ciubotariu 1647*aae0e689SCodrin Ciubotariu while (!(aggr_mask & member_bitfield)) { 1648*aae0e689SCodrin Ciubotariu aggr_mask <<= 1; 1649*aae0e689SCodrin Ciubotariu if (!(aggr_mask & VSC9953_PGID_PORT_MASK)) 1650*aae0e689SCodrin Ciubotariu aggr_mask = 1; 1651*aae0e689SCodrin Ciubotariu } 1652*aae0e689SCodrin Ciubotariu 1653*aae0e689SCodrin Ciubotariu return aggr_mask; 1654*aae0e689SCodrin Ciubotariu } 1655*aae0e689SCodrin Ciubotariu 1656*aae0e689SCodrin Ciubotariu static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old, 1657*aae0e689SCodrin Ciubotariu u32 membr_bitfld_new) 1658*aae0e689SCodrin Ciubotariu { 1659*aae0e689SCodrin Ciubotariu int i; 1660*aae0e689SCodrin Ciubotariu u32 pgid; 1661*aae0e689SCodrin Ciubotariu u32 aggr_mask_old = 0; 1662*aae0e689SCodrin Ciubotariu u32 aggr_mask_new = 0; 1663*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1664*aae0e689SCodrin Ciubotariu 1665*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1666*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1667*aae0e689SCodrin Ciubotariu 1668*aae0e689SCodrin Ciubotariu /* Update all the PGID aggregation masks */ 1669*aae0e689SCodrin Ciubotariu for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) { 1670*aae0e689SCodrin Ciubotariu pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]); 1671*aae0e689SCodrin Ciubotariu 1672*aae0e689SCodrin Ciubotariu aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old, 1673*aae0e689SCodrin Ciubotariu membr_bitfld_old); 1674*aae0e689SCodrin Ciubotariu pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old; 1675*aae0e689SCodrin Ciubotariu 1676*aae0e689SCodrin Ciubotariu aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new, 1677*aae0e689SCodrin Ciubotariu membr_bitfld_new); 1678*aae0e689SCodrin Ciubotariu pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new; 1679*aae0e689SCodrin Ciubotariu 1680*aae0e689SCodrin Ciubotariu out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid); 1681*aae0e689SCodrin Ciubotariu } 1682*aae0e689SCodrin Ciubotariu } 1683*aae0e689SCodrin Ciubotariu 1684*aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS]) 1685*aae0e689SCodrin Ciubotariu { 1686*aae0e689SCodrin Ciubotariu int i; 1687*aae0e689SCodrin Ciubotariu u32 member_bitfield = 0; 1688*aae0e689SCodrin Ciubotariu 1689*aae0e689SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 1690*aae0e689SCodrin Ciubotariu if (member[i]) 1691*aae0e689SCodrin Ciubotariu member_bitfield |= 1 << i; 1692*aae0e689SCodrin Ciubotariu } 1693*aae0e689SCodrin Ciubotariu member_bitfield &= VSC9953_PGID_PORT_MASK; 1694*aae0e689SCodrin Ciubotariu 1695*aae0e689SCodrin Ciubotariu return member_bitfield; 1696*aae0e689SCodrin Ciubotariu } 1697*aae0e689SCodrin Ciubotariu 1698*aae0e689SCodrin Ciubotariu static void vsc9953_update_members_masks(int port_no, 1699*aae0e689SCodrin Ciubotariu u8 member_old[VSC9953_MAX_PORTS], 1700*aae0e689SCodrin Ciubotariu u8 member_new[VSC9953_MAX_PORTS]) 1701*aae0e689SCodrin Ciubotariu { 1702*aae0e689SCodrin Ciubotariu u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old); 1703*aae0e689SCodrin Ciubotariu u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new); 1704*aae0e689SCodrin Ciubotariu 1705*aae0e689SCodrin Ciubotariu vsc9953_update_dest_members_masks(port_no, membr_bitfld_old, 1706*aae0e689SCodrin Ciubotariu membr_bitfld_new); 1707*aae0e689SCodrin Ciubotariu vsc9953_update_source_members_masks(port_no, membr_bitfld_old, 1708*aae0e689SCodrin Ciubotariu membr_bitfld_new); 1709*aae0e689SCodrin Ciubotariu vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old, 1710*aae0e689SCodrin Ciubotariu membr_bitfld_new); 1711*aae0e689SCodrin Ciubotariu } 1712*aae0e689SCodrin Ciubotariu 1713*aae0e689SCodrin Ciubotariu /* Set the aggregation group of a port */ 1714*aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp) 1715*aae0e689SCodrin Ciubotariu { 1716*aae0e689SCodrin Ciubotariu u8 aggr_membr_old[VSC9953_MAX_PORTS]; 1717*aae0e689SCodrin Ciubotariu u8 aggr_membr_new[VSC9953_MAX_PORTS]; 1718*aae0e689SCodrin Ciubotariu int rc; 1719*aae0e689SCodrin Ciubotariu int aggr_grp_old; 1720*aae0e689SCodrin Ciubotariu u32 val; 1721*aae0e689SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1722*aae0e689SCodrin Ciubotariu 1723*aae0e689SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp)) 1724*aae0e689SCodrin Ciubotariu return -EINVAL; 1725*aae0e689SCodrin Ciubotariu 1726*aae0e689SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1727*aae0e689SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1728*aae0e689SCodrin Ciubotariu 1729*aae0e689SCodrin Ciubotariu rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old); 1730*aae0e689SCodrin Ciubotariu if (rc) 1731*aae0e689SCodrin Ciubotariu return rc; 1732*aae0e689SCodrin Ciubotariu 1733*aae0e689SCodrin Ciubotariu /* get all the members of the old aggregation group */ 1734*aae0e689SCodrin Ciubotariu vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old); 1735*aae0e689SCodrin Ciubotariu 1736*aae0e689SCodrin Ciubotariu /* get all the members of the same aggregation group */ 1737*aae0e689SCodrin Ciubotariu vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new); 1738*aae0e689SCodrin Ciubotariu 1739*aae0e689SCodrin Ciubotariu /* add current port as member to the new aggregation group */ 1740*aae0e689SCodrin Ciubotariu aggr_membr_old[port_no] = 0; 1741*aae0e689SCodrin Ciubotariu aggr_membr_new[port_no] = 1; 1742*aae0e689SCodrin Ciubotariu 1743*aae0e689SCodrin Ciubotariu /* update masks */ 1744*aae0e689SCodrin Ciubotariu vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new); 1745*aae0e689SCodrin Ciubotariu 1746*aae0e689SCodrin Ciubotariu /* Change logical port number */ 1747*aae0e689SCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].port_cfg); 1748*aae0e689SCodrin Ciubotariu val = bitfield_replace_by_mask(val, 1749*aae0e689SCodrin Ciubotariu VSC9953_PORT_CFG_PORTID_MASK, aggr_grp); 1750*aae0e689SCodrin Ciubotariu out_le32(&l2ana_reg->port[port_no].port_cfg, val); 1751*aae0e689SCodrin Ciubotariu 1752*aae0e689SCodrin Ciubotariu return 0; 1753*aae0e689SCodrin Ciubotariu } 1754*aae0e689SCodrin Ciubotariu 175524a23debSCodrin Ciubotariu static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd) 175624a23debSCodrin Ciubotariu { 175724a23debSCodrin Ciubotariu int i; 175824a23debSCodrin Ciubotariu u8 enabled; 175924a23debSCodrin Ciubotariu 176024a23debSCodrin Ciubotariu /* Last keyword should tell us if we should enable/disable the port */ 176124a23debSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 176224a23debSCodrin Ciubotariu ethsw_id_enable) 176324a23debSCodrin Ciubotariu enabled = 1; 176424a23debSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 176524a23debSCodrin Ciubotariu ethsw_id_disable) 176624a23debSCodrin Ciubotariu enabled = 0; 176724a23debSCodrin Ciubotariu else 176824a23debSCodrin Ciubotariu return CMD_RET_USAGE; 176924a23debSCodrin Ciubotariu 177024a23debSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 177124a23debSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 177224a23debSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 177324a23debSCodrin Ciubotariu return CMD_RET_FAILURE; 177424a23debSCodrin Ciubotariu } 177524a23debSCodrin Ciubotariu vsc9953_port_status_set(parsed_cmd->port, enabled); 177624a23debSCodrin Ciubotariu } else { 177724a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 177824a23debSCodrin Ciubotariu vsc9953_port_status_set(i, enabled); 177924a23debSCodrin Ciubotariu } 178024a23debSCodrin Ciubotariu 178124a23debSCodrin Ciubotariu return CMD_RET_SUCCESS; 178224a23debSCodrin Ciubotariu } 178324a23debSCodrin Ciubotariu 178424a23debSCodrin Ciubotariu static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd) 178524a23debSCodrin Ciubotariu { 178624a23debSCodrin Ciubotariu int i; 178724a23debSCodrin Ciubotariu 178824a23debSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 178924a23debSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 179024a23debSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 179124a23debSCodrin Ciubotariu return CMD_RET_FAILURE; 179224a23debSCodrin Ciubotariu } 179324a23debSCodrin Ciubotariu vsc9953_phy_autoneg(parsed_cmd->port); 179424a23debSCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 179524a23debSCodrin Ciubotariu "Port", "Status", "Link", "Speed", 179624a23debSCodrin Ciubotariu "Duplex"); 179724a23debSCodrin Ciubotariu vsc9953_port_config_show(parsed_cmd->port); 179824a23debSCodrin Ciubotariu 179924a23debSCodrin Ciubotariu } else { 180024a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 180124a23debSCodrin Ciubotariu vsc9953_phy_autoneg(i); 180224a23debSCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 180324a23debSCodrin Ciubotariu "Port", "Status", "Link", "Speed", "Duplex"); 180424a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 180524a23debSCodrin Ciubotariu vsc9953_port_config_show(i); 180624a23debSCodrin Ciubotariu } 180724a23debSCodrin Ciubotariu 180824a23debSCodrin Ciubotariu return CMD_RET_SUCCESS; 180924a23debSCodrin Ciubotariu } 181024a23debSCodrin Ciubotariu 181186719f0cSCodrin Ciubotariu static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd) 181286719f0cSCodrin Ciubotariu { 181386719f0cSCodrin Ciubotariu int i; 181486719f0cSCodrin Ciubotariu 181586719f0cSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 181686719f0cSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 181786719f0cSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 181886719f0cSCodrin Ciubotariu return CMD_RET_FAILURE; 181986719f0cSCodrin Ciubotariu } 182086719f0cSCodrin Ciubotariu vsc9953_port_statistics_show(parsed_cmd->port); 182186719f0cSCodrin Ciubotariu } else { 182286719f0cSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 182386719f0cSCodrin Ciubotariu vsc9953_port_statistics_show(i); 182486719f0cSCodrin Ciubotariu } 182586719f0cSCodrin Ciubotariu 182686719f0cSCodrin Ciubotariu return CMD_RET_SUCCESS; 182786719f0cSCodrin Ciubotariu } 182886719f0cSCodrin Ciubotariu 182986719f0cSCodrin Ciubotariu static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def 183086719f0cSCodrin Ciubotariu *parsed_cmd) 183186719f0cSCodrin Ciubotariu { 183286719f0cSCodrin Ciubotariu int i; 183386719f0cSCodrin Ciubotariu 183486719f0cSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 183586719f0cSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 183686719f0cSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 183786719f0cSCodrin Ciubotariu return CMD_RET_FAILURE; 183886719f0cSCodrin Ciubotariu } 183986719f0cSCodrin Ciubotariu vsc9953_port_statistics_clear(parsed_cmd->port); 184086719f0cSCodrin Ciubotariu } else { 184186719f0cSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 184286719f0cSCodrin Ciubotariu vsc9953_port_statistics_clear(i); 184386719f0cSCodrin Ciubotariu } 184486719f0cSCodrin Ciubotariu 184586719f0cSCodrin Ciubotariu return CMD_RET_SUCCESS; 184686719f0cSCodrin Ciubotariu } 184786719f0cSCodrin Ciubotariu 184868c929daSCodrin Ciubotariu static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd) 184968c929daSCodrin Ciubotariu { 185068c929daSCodrin Ciubotariu int i; 185168c929daSCodrin Ciubotariu enum port_learn_mode mode; 185268c929daSCodrin Ciubotariu 185368c929daSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 185468c929daSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 185568c929daSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 185668c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 185768c929daSCodrin Ciubotariu } 185868c929daSCodrin Ciubotariu if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode)) 185968c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 186068c929daSCodrin Ciubotariu printf("%7s %11s\n", "Port", "Learn mode"); 186168c929daSCodrin Ciubotariu switch (mode) { 186268c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 186368c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "disable"); 186468c929daSCodrin Ciubotariu break; 186568c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 186668c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "auto"); 186768c929daSCodrin Ciubotariu break; 186868c929daSCodrin Ciubotariu default: 186968c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "-"); 187068c929daSCodrin Ciubotariu } 187168c929daSCodrin Ciubotariu } else { 187268c929daSCodrin Ciubotariu printf("%7s %11s\n", "Port", "Learn mode"); 187368c929daSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 187468c929daSCodrin Ciubotariu if (vsc9953_port_learn_mode_get(i, &mode)) 187568c929daSCodrin Ciubotariu continue; 187668c929daSCodrin Ciubotariu switch (mode) { 187768c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 187868c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "disable"); 187968c929daSCodrin Ciubotariu break; 188068c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 188168c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "auto"); 188268c929daSCodrin Ciubotariu break; 188368c929daSCodrin Ciubotariu default: 188468c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "-"); 188568c929daSCodrin Ciubotariu } 188668c929daSCodrin Ciubotariu } 188768c929daSCodrin Ciubotariu } 188868c929daSCodrin Ciubotariu 188968c929daSCodrin Ciubotariu return CMD_RET_SUCCESS; 189068c929daSCodrin Ciubotariu } 189168c929daSCodrin Ciubotariu 189268c929daSCodrin Ciubotariu static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd) 189368c929daSCodrin Ciubotariu { 189468c929daSCodrin Ciubotariu int i; 189568c929daSCodrin Ciubotariu enum port_learn_mode mode; 189668c929daSCodrin Ciubotariu 189768c929daSCodrin Ciubotariu /* Last keyword should tell us the learn mode */ 189868c929daSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 189968c929daSCodrin Ciubotariu ethsw_id_auto) 190068c929daSCodrin Ciubotariu mode = PORT_LEARN_AUTO; 190168c929daSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 190268c929daSCodrin Ciubotariu ethsw_id_disable) 190368c929daSCodrin Ciubotariu mode = PORT_LEARN_NONE; 190468c929daSCodrin Ciubotariu else 190568c929daSCodrin Ciubotariu return CMD_RET_USAGE; 190668c929daSCodrin Ciubotariu 190768c929daSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 190868c929daSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 190968c929daSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 191068c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 191168c929daSCodrin Ciubotariu } 191268c929daSCodrin Ciubotariu vsc9953_port_learn_mode_set(parsed_cmd->port, mode); 191368c929daSCodrin Ciubotariu } else { 191468c929daSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 191568c929daSCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode); 191668c929daSCodrin Ciubotariu } 191768c929daSCodrin Ciubotariu 191868c929daSCodrin Ciubotariu return CMD_RET_SUCCESS; 191968c929daSCodrin Ciubotariu } 192068c929daSCodrin Ciubotariu 192122449858SCodrin Ciubotariu static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd) 192222449858SCodrin Ciubotariu { 192322449858SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && 192422449858SCodrin Ciubotariu !VSC9953_PORT_CHECK(parsed_cmd->port)) { 192522449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 192622449858SCodrin Ciubotariu return CMD_RET_FAILURE; 192722449858SCodrin Ciubotariu } 192822449858SCodrin Ciubotariu 192922449858SCodrin Ciubotariu if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && 193022449858SCodrin Ciubotariu !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 193122449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 193222449858SCodrin Ciubotariu return CMD_RET_FAILURE; 193322449858SCodrin Ciubotariu } 193422449858SCodrin Ciubotariu 193522449858SCodrin Ciubotariu vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid); 193622449858SCodrin Ciubotariu 193722449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 193822449858SCodrin Ciubotariu } 193922449858SCodrin Ciubotariu 194022449858SCodrin Ciubotariu static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd) 194122449858SCodrin Ciubotariu { 194222449858SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && 194322449858SCodrin Ciubotariu !VSC9953_PORT_CHECK(parsed_cmd->port)) { 194422449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 194522449858SCodrin Ciubotariu return CMD_RET_FAILURE; 194622449858SCodrin Ciubotariu } 194722449858SCodrin Ciubotariu 194822449858SCodrin Ciubotariu if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && 194922449858SCodrin Ciubotariu !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 195022449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 195122449858SCodrin Ciubotariu return CMD_RET_FAILURE; 195222449858SCodrin Ciubotariu } 195322449858SCodrin Ciubotariu 195422449858SCodrin Ciubotariu vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid); 195522449858SCodrin Ciubotariu 195622449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 195722449858SCodrin Ciubotariu } 195822449858SCodrin Ciubotariu 195922449858SCodrin Ciubotariu static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd) 196022449858SCodrin Ciubotariu { 196122449858SCodrin Ciubotariu int vid; 196222449858SCodrin Ciubotariu 196322449858SCodrin Ciubotariu /* a port number must be present */ 196422449858SCodrin Ciubotariu if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) { 196522449858SCodrin Ciubotariu printf("Please specify a port\n"); 196622449858SCodrin Ciubotariu return CMD_RET_FAILURE; 196722449858SCodrin Ciubotariu } 196822449858SCodrin Ciubotariu 196922449858SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 197022449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 197122449858SCodrin Ciubotariu return CMD_RET_FAILURE; 197222449858SCodrin Ciubotariu } 197322449858SCodrin Ciubotariu 197422449858SCodrin Ciubotariu /* Use VLAN 1 if VID is not set */ 197522449858SCodrin Ciubotariu vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); 197622449858SCodrin Ciubotariu 197722449858SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(vid)) { 197822449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", vid); 197922449858SCodrin Ciubotariu return CMD_RET_FAILURE; 198022449858SCodrin Ciubotariu } 198122449858SCodrin Ciubotariu 198222449858SCodrin Ciubotariu if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid)) 198322449858SCodrin Ciubotariu return CMD_RET_FAILURE; 198422449858SCodrin Ciubotariu 198522449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 198622449858SCodrin Ciubotariu } 198722449858SCodrin Ciubotariu 198822449858SCodrin Ciubotariu static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd) 198922449858SCodrin Ciubotariu { 199022449858SCodrin Ciubotariu int vid; 199122449858SCodrin Ciubotariu 199222449858SCodrin Ciubotariu /* Use VLAN 1 if VID is not set */ 199322449858SCodrin Ciubotariu vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); 199422449858SCodrin Ciubotariu 199522449858SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(vid)) { 199622449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", vid); 199722449858SCodrin Ciubotariu return CMD_RET_FAILURE; 199822449858SCodrin Ciubotariu } 199922449858SCodrin Ciubotariu 200022449858SCodrin Ciubotariu if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid)) 200122449858SCodrin Ciubotariu return CMD_RET_FAILURE; 200222449858SCodrin Ciubotariu 200322449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 200422449858SCodrin Ciubotariu } 200522449858SCodrin Ciubotariu 2006a2477924SCodrin Ciubotariu static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd) 2007a2477924SCodrin Ciubotariu { 2008a2477924SCodrin Ciubotariu int i; 2009a2477924SCodrin Ciubotariu int pvid; 2010a2477924SCodrin Ciubotariu 2011a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2012a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2013a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2014a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2015a2477924SCodrin Ciubotariu } 2016a2477924SCodrin Ciubotariu 2017a2477924SCodrin Ciubotariu if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid)) 2018a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2019a2477924SCodrin Ciubotariu printf("%7s %7s\n", "Port", "PVID"); 2020a2477924SCodrin Ciubotariu printf("%7d %7d\n", parsed_cmd->port, pvid); 2021a2477924SCodrin Ciubotariu } else { 2022a2477924SCodrin Ciubotariu printf("%7s %7s\n", "Port", "PVID"); 2023a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 2024a2477924SCodrin Ciubotariu if (vsc9953_port_vlan_pvid_get(i, &pvid)) 2025a2477924SCodrin Ciubotariu continue; 2026a2477924SCodrin Ciubotariu printf("%7d %7d\n", i, pvid); 2027a2477924SCodrin Ciubotariu } 2028a2477924SCodrin Ciubotariu } 2029a2477924SCodrin Ciubotariu 2030a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2031a2477924SCodrin Ciubotariu } 2032a2477924SCodrin Ciubotariu 2033a2477924SCodrin Ciubotariu static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd) 2034a2477924SCodrin Ciubotariu { 2035a2477924SCodrin Ciubotariu /* PVID number should be set in parsed_cmd->vid */ 2036a2477924SCodrin Ciubotariu if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) { 2037a2477924SCodrin Ciubotariu printf("Please set a pvid value\n"); 2038a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2039a2477924SCodrin Ciubotariu } 2040a2477924SCodrin Ciubotariu 2041a2477924SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 2042a2477924SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 2043a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2044a2477924SCodrin Ciubotariu } 2045a2477924SCodrin Ciubotariu 2046a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2047a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2048a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2049a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2050a2477924SCodrin Ciubotariu } 2051a2477924SCodrin Ciubotariu vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid); 2052a2477924SCodrin Ciubotariu } else { 2053a2477924SCodrin Ciubotariu vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid); 2054a2477924SCodrin Ciubotariu } 2055a2477924SCodrin Ciubotariu 2056a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2057a2477924SCodrin Ciubotariu } 2058a2477924SCodrin Ciubotariu 2059a2477924SCodrin Ciubotariu static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd) 2060a2477924SCodrin Ciubotariu { 2061a2477924SCodrin Ciubotariu int i; 2062a2477924SCodrin Ciubotariu 2063a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2064a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2065a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2066a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2067a2477924SCodrin Ciubotariu } 2068a2477924SCodrin Ciubotariu vsc9953_vlan_membership_show(parsed_cmd->port); 2069a2477924SCodrin Ciubotariu } else { 2070a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2071a2477924SCodrin Ciubotariu vsc9953_vlan_membership_show(i); 2072a2477924SCodrin Ciubotariu } 2073a2477924SCodrin Ciubotariu 2074a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2075a2477924SCodrin Ciubotariu } 2076a2477924SCodrin Ciubotariu 2077a2477924SCodrin Ciubotariu static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd) 2078a2477924SCodrin Ciubotariu { 2079a2477924SCodrin Ciubotariu int i; 2080a2477924SCodrin Ciubotariu int add; 2081a2477924SCodrin Ciubotariu 2082a2477924SCodrin Ciubotariu /* VLAN should be set in parsed_cmd->vid */ 2083a2477924SCodrin Ciubotariu if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) { 2084a2477924SCodrin Ciubotariu printf("Please set a vlan value\n"); 2085a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2086a2477924SCodrin Ciubotariu } 2087a2477924SCodrin Ciubotariu 2088a2477924SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 2089a2477924SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 2090a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2091a2477924SCodrin Ciubotariu } 2092a2477924SCodrin Ciubotariu 2093a2477924SCodrin Ciubotariu /* keywords add/delete should be the last but one in array */ 2094a2477924SCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == 2095a2477924SCodrin Ciubotariu ethsw_id_add) 2096a2477924SCodrin Ciubotariu add = 1; 2097a2477924SCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == 2098a2477924SCodrin Ciubotariu ethsw_id_del) 2099a2477924SCodrin Ciubotariu add = 0; 2100a2477924SCodrin Ciubotariu else 2101a2477924SCodrin Ciubotariu return CMD_RET_USAGE; 2102a2477924SCodrin Ciubotariu 2103a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2104a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2105a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2106a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2107a2477924SCodrin Ciubotariu } 2108a2477924SCodrin Ciubotariu vsc9953_vlan_table_membership_set(parsed_cmd->vid, 2109a2477924SCodrin Ciubotariu parsed_cmd->port, add); 2110a2477924SCodrin Ciubotariu } else { 2111a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2112a2477924SCodrin Ciubotariu vsc9953_vlan_table_membership_set(parsed_cmd->vid, i, 2113a2477924SCodrin Ciubotariu add); 2114a2477924SCodrin Ciubotariu } 2115a2477924SCodrin Ciubotariu 2116a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2117a2477924SCodrin Ciubotariu } 2118a2477924SCodrin Ciubotariu static int vsc9953_port_untag_show_key_func( 2119a2477924SCodrin Ciubotariu struct ethsw_command_def *parsed_cmd) 2120a2477924SCodrin Ciubotariu { 2121a2477924SCodrin Ciubotariu int i; 2122a2477924SCodrin Ciubotariu 2123a2477924SCodrin Ciubotariu printf("%7s\t%17s\n", "Port", "Untag"); 2124a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2125a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2126a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2127a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2128a2477924SCodrin Ciubotariu } 2129a2477924SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_show(parsed_cmd->port); 2130a2477924SCodrin Ciubotariu } else { 2131a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2132a2477924SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_show(i); 2133a2477924SCodrin Ciubotariu } 2134a2477924SCodrin Ciubotariu 2135a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2136a2477924SCodrin Ciubotariu } 2137a2477924SCodrin Ciubotariu 2138a2477924SCodrin Ciubotariu static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd) 2139a2477924SCodrin Ciubotariu { 2140a2477924SCodrin Ciubotariu int i; 2141a2477924SCodrin Ciubotariu enum egress_untag_mode mode; 2142a2477924SCodrin Ciubotariu 2143a2477924SCodrin Ciubotariu /* keywords for the untagged mode are the last in the array */ 2144a2477924SCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 2145a2477924SCodrin Ciubotariu ethsw_id_all) 2146a2477924SCodrin Ciubotariu mode = EGRESS_UNTAG_ALL; 2147a2477924SCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 2148a2477924SCodrin Ciubotariu ethsw_id_none) 2149a2477924SCodrin Ciubotariu mode = EGRESS_UNTAG_NONE; 2150a2477924SCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 2151a2477924SCodrin Ciubotariu ethsw_id_pvid) 2152a2477924SCodrin Ciubotariu mode = EGRESS_UNTAG_PVID_AND_ZERO; 2153a2477924SCodrin Ciubotariu else 2154a2477924SCodrin Ciubotariu return CMD_RET_USAGE; 2155a2477924SCodrin Ciubotariu 2156a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2157a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2158a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2159a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2160a2477924SCodrin Ciubotariu } 2161a2477924SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode); 2162a2477924SCodrin Ciubotariu } else { 2163a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2164a2477924SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_set(i, mode); 2165a2477924SCodrin Ciubotariu } 2166a2477924SCodrin Ciubotariu 2167a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2168a2477924SCodrin Ciubotariu } 2169a2477924SCodrin Ciubotariu 2170a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_show_key_func( 2171a2477924SCodrin Ciubotariu struct ethsw_command_def *parsed_cmd) 2172a2477924SCodrin Ciubotariu { 2173a2477924SCodrin Ciubotariu int i; 2174a2477924SCodrin Ciubotariu enum egress_vlan_tag mode; 2175a2477924SCodrin Ciubotariu 2176a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2177a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2178a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2179a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2180a2477924SCodrin Ciubotariu } 2181a2477924SCodrin Ciubotariu vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode); 2182a2477924SCodrin Ciubotariu printf("%7s\t%12s\n", "Port", "Egress VID"); 2183a2477924SCodrin Ciubotariu printf("%7d\t", parsed_cmd->port); 2184a2477924SCodrin Ciubotariu switch (mode) { 2185a2477924SCodrin Ciubotariu case EGR_TAG_CLASS: 2186a2477924SCodrin Ciubotariu printf("%12s\n", "classified"); 2187a2477924SCodrin Ciubotariu break; 2188a2477924SCodrin Ciubotariu case EGR_TAG_PVID: 2189a2477924SCodrin Ciubotariu printf("%12s\n", "pvid"); 2190a2477924SCodrin Ciubotariu break; 2191a2477924SCodrin Ciubotariu default: 2192a2477924SCodrin Ciubotariu printf("%12s\n", "-"); 2193a2477924SCodrin Ciubotariu } 2194a2477924SCodrin Ciubotariu } else { 2195a2477924SCodrin Ciubotariu printf("%7s\t%12s\n", "Port", "Egress VID"); 2196a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 2197a2477924SCodrin Ciubotariu vsc9953_port_vlan_egress_tag_get(i, &mode); 2198a2477924SCodrin Ciubotariu switch (mode) { 2199a2477924SCodrin Ciubotariu case EGR_TAG_CLASS: 2200a2477924SCodrin Ciubotariu printf("%7d\t%12s\n", i, "classified"); 2201a2477924SCodrin Ciubotariu break; 2202a2477924SCodrin Ciubotariu case EGR_TAG_PVID: 2203a2477924SCodrin Ciubotariu printf("%7d\t%12s\n", i, "pvid"); 2204a2477924SCodrin Ciubotariu break; 2205a2477924SCodrin Ciubotariu default: 2206a2477924SCodrin Ciubotariu printf("%7d\t%12s\n", i, "-"); 2207a2477924SCodrin Ciubotariu } 2208a2477924SCodrin Ciubotariu } 2209a2477924SCodrin Ciubotariu } 2210a2477924SCodrin Ciubotariu 2211a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2212a2477924SCodrin Ciubotariu } 2213a2477924SCodrin Ciubotariu 2214a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_set_key_func( 2215a2477924SCodrin Ciubotariu struct ethsw_command_def *parsed_cmd) 2216a2477924SCodrin Ciubotariu { 2217a2477924SCodrin Ciubotariu int i; 2218a2477924SCodrin Ciubotariu enum egress_vlan_tag mode; 2219a2477924SCodrin Ciubotariu 2220a2477924SCodrin Ciubotariu /* keywords for the egress vlan tag mode are the last in the array */ 2221a2477924SCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 2222a2477924SCodrin Ciubotariu ethsw_id_pvid) 2223a2477924SCodrin Ciubotariu mode = EGR_TAG_PVID; 2224a2477924SCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 2225a2477924SCodrin Ciubotariu ethsw_id_classified) 2226a2477924SCodrin Ciubotariu mode = EGR_TAG_CLASS; 2227a2477924SCodrin Ciubotariu else 2228a2477924SCodrin Ciubotariu return CMD_RET_USAGE; 2229a2477924SCodrin Ciubotariu 2230a2477924SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2231a2477924SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2232a2477924SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2233a2477924SCodrin Ciubotariu return CMD_RET_FAILURE; 2234a2477924SCodrin Ciubotariu } 2235a2477924SCodrin Ciubotariu vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode); 2236a2477924SCodrin Ciubotariu } else { 2237a2477924SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2238a2477924SCodrin Ciubotariu vsc9953_port_vlan_egress_tag_set(i, mode); 2239a2477924SCodrin Ciubotariu } 2240a2477924SCodrin Ciubotariu 2241a2477924SCodrin Ciubotariu return CMD_RET_SUCCESS; 2242a2477924SCodrin Ciubotariu } 2243a2477924SCodrin Ciubotariu 224421d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_show_key_func( 224521d214fcSCodrin Ciubotariu struct ethsw_command_def *parsed_cmd) 224621d214fcSCodrin Ciubotariu { 224721d214fcSCodrin Ciubotariu int rc; 224821d214fcSCodrin Ciubotariu enum vlan_learning_mode mode; 224921d214fcSCodrin Ciubotariu 225021d214fcSCodrin Ciubotariu rc = vsc9953_vlan_learning_get(&mode); 225121d214fcSCodrin Ciubotariu if (rc) 225221d214fcSCodrin Ciubotariu return CMD_RET_FAILURE; 225321d214fcSCodrin Ciubotariu 225421d214fcSCodrin Ciubotariu switch (mode) { 225521d214fcSCodrin Ciubotariu case SHARED_VLAN_LEARNING: 225621d214fcSCodrin Ciubotariu printf("VLAN learning mode: shared\n"); 225721d214fcSCodrin Ciubotariu break; 225821d214fcSCodrin Ciubotariu case PRIVATE_VLAN_LEARNING: 225921d214fcSCodrin Ciubotariu printf("VLAN learning mode: private\n"); 226021d214fcSCodrin Ciubotariu break; 226121d214fcSCodrin Ciubotariu default: 226221d214fcSCodrin Ciubotariu printf("Unknown VLAN learning mode\n"); 226321d214fcSCodrin Ciubotariu rc = CMD_RET_FAILURE; 226421d214fcSCodrin Ciubotariu } 226521d214fcSCodrin Ciubotariu 226621d214fcSCodrin Ciubotariu return CMD_RET_SUCCESS; 226721d214fcSCodrin Ciubotariu } 226821d214fcSCodrin Ciubotariu 226921d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd) 227021d214fcSCodrin Ciubotariu { 227121d214fcSCodrin Ciubotariu enum vlan_learning_mode mode; 227221d214fcSCodrin Ciubotariu 227321d214fcSCodrin Ciubotariu /* keywords for shared/private are the last in the array */ 227421d214fcSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 227521d214fcSCodrin Ciubotariu ethsw_id_shared) 227621d214fcSCodrin Ciubotariu mode = SHARED_VLAN_LEARNING; 227721d214fcSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 227821d214fcSCodrin Ciubotariu ethsw_id_private) 227921d214fcSCodrin Ciubotariu mode = PRIVATE_VLAN_LEARNING; 228021d214fcSCodrin Ciubotariu else 228121d214fcSCodrin Ciubotariu return CMD_RET_USAGE; 228221d214fcSCodrin Ciubotariu 228321d214fcSCodrin Ciubotariu vsc9953_vlan_learning_set(mode); 228421d214fcSCodrin Ciubotariu 228521d214fcSCodrin Ciubotariu return CMD_RET_SUCCESS; 228621d214fcSCodrin Ciubotariu } 228721d214fcSCodrin Ciubotariu 22885ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd) 22895ed1bacdSCodrin Ciubotariu { 22905ed1bacdSCodrin Ciubotariu int i; 22915ed1bacdSCodrin Ciubotariu int enabled; 22925ed1bacdSCodrin Ciubotariu 22935ed1bacdSCodrin Ciubotariu printf("%7s\t%18s\n", "Port", "Ingress filtering"); 22945ed1bacdSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 22955ed1bacdSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 22965ed1bacdSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 22975ed1bacdSCodrin Ciubotariu return CMD_RET_FAILURE; 22985ed1bacdSCodrin Ciubotariu } 22995ed1bacdSCodrin Ciubotariu enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port); 23005ed1bacdSCodrin Ciubotariu printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" : 23015ed1bacdSCodrin Ciubotariu "disable"); 23025ed1bacdSCodrin Ciubotariu } else { 23035ed1bacdSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 23045ed1bacdSCodrin Ciubotariu enabled = vsc9953_port_ingress_filtering_get(i); 23055ed1bacdSCodrin Ciubotariu printf("%7d\t%18s\n", parsed_cmd->port, enabled ? 23065ed1bacdSCodrin Ciubotariu "enable" : 23075ed1bacdSCodrin Ciubotariu "disable"); 23085ed1bacdSCodrin Ciubotariu } 23095ed1bacdSCodrin Ciubotariu } 23105ed1bacdSCodrin Ciubotariu 23115ed1bacdSCodrin Ciubotariu return CMD_RET_SUCCESS; 23125ed1bacdSCodrin Ciubotariu } 23135ed1bacdSCodrin Ciubotariu 23145ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd) 23155ed1bacdSCodrin Ciubotariu { 23165ed1bacdSCodrin Ciubotariu int i; 23175ed1bacdSCodrin Ciubotariu int enable; 23185ed1bacdSCodrin Ciubotariu 23195ed1bacdSCodrin Ciubotariu /* keywords for enabling/disabling ingress filtering 23205ed1bacdSCodrin Ciubotariu * are the last in the array 23215ed1bacdSCodrin Ciubotariu */ 23225ed1bacdSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 23235ed1bacdSCodrin Ciubotariu ethsw_id_enable) 23245ed1bacdSCodrin Ciubotariu enable = 1; 23255ed1bacdSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 23265ed1bacdSCodrin Ciubotariu ethsw_id_disable) 23275ed1bacdSCodrin Ciubotariu enable = 0; 23285ed1bacdSCodrin Ciubotariu else 23295ed1bacdSCodrin Ciubotariu return CMD_RET_USAGE; 23305ed1bacdSCodrin Ciubotariu 23315ed1bacdSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 23325ed1bacdSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 23335ed1bacdSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 23345ed1bacdSCodrin Ciubotariu return CMD_RET_FAILURE; 23355ed1bacdSCodrin Ciubotariu } 23365ed1bacdSCodrin Ciubotariu vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable); 23375ed1bacdSCodrin Ciubotariu } else { 23385ed1bacdSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 23395ed1bacdSCodrin Ciubotariu vsc9953_port_ingress_filtering_set(i, enable); 23405ed1bacdSCodrin Ciubotariu } 23415ed1bacdSCodrin Ciubotariu 23425ed1bacdSCodrin Ciubotariu return CMD_RET_SUCCESS; 23435ed1bacdSCodrin Ciubotariu } 23445ed1bacdSCodrin Ciubotariu 2345*aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd) 2346*aae0e689SCodrin Ciubotariu { 2347*aae0e689SCodrin Ciubotariu int i; 2348*aae0e689SCodrin Ciubotariu int aggr_grp; 2349*aae0e689SCodrin Ciubotariu 2350*aae0e689SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2351*aae0e689SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2352*aae0e689SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2353*aae0e689SCodrin Ciubotariu return CMD_RET_FAILURE; 2354*aae0e689SCodrin Ciubotariu } 2355*aae0e689SCodrin Ciubotariu 2356*aae0e689SCodrin Ciubotariu if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp)) 2357*aae0e689SCodrin Ciubotariu return CMD_RET_FAILURE; 2358*aae0e689SCodrin Ciubotariu printf("%7s %10s\n", "Port", "Aggr grp"); 2359*aae0e689SCodrin Ciubotariu printf("%7d %10d\n", parsed_cmd->port, aggr_grp); 2360*aae0e689SCodrin Ciubotariu } else { 2361*aae0e689SCodrin Ciubotariu printf("%7s %10s\n", "Port", "Aggr grp"); 2362*aae0e689SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 2363*aae0e689SCodrin Ciubotariu if (vsc9953_port_aggr_grp_get(i, &aggr_grp)) 2364*aae0e689SCodrin Ciubotariu continue; 2365*aae0e689SCodrin Ciubotariu printf("%7d %10d\n", i, aggr_grp); 2366*aae0e689SCodrin Ciubotariu } 2367*aae0e689SCodrin Ciubotariu } 2368*aae0e689SCodrin Ciubotariu 2369*aae0e689SCodrin Ciubotariu return CMD_RET_SUCCESS; 2370*aae0e689SCodrin Ciubotariu } 2371*aae0e689SCodrin Ciubotariu 2372*aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd) 2373*aae0e689SCodrin Ciubotariu { 2374*aae0e689SCodrin Ciubotariu int i; 2375*aae0e689SCodrin Ciubotariu 2376*aae0e689SCodrin Ciubotariu /* Aggregation group number should be set in parsed_cmd->aggr_grp */ 2377*aae0e689SCodrin Ciubotariu if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) { 2378*aae0e689SCodrin Ciubotariu printf("Please set an aggregation group value\n"); 2379*aae0e689SCodrin Ciubotariu return CMD_RET_FAILURE; 2380*aae0e689SCodrin Ciubotariu } 2381*aae0e689SCodrin Ciubotariu 2382*aae0e689SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) { 2383*aae0e689SCodrin Ciubotariu printf("Invalid aggregation group number: %d\n", 2384*aae0e689SCodrin Ciubotariu parsed_cmd->aggr_grp); 2385*aae0e689SCodrin Ciubotariu return CMD_RET_FAILURE; 2386*aae0e689SCodrin Ciubotariu } 2387*aae0e689SCodrin Ciubotariu 2388*aae0e689SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 2389*aae0e689SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 2390*aae0e689SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 2391*aae0e689SCodrin Ciubotariu return CMD_RET_FAILURE; 2392*aae0e689SCodrin Ciubotariu } 2393*aae0e689SCodrin Ciubotariu if (vsc9953_port_aggr_grp_set(parsed_cmd->port, 2394*aae0e689SCodrin Ciubotariu parsed_cmd->aggr_grp)) { 2395*aae0e689SCodrin Ciubotariu printf("Port %d: failed to set aggr group %d\n", 2396*aae0e689SCodrin Ciubotariu parsed_cmd->port, parsed_cmd->aggr_grp); 2397*aae0e689SCodrin Ciubotariu } 2398*aae0e689SCodrin Ciubotariu } else { 2399*aae0e689SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 2400*aae0e689SCodrin Ciubotariu if (vsc9953_port_aggr_grp_set(i, 2401*aae0e689SCodrin Ciubotariu parsed_cmd->aggr_grp)) { 2402*aae0e689SCodrin Ciubotariu printf("Port %d: failed to set aggr group %d\n", 2403*aae0e689SCodrin Ciubotariu i, parsed_cmd->aggr_grp); 2404*aae0e689SCodrin Ciubotariu } 2405*aae0e689SCodrin Ciubotariu } 2406*aae0e689SCodrin Ciubotariu } 2407*aae0e689SCodrin Ciubotariu 2408*aae0e689SCodrin Ciubotariu return CMD_RET_SUCCESS; 2409*aae0e689SCodrin Ciubotariu } 2410*aae0e689SCodrin Ciubotariu 241124a23debSCodrin Ciubotariu static struct ethsw_command_func vsc9953_cmd_func = { 241224a23debSCodrin Ciubotariu .ethsw_name = "L2 Switch VSC9953", 241324a23debSCodrin Ciubotariu .port_enable = &vsc9953_port_status_key_func, 241424a23debSCodrin Ciubotariu .port_disable = &vsc9953_port_status_key_func, 241524a23debSCodrin Ciubotariu .port_show = &vsc9953_port_config_key_func, 241686719f0cSCodrin Ciubotariu .port_stats = &vsc9953_port_stats_key_func, 241786719f0cSCodrin Ciubotariu .port_stats_clear = &vsc9953_port_stats_clear_key_func, 241868c929daSCodrin Ciubotariu .port_learn = &vsc9953_learn_set_key_func, 241968c929daSCodrin Ciubotariu .port_learn_show = &vsc9953_learn_show_key_func, 242022449858SCodrin Ciubotariu .fdb_show = &vsc9953_fdb_show_key_func, 242122449858SCodrin Ciubotariu .fdb_flush = &vsc9953_fdb_flush_key_func, 242222449858SCodrin Ciubotariu .fdb_entry_add = &vsc9953_fdb_entry_add_key_func, 242322449858SCodrin Ciubotariu .fdb_entry_del = &vsc9953_fdb_entry_del_key_func, 2424a2477924SCodrin Ciubotariu .pvid_show = &vsc9953_pvid_show_key_func, 2425a2477924SCodrin Ciubotariu .pvid_set = &vsc9953_pvid_set_key_func, 2426a2477924SCodrin Ciubotariu .vlan_show = &vsc9953_vlan_show_key_func, 2427a2477924SCodrin Ciubotariu .vlan_set = &vsc9953_vlan_set_key_func, 2428a2477924SCodrin Ciubotariu .port_untag_show = &vsc9953_port_untag_show_key_func, 2429a2477924SCodrin Ciubotariu .port_untag_set = &vsc9953_port_untag_set_key_func, 2430a2477924SCodrin Ciubotariu .port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func, 2431a2477924SCodrin Ciubotariu .port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func, 243221d214fcSCodrin Ciubotariu .vlan_learn_show = &vsc9953_vlan_learn_show_key_func, 243321d214fcSCodrin Ciubotariu .vlan_learn_set = &vsc9953_vlan_learn_set_key_func, 24345ed1bacdSCodrin Ciubotariu .port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func, 2435*aae0e689SCodrin Ciubotariu .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func, 2436*aae0e689SCodrin Ciubotariu .port_aggr_show = &vsc9953_port_aggr_show_key_func, 2437*aae0e689SCodrin Ciubotariu .port_aggr_set = &vsc9953_port_aggr_set_key_func, 243824a23debSCodrin Ciubotariu }; 243924a23debSCodrin Ciubotariu 244024a23debSCodrin Ciubotariu #endif /* CONFIG_CMD_ETHSW */ 244124a23debSCodrin Ciubotariu 24429de05987SCodrin Ciubotariu /***************************************************************************** 24439de05987SCodrin Ciubotariu At startup, the default configuration would be: 24449de05987SCodrin Ciubotariu - HW learning enabled on all ports; (HW default) 24459de05987SCodrin Ciubotariu - All ports are in VLAN 1; 24469de05987SCodrin Ciubotariu - All ports are VLAN aware; 24479de05987SCodrin Ciubotariu - All ports have POP_COUNT 1; 24489de05987SCodrin Ciubotariu - All ports have PVID 1; 24499de05987SCodrin Ciubotariu - All ports have TPID 0x8100; (HW default) 24509de05987SCodrin Ciubotariu - All ports tag frames classified to all VLANs that are not PVID; 24519de05987SCodrin Ciubotariu *****************************************************************************/ 24529de05987SCodrin Ciubotariu void vsc9953_default_configuration(void) 24539de05987SCodrin Ciubotariu { 24549de05987SCodrin Ciubotariu int i; 24559de05987SCodrin Ciubotariu 2456ba389e65SCodrin Ciubotariu if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME)) 2457ba389e65SCodrin Ciubotariu debug("VSC9953: failed to set AGE time to %d\n", 2458ba389e65SCodrin Ciubotariu VSC9953_DEFAULT_AGE_TIME); 2459ba389e65SCodrin Ciubotariu 24609de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_VLAN; i++) 24619de05987SCodrin Ciubotariu vsc9953_vlan_table_membership_all_set(i, 0); 24629de05987SCodrin Ciubotariu vsc9953_port_all_vlan_aware_set(1); 24639de05987SCodrin Ciubotariu vsc9953_port_all_vlan_pvid_set(1); 24649de05987SCodrin Ciubotariu vsc9953_port_all_vlan_poncnt_set(1); 24659de05987SCodrin Ciubotariu vsc9953_vlan_table_membership_all_set(1, 1); 24669de05987SCodrin Ciubotariu vsc9953_vlan_ingr_fltr_learn_drop(1); 24679de05987SCodrin Ciubotariu vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO); 2468*aae0e689SCodrin Ciubotariu if (vsc9953_aggr_code_set(AGGR_CODE_ALL)) 2469*aae0e689SCodrin Ciubotariu debug("VSC9953: failed to set default aggregation code mode\n"); 24709de05987SCodrin Ciubotariu } 24719de05987SCodrin Ciubotariu 24726706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis) 24736706b115SCodrin Ciubotariu { 24743cc8cfffSCodrin Ciubotariu u32 i; 24753cc8cfffSCodrin Ciubotariu u32 hdx_cfg = 0; 24763cc8cfffSCodrin Ciubotariu u32 phy_addr = 0; 24776706b115SCodrin Ciubotariu int timeout; 24786706b115SCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 24796706b115SCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 24806706b115SCodrin Ciubotariu struct vsc9953_dev_gmii *l2dev_gmii_reg; 24816706b115SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 24826706b115SCodrin Ciubotariu struct vsc9953_devcpu_gcb *l2dev_gcb; 24836706b115SCodrin Ciubotariu 24846706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET + 24856706b115SCodrin Ciubotariu VSC9953_DEV_GMII_OFFSET); 24866706b115SCodrin Ciubotariu 24876706b115SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 24886706b115SCodrin Ciubotariu VSC9953_ANA_OFFSET); 24896706b115SCodrin Ciubotariu 24906706b115SCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 24916706b115SCodrin Ciubotariu VSC9953_SYS_OFFSET); 24926706b115SCodrin Ciubotariu 24936706b115SCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 24946706b115SCodrin Ciubotariu VSC9953_QSYS_OFFSET); 24956706b115SCodrin Ciubotariu 24966706b115SCodrin Ciubotariu l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET + 24976706b115SCodrin Ciubotariu VSC9953_DEVCPU_GCB); 24986706b115SCodrin Ciubotariu 24996706b115SCodrin Ciubotariu out_le32(&l2dev_gcb->chip_regs.soft_rst, 2500c4390486SCodrin Ciubotariu VSC9953_SOFT_SWC_RST_ENA); 25016706b115SCodrin Ciubotariu timeout = 50000; 25026706b115SCodrin Ciubotariu while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) & 2503c4390486SCodrin Ciubotariu VSC9953_SOFT_SWC_RST_ENA) && --timeout) 25046706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 soft reset */ 25056706b115SCodrin Ciubotariu if (timeout == 0) 25066706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 to reset\n"); 25076706b115SCodrin Ciubotariu 2508c4390486SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE | 2509c4390486SCodrin Ciubotariu VSC9953_MEM_INIT); 25106706b115SCodrin Ciubotariu 25116706b115SCodrin Ciubotariu timeout = 50000; 25126706b115SCodrin Ciubotariu while ((in_le32(&l2sys_reg->sys.reset_cfg) & 2513c4390486SCodrin Ciubotariu VSC9953_MEM_INIT) && --timeout) 25146706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 memory init */ 25156706b115SCodrin Ciubotariu if (timeout == 0) 25166706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 memory to initialize\n"); 25176706b115SCodrin Ciubotariu 25186706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg) 2519c4390486SCodrin Ciubotariu | VSC9953_CORE_ENABLE)); 25206706b115SCodrin Ciubotariu 25216706b115SCodrin Ciubotariu /* VSC9953 Setting to be done once only */ 25226706b115SCodrin Ciubotariu out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00); 25236706b115SCodrin Ciubotariu 25246706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 25256706b115SCodrin Ciubotariu if (vsc9953_port_init(i)) 25266706b115SCodrin Ciubotariu printf("Failed to initialize l2switch port %d\n", i); 25276706b115SCodrin Ciubotariu 25286706b115SCodrin Ciubotariu /* Enable VSC9953 GMII Ports Port ID 0 - 7 */ 25296706b115SCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(i)) { 25306706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 2531c4390486SCodrin Ciubotariu VSC9953_PFC_FC_QSGMII); 25326706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 2533c4390486SCodrin Ciubotariu VSC9953_MAC_FC_CFG_QSGMII); 25346706b115SCodrin Ciubotariu } else { 25356706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 2536c4390486SCodrin Ciubotariu VSC9953_PFC_FC); 25376706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 2538c4390486SCodrin Ciubotariu VSC9953_MAC_FC_CFG); 25396706b115SCodrin Ciubotariu } 25406706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->port_mode.clock_cfg, 2541c4390486SCodrin Ciubotariu VSC9953_CLOCK_CFG); 25426706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg, 2543c4390486SCodrin Ciubotariu VSC9953_MAC_ENA_CFG); 25446706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg, 2545c4390486SCodrin Ciubotariu VSC9953_MAC_MODE_CFG); 25466706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg, 2547c4390486SCodrin Ciubotariu VSC9953_MAC_IFG_CFG); 25486706b115SCodrin Ciubotariu /* mac_hdx_cfg varies with port id*/ 2549c4390486SCodrin Ciubotariu hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16); 25506706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg); 25516706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.front_port_mode[i], 2552c4390486SCodrin Ciubotariu VSC9953_FRONT_PORT_MODE); 2553fe91095bSCodrin Ciubotariu setbits_le32(&l2qsys_reg->sys.switch_port_mode[i], 2554c4390486SCodrin Ciubotariu VSC9953_PORT_ENA); 25556706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg, 2556c4390486SCodrin Ciubotariu VSC9953_MAC_MAX_LEN); 25576706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.pause_cfg[i], 2558c4390486SCodrin Ciubotariu VSC9953_PAUSE_CFG); 25596706b115SCodrin Ciubotariu /* WAIT FOR 2 us*/ 25606706b115SCodrin Ciubotariu udelay(2); 25616706b115SCodrin Ciubotariu 25626706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)( 25636706b115SCodrin Ciubotariu (char *)l2dev_gmii_reg 25646706b115SCodrin Ciubotariu + T1040_SWITCH_GMII_DEV_OFFSET); 25656706b115SCodrin Ciubotariu 25666706b115SCodrin Ciubotariu /* Initialize Lynx PHY Wrappers */ 25676706b115SCodrin Ciubotariu phy_addr = 0; 25686706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[i].enet_if == 25696706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_QSGMII) 25706706b115SCodrin Ciubotariu phy_addr = (i + 0x4) & 0x1F; 25716706b115SCodrin Ciubotariu else if (vsc9953_l2sw.port[i].enet_if == 25726706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_SGMII) 25736706b115SCodrin Ciubotariu phy_addr = (i + 1) & 0x1F; 25746706b115SCodrin Ciubotariu 25756706b115SCodrin Ciubotariu if (phy_addr) { 25766706b115SCodrin Ciubotariu /* SGMII IF mode + AN enable */ 25776706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 25786706b115SCodrin Ciubotariu 0x14, PHY_SGMII_IF_MODE_AN | 25796706b115SCodrin Ciubotariu PHY_SGMII_IF_MODE_SGMII); 25806706b115SCodrin Ciubotariu /* Dev ability according to SGMII specification */ 25816706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 25826706b115SCodrin Ciubotariu 0x4, PHY_SGMII_DEV_ABILITY_SGMII); 25836706b115SCodrin Ciubotariu /* Adjust link timer for SGMII 25846706b115SCodrin Ciubotariu * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 25856706b115SCodrin Ciubotariu */ 25866706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 25876706b115SCodrin Ciubotariu 0x13, 0x0003); 25886706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 25896706b115SCodrin Ciubotariu 0x12, 0x0d40); 25906706b115SCodrin Ciubotariu /* Restart AN */ 25916706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 25926706b115SCodrin Ciubotariu 0x0, PHY_SGMII_CR_DEF_VAL | 25936706b115SCodrin Ciubotariu PHY_SGMII_CR_RESET_AN); 25946706b115SCodrin Ciubotariu 25956706b115SCodrin Ciubotariu timeout = 50000; 25966706b115SCodrin Ciubotariu while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0], 25976706b115SCodrin Ciubotariu phy_addr, 0x01) & 0x0020) && --timeout) 25986706b115SCodrin Ciubotariu udelay(1); /* wait for AN to complete */ 25996706b115SCodrin Ciubotariu if (timeout == 0) 26006706b115SCodrin Ciubotariu debug("Timeout waiting for AN to complete\n"); 26016706b115SCodrin Ciubotariu } 26026706b115SCodrin Ciubotariu } 26036706b115SCodrin Ciubotariu 26049de05987SCodrin Ciubotariu vsc9953_default_configuration(); 26059de05987SCodrin Ciubotariu 260624a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW 260724a23debSCodrin Ciubotariu if (ethsw_define_functions(&vsc9953_cmd_func) < 0) 260824a23debSCodrin Ciubotariu debug("Unable to use \"ethsw\" commands\n"); 260924a23debSCodrin Ciubotariu #endif 261024a23debSCodrin Ciubotariu 26116706b115SCodrin Ciubotariu printf("VSC9953 L2 switch initialized\n"); 26126706b115SCodrin Ciubotariu return; 26136706b115SCodrin Ciubotariu } 2614