18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* Driver for Vitesse VSC7326 (Schaumburg) MAC */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "gmac.h" 78c2ecf20Sopenharmony_ci#include "elmer0.h" 88c2ecf20Sopenharmony_ci#include "vsc7326_reg.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* Update fast changing statistics every 15 seconds */ 118c2ecf20Sopenharmony_ci#define STATS_TICK_SECS 15 128c2ecf20Sopenharmony_ci/* 30 minutes for full statistics update */ 138c2ecf20Sopenharmony_ci#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* The egress WM value 0x01a01fff should be used only when the 168c2ecf20Sopenharmony_ci * interface is down (MAC port disabled). This is a workaround 178c2ecf20Sopenharmony_ci * for disabling the T2/MAC flow-control. When the interface is 188c2ecf20Sopenharmony_ci * enabled, the WM value should be set to 0x014a03F0. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#define WM_DISABLE 0x01a01fff 218c2ecf20Sopenharmony_ci#define WM_ENABLE 0x014a03F0 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct init_table { 248c2ecf20Sopenharmony_ci u32 addr; 258c2ecf20Sopenharmony_ci u32 data; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct _cmac_instance { 298c2ecf20Sopenharmony_ci u32 index; 308c2ecf20Sopenharmony_ci u32 ticks; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define INITBLOCK_SLEEP 0xffffffff 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void vsc_read(adapter_t *adapter, u32 addr, u32 *val) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u32 status, vlo, vhi; 388c2ecf20Sopenharmony_ci int i; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mac_lock); 418c2ecf20Sopenharmony_ci t1_tpi_read(adapter, (addr << 2) + 4, &vlo); 428c2ecf20Sopenharmony_ci i = 0; 438c2ecf20Sopenharmony_ci do { 448c2ecf20Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 458c2ecf20Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 468c2ecf20Sopenharmony_ci status = (vhi << 16) | vlo; 478c2ecf20Sopenharmony_ci i++; 488c2ecf20Sopenharmony_ci } while (((status & 1) == 0) && (i < 50)); 498c2ecf20Sopenharmony_ci if (i == 50) 508c2ecf20Sopenharmony_ci pr_err("Invalid tpi read from MAC, breaking loop.\n"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo); 538c2ecf20Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci *val = (vhi << 16) | vlo; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* pr_err("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", 588c2ecf20Sopenharmony_ci ((addr&0xe000)>>13), ((addr&0x1e00)>>9), 598c2ecf20Sopenharmony_ci ((addr&0x01fe)>>1), *val); */ 608c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mac_lock); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void vsc_write(adapter_t *adapter, u32 addr, u32 data) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci spin_lock_bh(&adapter->mac_lock); 668c2ecf20Sopenharmony_ci t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF); 678c2ecf20Sopenharmony_ci t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF); 688c2ecf20Sopenharmony_ci /* pr_err("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", 698c2ecf20Sopenharmony_ci ((addr&0xe000)>>13), ((addr&0x1e00)>>9), 708c2ecf20Sopenharmony_ci ((addr&0x01fe)>>1), data); */ 718c2ecf20Sopenharmony_ci spin_unlock_bh(&adapter->mac_lock); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Hard reset the MAC. This wipes out *all* configuration. */ 758c2ecf20Sopenharmony_cistatic void vsc7326_full_reset(adapter_t* adapter) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u32 val; 788c2ecf20Sopenharmony_ci u32 result = 0xffff; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 818c2ecf20Sopenharmony_ci val &= ~1; 828c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 838c2ecf20Sopenharmony_ci udelay(2); 848c2ecf20Sopenharmony_ci val |= 0x1; /* Enable mac MAC itself */ 858c2ecf20Sopenharmony_ci val |= 0x800; /* Turn off the red LED */ 868c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 878c2ecf20Sopenharmony_ci mdelay(1); 888c2ecf20Sopenharmony_ci vsc_write(adapter, REG_SW_RESET, 0x80000001); 898c2ecf20Sopenharmony_ci do { 908c2ecf20Sopenharmony_ci mdelay(1); 918c2ecf20Sopenharmony_ci vsc_read(adapter, REG_SW_RESET, &result); 928c2ecf20Sopenharmony_ci } while (result != 0x0); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct init_table vsc7326_reset[] = { 968c2ecf20Sopenharmony_ci { REG_IFACE_MODE, 0x00000000 }, 978c2ecf20Sopenharmony_ci { REG_CRC_CFG, 0x00000020 }, 988c2ecf20Sopenharmony_ci { REG_PLL_CLK_SPEED, 0x00050c00 }, 998c2ecf20Sopenharmony_ci { REG_PLL_CLK_SPEED, 0x00050c00 }, 1008c2ecf20Sopenharmony_ci { REG_MSCH, 0x00002f14 }, 1018c2ecf20Sopenharmony_ci { REG_SPI4_MISC, 0x00040409 }, 1028c2ecf20Sopenharmony_ci { REG_SPI4_DESKEW, 0x00080000 }, 1038c2ecf20Sopenharmony_ci { REG_SPI4_ING_SETUP2, 0x08080004 }, 1048c2ecf20Sopenharmony_ci { REG_SPI4_ING_SETUP0, 0x04111004 }, 1058c2ecf20Sopenharmony_ci { REG_SPI4_EGR_SETUP0, 0x80001a04 }, 1068c2ecf20Sopenharmony_ci { REG_SPI4_ING_SETUP1, 0x02010000 }, 1078c2ecf20Sopenharmony_ci { REG_AGE_INC(0), 0x00000000 }, 1088c2ecf20Sopenharmony_ci { REG_AGE_INC(1), 0x00000000 }, 1098c2ecf20Sopenharmony_ci { REG_ING_CONTROL, 0x0a200011 }, 1108c2ecf20Sopenharmony_ci { REG_EGR_CONTROL, 0xa0010091 }, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct init_table vsc7326_portinit[4][22] = { 1148c2ecf20Sopenharmony_ci { /* Port 0 */ 1158c2ecf20Sopenharmony_ci /* FIFO setup */ 1168c2ecf20Sopenharmony_ci { REG_DBG(0), 0x000004f0 }, 1178c2ecf20Sopenharmony_ci { REG_HDX(0), 0x00073101 }, 1188c2ecf20Sopenharmony_ci { REG_TEST(0,0), 0x00000022 }, 1198c2ecf20Sopenharmony_ci { REG_TEST(1,0), 0x00000022 }, 1208c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(0,0), 0x003f0000 }, 1218c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(1,0), 0x00120000 }, 1228c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(0,0), 0x07460757 }, 1238c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(1,0), WM_DISABLE }, 1248c2ecf20Sopenharmony_ci { REG_CT_THRHLD(0,0), 0x00000000 }, 1258c2ecf20Sopenharmony_ci { REG_CT_THRHLD(1,0), 0x00000000 }, 1268c2ecf20Sopenharmony_ci { REG_BUCKE(0), 0x0002ffff }, 1278c2ecf20Sopenharmony_ci { REG_BUCKI(0), 0x0002ffff }, 1288c2ecf20Sopenharmony_ci { REG_TEST(0,0), 0x00000020 }, 1298c2ecf20Sopenharmony_ci { REG_TEST(1,0), 0x00000020 }, 1308c2ecf20Sopenharmony_ci /* Port config */ 1318c2ecf20Sopenharmony_ci { REG_MAX_LEN(0), 0x00002710 }, 1328c2ecf20Sopenharmony_ci { REG_PORT_FAIL(0), 0x00000002 }, 1338c2ecf20Sopenharmony_ci { REG_NORMALIZER(0), 0x00000a64 }, 1348c2ecf20Sopenharmony_ci { REG_DENORM(0), 0x00000010 }, 1358c2ecf20Sopenharmony_ci { REG_STICK_BIT(0), 0x03baa370 }, 1368c2ecf20Sopenharmony_ci { REG_DEV_SETUP(0), 0x00000083 }, 1378c2ecf20Sopenharmony_ci { REG_DEV_SETUP(0), 0x00000082 }, 1388c2ecf20Sopenharmony_ci { REG_MODE_CFG(0), 0x0200259f }, 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci { /* Port 1 */ 1418c2ecf20Sopenharmony_ci /* FIFO setup */ 1428c2ecf20Sopenharmony_ci { REG_DBG(1), 0x000004f0 }, 1438c2ecf20Sopenharmony_ci { REG_HDX(1), 0x00073101 }, 1448c2ecf20Sopenharmony_ci { REG_TEST(0,1), 0x00000022 }, 1458c2ecf20Sopenharmony_ci { REG_TEST(1,1), 0x00000022 }, 1468c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(0,1), 0x007e003f }, 1478c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(1,1), 0x00240012 }, 1488c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(0,1), 0x07460757 }, 1498c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(1,1), WM_DISABLE }, 1508c2ecf20Sopenharmony_ci { REG_CT_THRHLD(0,1), 0x00000000 }, 1518c2ecf20Sopenharmony_ci { REG_CT_THRHLD(1,1), 0x00000000 }, 1528c2ecf20Sopenharmony_ci { REG_BUCKE(1), 0x0002ffff }, 1538c2ecf20Sopenharmony_ci { REG_BUCKI(1), 0x0002ffff }, 1548c2ecf20Sopenharmony_ci { REG_TEST(0,1), 0x00000020 }, 1558c2ecf20Sopenharmony_ci { REG_TEST(1,1), 0x00000020 }, 1568c2ecf20Sopenharmony_ci /* Port config */ 1578c2ecf20Sopenharmony_ci { REG_MAX_LEN(1), 0x00002710 }, 1588c2ecf20Sopenharmony_ci { REG_PORT_FAIL(1), 0x00000002 }, 1598c2ecf20Sopenharmony_ci { REG_NORMALIZER(1), 0x00000a64 }, 1608c2ecf20Sopenharmony_ci { REG_DENORM(1), 0x00000010 }, 1618c2ecf20Sopenharmony_ci { REG_STICK_BIT(1), 0x03baa370 }, 1628c2ecf20Sopenharmony_ci { REG_DEV_SETUP(1), 0x00000083 }, 1638c2ecf20Sopenharmony_ci { REG_DEV_SETUP(1), 0x00000082 }, 1648c2ecf20Sopenharmony_ci { REG_MODE_CFG(1), 0x0200259f }, 1658c2ecf20Sopenharmony_ci }, 1668c2ecf20Sopenharmony_ci { /* Port 2 */ 1678c2ecf20Sopenharmony_ci /* FIFO setup */ 1688c2ecf20Sopenharmony_ci { REG_DBG(2), 0x000004f0 }, 1698c2ecf20Sopenharmony_ci { REG_HDX(2), 0x00073101 }, 1708c2ecf20Sopenharmony_ci { REG_TEST(0,2), 0x00000022 }, 1718c2ecf20Sopenharmony_ci { REG_TEST(1,2), 0x00000022 }, 1728c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(0,2), 0x00bd007e }, 1738c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(1,2), 0x00360024 }, 1748c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(0,2), 0x07460757 }, 1758c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(1,2), WM_DISABLE }, 1768c2ecf20Sopenharmony_ci { REG_CT_THRHLD(0,2), 0x00000000 }, 1778c2ecf20Sopenharmony_ci { REG_CT_THRHLD(1,2), 0x00000000 }, 1788c2ecf20Sopenharmony_ci { REG_BUCKE(2), 0x0002ffff }, 1798c2ecf20Sopenharmony_ci { REG_BUCKI(2), 0x0002ffff }, 1808c2ecf20Sopenharmony_ci { REG_TEST(0,2), 0x00000020 }, 1818c2ecf20Sopenharmony_ci { REG_TEST(1,2), 0x00000020 }, 1828c2ecf20Sopenharmony_ci /* Port config */ 1838c2ecf20Sopenharmony_ci { REG_MAX_LEN(2), 0x00002710 }, 1848c2ecf20Sopenharmony_ci { REG_PORT_FAIL(2), 0x00000002 }, 1858c2ecf20Sopenharmony_ci { REG_NORMALIZER(2), 0x00000a64 }, 1868c2ecf20Sopenharmony_ci { REG_DENORM(2), 0x00000010 }, 1878c2ecf20Sopenharmony_ci { REG_STICK_BIT(2), 0x03baa370 }, 1888c2ecf20Sopenharmony_ci { REG_DEV_SETUP(2), 0x00000083 }, 1898c2ecf20Sopenharmony_ci { REG_DEV_SETUP(2), 0x00000082 }, 1908c2ecf20Sopenharmony_ci { REG_MODE_CFG(2), 0x0200259f }, 1918c2ecf20Sopenharmony_ci }, 1928c2ecf20Sopenharmony_ci { /* Port 3 */ 1938c2ecf20Sopenharmony_ci /* FIFO setup */ 1948c2ecf20Sopenharmony_ci { REG_DBG(3), 0x000004f0 }, 1958c2ecf20Sopenharmony_ci { REG_HDX(3), 0x00073101 }, 1968c2ecf20Sopenharmony_ci { REG_TEST(0,3), 0x00000022 }, 1978c2ecf20Sopenharmony_ci { REG_TEST(1,3), 0x00000022 }, 1988c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(0,3), 0x00fc00bd }, 1998c2ecf20Sopenharmony_ci { REG_TOP_BOTTOM(1,3), 0x00480036 }, 2008c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(0,3), 0x07460757 }, 2018c2ecf20Sopenharmony_ci { REG_HIGH_LOW_WM(1,3), WM_DISABLE }, 2028c2ecf20Sopenharmony_ci { REG_CT_THRHLD(0,3), 0x00000000 }, 2038c2ecf20Sopenharmony_ci { REG_CT_THRHLD(1,3), 0x00000000 }, 2048c2ecf20Sopenharmony_ci { REG_BUCKE(3), 0x0002ffff }, 2058c2ecf20Sopenharmony_ci { REG_BUCKI(3), 0x0002ffff }, 2068c2ecf20Sopenharmony_ci { REG_TEST(0,3), 0x00000020 }, 2078c2ecf20Sopenharmony_ci { REG_TEST(1,3), 0x00000020 }, 2088c2ecf20Sopenharmony_ci /* Port config */ 2098c2ecf20Sopenharmony_ci { REG_MAX_LEN(3), 0x00002710 }, 2108c2ecf20Sopenharmony_ci { REG_PORT_FAIL(3), 0x00000002 }, 2118c2ecf20Sopenharmony_ci { REG_NORMALIZER(3), 0x00000a64 }, 2128c2ecf20Sopenharmony_ci { REG_DENORM(3), 0x00000010 }, 2138c2ecf20Sopenharmony_ci { REG_STICK_BIT(3), 0x03baa370 }, 2148c2ecf20Sopenharmony_ci { REG_DEV_SETUP(3), 0x00000083 }, 2158c2ecf20Sopenharmony_ci { REG_DEV_SETUP(3), 0x00000082 }, 2168c2ecf20Sopenharmony_ci { REG_MODE_CFG(3), 0x0200259f }, 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void run_table(adapter_t *adapter, struct init_table *ib, int len) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2258c2ecf20Sopenharmony_ci if (ib[i].addr == INITBLOCK_SLEEP) { 2268c2ecf20Sopenharmony_ci udelay( ib[i].data ); 2278c2ecf20Sopenharmony_ci pr_err("sleep %d us\n",ib[i].data); 2288c2ecf20Sopenharmony_ci } else 2298c2ecf20Sopenharmony_ci vsc_write( adapter, ib[i].addr, ib[i].data ); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int bist_rd(adapter_t *adapter, int moduleid, int address) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int data = 0; 2368c2ecf20Sopenharmony_ci u32 result = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if ((address != 0x0) && 2398c2ecf20Sopenharmony_ci (address != 0x1) && 2408c2ecf20Sopenharmony_ci (address != 0x2) && 2418c2ecf20Sopenharmony_ci (address != 0xd) && 2428c2ecf20Sopenharmony_ci (address != 0xe)) 2438c2ecf20Sopenharmony_ci pr_err("No bist address: 0x%x\n", address); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | 2468c2ecf20Sopenharmony_ci ((moduleid & 0xff) << 0)); 2478c2ecf20Sopenharmony_ci vsc_write(adapter, REG_RAM_BIST_CMD, data); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci udelay(10); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci vsc_read(adapter, REG_RAM_BIST_RESULT, &result); 2528c2ecf20Sopenharmony_ci if ((result & (1 << 9)) != 0x0) 2538c2ecf20Sopenharmony_ci pr_err("Still in bist read: 0x%x\n", result); 2548c2ecf20Sopenharmony_ci else if ((result & (1 << 8)) != 0x0) 2558c2ecf20Sopenharmony_ci pr_err("bist read error: 0x%x\n", result); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return result & 0xff; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int bist_wr(adapter_t *adapter, int moduleid, int address, int value) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int data = 0; 2638c2ecf20Sopenharmony_ci u32 result = 0; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if ((address != 0x0) && 2668c2ecf20Sopenharmony_ci (address != 0x1) && 2678c2ecf20Sopenharmony_ci (address != 0x2) && 2688c2ecf20Sopenharmony_ci (address != 0xd) && 2698c2ecf20Sopenharmony_ci (address != 0xe)) 2708c2ecf20Sopenharmony_ci pr_err("No bist address: 0x%x\n", address); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (value > 255) 2738c2ecf20Sopenharmony_ci pr_err("Suspicious write out of range value: 0x%x\n", value); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | 2768c2ecf20Sopenharmony_ci ((moduleid & 0xff) << 0)); 2778c2ecf20Sopenharmony_ci vsc_write(adapter, REG_RAM_BIST_CMD, data); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci udelay(5); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci vsc_read(adapter, REG_RAM_BIST_CMD, &result); 2828c2ecf20Sopenharmony_ci if ((result & (1 << 27)) != 0x0) 2838c2ecf20Sopenharmony_ci pr_err("Still in bist write: 0x%x\n", result); 2848c2ecf20Sopenharmony_ci else if ((result & (1 << 26)) != 0x0) 2858c2ecf20Sopenharmony_ci pr_err("bist write error: 0x%x\n", result); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int run_bist(adapter_t *adapter, int moduleid) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci /*run bist*/ 2938c2ecf20Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x00, 0x02); 2948c2ecf20Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x01, 0x01); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int check_bist(adapter_t *adapter, int moduleid) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int result=0; 3028c2ecf20Sopenharmony_ci int column=0; 3038c2ecf20Sopenharmony_ci /*check bist*/ 3048c2ecf20Sopenharmony_ci result = bist_rd(adapter,moduleid, 0x02); 3058c2ecf20Sopenharmony_ci column = ((bist_rd(adapter,moduleid, 0x0e)<<8) + 3068c2ecf20Sopenharmony_ci (bist_rd(adapter,moduleid, 0x0d))); 3078c2ecf20Sopenharmony_ci if ((result & 3) != 0x3) 3088c2ecf20Sopenharmony_ci pr_err("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", 3098c2ecf20Sopenharmony_ci result, moduleid, column); 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int enable_mem(adapter_t *adapter, int moduleid) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci /*enable mem*/ 3168c2ecf20Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x00, 0x00); 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int run_bist_all(adapter_t *adapter) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci int port = 0; 3238c2ecf20Sopenharmony_ci u32 val = 0; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci vsc_write(adapter, REG_MEM_BIST, 0x5); 3268c2ecf20Sopenharmony_ci vsc_read(adapter, REG_MEM_BIST, &val); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci for (port = 0; port < 12; port++) 3298c2ecf20Sopenharmony_ci vsc_write(adapter, REG_DEV_SETUP(port), 0x0); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci udelay(300); 3328c2ecf20Sopenharmony_ci vsc_write(adapter, REG_SPI4_MISC, 0x00040409); 3338c2ecf20Sopenharmony_ci udelay(300); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci (void) run_bist(adapter,13); 3368c2ecf20Sopenharmony_ci (void) run_bist(adapter,14); 3378c2ecf20Sopenharmony_ci (void) run_bist(adapter,20); 3388c2ecf20Sopenharmony_ci (void) run_bist(adapter,21); 3398c2ecf20Sopenharmony_ci mdelay(200); 3408c2ecf20Sopenharmony_ci (void) check_bist(adapter,13); 3418c2ecf20Sopenharmony_ci (void) check_bist(adapter,14); 3428c2ecf20Sopenharmony_ci (void) check_bist(adapter,20); 3438c2ecf20Sopenharmony_ci (void) check_bist(adapter,21); 3448c2ecf20Sopenharmony_ci udelay(100); 3458c2ecf20Sopenharmony_ci (void) enable_mem(adapter,13); 3468c2ecf20Sopenharmony_ci (void) enable_mem(adapter,14); 3478c2ecf20Sopenharmony_ci (void) enable_mem(adapter,20); 3488c2ecf20Sopenharmony_ci (void) enable_mem(adapter,21); 3498c2ecf20Sopenharmony_ci udelay(300); 3508c2ecf20Sopenharmony_ci vsc_write(adapter, REG_SPI4_MISC, 0x60040400); 3518c2ecf20Sopenharmony_ci udelay(300); 3528c2ecf20Sopenharmony_ci for (port = 0; port < 12; port++) 3538c2ecf20Sopenharmony_ci vsc_write(adapter, REG_DEV_SETUP(port), 0x1); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci udelay(300); 3568c2ecf20Sopenharmony_ci vsc_write(adapter, REG_MEM_BIST, 0x0); 3578c2ecf20Sopenharmony_ci mdelay(10); 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int mac_intr_handler(struct cmac *mac) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int mac_intr_enable(struct cmac *mac) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int mac_intr_disable(struct cmac *mac) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int mac_intr_clear(struct cmac *mac) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/* Expect MAC address to be in network byte order. */ 3828c2ecf20Sopenharmony_cistatic int mac_set_address(struct cmac* mac, u8 addr[6]) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci u32 val; 3858c2ecf20Sopenharmony_ci int port = mac->instance->index; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port), 3888c2ecf20Sopenharmony_ci (addr[3] << 16) | (addr[4] << 8) | addr[5]); 3898c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port), 3908c2ecf20Sopenharmony_ci (addr[0] << 16) | (addr[1] << 8) | addr[2]); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val); 3938c2ecf20Sopenharmony_ci val &= ~0xf0000000; 3948c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK0, 3978c2ecf20Sopenharmony_ci 0xffff0000 | (addr[4] << 8) | addr[5]); 3988c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK1, 3998c2ecf20Sopenharmony_ci 0xffff0000 | (addr[2] << 8) | addr[3]); 4008c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK2, 4018c2ecf20Sopenharmony_ci 0xffff0000 | (addr[0] << 8) | addr[1]); 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int mac_get_address(struct cmac *mac, u8 addr[6]) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci u32 addr_lo, addr_hi; 4088c2ecf20Sopenharmony_ci int port = mac->instance->index; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo); 4118c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci addr[0] = (u8) (addr_hi >> 16); 4148c2ecf20Sopenharmony_ci addr[1] = (u8) (addr_hi >> 8); 4158c2ecf20Sopenharmony_ci addr[2] = (u8) addr_hi; 4168c2ecf20Sopenharmony_ci addr[3] = (u8) (addr_lo >> 16); 4178c2ecf20Sopenharmony_ci addr[4] = (u8) (addr_lo >> 8); 4188c2ecf20Sopenharmony_ci addr[5] = (u8) addr_lo; 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* This is intended to reset a port, not the whole MAC */ 4238c2ecf20Sopenharmony_cistatic int mac_reset(struct cmac *mac) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci int index = mac->instance->index; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci run_table(mac->adapter, vsc7326_portinit[index], 4288c2ecf20Sopenharmony_ci ARRAY_SIZE(vsc7326_portinit[index])); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci u32 v; 4368c2ecf20Sopenharmony_ci int port = mac->instance->index; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v); 4398c2ecf20Sopenharmony_ci v |= 1 << 12; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (t1_rx_mode_promisc(rm)) 4428c2ecf20Sopenharmony_ci v &= ~(1 << (port + 16)); 4438c2ecf20Sopenharmony_ci else 4448c2ecf20Sopenharmony_ci v |= 1 << (port + 16); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v); 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int mac_set_mtu(struct cmac *mac, int mtu) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci int port = mac->instance->index; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* max_len includes header and FCS */ 4558c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4); 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 4608c2ecf20Sopenharmony_ci int fc) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci u32 v; 4638c2ecf20Sopenharmony_ci int enable, port = mac->instance->index; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 && 4668c2ecf20Sopenharmony_ci speed != SPEED_1000) 4678c2ecf20Sopenharmony_ci return -1; 4688c2ecf20Sopenharmony_ci if (duplex > 0 && duplex != DUPLEX_FULL) 4698c2ecf20Sopenharmony_ci return -1; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (speed >= 0) { 4728c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &v); 4738c2ecf20Sopenharmony_ci enable = v & 3; /* save tx/rx enables */ 4748c2ecf20Sopenharmony_ci v &= ~0xf; 4758c2ecf20Sopenharmony_ci v |= 4; /* full duplex */ 4768c2ecf20Sopenharmony_ci if (speed == SPEED_1000) 4778c2ecf20Sopenharmony_ci v |= 8; /* GigE */ 4788c2ecf20Sopenharmony_ci enable |= v; 4798c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), v); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (speed == SPEED_1000) 4828c2ecf20Sopenharmony_ci v = 0x82; 4838c2ecf20Sopenharmony_ci else if (speed == SPEED_100) 4848c2ecf20Sopenharmony_ci v = 0x84; 4858c2ecf20Sopenharmony_ci else /* SPEED_10 */ 4868c2ecf20Sopenharmony_ci v = 0x86; 4878c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */ 4888c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_DEV_SETUP(port), v); 4898c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_DBG(port), &v); 4908c2ecf20Sopenharmony_ci v &= ~0xff00; 4918c2ecf20Sopenharmony_ci if (speed == SPEED_1000) 4928c2ecf20Sopenharmony_ci v |= 0x400; 4938c2ecf20Sopenharmony_ci else if (speed == SPEED_100) 4948c2ecf20Sopenharmony_ci v |= 0x2000; 4958c2ecf20Sopenharmony_ci else /* SPEED_10 */ 4968c2ecf20Sopenharmony_ci v |= 0xff00; 4978c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_DBG(port), v); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_TX_IFG(port), 5008c2ecf20Sopenharmony_ci speed == SPEED_1000 ? 5 : 0x11); 5018c2ecf20Sopenharmony_ci if (duplex == DUPLEX_HALF) 5028c2ecf20Sopenharmony_ci enable = 0x0; /* 100 or 10 */ 5038c2ecf20Sopenharmony_ci else if (speed == SPEED_1000) 5048c2ecf20Sopenharmony_ci enable = 0xc; 5058c2ecf20Sopenharmony_ci else /* SPEED_100 or 10 */ 5068c2ecf20Sopenharmony_ci enable = 0x4; 5078c2ecf20Sopenharmony_ci enable |= 0x9 << 10; /* IFG1 */ 5088c2ecf20Sopenharmony_ci enable |= 0x6 << 6; /* IFG2 */ 5098c2ecf20Sopenharmony_ci enable |= 0x1 << 4; /* VLAN */ 5108c2ecf20Sopenharmony_ci enable |= 0x3; /* RX/TX EN */ 5118c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), enable); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v); 5168c2ecf20Sopenharmony_ci v &= 0xfff0ffff; 5178c2ecf20Sopenharmony_ci v |= 0x20000; /* xon/xoff */ 5188c2ecf20Sopenharmony_ci if (fc & PAUSE_RX) 5198c2ecf20Sopenharmony_ci v |= 0x40000; 5208c2ecf20Sopenharmony_ci if (fc & PAUSE_TX) 5218c2ecf20Sopenharmony_ci v |= 0x80000; 5228c2ecf20Sopenharmony_ci if (fc == (PAUSE_RX | PAUSE_TX)) 5238c2ecf20Sopenharmony_ci v |= 0x10000; 5248c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_PAUSE_CFG(port), v); 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int mac_enable(struct cmac *mac, int which) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci u32 val; 5318c2ecf20Sopenharmony_ci int port = mac->instance->index; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Write the correct WM value when the port is enabled. */ 5348c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 5378c2ecf20Sopenharmony_ci if (which & MAC_DIRECTION_RX) 5388c2ecf20Sopenharmony_ci val |= 0x2; 5398c2ecf20Sopenharmony_ci if (which & MAC_DIRECTION_TX) 5408c2ecf20Sopenharmony_ci val |= 1; 5418c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), val); 5428c2ecf20Sopenharmony_ci return 0; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int mac_disable(struct cmac *mac, int which) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci u32 val; 5488c2ecf20Sopenharmony_ci int i, port = mac->instance->index; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Reset the port, this also writes the correct WM value */ 5518c2ecf20Sopenharmony_ci mac_reset(mac); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 5548c2ecf20Sopenharmony_ci if (which & MAC_DIRECTION_RX) 5558c2ecf20Sopenharmony_ci val &= ~0x2; 5568c2ecf20Sopenharmony_ci if (which & MAC_DIRECTION_TX) 5578c2ecf20Sopenharmony_ci val &= ~0x1; 5588c2ecf20Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), val); 5598c2ecf20Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Clear stats */ 5628c2ecf20Sopenharmony_ci for (i = 0; i <= 0x3a; ++i) 5638c2ecf20Sopenharmony_ci vsc_write(mac->adapter, CRA(4, port, i), 0); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Clear software counters */ 5668c2ecf20Sopenharmony_ci memset(&mac->stats, 0, sizeof(struct cmac_statistics)); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci u32 v, lo; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci vsc_read(mac->adapter, addr, &v); 5768c2ecf20Sopenharmony_ci lo = *stat; 5778c2ecf20Sopenharmony_ci *stat = *stat - lo + v; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (v == 0) 5808c2ecf20Sopenharmony_ci return; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (v < lo) 5838c2ecf20Sopenharmony_ci *stat += (1ULL << 32); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void port_stats_update(struct cmac *mac) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct { 5898c2ecf20Sopenharmony_ci unsigned int reg; 5908c2ecf20Sopenharmony_ci unsigned int offset; 5918c2ecf20Sopenharmony_ci } hw_stats[] = { 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci#define HW_STAT(reg, stat_name) \ 5948c2ecf20Sopenharmony_ci { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Rx stats */ 5978c2ecf20Sopenharmony_ci HW_STAT(RxUnicast, RxUnicastFramesOK), 5988c2ecf20Sopenharmony_ci HW_STAT(RxMulticast, RxMulticastFramesOK), 5998c2ecf20Sopenharmony_ci HW_STAT(RxBroadcast, RxBroadcastFramesOK), 6008c2ecf20Sopenharmony_ci HW_STAT(Crc, RxFCSErrors), 6018c2ecf20Sopenharmony_ci HW_STAT(RxAlignment, RxAlignErrors), 6028c2ecf20Sopenharmony_ci HW_STAT(RxOversize, RxFrameTooLongErrors), 6038c2ecf20Sopenharmony_ci HW_STAT(RxPause, RxPauseFrames), 6048c2ecf20Sopenharmony_ci HW_STAT(RxJabbers, RxJabberErrors), 6058c2ecf20Sopenharmony_ci HW_STAT(RxFragments, RxRuntErrors), 6068c2ecf20Sopenharmony_ci HW_STAT(RxUndersize, RxRuntErrors), 6078c2ecf20Sopenharmony_ci HW_STAT(RxSymbolCarrier, RxSymbolErrors), 6088c2ecf20Sopenharmony_ci HW_STAT(RxSize1519ToMax, RxJumboFramesOK), 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* Tx stats (skip collision stats as we are full-duplex only) */ 6118c2ecf20Sopenharmony_ci HW_STAT(TxUnicast, TxUnicastFramesOK), 6128c2ecf20Sopenharmony_ci HW_STAT(TxMulticast, TxMulticastFramesOK), 6138c2ecf20Sopenharmony_ci HW_STAT(TxBroadcast, TxBroadcastFramesOK), 6148c2ecf20Sopenharmony_ci HW_STAT(TxPause, TxPauseFrames), 6158c2ecf20Sopenharmony_ci HW_STAT(TxUnderrun, TxUnderrun), 6168c2ecf20Sopenharmony_ci HW_STAT(TxSize1519ToMax, TxJumboFramesOK), 6178c2ecf20Sopenharmony_ci }, *p = hw_stats; 6188c2ecf20Sopenharmony_ci unsigned int port = mac->instance->index; 6198c2ecf20Sopenharmony_ci u64 *stats = (u64 *)&mac->stats; 6208c2ecf20Sopenharmony_ci unsigned int i; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_stats); i++) 6238c2ecf20Sopenharmony_ci rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); 6268c2ecf20Sopenharmony_ci rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); 6278c2ecf20Sopenharmony_ci rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/* 6318c2ecf20Sopenharmony_ci * This function is called periodically to accumulate the current values of the 6328c2ecf20Sopenharmony_ci * RMON counters into the port statistics. Since the counters are only 32 bits 6338c2ecf20Sopenharmony_ci * some of them can overflow in less than a minute at GigE speeds, so this 6348c2ecf20Sopenharmony_ci * function should be called every 30 seconds or so. 6358c2ecf20Sopenharmony_ci * 6368c2ecf20Sopenharmony_ci * To cut down on reading costs we update only the octet counters at each tick 6378c2ecf20Sopenharmony_ci * and do a full update at major ticks, which can be every 30 minutes or more. 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_cistatic const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 6408c2ecf20Sopenharmony_ci int flag) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci if (flag == MAC_STATS_UPDATE_FULL || 6438c2ecf20Sopenharmony_ci mac->instance->ticks >= MAJOR_UPDATE_TICKS) { 6448c2ecf20Sopenharmony_ci port_stats_update(mac); 6458c2ecf20Sopenharmony_ci mac->instance->ticks = 0; 6468c2ecf20Sopenharmony_ci } else { 6478c2ecf20Sopenharmony_ci int port = mac->instance->index; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci rmon_update(mac, REG_RX_OK_BYTES(port), 6508c2ecf20Sopenharmony_ci &mac->stats.RxOctetsOK); 6518c2ecf20Sopenharmony_ci rmon_update(mac, REG_RX_BAD_BYTES(port), 6528c2ecf20Sopenharmony_ci &mac->stats.RxOctetsBad); 6538c2ecf20Sopenharmony_ci rmon_update(mac, REG_TX_OK_BYTES(port), 6548c2ecf20Sopenharmony_ci &mac->stats.TxOctetsOK); 6558c2ecf20Sopenharmony_ci mac->instance->ticks++; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci return &mac->stats; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void mac_destroy(struct cmac *mac) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci kfree(mac); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic const struct cmac_ops vsc7326_ops = { 6668c2ecf20Sopenharmony_ci .destroy = mac_destroy, 6678c2ecf20Sopenharmony_ci .reset = mac_reset, 6688c2ecf20Sopenharmony_ci .interrupt_handler = mac_intr_handler, 6698c2ecf20Sopenharmony_ci .interrupt_enable = mac_intr_enable, 6708c2ecf20Sopenharmony_ci .interrupt_disable = mac_intr_disable, 6718c2ecf20Sopenharmony_ci .interrupt_clear = mac_intr_clear, 6728c2ecf20Sopenharmony_ci .enable = mac_enable, 6738c2ecf20Sopenharmony_ci .disable = mac_disable, 6748c2ecf20Sopenharmony_ci .set_mtu = mac_set_mtu, 6758c2ecf20Sopenharmony_ci .set_rx_mode = mac_set_rx_mode, 6768c2ecf20Sopenharmony_ci .set_speed_duplex_fc = mac_set_speed_duplex_fc, 6778c2ecf20Sopenharmony_ci .statistics_update = mac_update_statistics, 6788c2ecf20Sopenharmony_ci .macaddress_get = mac_get_address, 6798c2ecf20Sopenharmony_ci .macaddress_set = mac_set_address, 6808c2ecf20Sopenharmony_ci}; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic struct cmac *vsc7326_mac_create(adapter_t *adapter, int index) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct cmac *mac; 6858c2ecf20Sopenharmony_ci u32 val; 6868c2ecf20Sopenharmony_ci int i; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); 6898c2ecf20Sopenharmony_ci if (!mac) 6908c2ecf20Sopenharmony_ci return NULL; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci mac->ops = &vsc7326_ops; 6938c2ecf20Sopenharmony_ci mac->instance = (cmac_instance *)(mac + 1); 6948c2ecf20Sopenharmony_ci mac->adapter = adapter; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci mac->instance->index = index; 6978c2ecf20Sopenharmony_ci mac->instance->ticks = 0; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci i = 0; 7008c2ecf20Sopenharmony_ci do { 7018c2ecf20Sopenharmony_ci u32 vhi, vlo; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci vhi = vlo = 0; 7048c2ecf20Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 7058c2ecf20Sopenharmony_ci udelay(1); 7068c2ecf20Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 7078c2ecf20Sopenharmony_ci udelay(5); 7088c2ecf20Sopenharmony_ci val = (vhi << 16) | vlo; 7098c2ecf20Sopenharmony_ci } while ((++i < 10000) && (val == 0xffffffff)); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return mac; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int vsc7326_mac_reset(adapter_t *adapter) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci vsc7326_full_reset(adapter); 7178c2ecf20Sopenharmony_ci (void) run_bist_all(adapter); 7188c2ecf20Sopenharmony_ci run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset)); 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ciconst struct gmac t1_vsc7326_ops = { 7238c2ecf20Sopenharmony_ci .stats_update_period = STATS_TICK_SECS, 7248c2ecf20Sopenharmony_ci .create = vsc7326_mac_create, 7258c2ecf20Sopenharmony_ci .reset = vsc7326_mac_reset, 7268c2ecf20Sopenharmony_ci}; 727