18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* SuperH Ethernet device driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Renesas Electronics Corporation 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2012 Nobuhiro Iwamatsu 68c2ecf20Sopenharmony_ci * Copyright (C) 2008-2014 Renesas Solutions Corp. 78c2ecf20Sopenharmony_ci * Copyright (C) 2013-2017 Cogent Embedded, Inc. 88c2ecf20Sopenharmony_ci * Copyright (C) 2014 Codethink Limited 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/mdio-bitbang.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 248c2ecf20Sopenharmony_ci#include <linux/of_net.h> 258c2ecf20Sopenharmony_ci#include <linux/phy.h> 268c2ecf20Sopenharmony_ci#include <linux/cache.h> 278c2ecf20Sopenharmony_ci#include <linux/io.h> 288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 318c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 328c2ecf20Sopenharmony_ci#include <linux/sh_eth.h> 338c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "sh_eth.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define SH_ETH_DEF_MSG_ENABLE \ 388c2ecf20Sopenharmony_ci (NETIF_MSG_LINK | \ 398c2ecf20Sopenharmony_ci NETIF_MSG_TIMER | \ 408c2ecf20Sopenharmony_ci NETIF_MSG_RX_ERR| \ 418c2ecf20Sopenharmony_ci NETIF_MSG_TX_ERR) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define SH_ETH_OFFSET_INVALID ((u16)~0) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SH_ETH_OFFSET_DEFAULTS \ 468c2ecf20Sopenharmony_ci [0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* use some intentionally tricky logic here to initialize the whole struct to 498c2ecf20Sopenharmony_ci * 0xffff, but then override certain fields, requiring us to indicate that we 508c2ecf20Sopenharmony_ci * "know" that there are overrides in this structure, and we'll need to disable 518c2ecf20Sopenharmony_ci * that warning from W=1 builds. GCC has supported this option since 4.2.X, but 528c2ecf20Sopenharmony_ci * the macros available to do this only define GCC 8. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci__diag_push(); 558c2ecf20Sopenharmony_ci__diag_ignore(GCC, 8, "-Woverride-init", 568c2ecf20Sopenharmony_ci "logic to initialize all and then override some is OK"); 578c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { 588c2ecf20Sopenharmony_ci SH_ETH_OFFSET_DEFAULTS, 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci [EDSR] = 0x0000, 618c2ecf20Sopenharmony_ci [EDMR] = 0x0400, 628c2ecf20Sopenharmony_ci [EDTRR] = 0x0408, 638c2ecf20Sopenharmony_ci [EDRRR] = 0x0410, 648c2ecf20Sopenharmony_ci [EESR] = 0x0428, 658c2ecf20Sopenharmony_ci [EESIPR] = 0x0430, 668c2ecf20Sopenharmony_ci [TDLAR] = 0x0010, 678c2ecf20Sopenharmony_ci [TDFAR] = 0x0014, 688c2ecf20Sopenharmony_ci [TDFXR] = 0x0018, 698c2ecf20Sopenharmony_ci [TDFFR] = 0x001c, 708c2ecf20Sopenharmony_ci [RDLAR] = 0x0030, 718c2ecf20Sopenharmony_ci [RDFAR] = 0x0034, 728c2ecf20Sopenharmony_ci [RDFXR] = 0x0038, 738c2ecf20Sopenharmony_ci [RDFFR] = 0x003c, 748c2ecf20Sopenharmony_ci [TRSCER] = 0x0438, 758c2ecf20Sopenharmony_ci [RMFCR] = 0x0440, 768c2ecf20Sopenharmony_ci [TFTR] = 0x0448, 778c2ecf20Sopenharmony_ci [FDR] = 0x0450, 788c2ecf20Sopenharmony_ci [RMCR] = 0x0458, 798c2ecf20Sopenharmony_ci [RPADIR] = 0x0460, 808c2ecf20Sopenharmony_ci [FCFTR] = 0x0468, 818c2ecf20Sopenharmony_ci [CSMR] = 0x04E4, 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci [ECMR] = 0x0500, 848c2ecf20Sopenharmony_ci [ECSR] = 0x0510, 858c2ecf20Sopenharmony_ci [ECSIPR] = 0x0518, 868c2ecf20Sopenharmony_ci [PIR] = 0x0520, 878c2ecf20Sopenharmony_ci [PSR] = 0x0528, 888c2ecf20Sopenharmony_ci [PIPR] = 0x052c, 898c2ecf20Sopenharmony_ci [RFLR] = 0x0508, 908c2ecf20Sopenharmony_ci [APR] = 0x0554, 918c2ecf20Sopenharmony_ci [MPR] = 0x0558, 928c2ecf20Sopenharmony_ci [PFTCR] = 0x055c, 938c2ecf20Sopenharmony_ci [PFRCR] = 0x0560, 948c2ecf20Sopenharmony_ci [TPAUSER] = 0x0564, 958c2ecf20Sopenharmony_ci [GECMR] = 0x05b0, 968c2ecf20Sopenharmony_ci [BCULR] = 0x05b4, 978c2ecf20Sopenharmony_ci [MAHR] = 0x05c0, 988c2ecf20Sopenharmony_ci [MALR] = 0x05c8, 998c2ecf20Sopenharmony_ci [TROCR] = 0x0700, 1008c2ecf20Sopenharmony_ci [CDCR] = 0x0708, 1018c2ecf20Sopenharmony_ci [LCCR] = 0x0710, 1028c2ecf20Sopenharmony_ci [CEFCR] = 0x0740, 1038c2ecf20Sopenharmony_ci [FRECR] = 0x0748, 1048c2ecf20Sopenharmony_ci [TSFRCR] = 0x0750, 1058c2ecf20Sopenharmony_ci [TLFRCR] = 0x0758, 1068c2ecf20Sopenharmony_ci [RFCR] = 0x0760, 1078c2ecf20Sopenharmony_ci [CERCR] = 0x0768, 1088c2ecf20Sopenharmony_ci [CEECR] = 0x0770, 1098c2ecf20Sopenharmony_ci [MAFCR] = 0x0778, 1108c2ecf20Sopenharmony_ci [RMII_MII] = 0x0790, 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci [ARSTR] = 0x0000, 1138c2ecf20Sopenharmony_ci [TSU_CTRST] = 0x0004, 1148c2ecf20Sopenharmony_ci [TSU_FWEN0] = 0x0010, 1158c2ecf20Sopenharmony_ci [TSU_FWEN1] = 0x0014, 1168c2ecf20Sopenharmony_ci [TSU_FCM] = 0x0018, 1178c2ecf20Sopenharmony_ci [TSU_BSYSL0] = 0x0020, 1188c2ecf20Sopenharmony_ci [TSU_BSYSL1] = 0x0024, 1198c2ecf20Sopenharmony_ci [TSU_PRISL0] = 0x0028, 1208c2ecf20Sopenharmony_ci [TSU_PRISL1] = 0x002c, 1218c2ecf20Sopenharmony_ci [TSU_FWSL0] = 0x0030, 1228c2ecf20Sopenharmony_ci [TSU_FWSL1] = 0x0034, 1238c2ecf20Sopenharmony_ci [TSU_FWSLC] = 0x0038, 1248c2ecf20Sopenharmony_ci [TSU_QTAGM0] = 0x0040, 1258c2ecf20Sopenharmony_ci [TSU_QTAGM1] = 0x0044, 1268c2ecf20Sopenharmony_ci [TSU_FWSR] = 0x0050, 1278c2ecf20Sopenharmony_ci [TSU_FWINMK] = 0x0054, 1288c2ecf20Sopenharmony_ci [TSU_ADQT0] = 0x0048, 1298c2ecf20Sopenharmony_ci [TSU_ADQT1] = 0x004c, 1308c2ecf20Sopenharmony_ci [TSU_VTAG0] = 0x0058, 1318c2ecf20Sopenharmony_ci [TSU_VTAG1] = 0x005c, 1328c2ecf20Sopenharmony_ci [TSU_ADSBSY] = 0x0060, 1338c2ecf20Sopenharmony_ci [TSU_TEN] = 0x0064, 1348c2ecf20Sopenharmony_ci [TSU_POST1] = 0x0070, 1358c2ecf20Sopenharmony_ci [TSU_POST2] = 0x0074, 1368c2ecf20Sopenharmony_ci [TSU_POST3] = 0x0078, 1378c2ecf20Sopenharmony_ci [TSU_POST4] = 0x007c, 1388c2ecf20Sopenharmony_ci [TSU_ADRH0] = 0x0100, 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci [TXNLCR0] = 0x0080, 1418c2ecf20Sopenharmony_ci [TXALCR0] = 0x0084, 1428c2ecf20Sopenharmony_ci [RXNLCR0] = 0x0088, 1438c2ecf20Sopenharmony_ci [RXALCR0] = 0x008c, 1448c2ecf20Sopenharmony_ci [FWNLCR0] = 0x0090, 1458c2ecf20Sopenharmony_ci [FWALCR0] = 0x0094, 1468c2ecf20Sopenharmony_ci [TXNLCR1] = 0x00a0, 1478c2ecf20Sopenharmony_ci [TXALCR1] = 0x00a4, 1488c2ecf20Sopenharmony_ci [RXNLCR1] = 0x00a8, 1498c2ecf20Sopenharmony_ci [RXALCR1] = 0x00ac, 1508c2ecf20Sopenharmony_ci [FWNLCR1] = 0x00b0, 1518c2ecf20Sopenharmony_ci [FWALCR1] = 0x00b4, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = { 1558c2ecf20Sopenharmony_ci SH_ETH_OFFSET_DEFAULTS, 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci [ECMR] = 0x0300, 1588c2ecf20Sopenharmony_ci [RFLR] = 0x0308, 1598c2ecf20Sopenharmony_ci [ECSR] = 0x0310, 1608c2ecf20Sopenharmony_ci [ECSIPR] = 0x0318, 1618c2ecf20Sopenharmony_ci [PIR] = 0x0320, 1628c2ecf20Sopenharmony_ci [PSR] = 0x0328, 1638c2ecf20Sopenharmony_ci [RDMLR] = 0x0340, 1648c2ecf20Sopenharmony_ci [IPGR] = 0x0350, 1658c2ecf20Sopenharmony_ci [APR] = 0x0354, 1668c2ecf20Sopenharmony_ci [MPR] = 0x0358, 1678c2ecf20Sopenharmony_ci [RFCF] = 0x0360, 1688c2ecf20Sopenharmony_ci [TPAUSER] = 0x0364, 1698c2ecf20Sopenharmony_ci [TPAUSECR] = 0x0368, 1708c2ecf20Sopenharmony_ci [MAHR] = 0x03c0, 1718c2ecf20Sopenharmony_ci [MALR] = 0x03c8, 1728c2ecf20Sopenharmony_ci [TROCR] = 0x03d0, 1738c2ecf20Sopenharmony_ci [CDCR] = 0x03d4, 1748c2ecf20Sopenharmony_ci [LCCR] = 0x03d8, 1758c2ecf20Sopenharmony_ci [CNDCR] = 0x03dc, 1768c2ecf20Sopenharmony_ci [CEFCR] = 0x03e4, 1778c2ecf20Sopenharmony_ci [FRECR] = 0x03e8, 1788c2ecf20Sopenharmony_ci [TSFRCR] = 0x03ec, 1798c2ecf20Sopenharmony_ci [TLFRCR] = 0x03f0, 1808c2ecf20Sopenharmony_ci [RFCR] = 0x03f4, 1818c2ecf20Sopenharmony_ci [MAFCR] = 0x03f8, 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci [EDMR] = 0x0200, 1848c2ecf20Sopenharmony_ci [EDTRR] = 0x0208, 1858c2ecf20Sopenharmony_ci [EDRRR] = 0x0210, 1868c2ecf20Sopenharmony_ci [TDLAR] = 0x0218, 1878c2ecf20Sopenharmony_ci [RDLAR] = 0x0220, 1888c2ecf20Sopenharmony_ci [EESR] = 0x0228, 1898c2ecf20Sopenharmony_ci [EESIPR] = 0x0230, 1908c2ecf20Sopenharmony_ci [TRSCER] = 0x0238, 1918c2ecf20Sopenharmony_ci [RMFCR] = 0x0240, 1928c2ecf20Sopenharmony_ci [TFTR] = 0x0248, 1938c2ecf20Sopenharmony_ci [FDR] = 0x0250, 1948c2ecf20Sopenharmony_ci [RMCR] = 0x0258, 1958c2ecf20Sopenharmony_ci [TFUCR] = 0x0264, 1968c2ecf20Sopenharmony_ci [RFOCR] = 0x0268, 1978c2ecf20Sopenharmony_ci [RMIIMODE] = 0x026c, 1988c2ecf20Sopenharmony_ci [FCFTR] = 0x0270, 1998c2ecf20Sopenharmony_ci [TRIMD] = 0x027c, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { 2038c2ecf20Sopenharmony_ci SH_ETH_OFFSET_DEFAULTS, 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci [ECMR] = 0x0100, 2068c2ecf20Sopenharmony_ci [RFLR] = 0x0108, 2078c2ecf20Sopenharmony_ci [ECSR] = 0x0110, 2088c2ecf20Sopenharmony_ci [ECSIPR] = 0x0118, 2098c2ecf20Sopenharmony_ci [PIR] = 0x0120, 2108c2ecf20Sopenharmony_ci [PSR] = 0x0128, 2118c2ecf20Sopenharmony_ci [RDMLR] = 0x0140, 2128c2ecf20Sopenharmony_ci [IPGR] = 0x0150, 2138c2ecf20Sopenharmony_ci [APR] = 0x0154, 2148c2ecf20Sopenharmony_ci [MPR] = 0x0158, 2158c2ecf20Sopenharmony_ci [TPAUSER] = 0x0164, 2168c2ecf20Sopenharmony_ci [RFCF] = 0x0160, 2178c2ecf20Sopenharmony_ci [TPAUSECR] = 0x0168, 2188c2ecf20Sopenharmony_ci [BCFRR] = 0x016c, 2198c2ecf20Sopenharmony_ci [MAHR] = 0x01c0, 2208c2ecf20Sopenharmony_ci [MALR] = 0x01c8, 2218c2ecf20Sopenharmony_ci [TROCR] = 0x01d0, 2228c2ecf20Sopenharmony_ci [CDCR] = 0x01d4, 2238c2ecf20Sopenharmony_ci [LCCR] = 0x01d8, 2248c2ecf20Sopenharmony_ci [CNDCR] = 0x01dc, 2258c2ecf20Sopenharmony_ci [CEFCR] = 0x01e4, 2268c2ecf20Sopenharmony_ci [FRECR] = 0x01e8, 2278c2ecf20Sopenharmony_ci [TSFRCR] = 0x01ec, 2288c2ecf20Sopenharmony_ci [TLFRCR] = 0x01f0, 2298c2ecf20Sopenharmony_ci [RFCR] = 0x01f4, 2308c2ecf20Sopenharmony_ci [MAFCR] = 0x01f8, 2318c2ecf20Sopenharmony_ci [RTRATE] = 0x01fc, 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci [EDMR] = 0x0000, 2348c2ecf20Sopenharmony_ci [EDTRR] = 0x0008, 2358c2ecf20Sopenharmony_ci [EDRRR] = 0x0010, 2368c2ecf20Sopenharmony_ci [TDLAR] = 0x0018, 2378c2ecf20Sopenharmony_ci [RDLAR] = 0x0020, 2388c2ecf20Sopenharmony_ci [EESR] = 0x0028, 2398c2ecf20Sopenharmony_ci [EESIPR] = 0x0030, 2408c2ecf20Sopenharmony_ci [TRSCER] = 0x0038, 2418c2ecf20Sopenharmony_ci [RMFCR] = 0x0040, 2428c2ecf20Sopenharmony_ci [TFTR] = 0x0048, 2438c2ecf20Sopenharmony_ci [FDR] = 0x0050, 2448c2ecf20Sopenharmony_ci [RMCR] = 0x0058, 2458c2ecf20Sopenharmony_ci [TFUCR] = 0x0064, 2468c2ecf20Sopenharmony_ci [RFOCR] = 0x0068, 2478c2ecf20Sopenharmony_ci [FCFTR] = 0x0070, 2488c2ecf20Sopenharmony_ci [RPADIR] = 0x0078, 2498c2ecf20Sopenharmony_ci [TRIMD] = 0x007c, 2508c2ecf20Sopenharmony_ci [RBWAR] = 0x00c8, 2518c2ecf20Sopenharmony_ci [RDFAR] = 0x00cc, 2528c2ecf20Sopenharmony_ci [TBRAR] = 0x00d4, 2538c2ecf20Sopenharmony_ci [TDFAR] = 0x00d8, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { 2578c2ecf20Sopenharmony_ci SH_ETH_OFFSET_DEFAULTS, 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci [EDMR] = 0x0000, 2608c2ecf20Sopenharmony_ci [EDTRR] = 0x0004, 2618c2ecf20Sopenharmony_ci [EDRRR] = 0x0008, 2628c2ecf20Sopenharmony_ci [TDLAR] = 0x000c, 2638c2ecf20Sopenharmony_ci [RDLAR] = 0x0010, 2648c2ecf20Sopenharmony_ci [EESR] = 0x0014, 2658c2ecf20Sopenharmony_ci [EESIPR] = 0x0018, 2668c2ecf20Sopenharmony_ci [TRSCER] = 0x001c, 2678c2ecf20Sopenharmony_ci [RMFCR] = 0x0020, 2688c2ecf20Sopenharmony_ci [TFTR] = 0x0024, 2698c2ecf20Sopenharmony_ci [FDR] = 0x0028, 2708c2ecf20Sopenharmony_ci [RMCR] = 0x002c, 2718c2ecf20Sopenharmony_ci [EDOCR] = 0x0030, 2728c2ecf20Sopenharmony_ci [FCFTR] = 0x0034, 2738c2ecf20Sopenharmony_ci [RPADIR] = 0x0038, 2748c2ecf20Sopenharmony_ci [TRIMD] = 0x003c, 2758c2ecf20Sopenharmony_ci [RBWAR] = 0x0040, 2768c2ecf20Sopenharmony_ci [RDFAR] = 0x0044, 2778c2ecf20Sopenharmony_ci [TBRAR] = 0x004c, 2788c2ecf20Sopenharmony_ci [TDFAR] = 0x0050, 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci [ECMR] = 0x0160, 2818c2ecf20Sopenharmony_ci [ECSR] = 0x0164, 2828c2ecf20Sopenharmony_ci [ECSIPR] = 0x0168, 2838c2ecf20Sopenharmony_ci [PIR] = 0x016c, 2848c2ecf20Sopenharmony_ci [MAHR] = 0x0170, 2858c2ecf20Sopenharmony_ci [MALR] = 0x0174, 2868c2ecf20Sopenharmony_ci [RFLR] = 0x0178, 2878c2ecf20Sopenharmony_ci [PSR] = 0x017c, 2888c2ecf20Sopenharmony_ci [TROCR] = 0x0180, 2898c2ecf20Sopenharmony_ci [CDCR] = 0x0184, 2908c2ecf20Sopenharmony_ci [LCCR] = 0x0188, 2918c2ecf20Sopenharmony_ci [CNDCR] = 0x018c, 2928c2ecf20Sopenharmony_ci [CEFCR] = 0x0194, 2938c2ecf20Sopenharmony_ci [FRECR] = 0x0198, 2948c2ecf20Sopenharmony_ci [TSFRCR] = 0x019c, 2958c2ecf20Sopenharmony_ci [TLFRCR] = 0x01a0, 2968c2ecf20Sopenharmony_ci [RFCR] = 0x01a4, 2978c2ecf20Sopenharmony_ci [MAFCR] = 0x01a8, 2988c2ecf20Sopenharmony_ci [IPGR] = 0x01b4, 2998c2ecf20Sopenharmony_ci [APR] = 0x01b8, 3008c2ecf20Sopenharmony_ci [MPR] = 0x01bc, 3018c2ecf20Sopenharmony_ci [TPAUSER] = 0x01c4, 3028c2ecf20Sopenharmony_ci [BCFR] = 0x01cc, 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci [ARSTR] = 0x0000, 3058c2ecf20Sopenharmony_ci [TSU_CTRST] = 0x0004, 3068c2ecf20Sopenharmony_ci [TSU_FWEN0] = 0x0010, 3078c2ecf20Sopenharmony_ci [TSU_FWEN1] = 0x0014, 3088c2ecf20Sopenharmony_ci [TSU_FCM] = 0x0018, 3098c2ecf20Sopenharmony_ci [TSU_BSYSL0] = 0x0020, 3108c2ecf20Sopenharmony_ci [TSU_BSYSL1] = 0x0024, 3118c2ecf20Sopenharmony_ci [TSU_PRISL0] = 0x0028, 3128c2ecf20Sopenharmony_ci [TSU_PRISL1] = 0x002c, 3138c2ecf20Sopenharmony_ci [TSU_FWSL0] = 0x0030, 3148c2ecf20Sopenharmony_ci [TSU_FWSL1] = 0x0034, 3158c2ecf20Sopenharmony_ci [TSU_FWSLC] = 0x0038, 3168c2ecf20Sopenharmony_ci [TSU_QTAGM0] = 0x0040, 3178c2ecf20Sopenharmony_ci [TSU_QTAGM1] = 0x0044, 3188c2ecf20Sopenharmony_ci [TSU_ADQT0] = 0x0048, 3198c2ecf20Sopenharmony_ci [TSU_ADQT1] = 0x004c, 3208c2ecf20Sopenharmony_ci [TSU_FWSR] = 0x0050, 3218c2ecf20Sopenharmony_ci [TSU_FWINMK] = 0x0054, 3228c2ecf20Sopenharmony_ci [TSU_ADSBSY] = 0x0060, 3238c2ecf20Sopenharmony_ci [TSU_TEN] = 0x0064, 3248c2ecf20Sopenharmony_ci [TSU_POST1] = 0x0070, 3258c2ecf20Sopenharmony_ci [TSU_POST2] = 0x0074, 3268c2ecf20Sopenharmony_ci [TSU_POST3] = 0x0078, 3278c2ecf20Sopenharmony_ci [TSU_POST4] = 0x007c, 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci [TXNLCR0] = 0x0080, 3308c2ecf20Sopenharmony_ci [TXALCR0] = 0x0084, 3318c2ecf20Sopenharmony_ci [RXNLCR0] = 0x0088, 3328c2ecf20Sopenharmony_ci [RXALCR0] = 0x008c, 3338c2ecf20Sopenharmony_ci [FWNLCR0] = 0x0090, 3348c2ecf20Sopenharmony_ci [FWALCR0] = 0x0094, 3358c2ecf20Sopenharmony_ci [TXNLCR1] = 0x00a0, 3368c2ecf20Sopenharmony_ci [TXALCR1] = 0x00a4, 3378c2ecf20Sopenharmony_ci [RXNLCR1] = 0x00a8, 3388c2ecf20Sopenharmony_ci [RXALCR1] = 0x00ac, 3398c2ecf20Sopenharmony_ci [FWNLCR1] = 0x00b0, 3408c2ecf20Sopenharmony_ci [FWALCR1] = 0x00b4, 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci [TSU_ADRH0] = 0x0100, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci__diag_pop(); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev); 3478c2ecf20Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void sh_eth_write(struct net_device *ndev, u32 data, int enum_index) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 3528c2ecf20Sopenharmony_ci u16 offset = mdp->reg_offset[enum_index]; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) 3558c2ecf20Sopenharmony_ci return; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci iowrite32(data, mdp->addr + offset); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic u32 sh_eth_read(struct net_device *ndev, int enum_index) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 3638c2ecf20Sopenharmony_ci u16 offset = mdp->reg_offset[enum_index]; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) 3668c2ecf20Sopenharmony_ci return ~0U; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return ioread32(mdp->addr + offset); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear, 3728c2ecf20Sopenharmony_ci u32 set) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci sh_eth_write(ndev, (sh_eth_read(ndev, enum_index) & ~clear) | set, 3758c2ecf20Sopenharmony_ci enum_index); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic u16 sh_eth_tsu_get_offset(struct sh_eth_private *mdp, int enum_index) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci return mdp->reg_offset[enum_index]; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, 3848c2ecf20Sopenharmony_ci int enum_index) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci u16 offset = sh_eth_tsu_get_offset(mdp, enum_index); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) 3898c2ecf20Sopenharmony_ci return; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci iowrite32(data, mdp->tsu_addr + offset); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci u16 offset = sh_eth_tsu_get_offset(mdp, enum_index); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) 3998c2ecf20Sopenharmony_ci return ~0U; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return ioread32(mdp->tsu_addr + offset); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void sh_eth_soft_swap(char *src, int len) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 4078c2ecf20Sopenharmony_ci u32 *p = (u32 *)src; 4088c2ecf20Sopenharmony_ci u32 *maxp = p + DIV_ROUND_UP(len, sizeof(u32)); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci for (; p < maxp; p++) 4118c2ecf20Sopenharmony_ci *p = swab32(*p); 4128c2ecf20Sopenharmony_ci#endif 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void sh_eth_select_mii(struct net_device *ndev) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 4188c2ecf20Sopenharmony_ci u32 value; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci switch (mdp->phy_interface) { 4218c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII ... PHY_INTERFACE_MODE_RGMII_TXID: 4228c2ecf20Sopenharmony_ci value = 0x3; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 4258c2ecf20Sopenharmony_ci value = 0x2; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 4288c2ecf20Sopenharmony_ci value = 0x1; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 4318c2ecf20Sopenharmony_ci value = 0x0; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci netdev_warn(ndev, 4358c2ecf20Sopenharmony_ci "PHY interface mode was not setup. Set to MII.\n"); 4368c2ecf20Sopenharmony_ci value = 0x1; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci sh_eth_write(ndev, value, RMII_MII); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void sh_eth_set_duplex(struct net_device *ndev) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_DM, mdp->duplex ? ECMR_DM : 0); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset(struct net_device *ndev) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* reset device */ 4558c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, ARSTR_ARST, ARSTR); 4568c2ecf20Sopenharmony_ci mdelay(1); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int sh_eth_soft_reset(struct net_device *ndev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, EDMR_SRST_ETHER); 4628c2ecf20Sopenharmony_ci mdelay(3); 4638c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EDMR, EDMR_SRST_ETHER, 0); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int sh_eth_check_soft_reset(struct net_device *ndev) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int cnt; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci for (cnt = 100; cnt > 0; cnt--) { 4738c2ecf20Sopenharmony_ci if (!(sh_eth_read(ndev, EDMR) & EDMR_SRST_GETHER)) 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci mdelay(1); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci netdev_err(ndev, "Device reset failed\n"); 4798c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int sh_eth_soft_reset_gether(struct net_device *ndev) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 4858c2ecf20Sopenharmony_ci int ret; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci sh_eth_write(ndev, EDSR_ENALL, EDSR); 4888c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EDMR, EDMR_SRST_GETHER, EDMR_SRST_GETHER); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ret = sh_eth_check_soft_reset(ndev); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci return ret; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* Table Init */ 4958c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TDLAR); 4968c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TDFAR); 4978c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TDFXR); 4988c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TDFFR); 4998c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, RDLAR); 5008c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, RDFAR); 5018c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, RDFXR); 5028c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, RDFFR); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Reset HW CRC register */ 5058c2ecf20Sopenharmony_ci if (mdp->cd->csmr) 5068c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, CSMR); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Select MII mode */ 5098c2ecf20Sopenharmony_ci if (mdp->cd->select_mii) 5108c2ecf20Sopenharmony_ci sh_eth_select_mii(ndev); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return ret; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_gether(struct net_device *ndev) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (WARN_ON(!mdp->cd->gecmr)) 5208c2ecf20Sopenharmony_ci return; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci switch (mdp->speed) { 5238c2ecf20Sopenharmony_ci case 10: /* 10BASE */ 5248c2ecf20Sopenharmony_ci sh_eth_write(ndev, GECMR_10, GECMR); 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci case 100:/* 100BASE */ 5278c2ecf20Sopenharmony_ci sh_eth_write(ndev, GECMR_100, GECMR); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case 1000: /* 1000BASE */ 5308c2ecf20Sopenharmony_ci sh_eth_write(ndev, GECMR_1000, GECMR); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 5368c2ecf20Sopenharmony_ci/* R7S72100 */ 5378c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r7s72100_data = { 5388c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci .chip_reset = sh_eth_chip_reset, 5418c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 5468c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD, 5478c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_ICDIP, 5488c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_TWB1IP | EESIPR_TWBIP | EESIPR_TC1IP | 5498c2ecf20Sopenharmony_ci EESIPR_TABTIP | EESIPR_RABTIP | EESIPR_RFCOFIP | 5508c2ecf20Sopenharmony_ci EESIPR_ECIIP | 5518c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 5528c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 5538c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | 5548c2ecf20Sopenharmony_ci EESIPR_RTLFIP | EESIPR_RTSFIP | 5558c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci .tx_check = EESR_TC1 | EESR_FTC, 5588c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 5598c2ecf20Sopenharmony_ci EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE | 5608c2ecf20Sopenharmony_ci EESR_TDE, 5618c2ecf20Sopenharmony_ci .fdr_value = 0x0000070f, 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci .trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5, 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci .no_psr = 1, 5668c2ecf20Sopenharmony_ci .apr = 1, 5678c2ecf20Sopenharmony_ci .mpr = 1, 5688c2ecf20Sopenharmony_ci .tpauser = 1, 5698c2ecf20Sopenharmony_ci .hw_swap = 1, 5708c2ecf20Sopenharmony_ci .rpadir = 1, 5718c2ecf20Sopenharmony_ci .no_trimd = 1, 5728c2ecf20Sopenharmony_ci .no_ade = 1, 5738c2ecf20Sopenharmony_ci .xdfar_rw = 1, 5748c2ecf20Sopenharmony_ci .csmr = 1, 5758c2ecf20Sopenharmony_ci .rx_csum = 1, 5768c2ecf20Sopenharmony_ci .tsu = 1, 5778c2ecf20Sopenharmony_ci .no_tx_cntrs = 1, 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset_r8a7740(struct net_device *ndev) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci sh_eth_chip_reset(ndev); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci sh_eth_select_mii(ndev); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* R8A7740 */ 5888c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r8a7740_data = { 5898c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci .chip_reset = sh_eth_chip_reset_r8a7740, 5928c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 5938c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_gether, 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 5988c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD | ECSR_MPD, 5998c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, 6008c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 6018c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 6028c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 6038c2ecf20Sopenharmony_ci 0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP | 6048c2ecf20Sopenharmony_ci EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP | 6058c2ecf20Sopenharmony_ci EESIPR_CEEFIP | EESIPR_CELFIP | 6068c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 6078c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci .tx_check = EESR_TC1 | EESR_FTC, 6108c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 6118c2ecf20Sopenharmony_ci EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE | 6128c2ecf20Sopenharmony_ci EESR_TDE, 6138c2ecf20Sopenharmony_ci .fdr_value = 0x0000070f, 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci .apr = 1, 6168c2ecf20Sopenharmony_ci .mpr = 1, 6178c2ecf20Sopenharmony_ci .tpauser = 1, 6188c2ecf20Sopenharmony_ci .gecmr = 1, 6198c2ecf20Sopenharmony_ci .bculr = 1, 6208c2ecf20Sopenharmony_ci .hw_swap = 1, 6218c2ecf20Sopenharmony_ci .rpadir = 1, 6228c2ecf20Sopenharmony_ci .no_trimd = 1, 6238c2ecf20Sopenharmony_ci .no_ade = 1, 6248c2ecf20Sopenharmony_ci .xdfar_rw = 1, 6258c2ecf20Sopenharmony_ci .csmr = 1, 6268c2ecf20Sopenharmony_ci .rx_csum = 1, 6278c2ecf20Sopenharmony_ci .tsu = 1, 6288c2ecf20Sopenharmony_ci .select_mii = 1, 6298c2ecf20Sopenharmony_ci .magic = 1, 6308c2ecf20Sopenharmony_ci .cexcr = 1, 6318c2ecf20Sopenharmony_ci}; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/* There is CPU dependent code */ 6348c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_rcar(struct net_device *ndev) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci switch (mdp->speed) { 6398c2ecf20Sopenharmony_ci case 10: /* 10BASE */ 6408c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_ELB, 0); 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci case 100:/* 100BASE */ 6438c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_ELB, ECMR_ELB); 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/* R-Car Gen1 */ 6498c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen1_data = { 6508c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 6538c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_rcar, 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_RCAR, 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 6588c2ecf20Sopenharmony_ci .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD, 6598c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP, 6608c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP | 6618c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 6628c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 6638c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | 6648c2ecf20Sopenharmony_ci EESIPR_RTLFIP | EESIPR_RTSFIP | 6658c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO, 6688c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | 6698c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 6708c2ecf20Sopenharmony_ci .fdr_value = 0x00000f0f, 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci .apr = 1, 6738c2ecf20Sopenharmony_ci .mpr = 1, 6748c2ecf20Sopenharmony_ci .tpauser = 1, 6758c2ecf20Sopenharmony_ci .hw_swap = 1, 6768c2ecf20Sopenharmony_ci .no_xdfar = 1, 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci/* R-Car Gen2 and RZ/G1 */ 6808c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data rcar_gen2_data = { 6818c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 6848c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_rcar, 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_RCAR, 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 6898c2ecf20Sopenharmony_ci .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD, 6908c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP | 6918c2ecf20Sopenharmony_ci ECSIPR_MPDIP, 6928c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP | 6938c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 6948c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 6958c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | 6968c2ecf20Sopenharmony_ci EESIPR_RTLFIP | EESIPR_RTSFIP | 6978c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO, 7008c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | 7018c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 7028c2ecf20Sopenharmony_ci .fdr_value = 0x00000f0f, 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci .trscer_err_mask = DESC_I_RINT8, 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci .apr = 1, 7078c2ecf20Sopenharmony_ci .mpr = 1, 7088c2ecf20Sopenharmony_ci .tpauser = 1, 7098c2ecf20Sopenharmony_ci .hw_swap = 1, 7108c2ecf20Sopenharmony_ci .no_xdfar = 1, 7118c2ecf20Sopenharmony_ci .rmiimode = 1, 7128c2ecf20Sopenharmony_ci .magic = 1, 7138c2ecf20Sopenharmony_ci}; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/* R8A77980 */ 7168c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r8a77980_data = { 7178c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 7208c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_gether, 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 7258c2ecf20Sopenharmony_ci .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | ECSR_MPD, 7268c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP | 7278c2ecf20Sopenharmony_ci ECSIPR_MPDIP, 7288c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 7298c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 7308c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 7318c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | 7328c2ecf20Sopenharmony_ci EESIPR_RTLFIP | EESIPR_RTSFIP | 7338c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CD | EESR_TRO, 7368c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 7378c2ecf20Sopenharmony_ci EESR_RFE | EESR_RDE | EESR_RFRMER | 7388c2ecf20Sopenharmony_ci EESR_TFE | EESR_TDE | EESR_ECI, 7398c2ecf20Sopenharmony_ci .fdr_value = 0x0000070f, 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci .apr = 1, 7428c2ecf20Sopenharmony_ci .mpr = 1, 7438c2ecf20Sopenharmony_ci .tpauser = 1, 7448c2ecf20Sopenharmony_ci .gecmr = 1, 7458c2ecf20Sopenharmony_ci .bculr = 1, 7468c2ecf20Sopenharmony_ci .hw_swap = 1, 7478c2ecf20Sopenharmony_ci .nbst = 1, 7488c2ecf20Sopenharmony_ci .rpadir = 1, 7498c2ecf20Sopenharmony_ci .no_trimd = 1, 7508c2ecf20Sopenharmony_ci .no_ade = 1, 7518c2ecf20Sopenharmony_ci .xdfar_rw = 1, 7528c2ecf20Sopenharmony_ci .csmr = 1, 7538c2ecf20Sopenharmony_ci .rx_csum = 1, 7548c2ecf20Sopenharmony_ci .select_mii = 1, 7558c2ecf20Sopenharmony_ci .magic = 1, 7568c2ecf20Sopenharmony_ci .cexcr = 1, 7578c2ecf20Sopenharmony_ci}; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* R7S9210 */ 7608c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data r7s9210_data = { 7618c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 7648c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_rcar, 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_SH4, 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 7698c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD, 7708c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_ICDIP, 7718c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_TWBIP | EESIPR_TABTIP | EESIPR_RABTIP | 7728c2ecf20Sopenharmony_ci EESIPR_RFCOFIP | EESIPR_ECIIP | EESIPR_FTCIP | 7738c2ecf20Sopenharmony_ci EESIPR_TDEIP | EESIPR_TFUFIP | EESIPR_FRIP | 7748c2ecf20Sopenharmony_ci EESIPR_RDEIP | EESIPR_RFOFIP | EESIPR_CNDIP | 7758c2ecf20Sopenharmony_ci EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP | 7768c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | EESIPR_RTLFIP | 7778c2ecf20Sopenharmony_ci EESIPR_RTSFIP | EESIPR_PREIP | EESIPR_CERFIP, 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO, 7808c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | 7818c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci .fdr_value = 0x0000070f, 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci .trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5, 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci .apr = 1, 7888c2ecf20Sopenharmony_ci .mpr = 1, 7898c2ecf20Sopenharmony_ci .tpauser = 1, 7908c2ecf20Sopenharmony_ci .hw_swap = 1, 7918c2ecf20Sopenharmony_ci .rpadir = 1, 7928c2ecf20Sopenharmony_ci .no_ade = 1, 7938c2ecf20Sopenharmony_ci .xdfar_rw = 1, 7948c2ecf20Sopenharmony_ci}; 7958c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */ 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_sh7724(struct net_device *ndev) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci switch (mdp->speed) { 8028c2ecf20Sopenharmony_ci case 10: /* 10BASE */ 8038c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_RTM, 0); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case 100:/* 100BASE */ 8068c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_RTM, ECMR_RTM); 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/* SH7724 */ 8128c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7724_data = { 8138c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 8168c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_sh7724, 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_SH4, 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 8218c2ecf20Sopenharmony_ci .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD, 8228c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP, 8238c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ADEIP | EESIPR_ECIIP | 8248c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 8258c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 8268c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_RRFIP | 8278c2ecf20Sopenharmony_ci EESIPR_RTLFIP | EESIPR_RTSFIP | 8288c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO, 8318c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | 8328c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci .apr = 1, 8358c2ecf20Sopenharmony_ci .mpr = 1, 8368c2ecf20Sopenharmony_ci .tpauser = 1, 8378c2ecf20Sopenharmony_ci .hw_swap = 1, 8388c2ecf20Sopenharmony_ci .rpadir = 1, 8398c2ecf20Sopenharmony_ci}; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_sh7757(struct net_device *ndev) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci switch (mdp->speed) { 8468c2ecf20Sopenharmony_ci case 10: /* 10BASE */ 8478c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, RTRATE); 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci case 100:/* 100BASE */ 8508c2ecf20Sopenharmony_ci sh_eth_write(ndev, 1, RTRATE); 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci/* SH7757 */ 8568c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data = { 8578c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 8608c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_sh7757, 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_SH4, 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 8658c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 8668c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 8678c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 8688c2ecf20Sopenharmony_ci 0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP | 8698c2ecf20Sopenharmony_ci EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP | 8708c2ecf20Sopenharmony_ci EESIPR_CEEFIP | EESIPR_CELFIP | 8718c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 8728c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_TRO, 8758c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | 8768c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci .irq_flags = IRQF_SHARED, 8798c2ecf20Sopenharmony_ci .apr = 1, 8808c2ecf20Sopenharmony_ci .mpr = 1, 8818c2ecf20Sopenharmony_ci .tpauser = 1, 8828c2ecf20Sopenharmony_ci .hw_swap = 1, 8838c2ecf20Sopenharmony_ci .no_ade = 1, 8848c2ecf20Sopenharmony_ci .rpadir = 1, 8858c2ecf20Sopenharmony_ci .rtrate = 1, 8868c2ecf20Sopenharmony_ci .dual_port = 1, 8878c2ecf20Sopenharmony_ci}; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci#define SH_GIGA_ETH_BASE 0xfee00000UL 8908c2ecf20Sopenharmony_ci#define GIGA_MALR(port) (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8) 8918c2ecf20Sopenharmony_ci#define GIGA_MAHR(port) (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0) 8928c2ecf20Sopenharmony_cistatic void sh_eth_chip_reset_giga(struct net_device *ndev) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci u32 mahr[2], malr[2]; 8958c2ecf20Sopenharmony_ci int i; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* save MAHR and MALR */ 8988c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 8998c2ecf20Sopenharmony_ci malr[i] = ioread32((void *)GIGA_MALR(i)); 9008c2ecf20Sopenharmony_ci mahr[i] = ioread32((void *)GIGA_MAHR(i)); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci sh_eth_chip_reset(ndev); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* restore MAHR and MALR */ 9068c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 9078c2ecf20Sopenharmony_ci iowrite32(malr[i], (void *)GIGA_MALR(i)); 9088c2ecf20Sopenharmony_ci iowrite32(mahr[i], (void *)GIGA_MAHR(i)); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic void sh_eth_set_rate_giga(struct net_device *ndev) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (WARN_ON(!mdp->cd->gecmr)) 9178c2ecf20Sopenharmony_ci return; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci switch (mdp->speed) { 9208c2ecf20Sopenharmony_ci case 10: /* 10BASE */ 9218c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x00000000, GECMR); 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci case 100:/* 100BASE */ 9248c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x00000010, GECMR); 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci case 1000: /* 1000BASE */ 9278c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x00000020, GECMR); 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci/* SH7757(GETHERC) */ 9338c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7757_data_giga = { 9348c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci .chip_reset = sh_eth_chip_reset_giga, 9378c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 9388c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_giga, 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 9438c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD | ECSR_MPD, 9448c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, 9458c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 9468c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 9478c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 9488c2ecf20Sopenharmony_ci 0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP | 9498c2ecf20Sopenharmony_ci EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP | 9508c2ecf20Sopenharmony_ci EESIPR_CEEFIP | EESIPR_CELFIP | 9518c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 9528c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci .tx_check = EESR_TC1 | EESR_FTC, 9558c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 9568c2ecf20Sopenharmony_ci EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE | 9578c2ecf20Sopenharmony_ci EESR_TDE, 9588c2ecf20Sopenharmony_ci .fdr_value = 0x0000072f, 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci .irq_flags = IRQF_SHARED, 9618c2ecf20Sopenharmony_ci .apr = 1, 9628c2ecf20Sopenharmony_ci .mpr = 1, 9638c2ecf20Sopenharmony_ci .tpauser = 1, 9648c2ecf20Sopenharmony_ci .gecmr = 1, 9658c2ecf20Sopenharmony_ci .bculr = 1, 9668c2ecf20Sopenharmony_ci .hw_swap = 1, 9678c2ecf20Sopenharmony_ci .rpadir = 1, 9688c2ecf20Sopenharmony_ci .no_trimd = 1, 9698c2ecf20Sopenharmony_ci .no_ade = 1, 9708c2ecf20Sopenharmony_ci .xdfar_rw = 1, 9718c2ecf20Sopenharmony_ci .tsu = 1, 9728c2ecf20Sopenharmony_ci .cexcr = 1, 9738c2ecf20Sopenharmony_ci .dual_port = 1, 9748c2ecf20Sopenharmony_ci}; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci/* SH7734 */ 9778c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7734_data = { 9788c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci .chip_reset = sh_eth_chip_reset, 9818c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 9828c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_gether, 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 9878c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD | ECSR_MPD, 9888c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, 9898c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 9908c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 9918c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 9928c2ecf20Sopenharmony_ci EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP | 9938c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP | 9948c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 9958c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci .tx_check = EESR_TC1 | EESR_FTC, 9988c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 9998c2ecf20Sopenharmony_ci EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE | 10008c2ecf20Sopenharmony_ci EESR_TDE, 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci .apr = 1, 10038c2ecf20Sopenharmony_ci .mpr = 1, 10048c2ecf20Sopenharmony_ci .tpauser = 1, 10058c2ecf20Sopenharmony_ci .gecmr = 1, 10068c2ecf20Sopenharmony_ci .bculr = 1, 10078c2ecf20Sopenharmony_ci .hw_swap = 1, 10088c2ecf20Sopenharmony_ci .no_trimd = 1, 10098c2ecf20Sopenharmony_ci .no_ade = 1, 10108c2ecf20Sopenharmony_ci .xdfar_rw = 1, 10118c2ecf20Sopenharmony_ci .tsu = 1, 10128c2ecf20Sopenharmony_ci .csmr = 1, 10138c2ecf20Sopenharmony_ci .rx_csum = 1, 10148c2ecf20Sopenharmony_ci .select_mii = 1, 10158c2ecf20Sopenharmony_ci .magic = 1, 10168c2ecf20Sopenharmony_ci .cexcr = 1, 10178c2ecf20Sopenharmony_ci}; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci/* SH7763 */ 10208c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7763_data = { 10218c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset_gether, 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci .chip_reset = sh_eth_chip_reset, 10248c2ecf20Sopenharmony_ci .set_duplex = sh_eth_set_duplex, 10258c2ecf20Sopenharmony_ci .set_rate = sh_eth_set_rate_gether, 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_GIGABIT, 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_GETHER, 10308c2ecf20Sopenharmony_ci .ecsr_value = ECSR_ICD | ECSR_MPD, 10318c2ecf20Sopenharmony_ci .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, 10328c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 10338c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 10348c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 10358c2ecf20Sopenharmony_ci EESIPR_DLCIP | EESIPR_CDIP | EESIPR_TROIP | 10368c2ecf20Sopenharmony_ci EESIPR_RMAFIP | EESIPR_CEEFIP | EESIPR_CELFIP | 10378c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 10388c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci .tx_check = EESR_TC1 | EESR_FTC, 10418c2ecf20Sopenharmony_ci .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | 10428c2ecf20Sopenharmony_ci EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE, 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci .apr = 1, 10458c2ecf20Sopenharmony_ci .mpr = 1, 10468c2ecf20Sopenharmony_ci .tpauser = 1, 10478c2ecf20Sopenharmony_ci .gecmr = 1, 10488c2ecf20Sopenharmony_ci .bculr = 1, 10498c2ecf20Sopenharmony_ci .hw_swap = 1, 10508c2ecf20Sopenharmony_ci .no_trimd = 1, 10518c2ecf20Sopenharmony_ci .no_ade = 1, 10528c2ecf20Sopenharmony_ci .xdfar_rw = 1, 10538c2ecf20Sopenharmony_ci .tsu = 1, 10548c2ecf20Sopenharmony_ci .irq_flags = IRQF_SHARED, 10558c2ecf20Sopenharmony_ci .magic = 1, 10568c2ecf20Sopenharmony_ci .cexcr = 1, 10578c2ecf20Sopenharmony_ci .rx_csum = 1, 10588c2ecf20Sopenharmony_ci .dual_port = 1, 10598c2ecf20Sopenharmony_ci}; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh7619_data = { 10628c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_SH3_SH2, 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 10678c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 10688c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 10698c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 10708c2ecf20Sopenharmony_ci 0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP | 10718c2ecf20Sopenharmony_ci EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP | 10728c2ecf20Sopenharmony_ci EESIPR_CEEFIP | EESIPR_CELFIP | 10738c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 10748c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci .apr = 1, 10778c2ecf20Sopenharmony_ci .mpr = 1, 10788c2ecf20Sopenharmony_ci .tpauser = 1, 10798c2ecf20Sopenharmony_ci .hw_swap = 1, 10808c2ecf20Sopenharmony_ci}; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic struct sh_eth_cpu_data sh771x_data = { 10838c2ecf20Sopenharmony_ci .soft_reset = sh_eth_soft_reset, 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci .register_type = SH_ETH_REG_FAST_SH3_SH2, 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci .edtrr_trns = EDTRR_TRNS_ETHER, 10888c2ecf20Sopenharmony_ci .eesipr_value = EESIPR_RFCOFIP | EESIPR_ECIIP | 10898c2ecf20Sopenharmony_ci EESIPR_FTCIP | EESIPR_TDEIP | EESIPR_TFUFIP | 10908c2ecf20Sopenharmony_ci EESIPR_FRIP | EESIPR_RDEIP | EESIPR_RFOFIP | 10918c2ecf20Sopenharmony_ci 0x0000f000 | EESIPR_CNDIP | EESIPR_DLCIP | 10928c2ecf20Sopenharmony_ci EESIPR_CDIP | EESIPR_TROIP | EESIPR_RMAFIP | 10938c2ecf20Sopenharmony_ci EESIPR_CEEFIP | EESIPR_CELFIP | 10948c2ecf20Sopenharmony_ci EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | 10958c2ecf20Sopenharmony_ci EESIPR_PREIP | EESIPR_CERFIP, 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci .trscer_err_mask = DESC_I_RINT8, 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci .tsu = 1, 11008c2ecf20Sopenharmony_ci .dual_port = 1, 11018c2ecf20Sopenharmony_ci}; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci if (!cd->ecsr_value) 11068c2ecf20Sopenharmony_ci cd->ecsr_value = DEFAULT_ECSR_INIT; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (!cd->ecsipr_value) 11098c2ecf20Sopenharmony_ci cd->ecsipr_value = DEFAULT_ECSIPR_INIT; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (!cd->fcftr_value) 11128c2ecf20Sopenharmony_ci cd->fcftr_value = DEFAULT_FIFO_F_D_RFF | 11138c2ecf20Sopenharmony_ci DEFAULT_FIFO_F_D_RFD; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!cd->fdr_value) 11168c2ecf20Sopenharmony_ci cd->fdr_value = DEFAULT_FDR_INIT; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (!cd->tx_check) 11198c2ecf20Sopenharmony_ci cd->tx_check = DEFAULT_TX_CHECK; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (!cd->eesr_err_check) 11228c2ecf20Sopenharmony_ci cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (!cd->trscer_err_mask) 11258c2ecf20Sopenharmony_ci cd->trscer_err_mask = DEFAULT_TRSCER_ERR_MASK; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic void sh_eth_set_receive_align(struct sk_buff *skb) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (reserve) 11338c2ecf20Sopenharmony_ci skb_reserve(skb, SH_ETH_RX_ALIGN - reserve); 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci/* Program the hardware MAC address from dev->dev_addr. */ 11378c2ecf20Sopenharmony_cistatic void update_mac_address(struct net_device *ndev) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci sh_eth_write(ndev, 11408c2ecf20Sopenharmony_ci (ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | 11418c2ecf20Sopenharmony_ci (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR); 11428c2ecf20Sopenharmony_ci sh_eth_write(ndev, 11438c2ecf20Sopenharmony_ci (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci/* Get MAC address from SuperH MAC address register 11478c2ecf20Sopenharmony_ci * 11488c2ecf20Sopenharmony_ci * SuperH's Ethernet device doesn't have 'ROM' to MAC address. 11498c2ecf20Sopenharmony_ci * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g). 11508c2ecf20Sopenharmony_ci * When you want use this device, you must set MAC address in bootloader. 11518c2ecf20Sopenharmony_ci * 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_cistatic void read_mac_address(struct net_device *ndev, unsigned char *mac) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) { 11568c2ecf20Sopenharmony_ci memcpy(ndev->dev_addr, mac, ETH_ALEN); 11578c2ecf20Sopenharmony_ci } else { 11588c2ecf20Sopenharmony_ci u32 mahr = sh_eth_read(ndev, MAHR); 11598c2ecf20Sopenharmony_ci u32 malr = sh_eth_read(ndev, MALR); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci ndev->dev_addr[0] = (mahr >> 24) & 0xFF; 11628c2ecf20Sopenharmony_ci ndev->dev_addr[1] = (mahr >> 16) & 0xFF; 11638c2ecf20Sopenharmony_ci ndev->dev_addr[2] = (mahr >> 8) & 0xFF; 11648c2ecf20Sopenharmony_ci ndev->dev_addr[3] = (mahr >> 0) & 0xFF; 11658c2ecf20Sopenharmony_ci ndev->dev_addr[4] = (malr >> 8) & 0xFF; 11668c2ecf20Sopenharmony_ci ndev->dev_addr[5] = (malr >> 0) & 0xFF; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistruct bb_info { 11718c2ecf20Sopenharmony_ci void (*set_gate)(void *addr); 11728c2ecf20Sopenharmony_ci struct mdiobb_ctrl ctrl; 11738c2ecf20Sopenharmony_ci void *addr; 11748c2ecf20Sopenharmony_ci}; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic void sh_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 11798c2ecf20Sopenharmony_ci u32 pir; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (bitbang->set_gate) 11828c2ecf20Sopenharmony_ci bitbang->set_gate(bitbang->addr); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci pir = ioread32(bitbang->addr); 11858c2ecf20Sopenharmony_ci if (set) 11868c2ecf20Sopenharmony_ci pir |= mask; 11878c2ecf20Sopenharmony_ci else 11888c2ecf20Sopenharmony_ci pir &= ~mask; 11898c2ecf20Sopenharmony_ci iowrite32(pir, bitbang->addr); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci/* Data I/O pin control */ 11938c2ecf20Sopenharmony_cistatic void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci sh_mdio_ctrl(ctrl, PIR_MMD, bit); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci/* Set bit data*/ 11998c2ecf20Sopenharmony_cistatic void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci sh_mdio_ctrl(ctrl, PIR_MDO, bit); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/* Get bit data*/ 12058c2ecf20Sopenharmony_cistatic int sh_get_mdio(struct mdiobb_ctrl *ctrl) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (bitbang->set_gate) 12108c2ecf20Sopenharmony_ci bitbang->set_gate(bitbang->addr); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return (ioread32(bitbang->addr) & PIR_MDI) != 0; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci/* MDC pin control */ 12168c2ecf20Sopenharmony_cistatic void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci sh_mdio_ctrl(ctrl, PIR_MDC, bit); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/* mdio bus control struct */ 12228c2ecf20Sopenharmony_cistatic const struct mdiobb_ops bb_ops = { 12238c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12248c2ecf20Sopenharmony_ci .set_mdc = sh_mdc_ctrl, 12258c2ecf20Sopenharmony_ci .set_mdio_dir = sh_mmd_ctrl, 12268c2ecf20Sopenharmony_ci .set_mdio_data = sh_set_mdio, 12278c2ecf20Sopenharmony_ci .get_mdio_data = sh_get_mdio, 12288c2ecf20Sopenharmony_ci}; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci/* free Tx skb function */ 12318c2ecf20Sopenharmony_cistatic int sh_eth_tx_free(struct net_device *ndev, bool sent_only) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 12348c2ecf20Sopenharmony_ci struct sh_eth_txdesc *txdesc; 12358c2ecf20Sopenharmony_ci int free_num = 0; 12368c2ecf20Sopenharmony_ci int entry; 12378c2ecf20Sopenharmony_ci bool sent; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) { 12408c2ecf20Sopenharmony_ci entry = mdp->dirty_tx % mdp->num_tx_ring; 12418c2ecf20Sopenharmony_ci txdesc = &mdp->tx_ring[entry]; 12428c2ecf20Sopenharmony_ci sent = !(txdesc->status & cpu_to_le32(TD_TACT)); 12438c2ecf20Sopenharmony_ci if (sent_only && !sent) 12448c2ecf20Sopenharmony_ci break; 12458c2ecf20Sopenharmony_ci /* TACT bit must be checked before all the following reads */ 12468c2ecf20Sopenharmony_ci dma_rmb(); 12478c2ecf20Sopenharmony_ci netif_info(mdp, tx_done, ndev, 12488c2ecf20Sopenharmony_ci "tx entry %d status 0x%08x\n", 12498c2ecf20Sopenharmony_ci entry, le32_to_cpu(txdesc->status)); 12508c2ecf20Sopenharmony_ci /* Free the original skb. */ 12518c2ecf20Sopenharmony_ci if (mdp->tx_skbuff[entry]) { 12528c2ecf20Sopenharmony_ci dma_unmap_single(&mdp->pdev->dev, 12538c2ecf20Sopenharmony_ci le32_to_cpu(txdesc->addr), 12548c2ecf20Sopenharmony_ci le32_to_cpu(txdesc->len) >> 16, 12558c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12568c2ecf20Sopenharmony_ci dev_kfree_skb_irq(mdp->tx_skbuff[entry]); 12578c2ecf20Sopenharmony_ci mdp->tx_skbuff[entry] = NULL; 12588c2ecf20Sopenharmony_ci free_num++; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci txdesc->status = cpu_to_le32(TD_TFP); 12618c2ecf20Sopenharmony_ci if (entry >= mdp->num_tx_ring - 1) 12628c2ecf20Sopenharmony_ci txdesc->status |= cpu_to_le32(TD_TDLE); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (sent) { 12658c2ecf20Sopenharmony_ci ndev->stats.tx_packets++; 12668c2ecf20Sopenharmony_ci ndev->stats.tx_bytes += le32_to_cpu(txdesc->len) >> 16; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci return free_num; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci/* free skb and descriptor buffer */ 12738c2ecf20Sopenharmony_cistatic void sh_eth_ring_free(struct net_device *ndev) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 12768c2ecf20Sopenharmony_ci int ringsize, i; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (mdp->rx_ring) { 12798c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_rx_ring; i++) { 12808c2ecf20Sopenharmony_ci if (mdp->rx_skbuff[i]) { 12818c2ecf20Sopenharmony_ci struct sh_eth_rxdesc *rxdesc = &mdp->rx_ring[i]; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci dma_unmap_single(&mdp->pdev->dev, 12848c2ecf20Sopenharmony_ci le32_to_cpu(rxdesc->addr), 12858c2ecf20Sopenharmony_ci ALIGN(mdp->rx_buf_sz, 32), 12868c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; 12908c2ecf20Sopenharmony_ci dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->rx_ring, 12918c2ecf20Sopenharmony_ci mdp->rx_desc_dma); 12928c2ecf20Sopenharmony_ci mdp->rx_ring = NULL; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* Free Rx skb ringbuffer */ 12968c2ecf20Sopenharmony_ci if (mdp->rx_skbuff) { 12978c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_rx_ring; i++) 12988c2ecf20Sopenharmony_ci dev_kfree_skb(mdp->rx_skbuff[i]); 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci kfree(mdp->rx_skbuff); 13018c2ecf20Sopenharmony_ci mdp->rx_skbuff = NULL; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (mdp->tx_ring) { 13048c2ecf20Sopenharmony_ci sh_eth_tx_free(ndev, false); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; 13078c2ecf20Sopenharmony_ci dma_free_coherent(&mdp->pdev->dev, ringsize, mdp->tx_ring, 13088c2ecf20Sopenharmony_ci mdp->tx_desc_dma); 13098c2ecf20Sopenharmony_ci mdp->tx_ring = NULL; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Free Tx skb ringbuffer */ 13138c2ecf20Sopenharmony_ci kfree(mdp->tx_skbuff); 13148c2ecf20Sopenharmony_ci mdp->tx_skbuff = NULL; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci/* format skb and descriptor buffer */ 13188c2ecf20Sopenharmony_cistatic void sh_eth_ring_format(struct net_device *ndev) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 13218c2ecf20Sopenharmony_ci int i; 13228c2ecf20Sopenharmony_ci struct sk_buff *skb; 13238c2ecf20Sopenharmony_ci struct sh_eth_rxdesc *rxdesc = NULL; 13248c2ecf20Sopenharmony_ci struct sh_eth_txdesc *txdesc = NULL; 13258c2ecf20Sopenharmony_ci int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; 13268c2ecf20Sopenharmony_ci int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; 13278c2ecf20Sopenharmony_ci int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1; 13288c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 13298c2ecf20Sopenharmony_ci u32 buf_len; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci mdp->cur_rx = 0; 13328c2ecf20Sopenharmony_ci mdp->cur_tx = 0; 13338c2ecf20Sopenharmony_ci mdp->dirty_rx = 0; 13348c2ecf20Sopenharmony_ci mdp->dirty_tx = 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci memset(mdp->rx_ring, 0, rx_ringsize); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* build Rx ring buffer */ 13398c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_rx_ring; i++) { 13408c2ecf20Sopenharmony_ci /* skb */ 13418c2ecf20Sopenharmony_ci mdp->rx_skbuff[i] = NULL; 13428c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(ndev, skbuff_size); 13438c2ecf20Sopenharmony_ci if (skb == NULL) 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci sh_eth_set_receive_align(skb); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci /* The size of the buffer is a multiple of 32 bytes. */ 13488c2ecf20Sopenharmony_ci buf_len = ALIGN(mdp->rx_buf_sz, 32); 13498c2ecf20Sopenharmony_ci dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, buf_len, 13508c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 13518c2ecf20Sopenharmony_ci if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) { 13528c2ecf20Sopenharmony_ci kfree_skb(skb); 13538c2ecf20Sopenharmony_ci break; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci mdp->rx_skbuff[i] = skb; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci /* RX descriptor */ 13588c2ecf20Sopenharmony_ci rxdesc = &mdp->rx_ring[i]; 13598c2ecf20Sopenharmony_ci rxdesc->len = cpu_to_le32(buf_len << 16); 13608c2ecf20Sopenharmony_ci rxdesc->addr = cpu_to_le32(dma_addr); 13618c2ecf20Sopenharmony_ci rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* Rx descriptor address set */ 13648c2ecf20Sopenharmony_ci if (i == 0) { 13658c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR); 13668c2ecf20Sopenharmony_ci if (mdp->cd->xdfar_rw) 13678c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci mdp->dirty_rx = (u32) (i - mdp->num_rx_ring); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* Mark the last entry as wrapping the ring. */ 13748c2ecf20Sopenharmony_ci if (rxdesc) 13758c2ecf20Sopenharmony_ci rxdesc->status |= cpu_to_le32(RD_RDLE); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci memset(mdp->tx_ring, 0, tx_ringsize); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* build Tx ring buffer */ 13808c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_tx_ring; i++) { 13818c2ecf20Sopenharmony_ci mdp->tx_skbuff[i] = NULL; 13828c2ecf20Sopenharmony_ci txdesc = &mdp->tx_ring[i]; 13838c2ecf20Sopenharmony_ci txdesc->status = cpu_to_le32(TD_TFP); 13848c2ecf20Sopenharmony_ci txdesc->len = cpu_to_le32(0); 13858c2ecf20Sopenharmony_ci if (i == 0) { 13868c2ecf20Sopenharmony_ci /* Tx descriptor address set */ 13878c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR); 13888c2ecf20Sopenharmony_ci if (mdp->cd->xdfar_rw) 13898c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR); 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci txdesc->status |= cpu_to_le32(TD_TDLE); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci/* Get skb and descriptor buffer */ 13978c2ecf20Sopenharmony_cistatic int sh_eth_ring_init(struct net_device *ndev) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 14008c2ecf20Sopenharmony_ci int rx_ringsize, tx_ringsize; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the 14038c2ecf20Sopenharmony_ci * card needs room to do 8 byte alignment, +2 so we can reserve 14048c2ecf20Sopenharmony_ci * the first 2 bytes, and +16 gets room for the status word from the 14058c2ecf20Sopenharmony_ci * card. 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_ci mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ : 14088c2ecf20Sopenharmony_ci (((ndev->mtu + 26 + 7) & ~7) + 2 + 16)); 14098c2ecf20Sopenharmony_ci if (mdp->cd->rpadir) 14108c2ecf20Sopenharmony_ci mdp->rx_buf_sz += NET_IP_ALIGN; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* Allocate RX and TX skb rings */ 14138c2ecf20Sopenharmony_ci mdp->rx_skbuff = kcalloc(mdp->num_rx_ring, sizeof(*mdp->rx_skbuff), 14148c2ecf20Sopenharmony_ci GFP_KERNEL); 14158c2ecf20Sopenharmony_ci if (!mdp->rx_skbuff) 14168c2ecf20Sopenharmony_ci return -ENOMEM; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci mdp->tx_skbuff = kcalloc(mdp->num_tx_ring, sizeof(*mdp->tx_skbuff), 14198c2ecf20Sopenharmony_ci GFP_KERNEL); 14208c2ecf20Sopenharmony_ci if (!mdp->tx_skbuff) 14218c2ecf20Sopenharmony_ci goto ring_free; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* Allocate all Rx descriptors. */ 14248c2ecf20Sopenharmony_ci rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; 14258c2ecf20Sopenharmony_ci mdp->rx_ring = dma_alloc_coherent(&mdp->pdev->dev, rx_ringsize, 14268c2ecf20Sopenharmony_ci &mdp->rx_desc_dma, GFP_KERNEL); 14278c2ecf20Sopenharmony_ci if (!mdp->rx_ring) 14288c2ecf20Sopenharmony_ci goto ring_free; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci mdp->dirty_rx = 0; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* Allocate all Tx descriptors. */ 14338c2ecf20Sopenharmony_ci tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; 14348c2ecf20Sopenharmony_ci mdp->tx_ring = dma_alloc_coherent(&mdp->pdev->dev, tx_ringsize, 14358c2ecf20Sopenharmony_ci &mdp->tx_desc_dma, GFP_KERNEL); 14368c2ecf20Sopenharmony_ci if (!mdp->tx_ring) 14378c2ecf20Sopenharmony_ci goto ring_free; 14388c2ecf20Sopenharmony_ci return 0; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ciring_free: 14418c2ecf20Sopenharmony_ci /* Free Rx and Tx skb ring buffer and DMA buffer */ 14428c2ecf20Sopenharmony_ci sh_eth_ring_free(ndev); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci return -ENOMEM; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic int sh_eth_dev_init(struct net_device *ndev) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 14508c2ecf20Sopenharmony_ci int ret; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* Soft Reset */ 14538c2ecf20Sopenharmony_ci ret = mdp->cd->soft_reset(ndev); 14548c2ecf20Sopenharmony_ci if (ret) 14558c2ecf20Sopenharmony_ci return ret; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (mdp->cd->rmiimode) 14588c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x1, RMIIMODE); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* Descriptor format */ 14618c2ecf20Sopenharmony_ci sh_eth_ring_format(ndev); 14628c2ecf20Sopenharmony_ci if (mdp->cd->rpadir) 14638c2ecf20Sopenharmony_ci sh_eth_write(ndev, NET_IP_ALIGN << 16, RPADIR); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* all sh_eth int mask */ 14668c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, EESIPR); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN) 14698c2ecf20Sopenharmony_ci if (mdp->cd->hw_swap) 14708c2ecf20Sopenharmony_ci sh_eth_write(ndev, EDMR_EL, EDMR); 14718c2ecf20Sopenharmony_ci else 14728c2ecf20Sopenharmony_ci#endif 14738c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, EDMR); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* FIFO size set */ 14768c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->fdr_value, FDR); 14778c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TFTR); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* Frame recv control (enable multiple-packets per rx irq) */ 14808c2ecf20Sopenharmony_ci sh_eth_write(ndev, RMCR_RNC, RMCR); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->trscer_err_mask, TRSCER); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* DMA transfer burst mode */ 14858c2ecf20Sopenharmony_ci if (mdp->cd->nbst) 14868c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EDMR, EDMR_NBST, EDMR_NBST); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* Burst cycle count upper-limit */ 14898c2ecf20Sopenharmony_ci if (mdp->cd->bculr) 14908c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x800, BCULR); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->fcftr_value, FCFTR); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (!mdp->cd->no_trimd) 14958c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, TRIMD); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* Recv frame limit set register */ 14988c2ecf20Sopenharmony_ci sh_eth_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, 14998c2ecf20Sopenharmony_ci RFLR); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EESR, 0, 0); 15028c2ecf20Sopenharmony_ci mdp->irq_enabled = true; 15038c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci /* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */ 15068c2ecf20Sopenharmony_ci sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | 15078c2ecf20Sopenharmony_ci (ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) | 15088c2ecf20Sopenharmony_ci ECMR_TE | ECMR_RE, ECMR); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (mdp->cd->set_rate) 15118c2ecf20Sopenharmony_ci mdp->cd->set_rate(ndev); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* E-MAC Status Register clear */ 15148c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->ecsr_value, ECSR); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* E-MAC Interrupt Enable register */ 15178c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* Set MAC address */ 15208c2ecf20Sopenharmony_ci update_mac_address(ndev); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci /* mask reset */ 15238c2ecf20Sopenharmony_ci if (mdp->cd->apr) 15248c2ecf20Sopenharmony_ci sh_eth_write(ndev, 1, APR); 15258c2ecf20Sopenharmony_ci if (mdp->cd->mpr) 15268c2ecf20Sopenharmony_ci sh_eth_write(ndev, 1, MPR); 15278c2ecf20Sopenharmony_ci if (mdp->cd->tpauser) 15288c2ecf20Sopenharmony_ci sh_eth_write(ndev, TPAUSER_UNLIMITED, TPAUSER); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* Setting the Rx mode will start the Rx process. */ 15318c2ecf20Sopenharmony_ci sh_eth_write(ndev, EDRRR_R, EDRRR); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci return ret; 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_cistatic void sh_eth_dev_exit(struct net_device *ndev) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 15398c2ecf20Sopenharmony_ci int i; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* Deactivate all TX descriptors, so DMA should stop at next 15428c2ecf20Sopenharmony_ci * packet boundary if it's currently running 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_tx_ring; i++) 15458c2ecf20Sopenharmony_ci mdp->tx_ring[i].status &= ~cpu_to_le32(TD_TACT); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci /* Disable TX FIFO egress to MAC */ 15488c2ecf20Sopenharmony_ci sh_eth_rcv_snd_disable(ndev); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci /* Stop RX DMA at next packet boundary */ 15518c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, EDRRR); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci /* Aside from TX DMA, we can't tell when the hardware is 15548c2ecf20Sopenharmony_ci * really stopped, so we need to reset to make sure. 15558c2ecf20Sopenharmony_ci * Before doing that, wait for long enough to *probably* 15568c2ecf20Sopenharmony_ci * finish transmitting the last packet and poll stats. 15578c2ecf20Sopenharmony_ci */ 15588c2ecf20Sopenharmony_ci msleep(2); /* max frame time at 10 Mbps < 1250 us */ 15598c2ecf20Sopenharmony_ci sh_eth_get_stats(ndev); 15608c2ecf20Sopenharmony_ci mdp->cd->soft_reset(ndev); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Set the RMII mode again if required */ 15638c2ecf20Sopenharmony_ci if (mdp->cd->rmiimode) 15648c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x1, RMIIMODE); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci /* Set MAC address again */ 15678c2ecf20Sopenharmony_ci update_mac_address(ndev); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic void sh_eth_rx_csum(struct sk_buff *skb) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci u8 *hw_csum; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci /* The hardware checksum is 2 bytes appended to packet data */ 15758c2ecf20Sopenharmony_ci if (unlikely(skb->len < sizeof(__sum16))) 15768c2ecf20Sopenharmony_ci return; 15778c2ecf20Sopenharmony_ci hw_csum = skb_tail_pointer(skb) - sizeof(__sum16); 15788c2ecf20Sopenharmony_ci skb->csum = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); 15798c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 15808c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - sizeof(__sum16)); 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci/* Packet receive function */ 15848c2ecf20Sopenharmony_cistatic int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 15878c2ecf20Sopenharmony_ci struct sh_eth_rxdesc *rxdesc; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci int entry = mdp->cur_rx % mdp->num_rx_ring; 15908c2ecf20Sopenharmony_ci int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx; 15918c2ecf20Sopenharmony_ci int limit; 15928c2ecf20Sopenharmony_ci struct sk_buff *skb; 15938c2ecf20Sopenharmony_ci u32 desc_status; 15948c2ecf20Sopenharmony_ci int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1; 15958c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 15968c2ecf20Sopenharmony_ci u16 pkt_len; 15978c2ecf20Sopenharmony_ci u32 buf_len; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci boguscnt = min(boguscnt, *quota); 16008c2ecf20Sopenharmony_ci limit = boguscnt; 16018c2ecf20Sopenharmony_ci rxdesc = &mdp->rx_ring[entry]; 16028c2ecf20Sopenharmony_ci while (!(rxdesc->status & cpu_to_le32(RD_RACT))) { 16038c2ecf20Sopenharmony_ci /* RACT bit must be checked before all the following reads */ 16048c2ecf20Sopenharmony_ci dma_rmb(); 16058c2ecf20Sopenharmony_ci desc_status = le32_to_cpu(rxdesc->status); 16068c2ecf20Sopenharmony_ci pkt_len = le32_to_cpu(rxdesc->len) & RD_RFL; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (--boguscnt < 0) 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci netif_info(mdp, rx_status, ndev, 16128c2ecf20Sopenharmony_ci "rx entry %d status 0x%08x len %d\n", 16138c2ecf20Sopenharmony_ci entry, desc_status, pkt_len); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (!(desc_status & RDFEND)) 16168c2ecf20Sopenharmony_ci ndev->stats.rx_length_errors++; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci /* In case of almost all GETHER/ETHERs, the Receive Frame State 16198c2ecf20Sopenharmony_ci * (RFS) bits in the Receive Descriptor 0 are from bit 9 to 16208c2ecf20Sopenharmony_ci * bit 0. However, in case of the R8A7740 and R7S72100 16218c2ecf20Sopenharmony_ci * the RFS bits are from bit 25 to bit 16. So, the 16228c2ecf20Sopenharmony_ci * driver needs right shifting by 16. 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_ci if (mdp->cd->csmr) 16258c2ecf20Sopenharmony_ci desc_status >>= 16; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci skb = mdp->rx_skbuff[entry]; 16288c2ecf20Sopenharmony_ci if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | 16298c2ecf20Sopenharmony_ci RD_RFS5 | RD_RFS6 | RD_RFS10)) { 16308c2ecf20Sopenharmony_ci ndev->stats.rx_errors++; 16318c2ecf20Sopenharmony_ci if (desc_status & RD_RFS1) 16328c2ecf20Sopenharmony_ci ndev->stats.rx_crc_errors++; 16338c2ecf20Sopenharmony_ci if (desc_status & RD_RFS2) 16348c2ecf20Sopenharmony_ci ndev->stats.rx_frame_errors++; 16358c2ecf20Sopenharmony_ci if (desc_status & RD_RFS3) 16368c2ecf20Sopenharmony_ci ndev->stats.rx_length_errors++; 16378c2ecf20Sopenharmony_ci if (desc_status & RD_RFS4) 16388c2ecf20Sopenharmony_ci ndev->stats.rx_length_errors++; 16398c2ecf20Sopenharmony_ci if (desc_status & RD_RFS6) 16408c2ecf20Sopenharmony_ci ndev->stats.rx_missed_errors++; 16418c2ecf20Sopenharmony_ci if (desc_status & RD_RFS10) 16428c2ecf20Sopenharmony_ci ndev->stats.rx_over_errors++; 16438c2ecf20Sopenharmony_ci } else if (skb) { 16448c2ecf20Sopenharmony_ci dma_addr = le32_to_cpu(rxdesc->addr); 16458c2ecf20Sopenharmony_ci if (!mdp->cd->hw_swap) 16468c2ecf20Sopenharmony_ci sh_eth_soft_swap( 16478c2ecf20Sopenharmony_ci phys_to_virt(ALIGN(dma_addr, 4)), 16488c2ecf20Sopenharmony_ci pkt_len + 2); 16498c2ecf20Sopenharmony_ci mdp->rx_skbuff[entry] = NULL; 16508c2ecf20Sopenharmony_ci if (mdp->cd->rpadir) 16518c2ecf20Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 16528c2ecf20Sopenharmony_ci dma_unmap_single(&mdp->pdev->dev, dma_addr, 16538c2ecf20Sopenharmony_ci ALIGN(mdp->rx_buf_sz, 32), 16548c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 16558c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 16568c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 16578c2ecf20Sopenharmony_ci if (ndev->features & NETIF_F_RXCSUM) 16588c2ecf20Sopenharmony_ci sh_eth_rx_csum(skb); 16598c2ecf20Sopenharmony_ci netif_receive_skb(skb); 16608c2ecf20Sopenharmony_ci ndev->stats.rx_packets++; 16618c2ecf20Sopenharmony_ci ndev->stats.rx_bytes += pkt_len; 16628c2ecf20Sopenharmony_ci if (desc_status & RD_RFS8) 16638c2ecf20Sopenharmony_ci ndev->stats.multicast++; 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci entry = (++mdp->cur_rx) % mdp->num_rx_ring; 16668c2ecf20Sopenharmony_ci rxdesc = &mdp->rx_ring[entry]; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci /* Refill the Rx ring buffers. */ 16708c2ecf20Sopenharmony_ci for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) { 16718c2ecf20Sopenharmony_ci entry = mdp->dirty_rx % mdp->num_rx_ring; 16728c2ecf20Sopenharmony_ci rxdesc = &mdp->rx_ring[entry]; 16738c2ecf20Sopenharmony_ci /* The size of the buffer is 32 byte boundary. */ 16748c2ecf20Sopenharmony_ci buf_len = ALIGN(mdp->rx_buf_sz, 32); 16758c2ecf20Sopenharmony_ci rxdesc->len = cpu_to_le32(buf_len << 16); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (mdp->rx_skbuff[entry] == NULL) { 16788c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(ndev, skbuff_size); 16798c2ecf20Sopenharmony_ci if (skb == NULL) 16808c2ecf20Sopenharmony_ci break; /* Better luck next round. */ 16818c2ecf20Sopenharmony_ci sh_eth_set_receive_align(skb); 16828c2ecf20Sopenharmony_ci dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, 16838c2ecf20Sopenharmony_ci buf_len, DMA_FROM_DEVICE); 16848c2ecf20Sopenharmony_ci if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) { 16858c2ecf20Sopenharmony_ci kfree_skb(skb); 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci mdp->rx_skbuff[entry] = skb; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 16918c2ecf20Sopenharmony_ci rxdesc->addr = cpu_to_le32(dma_addr); 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci dma_wmb(); /* RACT bit must be set after all the above writes */ 16948c2ecf20Sopenharmony_ci if (entry >= mdp->num_rx_ring - 1) 16958c2ecf20Sopenharmony_ci rxdesc->status |= 16968c2ecf20Sopenharmony_ci cpu_to_le32(RD_RACT | RD_RFP | RD_RDLE); 16978c2ecf20Sopenharmony_ci else 16988c2ecf20Sopenharmony_ci rxdesc->status |= cpu_to_le32(RD_RACT | RD_RFP); 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* Restart Rx engine if stopped. */ 17028c2ecf20Sopenharmony_ci /* If we don't need to check status, don't. -KDU */ 17038c2ecf20Sopenharmony_ci if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) { 17048c2ecf20Sopenharmony_ci /* fix the values for the next receiving if RDE is set */ 17058c2ecf20Sopenharmony_ci if (intr_status & EESR_RDE && !mdp->cd->no_xdfar) { 17068c2ecf20Sopenharmony_ci u32 count = (sh_eth_read(ndev, RDFAR) - 17078c2ecf20Sopenharmony_ci sh_eth_read(ndev, RDLAR)) >> 4; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci mdp->cur_rx = count; 17108c2ecf20Sopenharmony_ci mdp->dirty_rx = count; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci sh_eth_write(ndev, EDRRR_R, EDRRR); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci *quota -= limit - boguscnt - 1; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci return *quota <= 0; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_disable(struct net_device *ndev) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci /* disable tx and rx */ 17238c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, 0); 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic void sh_eth_rcv_snd_enable(struct net_device *ndev) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci /* enable tx and rx */ 17298c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_RE | ECMR_TE, ECMR_RE | ECMR_TE); 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci/* E-MAC interrupt handler */ 17338c2ecf20Sopenharmony_cistatic void sh_eth_emac_interrupt(struct net_device *ndev) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 17368c2ecf20Sopenharmony_ci u32 felic_stat; 17378c2ecf20Sopenharmony_ci u32 link_stat; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci felic_stat = sh_eth_read(ndev, ECSR) & sh_eth_read(ndev, ECSIPR); 17408c2ecf20Sopenharmony_ci sh_eth_write(ndev, felic_stat, ECSR); /* clear int */ 17418c2ecf20Sopenharmony_ci if (felic_stat & ECSR_ICD) 17428c2ecf20Sopenharmony_ci ndev->stats.tx_carrier_errors++; 17438c2ecf20Sopenharmony_ci if (felic_stat & ECSR_MPD) 17448c2ecf20Sopenharmony_ci pm_wakeup_event(&mdp->pdev->dev, 0); 17458c2ecf20Sopenharmony_ci if (felic_stat & ECSR_LCHNG) { 17468c2ecf20Sopenharmony_ci /* Link Changed */ 17478c2ecf20Sopenharmony_ci if (mdp->cd->no_psr || mdp->no_ether_link) 17488c2ecf20Sopenharmony_ci return; 17498c2ecf20Sopenharmony_ci link_stat = sh_eth_read(ndev, PSR); 17508c2ecf20Sopenharmony_ci if (mdp->ether_link_active_low) 17518c2ecf20Sopenharmony_ci link_stat = ~link_stat; 17528c2ecf20Sopenharmony_ci if (!(link_stat & PHY_ST_LINK)) { 17538c2ecf20Sopenharmony_ci sh_eth_rcv_snd_disable(ndev); 17548c2ecf20Sopenharmony_ci } else { 17558c2ecf20Sopenharmony_ci /* Link Up */ 17568c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, 0); 17578c2ecf20Sopenharmony_ci /* clear int */ 17588c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECSR, 0, 0); 17598c2ecf20Sopenharmony_ci sh_eth_modify(ndev, EESIPR, EESIPR_ECIIP, EESIPR_ECIIP); 17608c2ecf20Sopenharmony_ci /* enable tx and rx */ 17618c2ecf20Sopenharmony_ci sh_eth_rcv_snd_enable(ndev); 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci/* error control function */ 17678c2ecf20Sopenharmony_cistatic void sh_eth_error(struct net_device *ndev, u32 intr_status) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 17708c2ecf20Sopenharmony_ci u32 mask; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (intr_status & EESR_TWB) { 17738c2ecf20Sopenharmony_ci /* Unused write back interrupt */ 17748c2ecf20Sopenharmony_ci if (intr_status & EESR_TABT) { /* Transmit Abort int */ 17758c2ecf20Sopenharmony_ci ndev->stats.tx_aborted_errors++; 17768c2ecf20Sopenharmony_ci netif_err(mdp, tx_err, ndev, "Transmit Abort\n"); 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (intr_status & EESR_RABT) { 17818c2ecf20Sopenharmony_ci /* Receive Abort int */ 17828c2ecf20Sopenharmony_ci if (intr_status & EESR_RFRMER) { 17838c2ecf20Sopenharmony_ci /* Receive Frame Overflow int */ 17848c2ecf20Sopenharmony_ci ndev->stats.rx_frame_errors++; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (intr_status & EESR_TDE) { 17898c2ecf20Sopenharmony_ci /* Transmit Descriptor Empty int */ 17908c2ecf20Sopenharmony_ci ndev->stats.tx_fifo_errors++; 17918c2ecf20Sopenharmony_ci netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n"); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (intr_status & EESR_TFE) { 17958c2ecf20Sopenharmony_ci /* FIFO under flow */ 17968c2ecf20Sopenharmony_ci ndev->stats.tx_fifo_errors++; 17978c2ecf20Sopenharmony_ci netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n"); 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (intr_status & EESR_RDE) { 18018c2ecf20Sopenharmony_ci /* Receive Descriptor Empty int */ 18028c2ecf20Sopenharmony_ci ndev->stats.rx_over_errors++; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (intr_status & EESR_RFE) { 18068c2ecf20Sopenharmony_ci /* Receive FIFO Overflow int */ 18078c2ecf20Sopenharmony_ci ndev->stats.rx_fifo_errors++; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) { 18118c2ecf20Sopenharmony_ci /* Address Error */ 18128c2ecf20Sopenharmony_ci ndev->stats.tx_fifo_errors++; 18138c2ecf20Sopenharmony_ci netif_err(mdp, tx_err, ndev, "Address Error\n"); 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; 18178c2ecf20Sopenharmony_ci if (mdp->cd->no_ade) 18188c2ecf20Sopenharmony_ci mask &= ~EESR_ADE; 18198c2ecf20Sopenharmony_ci if (intr_status & mask) { 18208c2ecf20Sopenharmony_ci /* Tx error */ 18218c2ecf20Sopenharmony_ci u32 edtrr = sh_eth_read(ndev, EDTRR); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* dmesg */ 18248c2ecf20Sopenharmony_ci netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", 18258c2ecf20Sopenharmony_ci intr_status, mdp->cur_tx, mdp->dirty_tx, 18268c2ecf20Sopenharmony_ci (u32)ndev->state, edtrr); 18278c2ecf20Sopenharmony_ci /* dirty buffer free */ 18288c2ecf20Sopenharmony_ci sh_eth_tx_free(ndev, true); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci /* SH7712 BUG */ 18318c2ecf20Sopenharmony_ci if (edtrr ^ mdp->cd->edtrr_trns) { 18328c2ecf20Sopenharmony_ci /* tx dma start */ 18338c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR); 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci /* wakeup */ 18368c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic irqreturn_t sh_eth_interrupt(int irq, void *netdev) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci struct net_device *ndev = netdev; 18438c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 18448c2ecf20Sopenharmony_ci struct sh_eth_cpu_data *cd = mdp->cd; 18458c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 18468c2ecf20Sopenharmony_ci u32 intr_status, intr_enable; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci spin_lock(&mdp->lock); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci /* Get interrupt status */ 18518c2ecf20Sopenharmony_ci intr_status = sh_eth_read(ndev, EESR); 18528c2ecf20Sopenharmony_ci /* Mask it with the interrupt mask, forcing ECI interrupt to be always 18538c2ecf20Sopenharmony_ci * enabled since it's the one that comes thru regardless of the mask, 18548c2ecf20Sopenharmony_ci * and we need to fully handle it in sh_eth_emac_interrupt() in order 18558c2ecf20Sopenharmony_ci * to quench it as it doesn't get cleared by just writing 1 to the ECI 18568c2ecf20Sopenharmony_ci * bit... 18578c2ecf20Sopenharmony_ci */ 18588c2ecf20Sopenharmony_ci intr_enable = sh_eth_read(ndev, EESIPR); 18598c2ecf20Sopenharmony_ci intr_status &= intr_enable | EESIPR_ECIIP; 18608c2ecf20Sopenharmony_ci if (intr_status & (EESR_RX_CHECK | cd->tx_check | EESR_ECI | 18618c2ecf20Sopenharmony_ci cd->eesr_err_check)) 18628c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 18638c2ecf20Sopenharmony_ci else 18648c2ecf20Sopenharmony_ci goto out; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci if (unlikely(!mdp->irq_enabled)) { 18678c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, EESIPR); 18688c2ecf20Sopenharmony_ci goto out; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (intr_status & EESR_RX_CHECK) { 18728c2ecf20Sopenharmony_ci if (napi_schedule_prep(&mdp->napi)) { 18738c2ecf20Sopenharmony_ci /* Mask Rx interrupts */ 18748c2ecf20Sopenharmony_ci sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK, 18758c2ecf20Sopenharmony_ci EESIPR); 18768c2ecf20Sopenharmony_ci __napi_schedule(&mdp->napi); 18778c2ecf20Sopenharmony_ci } else { 18788c2ecf20Sopenharmony_ci netdev_warn(ndev, 18798c2ecf20Sopenharmony_ci "ignoring interrupt, status 0x%08x, mask 0x%08x.\n", 18808c2ecf20Sopenharmony_ci intr_status, intr_enable); 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* Tx Check */ 18858c2ecf20Sopenharmony_ci if (intr_status & cd->tx_check) { 18868c2ecf20Sopenharmony_ci /* Clear Tx interrupts */ 18878c2ecf20Sopenharmony_ci sh_eth_write(ndev, intr_status & cd->tx_check, EESR); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci sh_eth_tx_free(ndev, true); 18908c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* E-MAC interrupt */ 18948c2ecf20Sopenharmony_ci if (intr_status & EESR_ECI) 18958c2ecf20Sopenharmony_ci sh_eth_emac_interrupt(ndev); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci if (intr_status & cd->eesr_err_check) { 18988c2ecf20Sopenharmony_ci /* Clear error interrupts */ 18998c2ecf20Sopenharmony_ci sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci sh_eth_error(ndev, intr_status); 19028c2ecf20Sopenharmony_ci } 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ciout: 19058c2ecf20Sopenharmony_ci spin_unlock(&mdp->lock); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci return ret; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic int sh_eth_poll(struct napi_struct *napi, int budget) 19118c2ecf20Sopenharmony_ci{ 19128c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private, 19138c2ecf20Sopenharmony_ci napi); 19148c2ecf20Sopenharmony_ci struct net_device *ndev = napi->dev; 19158c2ecf20Sopenharmony_ci int quota = budget; 19168c2ecf20Sopenharmony_ci u32 intr_status; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci for (;;) { 19198c2ecf20Sopenharmony_ci intr_status = sh_eth_read(ndev, EESR); 19208c2ecf20Sopenharmony_ci if (!(intr_status & EESR_RX_CHECK)) 19218c2ecf20Sopenharmony_ci break; 19228c2ecf20Sopenharmony_ci /* Clear Rx interrupts */ 19238c2ecf20Sopenharmony_ci sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (sh_eth_rx(ndev, intr_status, "a)) 19268c2ecf20Sopenharmony_ci goto out; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci napi_complete(napi); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* Reenable Rx interrupts */ 19328c2ecf20Sopenharmony_ci if (mdp->irq_enabled) 19338c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); 19348c2ecf20Sopenharmony_ciout: 19358c2ecf20Sopenharmony_ci return budget - quota; 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci/* PHY state control function */ 19398c2ecf20Sopenharmony_cistatic void sh_eth_adjust_link(struct net_device *ndev) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 19428c2ecf20Sopenharmony_ci struct phy_device *phydev = ndev->phydev; 19438c2ecf20Sopenharmony_ci unsigned long flags; 19448c2ecf20Sopenharmony_ci int new_state = 0; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci spin_lock_irqsave(&mdp->lock, flags); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* Disable TX and RX right over here, if E-MAC change is ignored */ 19498c2ecf20Sopenharmony_ci if (mdp->cd->no_psr || mdp->no_ether_link) 19508c2ecf20Sopenharmony_ci sh_eth_rcv_snd_disable(ndev); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (phydev->link) { 19538c2ecf20Sopenharmony_ci if (phydev->duplex != mdp->duplex) { 19548c2ecf20Sopenharmony_ci new_state = 1; 19558c2ecf20Sopenharmony_ci mdp->duplex = phydev->duplex; 19568c2ecf20Sopenharmony_ci if (mdp->cd->set_duplex) 19578c2ecf20Sopenharmony_ci mdp->cd->set_duplex(ndev); 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (phydev->speed != mdp->speed) { 19618c2ecf20Sopenharmony_ci new_state = 1; 19628c2ecf20Sopenharmony_ci mdp->speed = phydev->speed; 19638c2ecf20Sopenharmony_ci if (mdp->cd->set_rate) 19648c2ecf20Sopenharmony_ci mdp->cd->set_rate(ndev); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci if (!mdp->link) { 19678c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_TXF, 0); 19688c2ecf20Sopenharmony_ci new_state = 1; 19698c2ecf20Sopenharmony_ci mdp->link = phydev->link; 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci } else if (mdp->link) { 19728c2ecf20Sopenharmony_ci new_state = 1; 19738c2ecf20Sopenharmony_ci mdp->link = 0; 19748c2ecf20Sopenharmony_ci mdp->speed = 0; 19758c2ecf20Sopenharmony_ci mdp->duplex = -1; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* Enable TX and RX right over here, if E-MAC change is ignored */ 19798c2ecf20Sopenharmony_ci if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link) 19808c2ecf20Sopenharmony_ci sh_eth_rcv_snd_enable(ndev); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdp->lock, flags); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (new_state && netif_msg_link(mdp)) 19858c2ecf20Sopenharmony_ci phy_print_status(phydev); 19868c2ecf20Sopenharmony_ci} 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci/* PHY init function */ 19898c2ecf20Sopenharmony_cistatic int sh_eth_phy_init(struct net_device *ndev) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct device_node *np = ndev->dev.parent->of_node; 19928c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 19938c2ecf20Sopenharmony_ci struct phy_device *phydev; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci mdp->link = 0; 19968c2ecf20Sopenharmony_ci mdp->speed = 0; 19978c2ecf20Sopenharmony_ci mdp->duplex = -1; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* Try connect to PHY */ 20008c2ecf20Sopenharmony_ci if (np) { 20018c2ecf20Sopenharmony_ci struct device_node *pn; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci pn = of_parse_phandle(np, "phy-handle", 0); 20048c2ecf20Sopenharmony_ci phydev = of_phy_connect(ndev, pn, 20058c2ecf20Sopenharmony_ci sh_eth_adjust_link, 0, 20068c2ecf20Sopenharmony_ci mdp->phy_interface); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci of_node_put(pn); 20098c2ecf20Sopenharmony_ci if (!phydev) 20108c2ecf20Sopenharmony_ci phydev = ERR_PTR(-ENOENT); 20118c2ecf20Sopenharmony_ci } else { 20128c2ecf20Sopenharmony_ci char phy_id[MII_BUS_ID_SIZE + 3]; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, 20158c2ecf20Sopenharmony_ci mdp->mii_bus->id, mdp->phy_id); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link, 20188c2ecf20Sopenharmony_ci mdp->phy_interface); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (IS_ERR(phydev)) { 20228c2ecf20Sopenharmony_ci netdev_err(ndev, "failed to connect PHY\n"); 20238c2ecf20Sopenharmony_ci return PTR_ERR(phydev); 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci /* mask with MAC supported features */ 20278c2ecf20Sopenharmony_ci if (mdp->cd->register_type != SH_ETH_REG_GIGABIT) { 20288c2ecf20Sopenharmony_ci int err = phy_set_max_speed(phydev, SPEED_100); 20298c2ecf20Sopenharmony_ci if (err) { 20308c2ecf20Sopenharmony_ci netdev_err(ndev, "failed to limit PHY to 100 Mbit/s\n"); 20318c2ecf20Sopenharmony_ci phy_disconnect(phydev); 20328c2ecf20Sopenharmony_ci return err; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci phy_attached_info(phydev); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci return 0; 20398c2ecf20Sopenharmony_ci} 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci/* PHY control start function */ 20428c2ecf20Sopenharmony_cistatic int sh_eth_phy_start(struct net_device *ndev) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci int ret; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci ret = sh_eth_phy_init(ndev); 20478c2ecf20Sopenharmony_ci if (ret) 20488c2ecf20Sopenharmony_ci return ret; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci phy_start(ndev->phydev); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci} 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci/* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the 20568c2ecf20Sopenharmony_ci * version must be bumped as well. Just adding registers up to that 20578c2ecf20Sopenharmony_ci * limit is fine, as long as the existing register indices don't 20588c2ecf20Sopenharmony_ci * change. 20598c2ecf20Sopenharmony_ci */ 20608c2ecf20Sopenharmony_ci#define SH_ETH_REG_DUMP_VERSION 1 20618c2ecf20Sopenharmony_ci#define SH_ETH_REG_DUMP_MAX_REGS 256 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_cistatic size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf) 20648c2ecf20Sopenharmony_ci{ 20658c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 20668c2ecf20Sopenharmony_ci struct sh_eth_cpu_data *cd = mdp->cd; 20678c2ecf20Sopenharmony_ci u32 *valid_map; 20688c2ecf20Sopenharmony_ci size_t len; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci BUILD_BUG_ON(SH_ETH_MAX_REGISTER_OFFSET > SH_ETH_REG_DUMP_MAX_REGS); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* Dump starts with a bitmap that tells ethtool which 20738c2ecf20Sopenharmony_ci * registers are defined for this chip. 20748c2ecf20Sopenharmony_ci */ 20758c2ecf20Sopenharmony_ci len = DIV_ROUND_UP(SH_ETH_REG_DUMP_MAX_REGS, 32); 20768c2ecf20Sopenharmony_ci if (buf) { 20778c2ecf20Sopenharmony_ci valid_map = buf; 20788c2ecf20Sopenharmony_ci buf += len; 20798c2ecf20Sopenharmony_ci } else { 20808c2ecf20Sopenharmony_ci valid_map = NULL; 20818c2ecf20Sopenharmony_ci } 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* Add a register to the dump, if it has a defined offset. 20848c2ecf20Sopenharmony_ci * This automatically skips most undefined registers, but for 20858c2ecf20Sopenharmony_ci * some it is also necessary to check a capability flag in 20868c2ecf20Sopenharmony_ci * struct sh_eth_cpu_data. 20878c2ecf20Sopenharmony_ci */ 20888c2ecf20Sopenharmony_ci#define mark_reg_valid(reg) valid_map[reg / 32] |= 1U << (reg % 32) 20898c2ecf20Sopenharmony_ci#define add_reg_from(reg, read_expr) do { \ 20908c2ecf20Sopenharmony_ci if (mdp->reg_offset[reg] != SH_ETH_OFFSET_INVALID) { \ 20918c2ecf20Sopenharmony_ci if (buf) { \ 20928c2ecf20Sopenharmony_ci mark_reg_valid(reg); \ 20938c2ecf20Sopenharmony_ci *buf++ = read_expr; \ 20948c2ecf20Sopenharmony_ci } \ 20958c2ecf20Sopenharmony_ci ++len; \ 20968c2ecf20Sopenharmony_ci } \ 20978c2ecf20Sopenharmony_ci } while (0) 20988c2ecf20Sopenharmony_ci#define add_reg(reg) add_reg_from(reg, sh_eth_read(ndev, reg)) 20998c2ecf20Sopenharmony_ci#define add_tsu_reg(reg) add_reg_from(reg, sh_eth_tsu_read(mdp, reg)) 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci add_reg(EDSR); 21028c2ecf20Sopenharmony_ci add_reg(EDMR); 21038c2ecf20Sopenharmony_ci add_reg(EDTRR); 21048c2ecf20Sopenharmony_ci add_reg(EDRRR); 21058c2ecf20Sopenharmony_ci add_reg(EESR); 21068c2ecf20Sopenharmony_ci add_reg(EESIPR); 21078c2ecf20Sopenharmony_ci add_reg(TDLAR); 21088c2ecf20Sopenharmony_ci if (!cd->no_xdfar) 21098c2ecf20Sopenharmony_ci add_reg(TDFAR); 21108c2ecf20Sopenharmony_ci add_reg(TDFXR); 21118c2ecf20Sopenharmony_ci add_reg(TDFFR); 21128c2ecf20Sopenharmony_ci add_reg(RDLAR); 21138c2ecf20Sopenharmony_ci if (!cd->no_xdfar) 21148c2ecf20Sopenharmony_ci add_reg(RDFAR); 21158c2ecf20Sopenharmony_ci add_reg(RDFXR); 21168c2ecf20Sopenharmony_ci add_reg(RDFFR); 21178c2ecf20Sopenharmony_ci add_reg(TRSCER); 21188c2ecf20Sopenharmony_ci add_reg(RMFCR); 21198c2ecf20Sopenharmony_ci add_reg(TFTR); 21208c2ecf20Sopenharmony_ci add_reg(FDR); 21218c2ecf20Sopenharmony_ci add_reg(RMCR); 21228c2ecf20Sopenharmony_ci add_reg(TFUCR); 21238c2ecf20Sopenharmony_ci add_reg(RFOCR); 21248c2ecf20Sopenharmony_ci if (cd->rmiimode) 21258c2ecf20Sopenharmony_ci add_reg(RMIIMODE); 21268c2ecf20Sopenharmony_ci add_reg(FCFTR); 21278c2ecf20Sopenharmony_ci if (cd->rpadir) 21288c2ecf20Sopenharmony_ci add_reg(RPADIR); 21298c2ecf20Sopenharmony_ci if (!cd->no_trimd) 21308c2ecf20Sopenharmony_ci add_reg(TRIMD); 21318c2ecf20Sopenharmony_ci add_reg(ECMR); 21328c2ecf20Sopenharmony_ci add_reg(ECSR); 21338c2ecf20Sopenharmony_ci add_reg(ECSIPR); 21348c2ecf20Sopenharmony_ci add_reg(PIR); 21358c2ecf20Sopenharmony_ci if (!cd->no_psr) 21368c2ecf20Sopenharmony_ci add_reg(PSR); 21378c2ecf20Sopenharmony_ci add_reg(RDMLR); 21388c2ecf20Sopenharmony_ci add_reg(RFLR); 21398c2ecf20Sopenharmony_ci add_reg(IPGR); 21408c2ecf20Sopenharmony_ci if (cd->apr) 21418c2ecf20Sopenharmony_ci add_reg(APR); 21428c2ecf20Sopenharmony_ci if (cd->mpr) 21438c2ecf20Sopenharmony_ci add_reg(MPR); 21448c2ecf20Sopenharmony_ci add_reg(RFCR); 21458c2ecf20Sopenharmony_ci add_reg(RFCF); 21468c2ecf20Sopenharmony_ci if (cd->tpauser) 21478c2ecf20Sopenharmony_ci add_reg(TPAUSER); 21488c2ecf20Sopenharmony_ci add_reg(TPAUSECR); 21498c2ecf20Sopenharmony_ci if (cd->gecmr) 21508c2ecf20Sopenharmony_ci add_reg(GECMR); 21518c2ecf20Sopenharmony_ci if (cd->bculr) 21528c2ecf20Sopenharmony_ci add_reg(BCULR); 21538c2ecf20Sopenharmony_ci add_reg(MAHR); 21548c2ecf20Sopenharmony_ci add_reg(MALR); 21558c2ecf20Sopenharmony_ci if (!cd->no_tx_cntrs) { 21568c2ecf20Sopenharmony_ci add_reg(TROCR); 21578c2ecf20Sopenharmony_ci add_reg(CDCR); 21588c2ecf20Sopenharmony_ci add_reg(LCCR); 21598c2ecf20Sopenharmony_ci add_reg(CNDCR); 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci add_reg(CEFCR); 21628c2ecf20Sopenharmony_ci add_reg(FRECR); 21638c2ecf20Sopenharmony_ci add_reg(TSFRCR); 21648c2ecf20Sopenharmony_ci add_reg(TLFRCR); 21658c2ecf20Sopenharmony_ci if (cd->cexcr) { 21668c2ecf20Sopenharmony_ci add_reg(CERCR); 21678c2ecf20Sopenharmony_ci add_reg(CEECR); 21688c2ecf20Sopenharmony_ci } 21698c2ecf20Sopenharmony_ci add_reg(MAFCR); 21708c2ecf20Sopenharmony_ci if (cd->rtrate) 21718c2ecf20Sopenharmony_ci add_reg(RTRATE); 21728c2ecf20Sopenharmony_ci if (cd->csmr) 21738c2ecf20Sopenharmony_ci add_reg(CSMR); 21748c2ecf20Sopenharmony_ci if (cd->select_mii) 21758c2ecf20Sopenharmony_ci add_reg(RMII_MII); 21768c2ecf20Sopenharmony_ci if (cd->tsu) { 21778c2ecf20Sopenharmony_ci add_tsu_reg(ARSTR); 21788c2ecf20Sopenharmony_ci add_tsu_reg(TSU_CTRST); 21798c2ecf20Sopenharmony_ci if (cd->dual_port) { 21808c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWEN0); 21818c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWEN1); 21828c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FCM); 21838c2ecf20Sopenharmony_ci add_tsu_reg(TSU_BSYSL0); 21848c2ecf20Sopenharmony_ci add_tsu_reg(TSU_BSYSL1); 21858c2ecf20Sopenharmony_ci add_tsu_reg(TSU_PRISL0); 21868c2ecf20Sopenharmony_ci add_tsu_reg(TSU_PRISL1); 21878c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWSL0); 21888c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWSL1); 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWSLC); 21918c2ecf20Sopenharmony_ci if (cd->dual_port) { 21928c2ecf20Sopenharmony_ci add_tsu_reg(TSU_QTAGM0); 21938c2ecf20Sopenharmony_ci add_tsu_reg(TSU_QTAGM1); 21948c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWSR); 21958c2ecf20Sopenharmony_ci add_tsu_reg(TSU_FWINMK); 21968c2ecf20Sopenharmony_ci add_tsu_reg(TSU_ADQT0); 21978c2ecf20Sopenharmony_ci add_tsu_reg(TSU_ADQT1); 21988c2ecf20Sopenharmony_ci add_tsu_reg(TSU_VTAG0); 21998c2ecf20Sopenharmony_ci add_tsu_reg(TSU_VTAG1); 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci add_tsu_reg(TSU_ADSBSY); 22028c2ecf20Sopenharmony_ci add_tsu_reg(TSU_TEN); 22038c2ecf20Sopenharmony_ci add_tsu_reg(TSU_POST1); 22048c2ecf20Sopenharmony_ci add_tsu_reg(TSU_POST2); 22058c2ecf20Sopenharmony_ci add_tsu_reg(TSU_POST3); 22068c2ecf20Sopenharmony_ci add_tsu_reg(TSU_POST4); 22078c2ecf20Sopenharmony_ci /* This is the start of a table, not just a single register. */ 22088c2ecf20Sopenharmony_ci if (buf) { 22098c2ecf20Sopenharmony_ci unsigned int i; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci mark_reg_valid(TSU_ADRH0); 22128c2ecf20Sopenharmony_ci for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES * 2; i++) 22138c2ecf20Sopenharmony_ci *buf++ = ioread32(mdp->tsu_addr + 22148c2ecf20Sopenharmony_ci mdp->reg_offset[TSU_ADRH0] + 22158c2ecf20Sopenharmony_ci i * 4); 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci len += SH_ETH_TSU_CAM_ENTRIES * 2; 22188c2ecf20Sopenharmony_ci } 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci#undef mark_reg_valid 22218c2ecf20Sopenharmony_ci#undef add_reg_from 22228c2ecf20Sopenharmony_ci#undef add_reg 22238c2ecf20Sopenharmony_ci#undef add_tsu_reg 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci return len * 4; 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cistatic int sh_eth_get_regs_len(struct net_device *ndev) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci return __sh_eth_get_regs(ndev, NULL); 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cistatic void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs, 22348c2ecf20Sopenharmony_ci void *buf) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci regs->version = SH_ETH_REG_DUMP_VERSION; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci pm_runtime_get_sync(&mdp->pdev->dev); 22418c2ecf20Sopenharmony_ci __sh_eth_get_regs(ndev, buf); 22428c2ecf20Sopenharmony_ci pm_runtime_put_sync(&mdp->pdev->dev); 22438c2ecf20Sopenharmony_ci} 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_cistatic u32 sh_eth_get_msglevel(struct net_device *ndev) 22468c2ecf20Sopenharmony_ci{ 22478c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 22488c2ecf20Sopenharmony_ci return mdp->msg_enable; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_cistatic void sh_eth_set_msglevel(struct net_device *ndev, u32 value) 22528c2ecf20Sopenharmony_ci{ 22538c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 22548c2ecf20Sopenharmony_ci mdp->msg_enable = value; 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_cistatic const char sh_eth_gstrings_stats[][ETH_GSTRING_LEN] = { 22588c2ecf20Sopenharmony_ci "rx_current", "tx_current", 22598c2ecf20Sopenharmony_ci "rx_dirty", "tx_dirty", 22608c2ecf20Sopenharmony_ci}; 22618c2ecf20Sopenharmony_ci#define SH_ETH_STATS_LEN ARRAY_SIZE(sh_eth_gstrings_stats) 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_cistatic int sh_eth_get_sset_count(struct net_device *netdev, int sset) 22648c2ecf20Sopenharmony_ci{ 22658c2ecf20Sopenharmony_ci switch (sset) { 22668c2ecf20Sopenharmony_ci case ETH_SS_STATS: 22678c2ecf20Sopenharmony_ci return SH_ETH_STATS_LEN; 22688c2ecf20Sopenharmony_ci default: 22698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic void sh_eth_get_ethtool_stats(struct net_device *ndev, 22748c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 22758c2ecf20Sopenharmony_ci{ 22768c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 22778c2ecf20Sopenharmony_ci int i = 0; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci /* device-specific stats */ 22808c2ecf20Sopenharmony_ci data[i++] = mdp->cur_rx; 22818c2ecf20Sopenharmony_ci data[i++] = mdp->cur_tx; 22828c2ecf20Sopenharmony_ci data[i++] = mdp->dirty_rx; 22838c2ecf20Sopenharmony_ci data[i++] = mdp->dirty_tx; 22848c2ecf20Sopenharmony_ci} 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_cistatic void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 22878c2ecf20Sopenharmony_ci{ 22888c2ecf20Sopenharmony_ci switch (stringset) { 22898c2ecf20Sopenharmony_ci case ETH_SS_STATS: 22908c2ecf20Sopenharmony_ci memcpy(data, sh_eth_gstrings_stats, 22918c2ecf20Sopenharmony_ci sizeof(sh_eth_gstrings_stats)); 22928c2ecf20Sopenharmony_ci break; 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic void sh_eth_get_ringparam(struct net_device *ndev, 22978c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci ring->rx_max_pending = RX_RING_MAX; 23028c2ecf20Sopenharmony_ci ring->tx_max_pending = TX_RING_MAX; 23038c2ecf20Sopenharmony_ci ring->rx_pending = mdp->num_rx_ring; 23048c2ecf20Sopenharmony_ci ring->tx_pending = mdp->num_tx_ring; 23058c2ecf20Sopenharmony_ci} 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cistatic int sh_eth_set_ringparam(struct net_device *ndev, 23088c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 23098c2ecf20Sopenharmony_ci{ 23108c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 23118c2ecf20Sopenharmony_ci int ret; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (ring->tx_pending > TX_RING_MAX || 23148c2ecf20Sopenharmony_ci ring->rx_pending > RX_RING_MAX || 23158c2ecf20Sopenharmony_ci ring->tx_pending < TX_RING_MIN || 23168c2ecf20Sopenharmony_ci ring->rx_pending < RX_RING_MIN) 23178c2ecf20Sopenharmony_ci return -EINVAL; 23188c2ecf20Sopenharmony_ci if (ring->rx_mini_pending || ring->rx_jumbo_pending) 23198c2ecf20Sopenharmony_ci return -EINVAL; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 23228c2ecf20Sopenharmony_ci netif_device_detach(ndev); 23238c2ecf20Sopenharmony_ci netif_tx_disable(ndev); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci /* Serialise with the interrupt handler and NAPI, then 23268c2ecf20Sopenharmony_ci * disable interrupts. We have to clear the 23278c2ecf20Sopenharmony_ci * irq_enabled flag first to ensure that interrupts 23288c2ecf20Sopenharmony_ci * won't be re-enabled. 23298c2ecf20Sopenharmony_ci */ 23308c2ecf20Sopenharmony_ci mdp->irq_enabled = false; 23318c2ecf20Sopenharmony_ci synchronize_irq(ndev->irq); 23328c2ecf20Sopenharmony_ci napi_synchronize(&mdp->napi); 23338c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x0000, EESIPR); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci sh_eth_dev_exit(ndev); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* Free all the skbuffs in the Rx queue and the DMA buffers. */ 23388c2ecf20Sopenharmony_ci sh_eth_ring_free(ndev); 23398c2ecf20Sopenharmony_ci } 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci /* Set new parameters */ 23428c2ecf20Sopenharmony_ci mdp->num_rx_ring = ring->rx_pending; 23438c2ecf20Sopenharmony_ci mdp->num_tx_ring = ring->tx_pending; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 23468c2ecf20Sopenharmony_ci ret = sh_eth_ring_init(ndev); 23478c2ecf20Sopenharmony_ci if (ret < 0) { 23488c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", 23498c2ecf20Sopenharmony_ci __func__); 23508c2ecf20Sopenharmony_ci return ret; 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci ret = sh_eth_dev_init(ndev); 23538c2ecf20Sopenharmony_ci if (ret < 0) { 23548c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", 23558c2ecf20Sopenharmony_ci __func__); 23568c2ecf20Sopenharmony_ci return ret; 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci netif_device_attach(ndev); 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci return 0; 23638c2ecf20Sopenharmony_ci} 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_cistatic void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 23668c2ecf20Sopenharmony_ci{ 23678c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci wol->supported = 0; 23708c2ecf20Sopenharmony_ci wol->wolopts = 0; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (mdp->cd->magic) { 23738c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 23748c2ecf20Sopenharmony_ci wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0; 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_cistatic int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) 23798c2ecf20Sopenharmony_ci{ 23808c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC) 23838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci device_set_wakeup_enable(&mdp->pdev->dev, mdp->wol_enabled); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci return 0; 23908c2ecf20Sopenharmony_ci} 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_cistatic const struct ethtool_ops sh_eth_ethtool_ops = { 23938c2ecf20Sopenharmony_ci .get_regs_len = sh_eth_get_regs_len, 23948c2ecf20Sopenharmony_ci .get_regs = sh_eth_get_regs, 23958c2ecf20Sopenharmony_ci .nway_reset = phy_ethtool_nway_reset, 23968c2ecf20Sopenharmony_ci .get_msglevel = sh_eth_get_msglevel, 23978c2ecf20Sopenharmony_ci .set_msglevel = sh_eth_set_msglevel, 23988c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 23998c2ecf20Sopenharmony_ci .get_strings = sh_eth_get_strings, 24008c2ecf20Sopenharmony_ci .get_ethtool_stats = sh_eth_get_ethtool_stats, 24018c2ecf20Sopenharmony_ci .get_sset_count = sh_eth_get_sset_count, 24028c2ecf20Sopenharmony_ci .get_ringparam = sh_eth_get_ringparam, 24038c2ecf20Sopenharmony_ci .set_ringparam = sh_eth_set_ringparam, 24048c2ecf20Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 24058c2ecf20Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 24068c2ecf20Sopenharmony_ci .get_wol = sh_eth_get_wol, 24078c2ecf20Sopenharmony_ci .set_wol = sh_eth_set_wol, 24088c2ecf20Sopenharmony_ci}; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci/* network device open function */ 24118c2ecf20Sopenharmony_cistatic int sh_eth_open(struct net_device *ndev) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 24148c2ecf20Sopenharmony_ci int ret; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci pm_runtime_get_sync(&mdp->pdev->dev); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci napi_enable(&mdp->napi); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci ret = request_irq(ndev->irq, sh_eth_interrupt, 24218c2ecf20Sopenharmony_ci mdp->cd->irq_flags, ndev->name, ndev); 24228c2ecf20Sopenharmony_ci if (ret) { 24238c2ecf20Sopenharmony_ci netdev_err(ndev, "Can not assign IRQ number\n"); 24248c2ecf20Sopenharmony_ci goto out_napi_off; 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* Descriptor set */ 24288c2ecf20Sopenharmony_ci ret = sh_eth_ring_init(ndev); 24298c2ecf20Sopenharmony_ci if (ret) 24308c2ecf20Sopenharmony_ci goto out_free_irq; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci /* device init */ 24338c2ecf20Sopenharmony_ci ret = sh_eth_dev_init(ndev); 24348c2ecf20Sopenharmony_ci if (ret) 24358c2ecf20Sopenharmony_ci goto out_free_irq; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci /* PHY control start*/ 24388c2ecf20Sopenharmony_ci ret = sh_eth_phy_start(ndev); 24398c2ecf20Sopenharmony_ci if (ret) 24408c2ecf20Sopenharmony_ci goto out_free_irq; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci netif_start_queue(ndev); 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci mdp->is_opened = 1; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci return ret; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ciout_free_irq: 24498c2ecf20Sopenharmony_ci free_irq(ndev->irq, ndev); 24508c2ecf20Sopenharmony_ciout_napi_off: 24518c2ecf20Sopenharmony_ci napi_disable(&mdp->napi); 24528c2ecf20Sopenharmony_ci pm_runtime_put_sync(&mdp->pdev->dev); 24538c2ecf20Sopenharmony_ci return ret; 24548c2ecf20Sopenharmony_ci} 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci/* Timeout function */ 24578c2ecf20Sopenharmony_cistatic void sh_eth_tx_timeout(struct net_device *ndev, unsigned int txqueue) 24588c2ecf20Sopenharmony_ci{ 24598c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 24608c2ecf20Sopenharmony_ci struct sh_eth_rxdesc *rxdesc; 24618c2ecf20Sopenharmony_ci int i; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci netif_err(mdp, timer, ndev, 24668c2ecf20Sopenharmony_ci "transmit timed out, status %8.8x, resetting...\n", 24678c2ecf20Sopenharmony_ci sh_eth_read(ndev, EESR)); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci /* tx_errors count up */ 24708c2ecf20Sopenharmony_ci ndev->stats.tx_errors++; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci /* Free all the skbuffs in the Rx queue. */ 24738c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_rx_ring; i++) { 24748c2ecf20Sopenharmony_ci rxdesc = &mdp->rx_ring[i]; 24758c2ecf20Sopenharmony_ci rxdesc->status = cpu_to_le32(0); 24768c2ecf20Sopenharmony_ci rxdesc->addr = cpu_to_le32(0xBADF00D0); 24778c2ecf20Sopenharmony_ci dev_kfree_skb(mdp->rx_skbuff[i]); 24788c2ecf20Sopenharmony_ci mdp->rx_skbuff[i] = NULL; 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci for (i = 0; i < mdp->num_tx_ring; i++) { 24818c2ecf20Sopenharmony_ci dev_kfree_skb(mdp->tx_skbuff[i]); 24828c2ecf20Sopenharmony_ci mdp->tx_skbuff[i] = NULL; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci /* device init */ 24868c2ecf20Sopenharmony_ci sh_eth_dev_init(ndev); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci netif_start_queue(ndev); 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci/* Packet transmit function */ 24928c2ecf20Sopenharmony_cistatic netdev_tx_t sh_eth_start_xmit(struct sk_buff *skb, 24938c2ecf20Sopenharmony_ci struct net_device *ndev) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 24968c2ecf20Sopenharmony_ci struct sh_eth_txdesc *txdesc; 24978c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 24988c2ecf20Sopenharmony_ci u32 entry; 24998c2ecf20Sopenharmony_ci unsigned long flags; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci spin_lock_irqsave(&mdp->lock, flags); 25028c2ecf20Sopenharmony_ci if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) { 25038c2ecf20Sopenharmony_ci if (!sh_eth_tx_free(ndev, true)) { 25048c2ecf20Sopenharmony_ci netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n"); 25058c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 25068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdp->lock, flags); 25078c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdp->lock, flags); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci if (skb_put_padto(skb, ETH_ZLEN)) 25138c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci entry = mdp->cur_tx % mdp->num_tx_ring; 25168c2ecf20Sopenharmony_ci mdp->tx_skbuff[entry] = skb; 25178c2ecf20Sopenharmony_ci txdesc = &mdp->tx_ring[entry]; 25188c2ecf20Sopenharmony_ci /* soft swap. */ 25198c2ecf20Sopenharmony_ci if (!mdp->cd->hw_swap) 25208c2ecf20Sopenharmony_ci sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2); 25218c2ecf20Sopenharmony_ci dma_addr = dma_map_single(&mdp->pdev->dev, skb->data, skb->len, 25228c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 25238c2ecf20Sopenharmony_ci if (dma_mapping_error(&mdp->pdev->dev, dma_addr)) { 25248c2ecf20Sopenharmony_ci kfree_skb(skb); 25258c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci txdesc->addr = cpu_to_le32(dma_addr); 25288c2ecf20Sopenharmony_ci txdesc->len = cpu_to_le32(skb->len << 16); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci dma_wmb(); /* TACT bit must be set after all the above writes */ 25318c2ecf20Sopenharmony_ci if (entry >= mdp->num_tx_ring - 1) 25328c2ecf20Sopenharmony_ci txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE); 25338c2ecf20Sopenharmony_ci else 25348c2ecf20Sopenharmony_ci txdesc->status |= cpu_to_le32(TD_TACT); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci wmb(); /* cur_tx must be incremented after TACT bit was set */ 25378c2ecf20Sopenharmony_ci mdp->cur_tx++; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci if (!(sh_eth_read(ndev, EDTRR) & mdp->cd->edtrr_trns)) 25408c2ecf20Sopenharmony_ci sh_eth_write(ndev, mdp->cd->edtrr_trns, EDTRR); 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 25438c2ecf20Sopenharmony_ci} 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci/* The statistics registers have write-clear behaviour, which means we 25468c2ecf20Sopenharmony_ci * will lose any increment between the read and write. We mitigate 25478c2ecf20Sopenharmony_ci * this by only clearing when we read a non-zero value, so we will 25488c2ecf20Sopenharmony_ci * never falsely report a total of zero. 25498c2ecf20Sopenharmony_ci */ 25508c2ecf20Sopenharmony_cistatic void 25518c2ecf20Sopenharmony_cish_eth_update_stat(struct net_device *ndev, unsigned long *stat, int reg) 25528c2ecf20Sopenharmony_ci{ 25538c2ecf20Sopenharmony_ci u32 delta = sh_eth_read(ndev, reg); 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (delta) { 25568c2ecf20Sopenharmony_ci *stat += delta; 25578c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0, reg); 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci if (mdp->cd->no_tx_cntrs) 25668c2ecf20Sopenharmony_ci return &ndev->stats; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci if (!mdp->is_opened) 25698c2ecf20Sopenharmony_ci return &ndev->stats; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.tx_dropped, TROCR); 25728c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.collisions, CDCR); 25738c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, LCCR); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci if (mdp->cd->cexcr) { 25768c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, 25778c2ecf20Sopenharmony_ci CERCR); 25788c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, 25798c2ecf20Sopenharmony_ci CEECR); 25808c2ecf20Sopenharmony_ci } else { 25818c2ecf20Sopenharmony_ci sh_eth_update_stat(ndev, &ndev->stats.tx_carrier_errors, 25828c2ecf20Sopenharmony_ci CNDCR); 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci return &ndev->stats; 25868c2ecf20Sopenharmony_ci} 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci/* device close function */ 25898c2ecf20Sopenharmony_cistatic int sh_eth_close(struct net_device *ndev) 25908c2ecf20Sopenharmony_ci{ 25918c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci /* Serialise with the interrupt handler and NAPI, then disable 25968c2ecf20Sopenharmony_ci * interrupts. We have to clear the irq_enabled flag first to 25978c2ecf20Sopenharmony_ci * ensure that interrupts won't be re-enabled. 25988c2ecf20Sopenharmony_ci */ 25998c2ecf20Sopenharmony_ci mdp->irq_enabled = false; 26008c2ecf20Sopenharmony_ci synchronize_irq(ndev->irq); 26018c2ecf20Sopenharmony_ci napi_disable(&mdp->napi); 26028c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x0000, EESIPR); 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci sh_eth_dev_exit(ndev); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci /* PHY Disconnect */ 26078c2ecf20Sopenharmony_ci if (ndev->phydev) { 26088c2ecf20Sopenharmony_ci phy_stop(ndev->phydev); 26098c2ecf20Sopenharmony_ci phy_disconnect(ndev->phydev); 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci free_irq(ndev->irq, ndev); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci /* Free all the skbuffs in the Rx queue and the DMA buffer. */ 26158c2ecf20Sopenharmony_ci sh_eth_ring_free(ndev); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci mdp->is_opened = 0; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci pm_runtime_put(&mdp->pdev->dev); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci return 0; 26228c2ecf20Sopenharmony_ci} 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_cistatic int sh_eth_change_mtu(struct net_device *ndev, int new_mtu) 26258c2ecf20Sopenharmony_ci{ 26268c2ecf20Sopenharmony_ci if (netif_running(ndev)) 26278c2ecf20Sopenharmony_ci return -EBUSY; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci ndev->mtu = new_mtu; 26308c2ecf20Sopenharmony_ci netdev_update_features(ndev); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci return 0; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci/* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */ 26368c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_get_post_mask(int entry) 26378c2ecf20Sopenharmony_ci{ 26388c2ecf20Sopenharmony_ci return 0x0f << (28 - ((entry % 8) * 4)); 26398c2ecf20Sopenharmony_ci} 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_cistatic u32 sh_eth_tsu_get_post_bit(struct sh_eth_private *mdp, int entry) 26428c2ecf20Sopenharmony_ci{ 26438c2ecf20Sopenharmony_ci return (0x08 >> (mdp->port << 1)) << (28 - ((entry % 8) * 4)); 26448c2ecf20Sopenharmony_ci} 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_cistatic void sh_eth_tsu_enable_cam_entry_post(struct net_device *ndev, 26478c2ecf20Sopenharmony_ci int entry) 26488c2ecf20Sopenharmony_ci{ 26498c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 26508c2ecf20Sopenharmony_ci int reg = TSU_POST1 + entry / 8; 26518c2ecf20Sopenharmony_ci u32 tmp; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci tmp = sh_eth_tsu_read(mdp, reg); 26548c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, tmp | sh_eth_tsu_get_post_bit(mdp, entry), reg); 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic bool sh_eth_tsu_disable_cam_entry_post(struct net_device *ndev, 26588c2ecf20Sopenharmony_ci int entry) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 26618c2ecf20Sopenharmony_ci int reg = TSU_POST1 + entry / 8; 26628c2ecf20Sopenharmony_ci u32 post_mask, ref_mask, tmp; 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci post_mask = sh_eth_tsu_get_post_mask(entry); 26658c2ecf20Sopenharmony_ci ref_mask = sh_eth_tsu_get_post_bit(mdp, entry) & ~post_mask; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci tmp = sh_eth_tsu_read(mdp, reg); 26688c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, tmp & ~post_mask, reg); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci /* If other port enables, the function returns "true" */ 26718c2ecf20Sopenharmony_ci return tmp & ref_mask; 26728c2ecf20Sopenharmony_ci} 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_cistatic int sh_eth_tsu_busy(struct net_device *ndev) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci int timeout = SH_ETH_TSU_TIMEOUT_MS * 100; 26778c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci while ((sh_eth_tsu_read(mdp, TSU_ADSBSY) & TSU_ADSBSY_0)) { 26808c2ecf20Sopenharmony_ci udelay(10); 26818c2ecf20Sopenharmony_ci timeout--; 26828c2ecf20Sopenharmony_ci if (timeout <= 0) { 26838c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: timeout\n", __func__); 26848c2ecf20Sopenharmony_ci return -ETIMEDOUT; 26858c2ecf20Sopenharmony_ci } 26868c2ecf20Sopenharmony_ci } 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci return 0; 26898c2ecf20Sopenharmony_ci} 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cistatic int sh_eth_tsu_write_entry(struct net_device *ndev, u16 offset, 26928c2ecf20Sopenharmony_ci const u8 *addr) 26938c2ecf20Sopenharmony_ci{ 26948c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 26958c2ecf20Sopenharmony_ci u32 val; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci val = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3]; 26988c2ecf20Sopenharmony_ci iowrite32(val, mdp->tsu_addr + offset); 26998c2ecf20Sopenharmony_ci if (sh_eth_tsu_busy(ndev) < 0) 27008c2ecf20Sopenharmony_ci return -EBUSY; 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci val = addr[4] << 8 | addr[5]; 27038c2ecf20Sopenharmony_ci iowrite32(val, mdp->tsu_addr + offset + 4); 27048c2ecf20Sopenharmony_ci if (sh_eth_tsu_busy(ndev) < 0) 27058c2ecf20Sopenharmony_ci return -EBUSY; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci return 0; 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_cistatic void sh_eth_tsu_read_entry(struct net_device *ndev, u16 offset, u8 *addr) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 27138c2ecf20Sopenharmony_ci u32 val; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci val = ioread32(mdp->tsu_addr + offset); 27168c2ecf20Sopenharmony_ci addr[0] = (val >> 24) & 0xff; 27178c2ecf20Sopenharmony_ci addr[1] = (val >> 16) & 0xff; 27188c2ecf20Sopenharmony_ci addr[2] = (val >> 8) & 0xff; 27198c2ecf20Sopenharmony_ci addr[3] = val & 0xff; 27208c2ecf20Sopenharmony_ci val = ioread32(mdp->tsu_addr + offset + 4); 27218c2ecf20Sopenharmony_ci addr[4] = (val >> 8) & 0xff; 27228c2ecf20Sopenharmony_ci addr[5] = val & 0xff; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistatic int sh_eth_tsu_find_entry(struct net_device *ndev, const u8 *addr) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 27298c2ecf20Sopenharmony_ci u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0); 27308c2ecf20Sopenharmony_ci int i; 27318c2ecf20Sopenharmony_ci u8 c_addr[ETH_ALEN]; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) { 27348c2ecf20Sopenharmony_ci sh_eth_tsu_read_entry(ndev, reg_offset, c_addr); 27358c2ecf20Sopenharmony_ci if (ether_addr_equal(addr, c_addr)) 27368c2ecf20Sopenharmony_ci return i; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci return -ENOENT; 27408c2ecf20Sopenharmony_ci} 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_cistatic int sh_eth_tsu_find_empty(struct net_device *ndev) 27438c2ecf20Sopenharmony_ci{ 27448c2ecf20Sopenharmony_ci u8 blank[ETH_ALEN]; 27458c2ecf20Sopenharmony_ci int entry; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci memset(blank, 0, sizeof(blank)); 27488c2ecf20Sopenharmony_ci entry = sh_eth_tsu_find_entry(ndev, blank); 27498c2ecf20Sopenharmony_ci return (entry < 0) ? -ENOMEM : entry; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_cistatic int sh_eth_tsu_disable_cam_entry_table(struct net_device *ndev, 27538c2ecf20Sopenharmony_ci int entry) 27548c2ecf20Sopenharmony_ci{ 27558c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 27568c2ecf20Sopenharmony_ci u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0); 27578c2ecf20Sopenharmony_ci int ret; 27588c2ecf20Sopenharmony_ci u8 blank[ETH_ALEN]; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) & 27618c2ecf20Sopenharmony_ci ~(1 << (31 - entry)), TSU_TEN); 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci memset(blank, 0, sizeof(blank)); 27648c2ecf20Sopenharmony_ci ret = sh_eth_tsu_write_entry(ndev, reg_offset + entry * 8, blank); 27658c2ecf20Sopenharmony_ci if (ret < 0) 27668c2ecf20Sopenharmony_ci return ret; 27678c2ecf20Sopenharmony_ci return 0; 27688c2ecf20Sopenharmony_ci} 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_cistatic int sh_eth_tsu_add_entry(struct net_device *ndev, const u8 *addr) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 27738c2ecf20Sopenharmony_ci u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0); 27748c2ecf20Sopenharmony_ci int i, ret; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (!mdp->cd->tsu) 27778c2ecf20Sopenharmony_ci return 0; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci i = sh_eth_tsu_find_entry(ndev, addr); 27808c2ecf20Sopenharmony_ci if (i < 0) { 27818c2ecf20Sopenharmony_ci /* No entry found, create one */ 27828c2ecf20Sopenharmony_ci i = sh_eth_tsu_find_empty(ndev); 27838c2ecf20Sopenharmony_ci if (i < 0) 27848c2ecf20Sopenharmony_ci return -ENOMEM; 27858c2ecf20Sopenharmony_ci ret = sh_eth_tsu_write_entry(ndev, reg_offset + i * 8, addr); 27868c2ecf20Sopenharmony_ci if (ret < 0) 27878c2ecf20Sopenharmony_ci return ret; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci /* Enable the entry */ 27908c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, sh_eth_tsu_read(mdp, TSU_TEN) | 27918c2ecf20Sopenharmony_ci (1 << (31 - i)), TSU_TEN); 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci /* Entry found or created, enable POST */ 27958c2ecf20Sopenharmony_ci sh_eth_tsu_enable_cam_entry_post(ndev, i); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci return 0; 27988c2ecf20Sopenharmony_ci} 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_cistatic int sh_eth_tsu_del_entry(struct net_device *ndev, const u8 *addr) 28018c2ecf20Sopenharmony_ci{ 28028c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 28038c2ecf20Sopenharmony_ci int i, ret; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (!mdp->cd->tsu) 28068c2ecf20Sopenharmony_ci return 0; 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci i = sh_eth_tsu_find_entry(ndev, addr); 28098c2ecf20Sopenharmony_ci if (i) { 28108c2ecf20Sopenharmony_ci /* Entry found */ 28118c2ecf20Sopenharmony_ci if (sh_eth_tsu_disable_cam_entry_post(ndev, i)) 28128c2ecf20Sopenharmony_ci goto done; 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci /* Disable the entry if both ports was disabled */ 28158c2ecf20Sopenharmony_ci ret = sh_eth_tsu_disable_cam_entry_table(ndev, i); 28168c2ecf20Sopenharmony_ci if (ret < 0) 28178c2ecf20Sopenharmony_ci return ret; 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_cidone: 28208c2ecf20Sopenharmony_ci return 0; 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_cistatic int sh_eth_tsu_purge_all(struct net_device *ndev) 28248c2ecf20Sopenharmony_ci{ 28258c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 28268c2ecf20Sopenharmony_ci int i, ret; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci if (!mdp->cd->tsu) 28298c2ecf20Sopenharmony_ci return 0; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) { 28328c2ecf20Sopenharmony_ci if (sh_eth_tsu_disable_cam_entry_post(ndev, i)) 28338c2ecf20Sopenharmony_ci continue; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci /* Disable the entry if both ports was disabled */ 28368c2ecf20Sopenharmony_ci ret = sh_eth_tsu_disable_cam_entry_table(ndev, i); 28378c2ecf20Sopenharmony_ci if (ret < 0) 28388c2ecf20Sopenharmony_ci return ret; 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci return 0; 28428c2ecf20Sopenharmony_ci} 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_cistatic void sh_eth_tsu_purge_mcast(struct net_device *ndev) 28458c2ecf20Sopenharmony_ci{ 28468c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 28478c2ecf20Sopenharmony_ci u16 reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0); 28488c2ecf20Sopenharmony_ci u8 addr[ETH_ALEN]; 28498c2ecf20Sopenharmony_ci int i; 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci if (!mdp->cd->tsu) 28528c2ecf20Sopenharmony_ci return; 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) { 28558c2ecf20Sopenharmony_ci sh_eth_tsu_read_entry(ndev, reg_offset, addr); 28568c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(addr)) 28578c2ecf20Sopenharmony_ci sh_eth_tsu_del_entry(ndev, addr); 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci} 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci/* Update promiscuous flag and multicast filter */ 28628c2ecf20Sopenharmony_cistatic void sh_eth_set_rx_mode(struct net_device *ndev) 28638c2ecf20Sopenharmony_ci{ 28648c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 28658c2ecf20Sopenharmony_ci u32 ecmr_bits; 28668c2ecf20Sopenharmony_ci int mcast_all = 0; 28678c2ecf20Sopenharmony_ci unsigned long flags; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci spin_lock_irqsave(&mdp->lock, flags); 28708c2ecf20Sopenharmony_ci /* Initial condition is MCT = 1, PRM = 0. 28718c2ecf20Sopenharmony_ci * Depending on ndev->flags, set PRM or clear MCT 28728c2ecf20Sopenharmony_ci */ 28738c2ecf20Sopenharmony_ci ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM; 28748c2ecf20Sopenharmony_ci if (mdp->cd->tsu) 28758c2ecf20Sopenharmony_ci ecmr_bits |= ECMR_MCT; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci if (!(ndev->flags & IFF_MULTICAST)) { 28788c2ecf20Sopenharmony_ci sh_eth_tsu_purge_mcast(ndev); 28798c2ecf20Sopenharmony_ci mcast_all = 1; 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci if (ndev->flags & IFF_ALLMULTI) { 28828c2ecf20Sopenharmony_ci sh_eth_tsu_purge_mcast(ndev); 28838c2ecf20Sopenharmony_ci ecmr_bits &= ~ECMR_MCT; 28848c2ecf20Sopenharmony_ci mcast_all = 1; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if (ndev->flags & IFF_PROMISC) { 28888c2ecf20Sopenharmony_ci sh_eth_tsu_purge_all(ndev); 28898c2ecf20Sopenharmony_ci ecmr_bits = (ecmr_bits & ~ECMR_MCT) | ECMR_PRM; 28908c2ecf20Sopenharmony_ci } else if (mdp->cd->tsu) { 28918c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 28928c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, ndev) { 28938c2ecf20Sopenharmony_ci if (mcast_all && is_multicast_ether_addr(ha->addr)) 28948c2ecf20Sopenharmony_ci continue; 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci if (sh_eth_tsu_add_entry(ndev, ha->addr) < 0) { 28978c2ecf20Sopenharmony_ci if (!mcast_all) { 28988c2ecf20Sopenharmony_ci sh_eth_tsu_purge_mcast(ndev); 28998c2ecf20Sopenharmony_ci ecmr_bits &= ~ECMR_MCT; 29008c2ecf20Sopenharmony_ci mcast_all = 1; 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci /* update the ethernet mode */ 29078c2ecf20Sopenharmony_ci sh_eth_write(ndev, ecmr_bits, ECMR); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdp->lock, flags); 29108c2ecf20Sopenharmony_ci} 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_cistatic void sh_eth_set_rx_csum(struct net_device *ndev, bool enable) 29138c2ecf20Sopenharmony_ci{ 29148c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 29158c2ecf20Sopenharmony_ci unsigned long flags; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci spin_lock_irqsave(&mdp->lock, flags); 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci /* Disable TX and RX */ 29208c2ecf20Sopenharmony_ci sh_eth_rcv_snd_disable(ndev); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci /* Modify RX Checksum setting */ 29238c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_RCSC, enable ? ECMR_RCSC : 0); 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci /* Enable TX and RX */ 29268c2ecf20Sopenharmony_ci sh_eth_rcv_snd_enable(ndev); 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mdp->lock, flags); 29298c2ecf20Sopenharmony_ci} 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_cistatic int sh_eth_set_features(struct net_device *ndev, 29328c2ecf20Sopenharmony_ci netdev_features_t features) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci netdev_features_t changed = ndev->features ^ features; 29358c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci if (changed & NETIF_F_RXCSUM && mdp->cd->rx_csum) 29388c2ecf20Sopenharmony_ci sh_eth_set_rx_csum(ndev, features & NETIF_F_RXCSUM); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci ndev->features = features; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci return 0; 29438c2ecf20Sopenharmony_ci} 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_cistatic int sh_eth_get_vtag_index(struct sh_eth_private *mdp) 29468c2ecf20Sopenharmony_ci{ 29478c2ecf20Sopenharmony_ci if (!mdp->port) 29488c2ecf20Sopenharmony_ci return TSU_VTAG0; 29498c2ecf20Sopenharmony_ci else 29508c2ecf20Sopenharmony_ci return TSU_VTAG1; 29518c2ecf20Sopenharmony_ci} 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_cistatic int sh_eth_vlan_rx_add_vid(struct net_device *ndev, 29548c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 29558c2ecf20Sopenharmony_ci{ 29568c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 29578c2ecf20Sopenharmony_ci int vtag_reg_index = sh_eth_get_vtag_index(mdp); 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci if (unlikely(!mdp->cd->tsu)) 29608c2ecf20Sopenharmony_ci return -EPERM; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci /* No filtering if vid = 0 */ 29638c2ecf20Sopenharmony_ci if (!vid) 29648c2ecf20Sopenharmony_ci return 0; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci mdp->vlan_num_ids++; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci /* The controller has one VLAN tag HW filter. So, if the filter is 29698c2ecf20Sopenharmony_ci * already enabled, the driver disables it and the filte 29708c2ecf20Sopenharmony_ci */ 29718c2ecf20Sopenharmony_ci if (mdp->vlan_num_ids > 1) { 29728c2ecf20Sopenharmony_ci /* disable VLAN filter */ 29738c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, vtag_reg_index); 29748c2ecf20Sopenharmony_ci return 0; 29758c2ecf20Sopenharmony_ci } 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, TSU_VTAG_ENABLE | (vid & TSU_VTAG_VID_MASK), 29788c2ecf20Sopenharmony_ci vtag_reg_index); 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci return 0; 29818c2ecf20Sopenharmony_ci} 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_cistatic int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, 29848c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 29858c2ecf20Sopenharmony_ci{ 29868c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 29878c2ecf20Sopenharmony_ci int vtag_reg_index = sh_eth_get_vtag_index(mdp); 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci if (unlikely(!mdp->cd->tsu)) 29908c2ecf20Sopenharmony_ci return -EPERM; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci /* No filtering if vid = 0 */ 29938c2ecf20Sopenharmony_ci if (!vid) 29948c2ecf20Sopenharmony_ci return 0; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci mdp->vlan_num_ids--; 29978c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, vtag_reg_index); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci return 0; 30008c2ecf20Sopenharmony_ci} 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci/* SuperH's TSU register init function */ 30038c2ecf20Sopenharmony_cistatic void sh_eth_tsu_init(struct sh_eth_private *mdp) 30048c2ecf20Sopenharmony_ci{ 30058c2ecf20Sopenharmony_ci if (!mdp->cd->dual_port) { 30068c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */ 30078c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, 30088c2ecf20Sopenharmony_ci TSU_FWSLC); /* Enable POST registers */ 30098c2ecf20Sopenharmony_ci return; 30108c2ecf20Sopenharmony_ci } 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWEN0); /* Disable forward(0->1) */ 30138c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWEN1); /* Disable forward(1->0) */ 30148c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FCM); /* forward fifo 3k-3k */ 30158c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL0); 30168c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0xc, TSU_BSYSL1); 30178c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_PRISL0); 30188c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_PRISL1); 30198c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWSL0); 30208c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWSL1); 30218c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC); 30228c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_QTAGM0); /* Disable QTAG(0->1) */ 30238c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_QTAGM1); /* Disable QTAG(1->0) */ 30248c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWSR); /* all interrupt status clear */ 30258c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_FWINMK); /* Disable all interrupt */ 30268c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */ 30278c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_POST1); /* Disable CAM entry [ 0- 7] */ 30288c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_POST2); /* Disable CAM entry [ 8-15] */ 30298c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_POST3); /* Disable CAM entry [16-23] */ 30308c2ecf20Sopenharmony_ci sh_eth_tsu_write(mdp, 0, TSU_POST4); /* Disable CAM entry [24-31] */ 30318c2ecf20Sopenharmony_ci} 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci/* MDIO bus release function */ 30348c2ecf20Sopenharmony_cistatic int sh_mdio_release(struct sh_eth_private *mdp) 30358c2ecf20Sopenharmony_ci{ 30368c2ecf20Sopenharmony_ci /* unregister mdio bus */ 30378c2ecf20Sopenharmony_ci mdiobus_unregister(mdp->mii_bus); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci /* free bitbang info */ 30408c2ecf20Sopenharmony_ci free_mdio_bitbang(mdp->mii_bus); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci return 0; 30438c2ecf20Sopenharmony_ci} 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci/* MDIO bus init function */ 30468c2ecf20Sopenharmony_cistatic int sh_mdio_init(struct sh_eth_private *mdp, 30478c2ecf20Sopenharmony_ci struct sh_eth_plat_data *pd) 30488c2ecf20Sopenharmony_ci{ 30498c2ecf20Sopenharmony_ci int ret; 30508c2ecf20Sopenharmony_ci struct bb_info *bitbang; 30518c2ecf20Sopenharmony_ci struct platform_device *pdev = mdp->pdev; 30528c2ecf20Sopenharmony_ci struct device *dev = &mdp->pdev->dev; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* create bit control struct for PHY */ 30558c2ecf20Sopenharmony_ci bitbang = devm_kzalloc(dev, sizeof(struct bb_info), GFP_KERNEL); 30568c2ecf20Sopenharmony_ci if (!bitbang) 30578c2ecf20Sopenharmony_ci return -ENOMEM; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci /* bitbang init */ 30608c2ecf20Sopenharmony_ci bitbang->addr = mdp->addr + mdp->reg_offset[PIR]; 30618c2ecf20Sopenharmony_ci bitbang->set_gate = pd->set_mdio_gate; 30628c2ecf20Sopenharmony_ci bitbang->ctrl.ops = &bb_ops; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci /* MII controller setting */ 30658c2ecf20Sopenharmony_ci mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl); 30668c2ecf20Sopenharmony_ci if (!mdp->mii_bus) 30678c2ecf20Sopenharmony_ci return -ENOMEM; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci /* Hook up MII support for ethtool */ 30708c2ecf20Sopenharmony_ci mdp->mii_bus->name = "sh_mii"; 30718c2ecf20Sopenharmony_ci mdp->mii_bus->parent = dev; 30728c2ecf20Sopenharmony_ci snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 30738c2ecf20Sopenharmony_ci pdev->name, pdev->id); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci /* register MDIO bus */ 30768c2ecf20Sopenharmony_ci if (pd->phy_irq > 0) 30778c2ecf20Sopenharmony_ci mdp->mii_bus->irq[pd->phy] = pd->phy_irq; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci ret = of_mdiobus_register(mdp->mii_bus, dev->of_node); 30808c2ecf20Sopenharmony_ci if (ret) 30818c2ecf20Sopenharmony_ci goto out_free_bus; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci return 0; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ciout_free_bus: 30868c2ecf20Sopenharmony_ci free_mdio_bitbang(mdp->mii_bus); 30878c2ecf20Sopenharmony_ci return ret; 30888c2ecf20Sopenharmony_ci} 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cistatic const u16 *sh_eth_get_register_offset(int register_type) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci const u16 *reg_offset = NULL; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci switch (register_type) { 30958c2ecf20Sopenharmony_ci case SH_ETH_REG_GIGABIT: 30968c2ecf20Sopenharmony_ci reg_offset = sh_eth_offset_gigabit; 30978c2ecf20Sopenharmony_ci break; 30988c2ecf20Sopenharmony_ci case SH_ETH_REG_FAST_RCAR: 30998c2ecf20Sopenharmony_ci reg_offset = sh_eth_offset_fast_rcar; 31008c2ecf20Sopenharmony_ci break; 31018c2ecf20Sopenharmony_ci case SH_ETH_REG_FAST_SH4: 31028c2ecf20Sopenharmony_ci reg_offset = sh_eth_offset_fast_sh4; 31038c2ecf20Sopenharmony_ci break; 31048c2ecf20Sopenharmony_ci case SH_ETH_REG_FAST_SH3_SH2: 31058c2ecf20Sopenharmony_ci reg_offset = sh_eth_offset_fast_sh3_sh2; 31068c2ecf20Sopenharmony_ci break; 31078c2ecf20Sopenharmony_ci } 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci return reg_offset; 31108c2ecf20Sopenharmony_ci} 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops = { 31138c2ecf20Sopenharmony_ci .ndo_open = sh_eth_open, 31148c2ecf20Sopenharmony_ci .ndo_stop = sh_eth_close, 31158c2ecf20Sopenharmony_ci .ndo_start_xmit = sh_eth_start_xmit, 31168c2ecf20Sopenharmony_ci .ndo_get_stats = sh_eth_get_stats, 31178c2ecf20Sopenharmony_ci .ndo_set_rx_mode = sh_eth_set_rx_mode, 31188c2ecf20Sopenharmony_ci .ndo_tx_timeout = sh_eth_tx_timeout, 31198c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl_running, 31208c2ecf20Sopenharmony_ci .ndo_change_mtu = sh_eth_change_mtu, 31218c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 31228c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 31238c2ecf20Sopenharmony_ci .ndo_set_features = sh_eth_set_features, 31248c2ecf20Sopenharmony_ci}; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_cistatic const struct net_device_ops sh_eth_netdev_ops_tsu = { 31278c2ecf20Sopenharmony_ci .ndo_open = sh_eth_open, 31288c2ecf20Sopenharmony_ci .ndo_stop = sh_eth_close, 31298c2ecf20Sopenharmony_ci .ndo_start_xmit = sh_eth_start_xmit, 31308c2ecf20Sopenharmony_ci .ndo_get_stats = sh_eth_get_stats, 31318c2ecf20Sopenharmony_ci .ndo_set_rx_mode = sh_eth_set_rx_mode, 31328c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = sh_eth_vlan_rx_add_vid, 31338c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = sh_eth_vlan_rx_kill_vid, 31348c2ecf20Sopenharmony_ci .ndo_tx_timeout = sh_eth_tx_timeout, 31358c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl_running, 31368c2ecf20Sopenharmony_ci .ndo_change_mtu = sh_eth_change_mtu, 31378c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 31388c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 31398c2ecf20Sopenharmony_ci .ndo_set_features = sh_eth_set_features, 31408c2ecf20Sopenharmony_ci}; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 31438c2ecf20Sopenharmony_cistatic struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) 31448c2ecf20Sopenharmony_ci{ 31458c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 31468c2ecf20Sopenharmony_ci struct sh_eth_plat_data *pdata; 31478c2ecf20Sopenharmony_ci phy_interface_t interface; 31488c2ecf20Sopenharmony_ci const char *mac_addr; 31498c2ecf20Sopenharmony_ci int ret; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 31528c2ecf20Sopenharmony_ci if (!pdata) 31538c2ecf20Sopenharmony_ci return NULL; 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci ret = of_get_phy_mode(np, &interface); 31568c2ecf20Sopenharmony_ci if (ret) 31578c2ecf20Sopenharmony_ci return NULL; 31588c2ecf20Sopenharmony_ci pdata->phy_interface = interface; 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci mac_addr = of_get_mac_address(np); 31618c2ecf20Sopenharmony_ci if (!IS_ERR(mac_addr)) 31628c2ecf20Sopenharmony_ci ether_addr_copy(pdata->mac_addr, mac_addr); 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci pdata->no_ether_link = 31658c2ecf20Sopenharmony_ci of_property_read_bool(np, "renesas,no-ether-link"); 31668c2ecf20Sopenharmony_ci pdata->ether_link_active_low = 31678c2ecf20Sopenharmony_ci of_property_read_bool(np, "renesas,ether-link-active-low"); 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci return pdata; 31708c2ecf20Sopenharmony_ci} 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_cistatic const struct of_device_id sh_eth_match_table[] = { 31738c2ecf20Sopenharmony_ci { .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data }, 31748c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7743", .data = &rcar_gen2_data }, 31758c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7745", .data = &rcar_gen2_data }, 31768c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7778", .data = &rcar_gen1_data }, 31778c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7779", .data = &rcar_gen1_data }, 31788c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7790", .data = &rcar_gen2_data }, 31798c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7791", .data = &rcar_gen2_data }, 31808c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7793", .data = &rcar_gen2_data }, 31818c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r8a7794", .data = &rcar_gen2_data }, 31828c2ecf20Sopenharmony_ci { .compatible = "renesas,gether-r8a77980", .data = &r8a77980_data }, 31838c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data }, 31848c2ecf20Sopenharmony_ci { .compatible = "renesas,ether-r7s9210", .data = &r7s9210_data }, 31858c2ecf20Sopenharmony_ci { .compatible = "renesas,rcar-gen1-ether", .data = &rcar_gen1_data }, 31868c2ecf20Sopenharmony_ci { .compatible = "renesas,rcar-gen2-ether", .data = &rcar_gen2_data }, 31878c2ecf20Sopenharmony_ci { } 31888c2ecf20Sopenharmony_ci}; 31898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_eth_match_table); 31908c2ecf20Sopenharmony_ci#else 31918c2ecf20Sopenharmony_cistatic inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) 31928c2ecf20Sopenharmony_ci{ 31938c2ecf20Sopenharmony_ci return NULL; 31948c2ecf20Sopenharmony_ci} 31958c2ecf20Sopenharmony_ci#endif 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_cistatic int sh_eth_drv_probe(struct platform_device *pdev) 31988c2ecf20Sopenharmony_ci{ 31998c2ecf20Sopenharmony_ci struct resource *res; 32008c2ecf20Sopenharmony_ci struct sh_eth_plat_data *pd = dev_get_platdata(&pdev->dev); 32018c2ecf20Sopenharmony_ci const struct platform_device_id *id = platform_get_device_id(pdev); 32028c2ecf20Sopenharmony_ci struct sh_eth_private *mdp; 32038c2ecf20Sopenharmony_ci struct net_device *ndev; 32048c2ecf20Sopenharmony_ci int ret; 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci /* get base addr */ 32078c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct sh_eth_private)); 32108c2ecf20Sopenharmony_ci if (!ndev) 32118c2ecf20Sopenharmony_ci return -ENOMEM; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 32148c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 32178c2ecf20Sopenharmony_ci if (ret < 0) 32188c2ecf20Sopenharmony_ci goto out_release; 32198c2ecf20Sopenharmony_ci ndev->irq = ret; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci mdp = netdev_priv(ndev); 32248c2ecf20Sopenharmony_ci mdp->num_tx_ring = TX_RING_SIZE; 32258c2ecf20Sopenharmony_ci mdp->num_rx_ring = RX_RING_SIZE; 32268c2ecf20Sopenharmony_ci mdp->addr = devm_ioremap_resource(&pdev->dev, res); 32278c2ecf20Sopenharmony_ci if (IS_ERR(mdp->addr)) { 32288c2ecf20Sopenharmony_ci ret = PTR_ERR(mdp->addr); 32298c2ecf20Sopenharmony_ci goto out_release; 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci ndev->base_addr = res->start; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci spin_lock_init(&mdp->lock); 32358c2ecf20Sopenharmony_ci mdp->pdev = pdev; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci if (pdev->dev.of_node) 32388c2ecf20Sopenharmony_ci pd = sh_eth_parse_dt(&pdev->dev); 32398c2ecf20Sopenharmony_ci if (!pd) { 32408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no platform data\n"); 32418c2ecf20Sopenharmony_ci ret = -EINVAL; 32428c2ecf20Sopenharmony_ci goto out_release; 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci /* get PHY ID */ 32468c2ecf20Sopenharmony_ci mdp->phy_id = pd->phy; 32478c2ecf20Sopenharmony_ci mdp->phy_interface = pd->phy_interface; 32488c2ecf20Sopenharmony_ci mdp->no_ether_link = pd->no_ether_link; 32498c2ecf20Sopenharmony_ci mdp->ether_link_active_low = pd->ether_link_active_low; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci /* set cpu data */ 32528c2ecf20Sopenharmony_ci if (id) 32538c2ecf20Sopenharmony_ci mdp->cd = (struct sh_eth_cpu_data *)id->driver_data; 32548c2ecf20Sopenharmony_ci else 32558c2ecf20Sopenharmony_ci mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type); 32588c2ecf20Sopenharmony_ci if (!mdp->reg_offset) { 32598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unknown register type (%d)\n", 32608c2ecf20Sopenharmony_ci mdp->cd->register_type); 32618c2ecf20Sopenharmony_ci ret = -EINVAL; 32628c2ecf20Sopenharmony_ci goto out_release; 32638c2ecf20Sopenharmony_ci } 32648c2ecf20Sopenharmony_ci sh_eth_set_default_cpu_data(mdp->cd); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci /* User's manual states max MTU should be 2048 but due to the 32678c2ecf20Sopenharmony_ci * alignment calculations in sh_eth_ring_init() the practical 32688c2ecf20Sopenharmony_ci * MTU is a bit less. Maybe this can be optimized some more. 32698c2ecf20Sopenharmony_ci */ 32708c2ecf20Sopenharmony_ci ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 32718c2ecf20Sopenharmony_ci ndev->min_mtu = ETH_MIN_MTU; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci if (mdp->cd->rx_csum) { 32748c2ecf20Sopenharmony_ci ndev->features = NETIF_F_RXCSUM; 32758c2ecf20Sopenharmony_ci ndev->hw_features = NETIF_F_RXCSUM; 32768c2ecf20Sopenharmony_ci } 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci /* set function */ 32798c2ecf20Sopenharmony_ci if (mdp->cd->tsu) 32808c2ecf20Sopenharmony_ci ndev->netdev_ops = &sh_eth_netdev_ops_tsu; 32818c2ecf20Sopenharmony_ci else 32828c2ecf20Sopenharmony_ci ndev->netdev_ops = &sh_eth_netdev_ops; 32838c2ecf20Sopenharmony_ci ndev->ethtool_ops = &sh_eth_ethtool_ops; 32848c2ecf20Sopenharmony_ci ndev->watchdog_timeo = TX_TIMEOUT; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci /* debug message level */ 32878c2ecf20Sopenharmony_ci mdp->msg_enable = SH_ETH_DEF_MSG_ENABLE; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci /* read and set MAC address */ 32908c2ecf20Sopenharmony_ci read_mac_address(ndev, pd->mac_addr); 32918c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(ndev->dev_addr)) { 32928c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 32938c2ecf20Sopenharmony_ci "no valid MAC address supplied, using a random one.\n"); 32948c2ecf20Sopenharmony_ci eth_hw_addr_random(ndev); 32958c2ecf20Sopenharmony_ci } 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci if (mdp->cd->tsu) { 32988c2ecf20Sopenharmony_ci int port = pdev->id < 0 ? 0 : pdev->id % 2; 32998c2ecf20Sopenharmony_ci struct resource *rtsu; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1); 33028c2ecf20Sopenharmony_ci if (!rtsu) { 33038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no TSU resource\n"); 33048c2ecf20Sopenharmony_ci ret = -ENODEV; 33058c2ecf20Sopenharmony_ci goto out_release; 33068c2ecf20Sopenharmony_ci } 33078c2ecf20Sopenharmony_ci /* We can only request the TSU region for the first port 33088c2ecf20Sopenharmony_ci * of the two sharing this TSU for the probe to succeed... 33098c2ecf20Sopenharmony_ci */ 33108c2ecf20Sopenharmony_ci if (port == 0 && 33118c2ecf20Sopenharmony_ci !devm_request_mem_region(&pdev->dev, rtsu->start, 33128c2ecf20Sopenharmony_ci resource_size(rtsu), 33138c2ecf20Sopenharmony_ci dev_name(&pdev->dev))) { 33148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't request TSU resource.\n"); 33158c2ecf20Sopenharmony_ci ret = -EBUSY; 33168c2ecf20Sopenharmony_ci goto out_release; 33178c2ecf20Sopenharmony_ci } 33188c2ecf20Sopenharmony_ci /* ioremap the TSU registers */ 33198c2ecf20Sopenharmony_ci mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start, 33208c2ecf20Sopenharmony_ci resource_size(rtsu)); 33218c2ecf20Sopenharmony_ci if (!mdp->tsu_addr) { 33228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "TSU region ioremap() failed.\n"); 33238c2ecf20Sopenharmony_ci ret = -ENOMEM; 33248c2ecf20Sopenharmony_ci goto out_release; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci mdp->port = port; 33278c2ecf20Sopenharmony_ci ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci /* Need to init only the first port of the two sharing a TSU */ 33308c2ecf20Sopenharmony_ci if (port == 0) { 33318c2ecf20Sopenharmony_ci if (mdp->cd->chip_reset) 33328c2ecf20Sopenharmony_ci mdp->cd->chip_reset(ndev); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci /* TSU init (Init only)*/ 33358c2ecf20Sopenharmony_ci sh_eth_tsu_init(mdp); 33368c2ecf20Sopenharmony_ci } 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci if (mdp->cd->rmiimode) 33408c2ecf20Sopenharmony_ci sh_eth_write(ndev, 0x1, RMIIMODE); 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci /* MDIO bus init */ 33438c2ecf20Sopenharmony_ci ret = sh_mdio_init(mdp, pd); 33448c2ecf20Sopenharmony_ci if (ret) { 33458c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 33468c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MDIO init failed: %d\n", ret); 33478c2ecf20Sopenharmony_ci goto out_release; 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64); 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci /* network device register */ 33538c2ecf20Sopenharmony_ci ret = register_netdev(ndev); 33548c2ecf20Sopenharmony_ci if (ret) 33558c2ecf20Sopenharmony_ci goto out_napi_del; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci if (mdp->cd->magic) 33588c2ecf20Sopenharmony_ci device_set_wakeup_capable(&pdev->dev, 1); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci /* print device information */ 33618c2ecf20Sopenharmony_ci netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n", 33628c2ecf20Sopenharmony_ci (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci pm_runtime_put(&pdev->dev); 33658c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ndev); 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci return ret; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ciout_napi_del: 33708c2ecf20Sopenharmony_ci netif_napi_del(&mdp->napi); 33718c2ecf20Sopenharmony_ci sh_mdio_release(mdp); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ciout_release: 33748c2ecf20Sopenharmony_ci /* net_dev free */ 33758c2ecf20Sopenharmony_ci free_netdev(ndev); 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci pm_runtime_put(&pdev->dev); 33788c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 33798c2ecf20Sopenharmony_ci return ret; 33808c2ecf20Sopenharmony_ci} 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_cistatic int sh_eth_drv_remove(struct platform_device *pdev) 33838c2ecf20Sopenharmony_ci{ 33848c2ecf20Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 33858c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci unregister_netdev(ndev); 33888c2ecf20Sopenharmony_ci netif_napi_del(&mdp->napi); 33898c2ecf20Sopenharmony_ci sh_mdio_release(mdp); 33908c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 33918c2ecf20Sopenharmony_ci free_netdev(ndev); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci return 0; 33948c2ecf20Sopenharmony_ci} 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 33978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 33988c2ecf20Sopenharmony_cistatic int sh_eth_wol_setup(struct net_device *ndev) 33998c2ecf20Sopenharmony_ci{ 34008c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci /* Only allow ECI interrupts */ 34038c2ecf20Sopenharmony_ci synchronize_irq(ndev->irq); 34048c2ecf20Sopenharmony_ci napi_disable(&mdp->napi); 34058c2ecf20Sopenharmony_ci sh_eth_write(ndev, EESIPR_ECIIP, EESIPR); 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci /* Enable MagicPacket */ 34088c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci return enable_irq_wake(ndev->irq); 34118c2ecf20Sopenharmony_ci} 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_cistatic int sh_eth_wol_restore(struct net_device *ndev) 34148c2ecf20Sopenharmony_ci{ 34158c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 34168c2ecf20Sopenharmony_ci int ret; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci napi_enable(&mdp->napi); 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci /* Disable MagicPacket */ 34218c2ecf20Sopenharmony_ci sh_eth_modify(ndev, ECMR, ECMR_MPDE, 0); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci /* The device needs to be reset to restore MagicPacket logic 34248c2ecf20Sopenharmony_ci * for next wakeup. If we close and open the device it will 34258c2ecf20Sopenharmony_ci * both be reset and all registers restored. This is what 34268c2ecf20Sopenharmony_ci * happens during suspend and resume without WoL enabled. 34278c2ecf20Sopenharmony_ci */ 34288c2ecf20Sopenharmony_ci ret = sh_eth_close(ndev); 34298c2ecf20Sopenharmony_ci if (ret < 0) 34308c2ecf20Sopenharmony_ci return ret; 34318c2ecf20Sopenharmony_ci ret = sh_eth_open(ndev); 34328c2ecf20Sopenharmony_ci if (ret < 0) 34338c2ecf20Sopenharmony_ci return ret; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci return disable_irq_wake(ndev->irq); 34368c2ecf20Sopenharmony_ci} 34378c2ecf20Sopenharmony_ci 34388c2ecf20Sopenharmony_cistatic int sh_eth_suspend(struct device *dev) 34398c2ecf20Sopenharmony_ci{ 34408c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 34418c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 34428c2ecf20Sopenharmony_ci int ret = 0; 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci if (!netif_running(ndev)) 34458c2ecf20Sopenharmony_ci return 0; 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci netif_device_detach(ndev); 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci if (mdp->wol_enabled) 34508c2ecf20Sopenharmony_ci ret = sh_eth_wol_setup(ndev); 34518c2ecf20Sopenharmony_ci else 34528c2ecf20Sopenharmony_ci ret = sh_eth_close(ndev); 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci return ret; 34558c2ecf20Sopenharmony_ci} 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_cistatic int sh_eth_resume(struct device *dev) 34588c2ecf20Sopenharmony_ci{ 34598c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 34608c2ecf20Sopenharmony_ci struct sh_eth_private *mdp = netdev_priv(ndev); 34618c2ecf20Sopenharmony_ci int ret = 0; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci if (!netif_running(ndev)) 34648c2ecf20Sopenharmony_ci return 0; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci if (mdp->wol_enabled) 34678c2ecf20Sopenharmony_ci ret = sh_eth_wol_restore(ndev); 34688c2ecf20Sopenharmony_ci else 34698c2ecf20Sopenharmony_ci ret = sh_eth_open(ndev); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci if (ret < 0) 34728c2ecf20Sopenharmony_ci return ret; 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci netif_device_attach(ndev); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci return ret; 34778c2ecf20Sopenharmony_ci} 34788c2ecf20Sopenharmony_ci#endif 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_cistatic int sh_eth_runtime_nop(struct device *dev) 34818c2ecf20Sopenharmony_ci{ 34828c2ecf20Sopenharmony_ci /* Runtime PM callback shared between ->runtime_suspend() 34838c2ecf20Sopenharmony_ci * and ->runtime_resume(). Simply returns success. 34848c2ecf20Sopenharmony_ci * 34858c2ecf20Sopenharmony_ci * This driver re-initializes all registers after 34868c2ecf20Sopenharmony_ci * pm_runtime_get_sync() anyway so there is no need 34878c2ecf20Sopenharmony_ci * to save and restore registers here. 34888c2ecf20Sopenharmony_ci */ 34898c2ecf20Sopenharmony_ci return 0; 34908c2ecf20Sopenharmony_ci} 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sh_eth_dev_pm_ops = { 34938c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume) 34948c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL) 34958c2ecf20Sopenharmony_ci}; 34968c2ecf20Sopenharmony_ci#define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops) 34978c2ecf20Sopenharmony_ci#else 34988c2ecf20Sopenharmony_ci#define SH_ETH_PM_OPS NULL 34998c2ecf20Sopenharmony_ci#endif 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_cistatic const struct platform_device_id sh_eth_id_table[] = { 35028c2ecf20Sopenharmony_ci { "sh7619-ether", (kernel_ulong_t)&sh7619_data }, 35038c2ecf20Sopenharmony_ci { "sh771x-ether", (kernel_ulong_t)&sh771x_data }, 35048c2ecf20Sopenharmony_ci { "sh7724-ether", (kernel_ulong_t)&sh7724_data }, 35058c2ecf20Sopenharmony_ci { "sh7734-gether", (kernel_ulong_t)&sh7734_data }, 35068c2ecf20Sopenharmony_ci { "sh7757-ether", (kernel_ulong_t)&sh7757_data }, 35078c2ecf20Sopenharmony_ci { "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga }, 35088c2ecf20Sopenharmony_ci { "sh7763-gether", (kernel_ulong_t)&sh7763_data }, 35098c2ecf20Sopenharmony_ci { } 35108c2ecf20Sopenharmony_ci}; 35118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sh_eth_id_table); 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_cistatic struct platform_driver sh_eth_driver = { 35148c2ecf20Sopenharmony_ci .probe = sh_eth_drv_probe, 35158c2ecf20Sopenharmony_ci .remove = sh_eth_drv_remove, 35168c2ecf20Sopenharmony_ci .id_table = sh_eth_id_table, 35178c2ecf20Sopenharmony_ci .driver = { 35188c2ecf20Sopenharmony_ci .name = CARDNAME, 35198c2ecf20Sopenharmony_ci .pm = SH_ETH_PM_OPS, 35208c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sh_eth_match_table), 35218c2ecf20Sopenharmony_ci }, 35228c2ecf20Sopenharmony_ci}; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_cimodule_platform_driver(sh_eth_driver); 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nobuhiro Iwamatsu, Yoshihiro Shimoda"); 35278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Renesas SuperH Ethernet driver"); 35288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3529