16706b115SCodrin Ciubotariu /* 26706b115SCodrin Ciubotariu * Copyright 2014 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 1999de05987SCodrin Ciubotariu /* vlan table set/clear all membership of vid */ 2009de05987SCodrin Ciubotariu static void vsc9953_vlan_table_membership_all_set(int vid, int set_member) 2019de05987SCodrin Ciubotariu { 2029de05987SCodrin Ciubotariu uint val; 2039de05987SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 2049de05987SCodrin Ciubotariu 2059de05987SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 2069de05987SCodrin Ciubotariu VSC9953_ANA_OFFSET); 2079de05987SCodrin Ciubotariu 2089de05987SCodrin Ciubotariu if (vsc9953_vlan_table_poll_idle() < 0) { 2099de05987SCodrin Ciubotariu debug("VLAN table timeout\n"); 2109de05987SCodrin Ciubotariu return; 2119de05987SCodrin Ciubotariu } 2129de05987SCodrin Ciubotariu 2139de05987SCodrin Ciubotariu /* read current vlan configuration */ 2149de05987SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); 2159de05987SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.vlan_tidx, 2169de05987SCodrin Ciubotariu bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid)); 2179de05987SCodrin Ciubotariu 2189de05987SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, 2199de05987SCodrin Ciubotariu VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ); 2209de05987SCodrin Ciubotariu 2219de05987SCodrin Ciubotariu if (vsc9953_vlan_table_poll_idle() < 0) { 2229de05987SCodrin Ciubotariu debug("VLAN table timeout\n"); 2239de05987SCodrin Ciubotariu return; 2249de05987SCodrin Ciubotariu } 2259de05987SCodrin Ciubotariu 2269de05987SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); 2279de05987SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.vlan_tidx, 2289de05987SCodrin Ciubotariu bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid)); 2299de05987SCodrin Ciubotariu 2309de05987SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, 2319de05987SCodrin Ciubotariu VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK, 2329de05987SCodrin Ciubotariu VSC9953_VLAN_CMD_WRITE | 2339de05987SCodrin Ciubotariu (set_member ? VSC9953_VLAN_PORT_MASK : 0)); 2349de05987SCodrin Ciubotariu } 2359de05987SCodrin Ciubotariu 2369de05987SCodrin Ciubotariu /* Set PVID for a VSC9953 port */ 2379de05987SCodrin Ciubotariu static void vsc9953_port_vlan_pvid_set(int port_no, int pvid) 2389de05987SCodrin Ciubotariu { 2399de05987SCodrin Ciubotariu uint val; 2409de05987SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 2419de05987SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 2429de05987SCodrin Ciubotariu 2439de05987SCodrin Ciubotariu /* Administrative down */ 2449de05987SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 2459de05987SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 2469de05987SCodrin Ciubotariu return; 2479de05987SCodrin Ciubotariu } 2489de05987SCodrin Ciubotariu 2499de05987SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 2509de05987SCodrin Ciubotariu VSC9953_ANA_OFFSET); 2519de05987SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 2529de05987SCodrin Ciubotariu VSC9953_REW_OFFSET); 2539de05987SCodrin Ciubotariu 2549de05987SCodrin Ciubotariu /* Set PVID on ingress */ 2559de05987SCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].vlan_cfg); 2569de05987SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid); 2579de05987SCodrin Ciubotariu out_le32(&l2ana_reg->port[port_no].vlan_cfg, val); 2589de05987SCodrin Ciubotariu 2599de05987SCodrin Ciubotariu /* Set PVID on egress */ 2609de05987SCodrin Ciubotariu val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg); 2619de05987SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK, 2629de05987SCodrin Ciubotariu pvid); 2639de05987SCodrin Ciubotariu out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val); 2649de05987SCodrin Ciubotariu } 2659de05987SCodrin Ciubotariu 2669de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_pvid_set(int pvid) 2679de05987SCodrin Ciubotariu { 2689de05987SCodrin Ciubotariu int i; 2699de05987SCodrin Ciubotariu 2709de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 2719de05987SCodrin Ciubotariu vsc9953_port_vlan_pvid_set(i, pvid); 2729de05987SCodrin Ciubotariu } 2739de05987SCodrin Ciubotariu 2749de05987SCodrin Ciubotariu /* Enable/disable vlan aware of a VSC9953 port */ 2759de05987SCodrin Ciubotariu static void vsc9953_port_vlan_aware_set(int port_no, int enabled) 2769de05987SCodrin Ciubotariu { 2779de05987SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 2789de05987SCodrin Ciubotariu 2799de05987SCodrin Ciubotariu /* Administrative down */ 2809de05987SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 2819de05987SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 2829de05987SCodrin Ciubotariu return; 2839de05987SCodrin Ciubotariu } 2849de05987SCodrin Ciubotariu 2859de05987SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 2869de05987SCodrin Ciubotariu VSC9953_ANA_OFFSET); 2879de05987SCodrin Ciubotariu 2889de05987SCodrin Ciubotariu if (enabled) 2899de05987SCodrin Ciubotariu setbits_le32(&l2ana_reg->port[port_no].vlan_cfg, 2909de05987SCodrin Ciubotariu VSC9953_VLAN_CFG_AWARE_ENA); 2919de05987SCodrin Ciubotariu else 2929de05987SCodrin Ciubotariu clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg, 2939de05987SCodrin Ciubotariu VSC9953_VLAN_CFG_AWARE_ENA); 2949de05987SCodrin Ciubotariu } 2959de05987SCodrin Ciubotariu 2969de05987SCodrin Ciubotariu /* Set all VSC9953 ports' vlan aware */ 2979de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_aware_set(int enabled) 2989de05987SCodrin Ciubotariu { 2999de05987SCodrin Ciubotariu int i; 3009de05987SCodrin Ciubotariu 3019de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 3029de05987SCodrin Ciubotariu vsc9953_port_vlan_aware_set(i, enabled); 3039de05987SCodrin Ciubotariu } 3049de05987SCodrin Ciubotariu 3059de05987SCodrin Ciubotariu /* Enable/disable vlan pop count of a VSC9953 port */ 3069de05987SCodrin Ciubotariu static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt) 3079de05987SCodrin Ciubotariu { 3089de05987SCodrin Ciubotariu uint val; 3099de05987SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 3109de05987SCodrin Ciubotariu 3119de05987SCodrin Ciubotariu /* Administrative down */ 3129de05987SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 3139de05987SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 3149de05987SCodrin Ciubotariu return; 3159de05987SCodrin Ciubotariu } 3169de05987SCodrin Ciubotariu 3179de05987SCodrin Ciubotariu if (popcnt > 3 || popcnt < 0) { 3189de05987SCodrin Ciubotariu printf("Invalid pop count value: %d\n", port_no); 3199de05987SCodrin Ciubotariu return; 3209de05987SCodrin Ciubotariu } 3219de05987SCodrin Ciubotariu 3229de05987SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 3239de05987SCodrin Ciubotariu VSC9953_ANA_OFFSET); 3249de05987SCodrin Ciubotariu 3259de05987SCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].vlan_cfg); 3269de05987SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK, 3279de05987SCodrin Ciubotariu popcnt); 3289de05987SCodrin Ciubotariu out_le32(&l2ana_reg->port[port_no].vlan_cfg, val); 3299de05987SCodrin Ciubotariu } 3309de05987SCodrin Ciubotariu 3319de05987SCodrin Ciubotariu /* Set all VSC9953 ports' pop count */ 3329de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_poncnt_set(int popcnt) 3339de05987SCodrin Ciubotariu { 3349de05987SCodrin Ciubotariu int i; 3359de05987SCodrin Ciubotariu 3369de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 3379de05987SCodrin Ciubotariu vsc9953_port_vlan_popcnt_set(i, popcnt); 3389de05987SCodrin Ciubotariu } 3399de05987SCodrin Ciubotariu 3409de05987SCodrin Ciubotariu /* Enable/disable learning for frames dropped due to ingress filtering */ 3419de05987SCodrin Ciubotariu static void vsc9953_vlan_ingr_fltr_learn_drop(int enable) 3429de05987SCodrin Ciubotariu { 3439de05987SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 3449de05987SCodrin Ciubotariu 3459de05987SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 3469de05987SCodrin Ciubotariu VSC9953_ANA_OFFSET); 3479de05987SCodrin Ciubotariu 3489de05987SCodrin Ciubotariu if (enable) 3499de05987SCodrin Ciubotariu setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK); 3509de05987SCodrin Ciubotariu else 3519de05987SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK); 3529de05987SCodrin Ciubotariu } 3539de05987SCodrin Ciubotariu 3549de05987SCodrin Ciubotariu /* Egress untag modes of a VSC9953 port */ 3559de05987SCodrin Ciubotariu enum egress_untag_mode { 3569de05987SCodrin Ciubotariu EGRESS_UNTAG_ALL = 0, 3579de05987SCodrin Ciubotariu EGRESS_UNTAG_PVID_AND_ZERO, 3589de05987SCodrin Ciubotariu EGRESS_UNTAG_ZERO, 3599de05987SCodrin Ciubotariu EGRESS_UNTAG_NONE, 3609de05987SCodrin Ciubotariu }; 3619de05987SCodrin Ciubotariu 3629de05987SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_set(int port_no, 3639de05987SCodrin Ciubotariu enum egress_untag_mode mode) 3649de05987SCodrin Ciubotariu { 3659de05987SCodrin Ciubotariu struct vsc9953_rew_reg *l2rew_reg; 3669de05987SCodrin Ciubotariu 3679de05987SCodrin Ciubotariu /* Administrative down */ 3689de05987SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 3699de05987SCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 3709de05987SCodrin Ciubotariu return; 3719de05987SCodrin Ciubotariu } 3729de05987SCodrin Ciubotariu 3739de05987SCodrin Ciubotariu l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + 3749de05987SCodrin Ciubotariu VSC9953_REW_OFFSET); 3759de05987SCodrin Ciubotariu 3769de05987SCodrin Ciubotariu switch (mode) { 3779de05987SCodrin Ciubotariu case EGRESS_UNTAG_ALL: 3789de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 3799de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE); 3809de05987SCodrin Ciubotariu break; 3819de05987SCodrin Ciubotariu case EGRESS_UNTAG_PVID_AND_ZERO: 3829de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 3839de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, 3849de05987SCodrin Ciubotariu VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO); 3859de05987SCodrin Ciubotariu break; 3869de05987SCodrin Ciubotariu case EGRESS_UNTAG_ZERO: 3879de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 3889de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, 3899de05987SCodrin Ciubotariu VSC9953_TAG_CFG_ALL_BUT_ZERO); 3909de05987SCodrin Ciubotariu break; 3919de05987SCodrin Ciubotariu case EGRESS_UNTAG_NONE: 3929de05987SCodrin Ciubotariu clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, 3939de05987SCodrin Ciubotariu VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL); 3949de05987SCodrin Ciubotariu break; 3959de05987SCodrin Ciubotariu default: 3969de05987SCodrin Ciubotariu printf("Unknown untag mode for port %d\n", port_no); 3979de05987SCodrin Ciubotariu } 3989de05987SCodrin Ciubotariu } 3999de05987SCodrin Ciubotariu 4009de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_egress_untagged_set( 4019de05987SCodrin Ciubotariu enum egress_untag_mode mode) 4029de05987SCodrin Ciubotariu { 4039de05987SCodrin Ciubotariu int i; 4049de05987SCodrin Ciubotariu 4059de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 4069de05987SCodrin Ciubotariu vsc9953_port_vlan_egr_untag_set(i, mode); 4079de05987SCodrin Ciubotariu } 4089de05987SCodrin Ciubotariu 40924a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW 41024a23debSCodrin Ciubotariu 41124a23debSCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */ 41224a23debSCodrin Ciubotariu static void vsc9953_port_status_set(int port_no, u8 enabled) 41324a23debSCodrin Ciubotariu { 41424a23debSCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 41524a23debSCodrin Ciubotariu 41624a23debSCodrin Ciubotariu /* Administrative down */ 41724a23debSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) 41824a23debSCodrin Ciubotariu return; 41924a23debSCodrin Ciubotariu 42024a23debSCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 42124a23debSCodrin Ciubotariu VSC9953_QSYS_OFFSET); 42224a23debSCodrin Ciubotariu 42324a23debSCodrin Ciubotariu if (enabled) 42424a23debSCodrin Ciubotariu setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], 42524a23debSCodrin Ciubotariu VSC9953_PORT_ENA); 42624a23debSCodrin Ciubotariu else 42724a23debSCodrin Ciubotariu clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], 42824a23debSCodrin Ciubotariu VSC9953_PORT_ENA); 42924a23debSCodrin Ciubotariu } 43024a23debSCodrin Ciubotariu 43124a23debSCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */ 43224a23debSCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_no) 43324a23debSCodrin Ciubotariu { 43424a23debSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].phydev) 43524a23debSCodrin Ciubotariu return; 43624a23debSCodrin Ciubotariu 43724a23debSCodrin Ciubotariu if (vsc9953_l2sw.port[port_no].phydev->drv->startup( 43824a23debSCodrin Ciubotariu vsc9953_l2sw.port[port_no].phydev)) 43924a23debSCodrin Ciubotariu printf("Failed to start PHY for port %d\n", port_no); 44024a23debSCodrin Ciubotariu } 44124a23debSCodrin Ciubotariu 44224a23debSCodrin Ciubotariu /* Print a VSC9953 port's configuration */ 44324a23debSCodrin Ciubotariu static void vsc9953_port_config_show(int port_no) 44424a23debSCodrin Ciubotariu { 44524a23debSCodrin Ciubotariu int speed; 44624a23debSCodrin Ciubotariu int duplex; 44724a23debSCodrin Ciubotariu int link; 44824a23debSCodrin Ciubotariu u8 enabled; 44924a23debSCodrin Ciubotariu u32 val; 45024a23debSCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 45124a23debSCodrin Ciubotariu 45224a23debSCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 45324a23debSCodrin Ciubotariu VSC9953_QSYS_OFFSET); 45424a23debSCodrin Ciubotariu 45524a23debSCodrin Ciubotariu val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]); 45624a23debSCodrin Ciubotariu enabled = vsc9953_l2sw.port[port_no].enabled && 45724a23debSCodrin Ciubotariu (val & VSC9953_PORT_ENA); 45824a23debSCodrin Ciubotariu 45924a23debSCodrin Ciubotariu /* internal ports (8 and 9) are fixed */ 46024a23debSCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(port_no)) { 46124a23debSCodrin Ciubotariu link = 1; 46224a23debSCodrin Ciubotariu speed = SPEED_2500; 46324a23debSCodrin Ciubotariu duplex = DUPLEX_FULL; 46424a23debSCodrin Ciubotariu } else { 46524a23debSCodrin Ciubotariu if (vsc9953_l2sw.port[port_no].phydev) { 46624a23debSCodrin Ciubotariu link = vsc9953_l2sw.port[port_no].phydev->link; 46724a23debSCodrin Ciubotariu speed = vsc9953_l2sw.port[port_no].phydev->speed; 46824a23debSCodrin Ciubotariu duplex = vsc9953_l2sw.port[port_no].phydev->duplex; 46924a23debSCodrin Ciubotariu } else { 47024a23debSCodrin Ciubotariu link = -1; 47124a23debSCodrin Ciubotariu speed = -1; 47224a23debSCodrin Ciubotariu duplex = -1; 47324a23debSCodrin Ciubotariu } 47424a23debSCodrin Ciubotariu } 47524a23debSCodrin Ciubotariu 47624a23debSCodrin Ciubotariu printf("%8d ", port_no); 47724a23debSCodrin Ciubotariu printf("%8s ", enabled == 1 ? "enabled" : "disabled"); 47824a23debSCodrin Ciubotariu printf("%8s ", link == 1 ? "up" : "down"); 47924a23debSCodrin Ciubotariu 48024a23debSCodrin Ciubotariu switch (speed) { 48124a23debSCodrin Ciubotariu case SPEED_10: 48224a23debSCodrin Ciubotariu printf("%8d ", 10); 48324a23debSCodrin Ciubotariu break; 48424a23debSCodrin Ciubotariu case SPEED_100: 48524a23debSCodrin Ciubotariu printf("%8d ", 100); 48624a23debSCodrin Ciubotariu break; 48724a23debSCodrin Ciubotariu case SPEED_1000: 48824a23debSCodrin Ciubotariu printf("%8d ", 1000); 48924a23debSCodrin Ciubotariu break; 49024a23debSCodrin Ciubotariu case SPEED_2500: 49124a23debSCodrin Ciubotariu printf("%8d ", 2500); 49224a23debSCodrin Ciubotariu break; 49324a23debSCodrin Ciubotariu case SPEED_10000: 49424a23debSCodrin Ciubotariu printf("%8d ", 10000); 49524a23debSCodrin Ciubotariu break; 49624a23debSCodrin Ciubotariu default: 49724a23debSCodrin Ciubotariu printf("%8s ", "-"); 49824a23debSCodrin Ciubotariu } 49924a23debSCodrin Ciubotariu 50024a23debSCodrin Ciubotariu printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half"); 50124a23debSCodrin Ciubotariu } 50224a23debSCodrin Ciubotariu 50386719f0cSCodrin Ciubotariu /* Show VSC9953 ports' statistics */ 50486719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_show(int port_no) 50586719f0cSCodrin Ciubotariu { 50686719f0cSCodrin Ciubotariu u32 rx_val; 50786719f0cSCodrin Ciubotariu u32 tx_val; 50886719f0cSCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 50986719f0cSCodrin Ciubotariu 51086719f0cSCodrin Ciubotariu /* Administrative down */ 51186719f0cSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 51286719f0cSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 51386719f0cSCodrin Ciubotariu return; 51486719f0cSCodrin Ciubotariu } 51586719f0cSCodrin Ciubotariu 51686719f0cSCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 51786719f0cSCodrin Ciubotariu VSC9953_SYS_OFFSET); 51886719f0cSCodrin Ciubotariu 51986719f0cSCodrin Ciubotariu printf("Statistics for L2 Switch port %d:\n", port_no); 52086719f0cSCodrin Ciubotariu 52186719f0cSCodrin Ciubotariu /* Set counter view for our port */ 52286719f0cSCodrin Ciubotariu out_le32(&l2sys_reg->sys.stat_cfg, port_no); 52386719f0cSCodrin Ciubotariu 52486719f0cSCodrin Ciubotariu #define VSC9953_STATS_PRINTF "%-15s %10u" 52586719f0cSCodrin Ciubotariu 52686719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames */ 52786719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) + 52886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) + 52986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) + 53086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) + 53186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) + 53286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) + 53386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) + 53486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) + 53586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) + 53686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) + 53786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); 53886719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + 53986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + 54086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + 54186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + 54286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + 54386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + 54486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 54586719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 54686719f0cSCodrin Ciubotariu "Rx frames:", rx_val, "Tx frames:", tx_val); 54786719f0cSCodrin Ciubotariu 54886719f0cSCodrin Ciubotariu /* Get number of Rx and Tx bytes */ 54986719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct); 55086719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct); 55186719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 55286719f0cSCodrin Ciubotariu "Rx bytes:", rx_val, "Tx bytes:", tx_val); 55386719f0cSCodrin Ciubotariu 55486719f0cSCodrin Ciubotariu /* Get number of Rx frames received ok and Tx frames sent ok */ 55586719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) + 55686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) + 55786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) + 55886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) + 55986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) + 56086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) + 56186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) + 56286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) + 56386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) + 56486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) + 56586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) + 56686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) + 56786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) + 56886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) + 56986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) + 57086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7); 57186719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + 57286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + 57386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + 57486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + 57586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + 57686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + 57786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 57886719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 57986719f0cSCodrin Ciubotariu "Rx frames ok:", rx_val, "Tx frames ok:", tx_val); 58086719f0cSCodrin Ciubotariu 58186719f0cSCodrin Ciubotariu /* Get number of Rx and Tx unicast frames */ 58286719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc); 58386719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc); 58486719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 58586719f0cSCodrin Ciubotariu "Rx unicast:", rx_val, "Tx unicast:", tx_val); 58686719f0cSCodrin Ciubotariu 58786719f0cSCodrin Ciubotariu /* Get number of Rx and Tx broadcast frames */ 58886719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc); 58986719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc); 59086719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 59186719f0cSCodrin Ciubotariu "Rx broadcast:", rx_val, "Tx broadcast:", tx_val); 59286719f0cSCodrin Ciubotariu 59386719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames of 64B */ 59486719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64); 59586719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64); 59686719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 59786719f0cSCodrin Ciubotariu "Rx 64B:", rx_val, "Tx 64B:", tx_val); 59886719f0cSCodrin Ciubotariu 59986719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 65B and 127B */ 60086719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127); 60186719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127); 60286719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 60386719f0cSCodrin Ciubotariu "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val); 60486719f0cSCodrin Ciubotariu 60586719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 128B and 255B */ 60686719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255); 60786719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255); 60886719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 60986719f0cSCodrin Ciubotariu "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val); 61086719f0cSCodrin Ciubotariu 61186719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 256B and 511B */ 61286719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511); 61386719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511); 61486719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 61586719f0cSCodrin Ciubotariu "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val); 61686719f0cSCodrin Ciubotariu 61786719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 512B and 1023B */ 61886719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023); 61986719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023); 62086719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 62186719f0cSCodrin Ciubotariu "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val); 62286719f0cSCodrin Ciubotariu 62386719f0cSCodrin Ciubotariu /* Get number of Rx and Tx frames with sizes between 1024B and 1526B */ 62486719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526); 62586719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526); 62686719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 62786719f0cSCodrin Ciubotariu "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val); 62886719f0cSCodrin Ciubotariu 62986719f0cSCodrin Ciubotariu /* Get number of Rx and Tx jumbo frames */ 63086719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); 63186719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); 63286719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 63386719f0cSCodrin Ciubotariu "Rx jumbo:", rx_val, "Tx jumbo:", tx_val); 63486719f0cSCodrin Ciubotariu 63586719f0cSCodrin Ciubotariu /* Get number of Rx and Tx dropped frames */ 63686719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + 63786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) + 63886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) + 63986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) + 64086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) + 64186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) + 64286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) + 64386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) + 64486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) + 64586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) + 64686719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) + 64786719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) + 64886719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) + 64986719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) + 65086719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) + 65186719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) + 65286719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) + 65386719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7); 65486719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) + 65586719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); 65686719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 65786719f0cSCodrin Ciubotariu "Rx drops:", rx_val, "Tx drops:", tx_val); 65886719f0cSCodrin Ciubotariu 65986719f0cSCodrin Ciubotariu /* 66086719f0cSCodrin Ciubotariu * Get number of Rx frames with CRC or alignment errors 66186719f0cSCodrin Ciubotariu * and number of detected Tx collisions 66286719f0cSCodrin Ciubotariu */ 66386719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc); 66486719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col); 66586719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 66686719f0cSCodrin Ciubotariu "Rx CRC&align:", rx_val, "Tx coll:", tx_val); 66786719f0cSCodrin Ciubotariu 66886719f0cSCodrin Ciubotariu /* 66986719f0cSCodrin Ciubotariu * Get number of Rx undersized frames and 67086719f0cSCodrin Ciubotariu * number of Tx aged frames 67186719f0cSCodrin Ciubotariu */ 67286719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short); 67386719f0cSCodrin Ciubotariu tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); 67486719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", 67586719f0cSCodrin Ciubotariu "Rx undersize:", rx_val, "Tx aged:", tx_val); 67686719f0cSCodrin Ciubotariu 67786719f0cSCodrin Ciubotariu /* Get number of Rx oversized frames */ 67886719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long); 67986719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val); 68086719f0cSCodrin Ciubotariu 68186719f0cSCodrin Ciubotariu /* Get number of Rx fragmented frames */ 68286719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag); 68386719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val); 68486719f0cSCodrin Ciubotariu 68586719f0cSCodrin Ciubotariu /* Get number of Rx jabber errors */ 68686719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber); 68786719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val); 68886719f0cSCodrin Ciubotariu 68986719f0cSCodrin Ciubotariu /* 69086719f0cSCodrin Ciubotariu * Get number of Rx frames filtered due to classification rules or 69186719f0cSCodrin Ciubotariu * no destination ports 69286719f0cSCodrin Ciubotariu */ 69386719f0cSCodrin Ciubotariu rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + 69486719f0cSCodrin Ciubotariu in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local); 69586719f0cSCodrin Ciubotariu printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val); 69686719f0cSCodrin Ciubotariu 69786719f0cSCodrin Ciubotariu printf("\n"); 69886719f0cSCodrin Ciubotariu } 69986719f0cSCodrin Ciubotariu 70086719f0cSCodrin Ciubotariu /* Clear statistics for a VSC9953 port */ 70186719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_clear(int port_no) 70286719f0cSCodrin Ciubotariu { 70386719f0cSCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 70486719f0cSCodrin Ciubotariu 70586719f0cSCodrin Ciubotariu /* Administrative down */ 70686719f0cSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 70786719f0cSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 70886719f0cSCodrin Ciubotariu return; 70986719f0cSCodrin Ciubotariu } 71086719f0cSCodrin Ciubotariu 71186719f0cSCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 71286719f0cSCodrin Ciubotariu VSC9953_SYS_OFFSET); 71386719f0cSCodrin Ciubotariu 71486719f0cSCodrin Ciubotariu /* Clear all counter groups for our ports */ 71586719f0cSCodrin Ciubotariu out_le32(&l2sys_reg->sys.stat_cfg, port_no | 71686719f0cSCodrin Ciubotariu VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX | 71786719f0cSCodrin Ciubotariu VSC9953_STAT_CLEAR_DR); 71886719f0cSCodrin Ciubotariu } 71986719f0cSCodrin Ciubotariu 72068c929daSCodrin Ciubotariu enum port_learn_mode { 72168c929daSCodrin Ciubotariu PORT_LEARN_NONE, 72268c929daSCodrin Ciubotariu PORT_LEARN_AUTO 72368c929daSCodrin Ciubotariu }; 72468c929daSCodrin Ciubotariu 72568c929daSCodrin Ciubotariu /* Set learning configuration for a VSC9953 port */ 72668c929daSCodrin Ciubotariu static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode) 72768c929daSCodrin Ciubotariu { 72868c929daSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 72968c929daSCodrin Ciubotariu 73068c929daSCodrin Ciubotariu /* Administrative down */ 73168c929daSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 73268c929daSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 73368c929daSCodrin Ciubotariu return; 73468c929daSCodrin Ciubotariu } 73568c929daSCodrin Ciubotariu 73668c929daSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 73768c929daSCodrin Ciubotariu VSC9953_ANA_OFFSET); 73868c929daSCodrin Ciubotariu 73968c929daSCodrin Ciubotariu switch (mode) { 74068c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 74168c929daSCodrin Ciubotariu clrbits_le32(&l2ana_reg->port[port_no].port_cfg, 74268c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_DROP | 74368c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_CPU | 74468c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO | 74568c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_ENA); 74668c929daSCodrin Ciubotariu break; 74768c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 74868c929daSCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg, 74968c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_DROP | 75068c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_CPU, 75168c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_ENA | 75268c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO); 75368c929daSCodrin Ciubotariu break; 75468c929daSCodrin Ciubotariu default: 75568c929daSCodrin Ciubotariu printf("Unknown learn mode for port %d\n", port_no); 75668c929daSCodrin Ciubotariu } 75768c929daSCodrin Ciubotariu } 75868c929daSCodrin Ciubotariu 75968c929daSCodrin Ciubotariu /* Get learning configuration for a VSC9953 port */ 76068c929daSCodrin Ciubotariu static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode) 76168c929daSCodrin Ciubotariu { 76268c929daSCodrin Ciubotariu u32 val; 76368c929daSCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 76468c929daSCodrin Ciubotariu 76568c929daSCodrin Ciubotariu /* Administrative down */ 76668c929daSCodrin Ciubotariu if (!vsc9953_l2sw.port[port_no].enabled) { 76768c929daSCodrin Ciubotariu printf("Port %d is administrative down\n", port_no); 76868c929daSCodrin Ciubotariu return -1; 76968c929daSCodrin Ciubotariu } 77068c929daSCodrin Ciubotariu 77168c929daSCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 77268c929daSCodrin Ciubotariu VSC9953_ANA_OFFSET); 77368c929daSCodrin Ciubotariu 77468c929daSCodrin Ciubotariu /* For now we only support HW learning (auto) and no learning */ 77568c929daSCodrin Ciubotariu val = in_le32(&l2ana_reg->port[port_no].port_cfg); 77668c929daSCodrin Ciubotariu if ((val & (VSC9953_PORT_CFG_LEARN_ENA | 77768c929daSCodrin Ciubotariu VSC9953_PORT_CFG_LEARN_AUTO)) == 77868c929daSCodrin Ciubotariu (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO)) 77968c929daSCodrin Ciubotariu *mode = PORT_LEARN_AUTO; 78068c929daSCodrin Ciubotariu else 78168c929daSCodrin Ciubotariu *mode = PORT_LEARN_NONE; 78268c929daSCodrin Ciubotariu 78368c929daSCodrin Ciubotariu return 0; 78468c929daSCodrin Ciubotariu } 78568c929daSCodrin Ciubotariu 786*22449858SCodrin Ciubotariu /* wait for FDB to become available */ 787*22449858SCodrin Ciubotariu static int vsc9953_mac_table_poll_idle(void) 788*22449858SCodrin Ciubotariu { 789*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 790*22449858SCodrin Ciubotariu u32 timeout; 791*22449858SCodrin Ciubotariu 792*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 793*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 794*22449858SCodrin Ciubotariu 795*22449858SCodrin Ciubotariu timeout = 50000; 796*22449858SCodrin Ciubotariu while (((in_le32(&l2ana_reg->ana_tables.mac_access) & 797*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK) != 798*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_IDLE) && --timeout) 799*22449858SCodrin Ciubotariu udelay(1); 800*22449858SCodrin Ciubotariu 801*22449858SCodrin Ciubotariu return timeout ? 0 : -EBUSY; 802*22449858SCodrin Ciubotariu } 803*22449858SCodrin Ciubotariu 804*22449858SCodrin Ciubotariu /* enum describing available commands for the MAC table */ 805*22449858SCodrin Ciubotariu enum mac_table_cmd { 806*22449858SCodrin Ciubotariu MAC_TABLE_READ, 807*22449858SCodrin Ciubotariu MAC_TABLE_LOOKUP, 808*22449858SCodrin Ciubotariu MAC_TABLE_WRITE, 809*22449858SCodrin Ciubotariu MAC_TABLE_LEARN, 810*22449858SCodrin Ciubotariu MAC_TABLE_FORGET, 811*22449858SCodrin Ciubotariu MAC_TABLE_GET_NEXT, 812*22449858SCodrin Ciubotariu MAC_TABLE_AGE, 813*22449858SCodrin Ciubotariu }; 814*22449858SCodrin Ciubotariu 815*22449858SCodrin Ciubotariu /* Issues a command to the FDB table */ 816*22449858SCodrin Ciubotariu static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd) 817*22449858SCodrin Ciubotariu { 818*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 819*22449858SCodrin Ciubotariu 820*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 821*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 822*22449858SCodrin Ciubotariu 823*22449858SCodrin Ciubotariu switch (cmd) { 824*22449858SCodrin Ciubotariu case MAC_TABLE_READ: 825*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 826*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID, 827*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_READ); 828*22449858SCodrin Ciubotariu break; 829*22449858SCodrin Ciubotariu case MAC_TABLE_LOOKUP: 830*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 831*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ | 832*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID); 833*22449858SCodrin Ciubotariu break; 834*22449858SCodrin Ciubotariu case MAC_TABLE_WRITE: 835*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 836*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 837*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 838*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_WRITE | 839*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_LOCKED); 840*22449858SCodrin Ciubotariu break; 841*22449858SCodrin Ciubotariu case MAC_TABLE_LEARN: 842*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 843*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 844*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 845*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_LEARN | 846*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_LOCKED | 847*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID); 848*22449858SCodrin Ciubotariu break; 849*22449858SCodrin Ciubotariu case MAC_TABLE_FORGET: 850*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 851*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 852*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 853*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_FORGET); 854*22449858SCodrin Ciubotariu break; 855*22449858SCodrin Ciubotariu case MAC_TABLE_GET_NEXT: 856*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 857*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 858*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 859*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_NEXT); 860*22449858SCodrin Ciubotariu break; 861*22449858SCodrin Ciubotariu case MAC_TABLE_AGE: 862*22449858SCodrin Ciubotariu clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, 863*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_MASK | 864*22449858SCodrin Ciubotariu VSC9953_MAC_ENTRYTYPE_MASK, 865*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_AGE); 866*22449858SCodrin Ciubotariu break; 867*22449858SCodrin Ciubotariu default: 868*22449858SCodrin Ciubotariu printf("Unknown MAC table command\n"); 869*22449858SCodrin Ciubotariu } 870*22449858SCodrin Ciubotariu 871*22449858SCodrin Ciubotariu if (vsc9953_mac_table_poll_idle() < 0) { 872*22449858SCodrin Ciubotariu debug("MAC table timeout\n"); 873*22449858SCodrin Ciubotariu return -1; 874*22449858SCodrin Ciubotariu } 875*22449858SCodrin Ciubotariu 876*22449858SCodrin Ciubotariu return 0; 877*22449858SCodrin Ciubotariu } 878*22449858SCodrin Ciubotariu 879*22449858SCodrin Ciubotariu /* show the FDB entries that correspond to a port and a VLAN */ 880*22449858SCodrin Ciubotariu static void vsc9953_mac_table_show(int port_no, int vid) 881*22449858SCodrin Ciubotariu { 882*22449858SCodrin Ciubotariu int rc[VSC9953_MAX_PORTS]; 883*22449858SCodrin Ciubotariu enum port_learn_mode mode[VSC9953_MAX_PORTS]; 884*22449858SCodrin Ciubotariu int i; 885*22449858SCodrin Ciubotariu u32 val; 886*22449858SCodrin Ciubotariu u32 vlan; 887*22449858SCodrin Ciubotariu u32 mach; 888*22449858SCodrin Ciubotariu u32 macl; 889*22449858SCodrin Ciubotariu u32 dest_indx; 890*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 891*22449858SCodrin Ciubotariu 892*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 893*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 894*22449858SCodrin Ciubotariu 895*22449858SCodrin Ciubotariu /* disable auto learning */ 896*22449858SCodrin Ciubotariu if (port_no == ETHSW_CMD_PORT_ALL) { 897*22449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 898*22449858SCodrin Ciubotariu rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); 899*22449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 900*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); 901*22449858SCodrin Ciubotariu } 902*22449858SCodrin Ciubotariu } else { 903*22449858SCodrin Ciubotariu rc[port_no] = vsc9953_port_learn_mode_get(port_no, 904*22449858SCodrin Ciubotariu &mode[port_no]); 905*22449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 906*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); 907*22449858SCodrin Ciubotariu } 908*22449858SCodrin Ciubotariu 909*22449858SCodrin Ciubotariu /* write port and vid to get selected FDB entries */ 910*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.anag_efil); 911*22449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 912*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, 913*22449858SCodrin Ciubotariu port_no) | VSC9953_AGE_PORT_EN; 914*22449858SCodrin Ciubotariu } 915*22449858SCodrin Ciubotariu if (vid != ETHSW_CMD_VLAN_ALL) { 916*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, 917*22449858SCodrin Ciubotariu vid) | VSC9953_AGE_VID_EN; 918*22449858SCodrin Ciubotariu } 919*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana.anag_efil, val); 920*22449858SCodrin Ciubotariu 921*22449858SCodrin Ciubotariu /* set MAC and VLAN to 0 to look from beginning */ 922*22449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana_tables.mach_data, 923*22449858SCodrin Ciubotariu VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK); 924*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 0); 925*22449858SCodrin Ciubotariu 926*22449858SCodrin Ciubotariu /* get entries */ 927*22449858SCodrin Ciubotariu printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID"); 928*22449858SCodrin Ciubotariu do { 929*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) { 930*22449858SCodrin Ciubotariu debug("GET NEXT MAC table command failed\n"); 931*22449858SCodrin Ciubotariu break; 932*22449858SCodrin Ciubotariu } 933*22449858SCodrin Ciubotariu 934*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 935*22449858SCodrin Ciubotariu 936*22449858SCodrin Ciubotariu /* get out when an invalid entry is found */ 937*22449858SCodrin Ciubotariu if (!(val & VSC9953_MAC_CMD_VALID)) 938*22449858SCodrin Ciubotariu break; 939*22449858SCodrin Ciubotariu 940*22449858SCodrin Ciubotariu switch (val & VSC9953_MAC_ENTRYTYPE_MASK) { 941*22449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_NORMAL: 942*22449858SCodrin Ciubotariu printf("%10s ", "Dynamic"); 943*22449858SCodrin Ciubotariu break; 944*22449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_LOCKED: 945*22449858SCodrin Ciubotariu printf("%10s ", "Static"); 946*22449858SCodrin Ciubotariu break; 947*22449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_IPV4MCAST: 948*22449858SCodrin Ciubotariu printf("%10s ", "IPv4 Mcast"); 949*22449858SCodrin Ciubotariu break; 950*22449858SCodrin Ciubotariu case VSC9953_MAC_ENTRYTYPE_IPV6MCAST: 951*22449858SCodrin Ciubotariu printf("%10s ", "IPv6 Mcast"); 952*22449858SCodrin Ciubotariu break; 953*22449858SCodrin Ciubotariu default: 954*22449858SCodrin Ciubotariu printf("%10s ", "Unknown"); 955*22449858SCodrin Ciubotariu } 956*22449858SCodrin Ciubotariu 957*22449858SCodrin Ciubotariu dest_indx = bitfield_extract_by_mask(val, 958*22449858SCodrin Ciubotariu VSC9953_MAC_DESTIDX_MASK); 959*22449858SCodrin Ciubotariu 960*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 961*22449858SCodrin Ciubotariu vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK); 962*22449858SCodrin Ciubotariu mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK); 963*22449858SCodrin Ciubotariu macl = in_le32(&l2ana_reg->ana_tables.macl_data); 964*22449858SCodrin Ciubotariu 965*22449858SCodrin Ciubotariu printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff, 966*22449858SCodrin Ciubotariu mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff, 967*22449858SCodrin Ciubotariu (macl >> 8) & 0xff, macl & 0xff); 968*22449858SCodrin Ciubotariu printf("%5d ", dest_indx); 969*22449858SCodrin Ciubotariu printf("%4d\n", vlan); 970*22449858SCodrin Ciubotariu } while (1); 971*22449858SCodrin Ciubotariu 972*22449858SCodrin Ciubotariu /* set learning mode to previous value */ 973*22449858SCodrin Ciubotariu if (port_no == ETHSW_CMD_PORT_ALL) { 974*22449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 975*22449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 976*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode[i]); 977*22449858SCodrin Ciubotariu } 978*22449858SCodrin Ciubotariu } else { 979*22449858SCodrin Ciubotariu /* If administrative down, skip */ 980*22449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 981*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, mode[port_no]); 982*22449858SCodrin Ciubotariu } 983*22449858SCodrin Ciubotariu 984*22449858SCodrin Ciubotariu /* reset FDB port and VLAN FDB selection */ 985*22449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | 986*22449858SCodrin Ciubotariu VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | 987*22449858SCodrin Ciubotariu VSC9953_AGE_VID_MASK); 988*22449858SCodrin Ciubotariu } 989*22449858SCodrin Ciubotariu 990*22449858SCodrin Ciubotariu /* Add a static FDB entry */ 991*22449858SCodrin Ciubotariu static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid) 992*22449858SCodrin Ciubotariu { 993*22449858SCodrin Ciubotariu u32 val; 994*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 995*22449858SCodrin Ciubotariu 996*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 997*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 998*22449858SCodrin Ciubotariu 999*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 1000*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 1001*22449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 1002*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 1003*22449858SCodrin Ciubotariu 1004*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 1005*22449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 1006*22449858SCodrin Ciubotariu (mac[5] << 0)); 1007*22449858SCodrin Ciubotariu 1008*22449858SCodrin Ciubotariu /* set on which port is the MAC address added */ 1009*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 1010*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no); 1011*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mac_access, val); 1012*22449858SCodrin Ciubotariu 1013*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0) 1014*22449858SCodrin Ciubotariu return -1; 1015*22449858SCodrin Ciubotariu 1016*22449858SCodrin Ciubotariu /* check if the MAC address was indeed added */ 1017*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 1018*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 1019*22449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 1020*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 1021*22449858SCodrin Ciubotariu 1022*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 1023*22449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 1024*22449858SCodrin Ciubotariu (mac[5] << 0)); 1025*22449858SCodrin Ciubotariu 1026*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0) 1027*22449858SCodrin Ciubotariu return -1; 1028*22449858SCodrin Ciubotariu 1029*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mac_access); 1030*22449858SCodrin Ciubotariu 1031*22449858SCodrin Ciubotariu if ((port_no != bitfield_extract_by_mask(val, 1032*22449858SCodrin Ciubotariu VSC9953_MAC_DESTIDX_MASK))) { 1033*22449858SCodrin Ciubotariu printf("Failed to add MAC address\n"); 1034*22449858SCodrin Ciubotariu return -1; 1035*22449858SCodrin Ciubotariu } 1036*22449858SCodrin Ciubotariu return 0; 1037*22449858SCodrin Ciubotariu } 1038*22449858SCodrin Ciubotariu 1039*22449858SCodrin Ciubotariu /* Delete a FDB entry */ 1040*22449858SCodrin Ciubotariu static int vsc9953_mac_table_del(uchar mac[6], u16 vid) 1041*22449858SCodrin Ciubotariu { 1042*22449858SCodrin Ciubotariu u32 val; 1043*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1044*22449858SCodrin Ciubotariu 1045*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1046*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1047*22449858SCodrin Ciubotariu 1048*22449858SCodrin Ciubotariu /* check first if MAC entry is present */ 1049*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 1050*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 1051*22449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 1052*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 1053*22449858SCodrin Ciubotariu 1054*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, 1055*22449858SCodrin Ciubotariu (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | 1056*22449858SCodrin Ciubotariu (mac[5] << 0)); 1057*22449858SCodrin Ciubotariu 1058*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { 1059*22449858SCodrin Ciubotariu debug("Lookup in the MAC table failed\n"); 1060*22449858SCodrin Ciubotariu return -1; 1061*22449858SCodrin Ciubotariu } 1062*22449858SCodrin Ciubotariu 1063*22449858SCodrin Ciubotariu if (!(in_le32(&l2ana_reg->ana_tables.mac_access) & 1064*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID)) { 1065*22449858SCodrin Ciubotariu printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ", 1066*22449858SCodrin Ciubotariu mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 1067*22449858SCodrin Ciubotariu printf("VLAN: %d does not exist.\n", vid); 1068*22449858SCodrin Ciubotariu return -1; 1069*22449858SCodrin Ciubotariu } 1070*22449858SCodrin Ciubotariu 1071*22449858SCodrin Ciubotariu /* FDB entry found, proceed to delete */ 1072*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 1073*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 1074*22449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 1075*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 1076*22449858SCodrin Ciubotariu 1077*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | 1078*22449858SCodrin Ciubotariu (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); 1079*22449858SCodrin Ciubotariu 1080*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0) 1081*22449858SCodrin Ciubotariu return -1; 1082*22449858SCodrin Ciubotariu 1083*22449858SCodrin Ciubotariu /* check if the MAC entry is still in FDB */ 1084*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana_tables.mach_data); 1085*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | 1086*22449858SCodrin Ciubotariu (mac[0] << 8) | (mac[1] << 0); 1087*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.mach_data, val); 1088*22449858SCodrin Ciubotariu 1089*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | 1090*22449858SCodrin Ciubotariu (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); 1091*22449858SCodrin Ciubotariu 1092*22449858SCodrin Ciubotariu if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { 1093*22449858SCodrin Ciubotariu debug("Lookup in the MAC table failed\n"); 1094*22449858SCodrin Ciubotariu return -1; 1095*22449858SCodrin Ciubotariu } 1096*22449858SCodrin Ciubotariu if (in_le32(&l2ana_reg->ana_tables.mac_access) & 1097*22449858SCodrin Ciubotariu VSC9953_MAC_CMD_VALID) { 1098*22449858SCodrin Ciubotariu printf("Failed to delete MAC address\n"); 1099*22449858SCodrin Ciubotariu return -1; 1100*22449858SCodrin Ciubotariu } 1101*22449858SCodrin Ciubotariu 1102*22449858SCodrin Ciubotariu return 0; 1103*22449858SCodrin Ciubotariu } 1104*22449858SCodrin Ciubotariu 1105*22449858SCodrin Ciubotariu /* age the unlocked entries in FDB */ 1106*22449858SCodrin Ciubotariu static void vsc9953_mac_table_age(int port_no, int vid) 1107*22449858SCodrin Ciubotariu { 1108*22449858SCodrin Ciubotariu int rc[VSC9953_MAX_PORTS]; 1109*22449858SCodrin Ciubotariu enum port_learn_mode mode[VSC9953_MAX_PORTS]; 1110*22449858SCodrin Ciubotariu u32 val; 1111*22449858SCodrin Ciubotariu int i; 1112*22449858SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1113*22449858SCodrin Ciubotariu 1114*22449858SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1115*22449858SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1116*22449858SCodrin Ciubotariu 1117*22449858SCodrin Ciubotariu /* set port and VID for selective aging */ 1118*22449858SCodrin Ciubotariu val = in_le32(&l2ana_reg->ana.anag_efil); 1119*22449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 1120*22449858SCodrin Ciubotariu /* disable auto learning */ 1121*22449858SCodrin Ciubotariu rc[port_no] = vsc9953_port_learn_mode_get(port_no, 1122*22449858SCodrin Ciubotariu &mode[port_no]); 1123*22449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 1124*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); 1125*22449858SCodrin Ciubotariu 1126*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, 1127*22449858SCodrin Ciubotariu port_no) | VSC9953_AGE_PORT_EN; 1128*22449858SCodrin Ciubotariu } else { 1129*22449858SCodrin Ciubotariu /* disable auto learning on all ports */ 1130*22449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 1131*22449858SCodrin Ciubotariu rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); 1132*22449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 1133*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); 1134*22449858SCodrin Ciubotariu } 1135*22449858SCodrin Ciubotariu } 1136*22449858SCodrin Ciubotariu 1137*22449858SCodrin Ciubotariu if (vid != ETHSW_CMD_VLAN_ALL) { 1138*22449858SCodrin Ciubotariu val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) | 1139*22449858SCodrin Ciubotariu VSC9953_AGE_VID_EN; 1140*22449858SCodrin Ciubotariu } 1141*22449858SCodrin Ciubotariu out_le32(&l2ana_reg->ana.anag_efil, val); 1142*22449858SCodrin Ciubotariu 1143*22449858SCodrin Ciubotariu /* age the dynamic FDB entries */ 1144*22449858SCodrin Ciubotariu vsc9953_mac_table_cmd(MAC_TABLE_AGE); 1145*22449858SCodrin Ciubotariu 1146*22449858SCodrin Ciubotariu /* clear previously set port and VID */ 1147*22449858SCodrin Ciubotariu clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | 1148*22449858SCodrin Ciubotariu VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | 1149*22449858SCodrin Ciubotariu VSC9953_AGE_VID_MASK); 1150*22449858SCodrin Ciubotariu 1151*22449858SCodrin Ciubotariu if (port_no != ETHSW_CMD_PORT_ALL) { 1152*22449858SCodrin Ciubotariu if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) 1153*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(port_no, mode[port_no]); 1154*22449858SCodrin Ciubotariu } else { 1155*22449858SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 1156*22449858SCodrin Ciubotariu if (!rc[i] && mode[i] != PORT_LEARN_NONE) 1157*22449858SCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode[i]); 1158*22449858SCodrin Ciubotariu } 1159*22449858SCodrin Ciubotariu } 1160*22449858SCodrin Ciubotariu } 1161*22449858SCodrin Ciubotariu 1162*22449858SCodrin Ciubotariu /* Delete all the dynamic FDB entries */ 1163*22449858SCodrin Ciubotariu static void vsc9953_mac_table_flush(int port, int vid) 1164*22449858SCodrin Ciubotariu { 1165*22449858SCodrin Ciubotariu vsc9953_mac_table_age(port, vid); 1166*22449858SCodrin Ciubotariu vsc9953_mac_table_age(port, vid); 1167*22449858SCodrin Ciubotariu } 1168*22449858SCodrin Ciubotariu 116924a23debSCodrin Ciubotariu static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd) 117024a23debSCodrin Ciubotariu { 117124a23debSCodrin Ciubotariu int i; 117224a23debSCodrin Ciubotariu u8 enabled; 117324a23debSCodrin Ciubotariu 117424a23debSCodrin Ciubotariu /* Last keyword should tell us if we should enable/disable the port */ 117524a23debSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 117624a23debSCodrin Ciubotariu ethsw_id_enable) 117724a23debSCodrin Ciubotariu enabled = 1; 117824a23debSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 117924a23debSCodrin Ciubotariu ethsw_id_disable) 118024a23debSCodrin Ciubotariu enabled = 0; 118124a23debSCodrin Ciubotariu else 118224a23debSCodrin Ciubotariu return CMD_RET_USAGE; 118324a23debSCodrin Ciubotariu 118424a23debSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 118524a23debSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 118624a23debSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 118724a23debSCodrin Ciubotariu return CMD_RET_FAILURE; 118824a23debSCodrin Ciubotariu } 118924a23debSCodrin Ciubotariu vsc9953_port_status_set(parsed_cmd->port, enabled); 119024a23debSCodrin Ciubotariu } else { 119124a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 119224a23debSCodrin Ciubotariu vsc9953_port_status_set(i, enabled); 119324a23debSCodrin Ciubotariu } 119424a23debSCodrin Ciubotariu 119524a23debSCodrin Ciubotariu return CMD_RET_SUCCESS; 119624a23debSCodrin Ciubotariu } 119724a23debSCodrin Ciubotariu 119824a23debSCodrin Ciubotariu static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd) 119924a23debSCodrin Ciubotariu { 120024a23debSCodrin Ciubotariu int i; 120124a23debSCodrin Ciubotariu 120224a23debSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 120324a23debSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 120424a23debSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 120524a23debSCodrin Ciubotariu return CMD_RET_FAILURE; 120624a23debSCodrin Ciubotariu } 120724a23debSCodrin Ciubotariu vsc9953_phy_autoneg(parsed_cmd->port); 120824a23debSCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 120924a23debSCodrin Ciubotariu "Port", "Status", "Link", "Speed", 121024a23debSCodrin Ciubotariu "Duplex"); 121124a23debSCodrin Ciubotariu vsc9953_port_config_show(parsed_cmd->port); 121224a23debSCodrin Ciubotariu 121324a23debSCodrin Ciubotariu } else { 121424a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 121524a23debSCodrin Ciubotariu vsc9953_phy_autoneg(i); 121624a23debSCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 121724a23debSCodrin Ciubotariu "Port", "Status", "Link", "Speed", "Duplex"); 121824a23debSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 121924a23debSCodrin Ciubotariu vsc9953_port_config_show(i); 122024a23debSCodrin Ciubotariu } 122124a23debSCodrin Ciubotariu 122224a23debSCodrin Ciubotariu return CMD_RET_SUCCESS; 122324a23debSCodrin Ciubotariu } 122424a23debSCodrin Ciubotariu 122586719f0cSCodrin Ciubotariu static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd) 122686719f0cSCodrin Ciubotariu { 122786719f0cSCodrin Ciubotariu int i; 122886719f0cSCodrin Ciubotariu 122986719f0cSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 123086719f0cSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 123186719f0cSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 123286719f0cSCodrin Ciubotariu return CMD_RET_FAILURE; 123386719f0cSCodrin Ciubotariu } 123486719f0cSCodrin Ciubotariu vsc9953_port_statistics_show(parsed_cmd->port); 123586719f0cSCodrin Ciubotariu } else { 123686719f0cSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 123786719f0cSCodrin Ciubotariu vsc9953_port_statistics_show(i); 123886719f0cSCodrin Ciubotariu } 123986719f0cSCodrin Ciubotariu 124086719f0cSCodrin Ciubotariu return CMD_RET_SUCCESS; 124186719f0cSCodrin Ciubotariu } 124286719f0cSCodrin Ciubotariu 124386719f0cSCodrin Ciubotariu static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def 124486719f0cSCodrin Ciubotariu *parsed_cmd) 124586719f0cSCodrin Ciubotariu { 124686719f0cSCodrin Ciubotariu int i; 124786719f0cSCodrin Ciubotariu 124886719f0cSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 124986719f0cSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 125086719f0cSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 125186719f0cSCodrin Ciubotariu return CMD_RET_FAILURE; 125286719f0cSCodrin Ciubotariu } 125386719f0cSCodrin Ciubotariu vsc9953_port_statistics_clear(parsed_cmd->port); 125486719f0cSCodrin Ciubotariu } else { 125586719f0cSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 125686719f0cSCodrin Ciubotariu vsc9953_port_statistics_clear(i); 125786719f0cSCodrin Ciubotariu } 125886719f0cSCodrin Ciubotariu 125986719f0cSCodrin Ciubotariu return CMD_RET_SUCCESS; 126086719f0cSCodrin Ciubotariu } 126186719f0cSCodrin Ciubotariu 126268c929daSCodrin Ciubotariu static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd) 126368c929daSCodrin Ciubotariu { 126468c929daSCodrin Ciubotariu int i; 126568c929daSCodrin Ciubotariu enum port_learn_mode mode; 126668c929daSCodrin Ciubotariu 126768c929daSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 126868c929daSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 126968c929daSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 127068c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 127168c929daSCodrin Ciubotariu } 127268c929daSCodrin Ciubotariu if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode)) 127368c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 127468c929daSCodrin Ciubotariu printf("%7s %11s\n", "Port", "Learn mode"); 127568c929daSCodrin Ciubotariu switch (mode) { 127668c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 127768c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "disable"); 127868c929daSCodrin Ciubotariu break; 127968c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 128068c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "auto"); 128168c929daSCodrin Ciubotariu break; 128268c929daSCodrin Ciubotariu default: 128368c929daSCodrin Ciubotariu printf("%7d %11s\n", parsed_cmd->port, "-"); 128468c929daSCodrin Ciubotariu } 128568c929daSCodrin Ciubotariu } else { 128668c929daSCodrin Ciubotariu printf("%7s %11s\n", "Port", "Learn mode"); 128768c929daSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 128868c929daSCodrin Ciubotariu if (vsc9953_port_learn_mode_get(i, &mode)) 128968c929daSCodrin Ciubotariu continue; 129068c929daSCodrin Ciubotariu switch (mode) { 129168c929daSCodrin Ciubotariu case PORT_LEARN_NONE: 129268c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "disable"); 129368c929daSCodrin Ciubotariu break; 129468c929daSCodrin Ciubotariu case PORT_LEARN_AUTO: 129568c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "auto"); 129668c929daSCodrin Ciubotariu break; 129768c929daSCodrin Ciubotariu default: 129868c929daSCodrin Ciubotariu printf("%7d %11s\n", i, "-"); 129968c929daSCodrin Ciubotariu } 130068c929daSCodrin Ciubotariu } 130168c929daSCodrin Ciubotariu } 130268c929daSCodrin Ciubotariu 130368c929daSCodrin Ciubotariu return CMD_RET_SUCCESS; 130468c929daSCodrin Ciubotariu } 130568c929daSCodrin Ciubotariu 130668c929daSCodrin Ciubotariu static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd) 130768c929daSCodrin Ciubotariu { 130868c929daSCodrin Ciubotariu int i; 130968c929daSCodrin Ciubotariu enum port_learn_mode mode; 131068c929daSCodrin Ciubotariu 131168c929daSCodrin Ciubotariu /* Last keyword should tell us the learn mode */ 131268c929daSCodrin Ciubotariu if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 131368c929daSCodrin Ciubotariu ethsw_id_auto) 131468c929daSCodrin Ciubotariu mode = PORT_LEARN_AUTO; 131568c929daSCodrin Ciubotariu else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == 131668c929daSCodrin Ciubotariu ethsw_id_disable) 131768c929daSCodrin Ciubotariu mode = PORT_LEARN_NONE; 131868c929daSCodrin Ciubotariu else 131968c929daSCodrin Ciubotariu return CMD_RET_USAGE; 132068c929daSCodrin Ciubotariu 132168c929daSCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { 132268c929daSCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 132368c929daSCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 132468c929daSCodrin Ciubotariu return CMD_RET_FAILURE; 132568c929daSCodrin Ciubotariu } 132668c929daSCodrin Ciubotariu vsc9953_port_learn_mode_set(parsed_cmd->port, mode); 132768c929daSCodrin Ciubotariu } else { 132868c929daSCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 132968c929daSCodrin Ciubotariu vsc9953_port_learn_mode_set(i, mode); 133068c929daSCodrin Ciubotariu } 133168c929daSCodrin Ciubotariu 133268c929daSCodrin Ciubotariu return CMD_RET_SUCCESS; 133368c929daSCodrin Ciubotariu } 133468c929daSCodrin Ciubotariu 1335*22449858SCodrin Ciubotariu static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd) 1336*22449858SCodrin Ciubotariu { 1337*22449858SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && 1338*22449858SCodrin Ciubotariu !VSC9953_PORT_CHECK(parsed_cmd->port)) { 1339*22449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 1340*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1341*22449858SCodrin Ciubotariu } 1342*22449858SCodrin Ciubotariu 1343*22449858SCodrin Ciubotariu if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && 1344*22449858SCodrin Ciubotariu !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 1345*22449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 1346*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1347*22449858SCodrin Ciubotariu } 1348*22449858SCodrin Ciubotariu 1349*22449858SCodrin Ciubotariu vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid); 1350*22449858SCodrin Ciubotariu 1351*22449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 1352*22449858SCodrin Ciubotariu } 1353*22449858SCodrin Ciubotariu 1354*22449858SCodrin Ciubotariu static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd) 1355*22449858SCodrin Ciubotariu { 1356*22449858SCodrin Ciubotariu if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && 1357*22449858SCodrin Ciubotariu !VSC9953_PORT_CHECK(parsed_cmd->port)) { 1358*22449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 1359*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1360*22449858SCodrin Ciubotariu } 1361*22449858SCodrin Ciubotariu 1362*22449858SCodrin Ciubotariu if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && 1363*22449858SCodrin Ciubotariu !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { 1364*22449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", parsed_cmd->vid); 1365*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1366*22449858SCodrin Ciubotariu } 1367*22449858SCodrin Ciubotariu 1368*22449858SCodrin Ciubotariu vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid); 1369*22449858SCodrin Ciubotariu 1370*22449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 1371*22449858SCodrin Ciubotariu } 1372*22449858SCodrin Ciubotariu 1373*22449858SCodrin Ciubotariu static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd) 1374*22449858SCodrin Ciubotariu { 1375*22449858SCodrin Ciubotariu int vid; 1376*22449858SCodrin Ciubotariu 1377*22449858SCodrin Ciubotariu /* a port number must be present */ 1378*22449858SCodrin Ciubotariu if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) { 1379*22449858SCodrin Ciubotariu printf("Please specify a port\n"); 1380*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1381*22449858SCodrin Ciubotariu } 1382*22449858SCodrin Ciubotariu 1383*22449858SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { 1384*22449858SCodrin Ciubotariu printf("Invalid port number: %d\n", parsed_cmd->port); 1385*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1386*22449858SCodrin Ciubotariu } 1387*22449858SCodrin Ciubotariu 1388*22449858SCodrin Ciubotariu /* Use VLAN 1 if VID is not set */ 1389*22449858SCodrin Ciubotariu vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); 1390*22449858SCodrin Ciubotariu 1391*22449858SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(vid)) { 1392*22449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", vid); 1393*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1394*22449858SCodrin Ciubotariu } 1395*22449858SCodrin Ciubotariu 1396*22449858SCodrin Ciubotariu if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid)) 1397*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1398*22449858SCodrin Ciubotariu 1399*22449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 1400*22449858SCodrin Ciubotariu } 1401*22449858SCodrin Ciubotariu 1402*22449858SCodrin Ciubotariu static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd) 1403*22449858SCodrin Ciubotariu { 1404*22449858SCodrin Ciubotariu int vid; 1405*22449858SCodrin Ciubotariu 1406*22449858SCodrin Ciubotariu /* Use VLAN 1 if VID is not set */ 1407*22449858SCodrin Ciubotariu vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); 1408*22449858SCodrin Ciubotariu 1409*22449858SCodrin Ciubotariu if (!VSC9953_VLAN_CHECK(vid)) { 1410*22449858SCodrin Ciubotariu printf("Invalid VID number: %d\n", vid); 1411*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1412*22449858SCodrin Ciubotariu } 1413*22449858SCodrin Ciubotariu 1414*22449858SCodrin Ciubotariu if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid)) 1415*22449858SCodrin Ciubotariu return CMD_RET_FAILURE; 1416*22449858SCodrin Ciubotariu 1417*22449858SCodrin Ciubotariu return CMD_RET_SUCCESS; 1418*22449858SCodrin Ciubotariu } 1419*22449858SCodrin Ciubotariu 142024a23debSCodrin Ciubotariu static struct ethsw_command_func vsc9953_cmd_func = { 142124a23debSCodrin Ciubotariu .ethsw_name = "L2 Switch VSC9953", 142224a23debSCodrin Ciubotariu .port_enable = &vsc9953_port_status_key_func, 142324a23debSCodrin Ciubotariu .port_disable = &vsc9953_port_status_key_func, 142424a23debSCodrin Ciubotariu .port_show = &vsc9953_port_config_key_func, 142586719f0cSCodrin Ciubotariu .port_stats = &vsc9953_port_stats_key_func, 142686719f0cSCodrin Ciubotariu .port_stats_clear = &vsc9953_port_stats_clear_key_func, 142768c929daSCodrin Ciubotariu .port_learn = &vsc9953_learn_set_key_func, 142868c929daSCodrin Ciubotariu .port_learn_show = &vsc9953_learn_show_key_func, 1429*22449858SCodrin Ciubotariu .fdb_show = &vsc9953_fdb_show_key_func, 1430*22449858SCodrin Ciubotariu .fdb_flush = &vsc9953_fdb_flush_key_func, 1431*22449858SCodrin Ciubotariu .fdb_entry_add = &vsc9953_fdb_entry_add_key_func, 1432*22449858SCodrin Ciubotariu .fdb_entry_del = &vsc9953_fdb_entry_del_key_func, 143324a23debSCodrin Ciubotariu }; 143424a23debSCodrin Ciubotariu 143524a23debSCodrin Ciubotariu #endif /* CONFIG_CMD_ETHSW */ 143624a23debSCodrin Ciubotariu 14379de05987SCodrin Ciubotariu /***************************************************************************** 14389de05987SCodrin Ciubotariu At startup, the default configuration would be: 14399de05987SCodrin Ciubotariu - HW learning enabled on all ports; (HW default) 14409de05987SCodrin Ciubotariu - All ports are in VLAN 1; 14419de05987SCodrin Ciubotariu - All ports are VLAN aware; 14429de05987SCodrin Ciubotariu - All ports have POP_COUNT 1; 14439de05987SCodrin Ciubotariu - All ports have PVID 1; 14449de05987SCodrin Ciubotariu - All ports have TPID 0x8100; (HW default) 14459de05987SCodrin Ciubotariu - All ports tag frames classified to all VLANs that are not PVID; 14469de05987SCodrin Ciubotariu *****************************************************************************/ 14479de05987SCodrin Ciubotariu void vsc9953_default_configuration(void) 14489de05987SCodrin Ciubotariu { 14499de05987SCodrin Ciubotariu int i; 14509de05987SCodrin Ciubotariu 14519de05987SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_VLAN; i++) 14529de05987SCodrin Ciubotariu vsc9953_vlan_table_membership_all_set(i, 0); 14539de05987SCodrin Ciubotariu vsc9953_port_all_vlan_aware_set(1); 14549de05987SCodrin Ciubotariu vsc9953_port_all_vlan_pvid_set(1); 14559de05987SCodrin Ciubotariu vsc9953_port_all_vlan_poncnt_set(1); 14569de05987SCodrin Ciubotariu vsc9953_vlan_table_membership_all_set(1, 1); 14579de05987SCodrin Ciubotariu vsc9953_vlan_ingr_fltr_learn_drop(1); 14589de05987SCodrin Ciubotariu vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO); 14599de05987SCodrin Ciubotariu } 14609de05987SCodrin Ciubotariu 14616706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis) 14626706b115SCodrin Ciubotariu { 14633cc8cfffSCodrin Ciubotariu u32 i; 14643cc8cfffSCodrin Ciubotariu u32 hdx_cfg = 0; 14653cc8cfffSCodrin Ciubotariu u32 phy_addr = 0; 14666706b115SCodrin Ciubotariu int timeout; 14676706b115SCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 14686706b115SCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 14696706b115SCodrin Ciubotariu struct vsc9953_dev_gmii *l2dev_gmii_reg; 14706706b115SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 14716706b115SCodrin Ciubotariu struct vsc9953_devcpu_gcb *l2dev_gcb; 14726706b115SCodrin Ciubotariu 14736706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET + 14746706b115SCodrin Ciubotariu VSC9953_DEV_GMII_OFFSET); 14756706b115SCodrin Ciubotariu 14766706b115SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 14776706b115SCodrin Ciubotariu VSC9953_ANA_OFFSET); 14786706b115SCodrin Ciubotariu 14796706b115SCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 14806706b115SCodrin Ciubotariu VSC9953_SYS_OFFSET); 14816706b115SCodrin Ciubotariu 14826706b115SCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 14836706b115SCodrin Ciubotariu VSC9953_QSYS_OFFSET); 14846706b115SCodrin Ciubotariu 14856706b115SCodrin Ciubotariu l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET + 14866706b115SCodrin Ciubotariu VSC9953_DEVCPU_GCB); 14876706b115SCodrin Ciubotariu 14886706b115SCodrin Ciubotariu out_le32(&l2dev_gcb->chip_regs.soft_rst, 1489c4390486SCodrin Ciubotariu VSC9953_SOFT_SWC_RST_ENA); 14906706b115SCodrin Ciubotariu timeout = 50000; 14916706b115SCodrin Ciubotariu while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) & 1492c4390486SCodrin Ciubotariu VSC9953_SOFT_SWC_RST_ENA) && --timeout) 14936706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 soft reset */ 14946706b115SCodrin Ciubotariu if (timeout == 0) 14956706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 to reset\n"); 14966706b115SCodrin Ciubotariu 1497c4390486SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE | 1498c4390486SCodrin Ciubotariu VSC9953_MEM_INIT); 14996706b115SCodrin Ciubotariu 15006706b115SCodrin Ciubotariu timeout = 50000; 15016706b115SCodrin Ciubotariu while ((in_le32(&l2sys_reg->sys.reset_cfg) & 1502c4390486SCodrin Ciubotariu VSC9953_MEM_INIT) && --timeout) 15036706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 memory init */ 15046706b115SCodrin Ciubotariu if (timeout == 0) 15056706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 memory to initialize\n"); 15066706b115SCodrin Ciubotariu 15076706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg) 1508c4390486SCodrin Ciubotariu | VSC9953_CORE_ENABLE)); 15096706b115SCodrin Ciubotariu 15106706b115SCodrin Ciubotariu /* VSC9953 Setting to be done once only */ 15116706b115SCodrin Ciubotariu out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00); 15126706b115SCodrin Ciubotariu 15136706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 15146706b115SCodrin Ciubotariu if (vsc9953_port_init(i)) 15156706b115SCodrin Ciubotariu printf("Failed to initialize l2switch port %d\n", i); 15166706b115SCodrin Ciubotariu 15176706b115SCodrin Ciubotariu /* Enable VSC9953 GMII Ports Port ID 0 - 7 */ 15186706b115SCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(i)) { 15196706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 1520c4390486SCodrin Ciubotariu VSC9953_PFC_FC_QSGMII); 15216706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 1522c4390486SCodrin Ciubotariu VSC9953_MAC_FC_CFG_QSGMII); 15236706b115SCodrin Ciubotariu } else { 15246706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 1525c4390486SCodrin Ciubotariu VSC9953_PFC_FC); 15266706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 1527c4390486SCodrin Ciubotariu VSC9953_MAC_FC_CFG); 15286706b115SCodrin Ciubotariu } 15296706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->port_mode.clock_cfg, 1530c4390486SCodrin Ciubotariu VSC9953_CLOCK_CFG); 15316706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg, 1532c4390486SCodrin Ciubotariu VSC9953_MAC_ENA_CFG); 15336706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg, 1534c4390486SCodrin Ciubotariu VSC9953_MAC_MODE_CFG); 15356706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg, 1536c4390486SCodrin Ciubotariu VSC9953_MAC_IFG_CFG); 15376706b115SCodrin Ciubotariu /* mac_hdx_cfg varies with port id*/ 1538c4390486SCodrin Ciubotariu hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16); 15396706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg); 15406706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.front_port_mode[i], 1541c4390486SCodrin Ciubotariu VSC9953_FRONT_PORT_MODE); 1542fe91095bSCodrin Ciubotariu setbits_le32(&l2qsys_reg->sys.switch_port_mode[i], 1543c4390486SCodrin Ciubotariu VSC9953_PORT_ENA); 15446706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg, 1545c4390486SCodrin Ciubotariu VSC9953_MAC_MAX_LEN); 15466706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.pause_cfg[i], 1547c4390486SCodrin Ciubotariu VSC9953_PAUSE_CFG); 15486706b115SCodrin Ciubotariu /* WAIT FOR 2 us*/ 15496706b115SCodrin Ciubotariu udelay(2); 15506706b115SCodrin Ciubotariu 15516706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)( 15526706b115SCodrin Ciubotariu (char *)l2dev_gmii_reg 15536706b115SCodrin Ciubotariu + T1040_SWITCH_GMII_DEV_OFFSET); 15546706b115SCodrin Ciubotariu 15556706b115SCodrin Ciubotariu /* Initialize Lynx PHY Wrappers */ 15566706b115SCodrin Ciubotariu phy_addr = 0; 15576706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[i].enet_if == 15586706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_QSGMII) 15596706b115SCodrin Ciubotariu phy_addr = (i + 0x4) & 0x1F; 15606706b115SCodrin Ciubotariu else if (vsc9953_l2sw.port[i].enet_if == 15616706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_SGMII) 15626706b115SCodrin Ciubotariu phy_addr = (i + 1) & 0x1F; 15636706b115SCodrin Ciubotariu 15646706b115SCodrin Ciubotariu if (phy_addr) { 15656706b115SCodrin Ciubotariu /* SGMII IF mode + AN enable */ 15666706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 15676706b115SCodrin Ciubotariu 0x14, PHY_SGMII_IF_MODE_AN | 15686706b115SCodrin Ciubotariu PHY_SGMII_IF_MODE_SGMII); 15696706b115SCodrin Ciubotariu /* Dev ability according to SGMII specification */ 15706706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 15716706b115SCodrin Ciubotariu 0x4, PHY_SGMII_DEV_ABILITY_SGMII); 15726706b115SCodrin Ciubotariu /* Adjust link timer for SGMII 15736706b115SCodrin Ciubotariu * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 15746706b115SCodrin Ciubotariu */ 15756706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 15766706b115SCodrin Ciubotariu 0x13, 0x0003); 15776706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 15786706b115SCodrin Ciubotariu 0x12, 0x0d40); 15796706b115SCodrin Ciubotariu /* Restart AN */ 15806706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 15816706b115SCodrin Ciubotariu 0x0, PHY_SGMII_CR_DEF_VAL | 15826706b115SCodrin Ciubotariu PHY_SGMII_CR_RESET_AN); 15836706b115SCodrin Ciubotariu 15846706b115SCodrin Ciubotariu timeout = 50000; 15856706b115SCodrin Ciubotariu while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0], 15866706b115SCodrin Ciubotariu phy_addr, 0x01) & 0x0020) && --timeout) 15876706b115SCodrin Ciubotariu udelay(1); /* wait for AN to complete */ 15886706b115SCodrin Ciubotariu if (timeout == 0) 15896706b115SCodrin Ciubotariu debug("Timeout waiting for AN to complete\n"); 15906706b115SCodrin Ciubotariu } 15916706b115SCodrin Ciubotariu } 15926706b115SCodrin Ciubotariu 15939de05987SCodrin Ciubotariu vsc9953_default_configuration(); 15949de05987SCodrin Ciubotariu 159524a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW 159624a23debSCodrin Ciubotariu if (ethsw_define_functions(&vsc9953_cmd_func) < 0) 159724a23debSCodrin Ciubotariu debug("Unable to use \"ethsw\" commands\n"); 159824a23debSCodrin Ciubotariu #endif 159924a23debSCodrin Ciubotariu 16006706b115SCodrin Ciubotariu printf("VSC9953 L2 switch initialized\n"); 16016706b115SCodrin Ciubotariu return; 16026706b115SCodrin Ciubotariu } 1603