18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Atheros AR71xx built-in ethernet mac driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Oleksij Rempel <o.rempel@pengutronix.de> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * List of authors contributed to this driver before mainlining: 78c2ecf20Sopenharmony_ci * Alexander Couzens <lynxis@fe80.eu> 88c2ecf20Sopenharmony_ci * Christian Lamparter <chunkeey@gmail.com> 98c2ecf20Sopenharmony_ci * Chuanhong Guo <gch981213@gmail.com> 108c2ecf20Sopenharmony_ci * Daniel F. Dickinson <cshored@thecshore.com> 118c2ecf20Sopenharmony_ci * David Bauer <mail@david-bauer.net> 128c2ecf20Sopenharmony_ci * Felix Fietkau <nbd@nbd.name> 138c2ecf20Sopenharmony_ci * Gabor Juhos <juhosg@freemail.hu> 148c2ecf20Sopenharmony_ci * Hauke Mehrtens <hauke@hauke-m.de> 158c2ecf20Sopenharmony_ci * Johann Neuhauser <johann@it-neuhauser.de> 168c2ecf20Sopenharmony_ci * John Crispin <john@phrozen.org> 178c2ecf20Sopenharmony_ci * Jo-Philipp Wich <jo@mein.io> 188c2ecf20Sopenharmony_ci * Koen Vandeputte <koen.vandeputte@ncentric.com> 198c2ecf20Sopenharmony_ci * Lucian Cristian <lucian.cristian@gmail.com> 208c2ecf20Sopenharmony_ci * Matt Merhar <mattmerhar@protonmail.com> 218c2ecf20Sopenharmony_ci * Milan Krstic <milan.krstic@gmail.com> 228c2ecf20Sopenharmony_ci * Petr Štetiar <ynezz@true.cz> 238c2ecf20Sopenharmony_ci * Rosen Penev <rosenp@gmail.com> 248c2ecf20Sopenharmony_ci * Stephen Walker <stephendwalker+github@gmail.com> 258c2ecf20Sopenharmony_ci * Vittorio Gambaletta <openwrt@vittgam.net> 268c2ecf20Sopenharmony_ci * Weijie Gao <hackpascal@gmail.com> 278c2ecf20Sopenharmony_ci * Imre Kaloz <kaloz@openwrt.org> 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 318c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 328c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 338c2ecf20Sopenharmony_ci#include <linux/of_net.h> 348c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 358c2ecf20Sopenharmony_ci#include <linux/phylink.h> 368c2ecf20Sopenharmony_ci#include <linux/regmap.h> 378c2ecf20Sopenharmony_ci#include <linux/reset.h> 388c2ecf20Sopenharmony_ci#include <linux/clk.h> 398c2ecf20Sopenharmony_ci#include <linux/io.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* For our NAPI weight bigger does *NOT* mean better - it means more 428c2ecf20Sopenharmony_ci * D-cache misses and lots more wasted cycles than we'll ever 438c2ecf20Sopenharmony_ci * possibly gain from saving instructions. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci#define AG71XX_NAPI_WEIGHT 32 468c2ecf20Sopenharmony_ci#define AG71XX_OOM_REFILL (1 + HZ / 10) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define AG71XX_INT_ERR (AG71XX_INT_RX_BE | AG71XX_INT_TX_BE) 498c2ecf20Sopenharmony_ci#define AG71XX_INT_TX (AG71XX_INT_TX_PS) 508c2ecf20Sopenharmony_ci#define AG71XX_INT_RX (AG71XX_INT_RX_PR | AG71XX_INT_RX_OF) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX) 538c2ecf20Sopenharmony_ci#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define AG71XX_TX_MTU_LEN 1540 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define AG71XX_TX_RING_SPLIT 512 588c2ecf20Sopenharmony_ci#define AG71XX_TX_RING_DS_PER_PKT DIV_ROUND_UP(AG71XX_TX_MTU_LEN, \ 598c2ecf20Sopenharmony_ci AG71XX_TX_RING_SPLIT) 608c2ecf20Sopenharmony_ci#define AG71XX_TX_RING_SIZE_DEFAULT 128 618c2ecf20Sopenharmony_ci#define AG71XX_RX_RING_SIZE_DEFAULT 256 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define AG71XX_MDIO_RETRY 1000 648c2ecf20Sopenharmony_ci#define AG71XX_MDIO_DELAY 5 658c2ecf20Sopenharmony_ci#define AG71XX_MDIO_MAX_CLK 5000000 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* Register offsets */ 688c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_CFG1 0x0000 698c2ecf20Sopenharmony_ci#define MAC_CFG1_TXE BIT(0) /* Tx Enable */ 708c2ecf20Sopenharmony_ci#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */ 718c2ecf20Sopenharmony_ci#define MAC_CFG1_RXE BIT(2) /* Rx Enable */ 728c2ecf20Sopenharmony_ci#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */ 738c2ecf20Sopenharmony_ci#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */ 748c2ecf20Sopenharmony_ci#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */ 758c2ecf20Sopenharmony_ci#define MAC_CFG1_SR BIT(31) /* Soft Reset */ 768c2ecf20Sopenharmony_ci#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \ 778c2ecf20Sopenharmony_ci MAC_CFG1_SRX | MAC_CFG1_STX) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_CFG2 0x0004 808c2ecf20Sopenharmony_ci#define MAC_CFG2_FDX BIT(0) 818c2ecf20Sopenharmony_ci#define MAC_CFG2_PAD_CRC_EN BIT(2) 828c2ecf20Sopenharmony_ci#define MAC_CFG2_LEN_CHECK BIT(4) 838c2ecf20Sopenharmony_ci#define MAC_CFG2_IF_1000 BIT(9) 848c2ecf20Sopenharmony_ci#define MAC_CFG2_IF_10_100 BIT(8) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_MFL 0x0010 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_CFG 0x0020 898c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_4 0 908c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_6 2 918c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_8 3 928c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_10 4 938c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_14 5 948c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_20 6 958c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_28 7 968c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_34 8 978c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_42 9 988c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_50 10 998c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_58 11 1008c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_66 12 1018c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_74 13 1028c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_82 14 1038c2ecf20Sopenharmony_ci#define MII_CFG_CLK_DIV_98 15 1048c2ecf20Sopenharmony_ci#define MII_CFG_RESET BIT(31) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_CMD 0x0024 1078c2ecf20Sopenharmony_ci#define MII_CMD_READ BIT(0) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_ADDR 0x0028 1108c2ecf20Sopenharmony_ci#define MII_ADDR_SHIFT 8 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_CTRL 0x002c 1138c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_STATUS 0x0030 1148c2ecf20Sopenharmony_ci#define AG71XX_REG_MII_IND 0x0034 1158c2ecf20Sopenharmony_ci#define MII_IND_BUSY BIT(0) 1168c2ecf20Sopenharmony_ci#define MII_IND_INVALID BIT(2) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_IFCTL 0x0038 1198c2ecf20Sopenharmony_ci#define MAC_IFCTL_SPEED BIT(16) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_ADDR1 0x0040 1228c2ecf20Sopenharmony_ci#define AG71XX_REG_MAC_ADDR2 0x0044 1238c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG0 0x0048 1248c2ecf20Sopenharmony_ci#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */ 1258c2ecf20Sopenharmony_ci#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */ 1268c2ecf20Sopenharmony_ci#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */ 1278c2ecf20Sopenharmony_ci#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */ 1288c2ecf20Sopenharmony_ci#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */ 1298c2ecf20Sopenharmony_ci#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \ 1308c2ecf20Sopenharmony_ci | FIFO_CFG0_TXS | FIFO_CFG0_TXF) 1318c2ecf20Sopenharmony_ci#define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define FIFO_CFG0_ENABLE_SHIFT 8 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG1 0x004c 1368c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG2 0x0050 1378c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG3 0x0054 1388c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG4 0x0058 1398c2ecf20Sopenharmony_ci#define FIFO_CFG4_DE BIT(0) /* Drop Event */ 1408c2ecf20Sopenharmony_ci#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */ 1418c2ecf20Sopenharmony_ci#define FIFO_CFG4_FC BIT(2) /* False Carrier */ 1428c2ecf20Sopenharmony_ci#define FIFO_CFG4_CE BIT(3) /* Code Error */ 1438c2ecf20Sopenharmony_ci#define FIFO_CFG4_CR BIT(4) /* CRC error */ 1448c2ecf20Sopenharmony_ci#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */ 1458c2ecf20Sopenharmony_ci#define FIFO_CFG4_LO BIT(6) /* Length out of range */ 1468c2ecf20Sopenharmony_ci#define FIFO_CFG4_OK BIT(7) /* Packet is OK */ 1478c2ecf20Sopenharmony_ci#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */ 1488c2ecf20Sopenharmony_ci#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */ 1498c2ecf20Sopenharmony_ci#define FIFO_CFG4_DR BIT(10) /* Dribble */ 1508c2ecf20Sopenharmony_ci#define FIFO_CFG4_LE BIT(11) /* Long Event */ 1518c2ecf20Sopenharmony_ci#define FIFO_CFG4_CF BIT(12) /* Control Frame */ 1528c2ecf20Sopenharmony_ci#define FIFO_CFG4_PF BIT(13) /* Pause Frame */ 1538c2ecf20Sopenharmony_ci#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */ 1548c2ecf20Sopenharmony_ci#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */ 1558c2ecf20Sopenharmony_ci#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */ 1568c2ecf20Sopenharmony_ci#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */ 1578c2ecf20Sopenharmony_ci#define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \ 1588c2ecf20Sopenharmony_ci FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \ 1598c2ecf20Sopenharmony_ci FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \ 1608c2ecf20Sopenharmony_ci FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \ 1618c2ecf20Sopenharmony_ci FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \ 1628c2ecf20Sopenharmony_ci FIFO_CFG4_VT) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_CFG5 0x005c 1658c2ecf20Sopenharmony_ci#define FIFO_CFG5_DE BIT(0) /* Drop Event */ 1668c2ecf20Sopenharmony_ci#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */ 1678c2ecf20Sopenharmony_ci#define FIFO_CFG5_FC BIT(2) /* False Carrier */ 1688c2ecf20Sopenharmony_ci#define FIFO_CFG5_CE BIT(3) /* Code Error */ 1698c2ecf20Sopenharmony_ci#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */ 1708c2ecf20Sopenharmony_ci#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */ 1718c2ecf20Sopenharmony_ci#define FIFO_CFG5_OK BIT(6) /* Packet is OK */ 1728c2ecf20Sopenharmony_ci#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */ 1738c2ecf20Sopenharmony_ci#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */ 1748c2ecf20Sopenharmony_ci#define FIFO_CFG5_DR BIT(9) /* Dribble */ 1758c2ecf20Sopenharmony_ci#define FIFO_CFG5_CF BIT(10) /* Control Frame */ 1768c2ecf20Sopenharmony_ci#define FIFO_CFG5_PF BIT(11) /* Pause Frame */ 1778c2ecf20Sopenharmony_ci#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */ 1788c2ecf20Sopenharmony_ci#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */ 1798c2ecf20Sopenharmony_ci#define FIFO_CFG5_LE BIT(14) /* Long Event */ 1808c2ecf20Sopenharmony_ci#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */ 1818c2ecf20Sopenharmony_ci#define FIFO_CFG5_16 BIT(16) /* unknown */ 1828c2ecf20Sopenharmony_ci#define FIFO_CFG5_17 BIT(17) /* unknown */ 1838c2ecf20Sopenharmony_ci#define FIFO_CFG5_SF BIT(18) /* Short Frame */ 1848c2ecf20Sopenharmony_ci#define FIFO_CFG5_BM BIT(19) /* Byte Mode */ 1858c2ecf20Sopenharmony_ci#define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \ 1868c2ecf20Sopenharmony_ci FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \ 1878c2ecf20Sopenharmony_ci FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \ 1888c2ecf20Sopenharmony_ci FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \ 1898c2ecf20Sopenharmony_ci FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \ 1908c2ecf20Sopenharmony_ci FIFO_CFG5_17 | FIFO_CFG5_SF) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define AG71XX_REG_TX_CTRL 0x0180 1938c2ecf20Sopenharmony_ci#define TX_CTRL_TXE BIT(0) /* Tx Enable */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define AG71XX_REG_TX_DESC 0x0184 1968c2ecf20Sopenharmony_ci#define AG71XX_REG_TX_STATUS 0x0188 1978c2ecf20Sopenharmony_ci#define TX_STATUS_PS BIT(0) /* Packet Sent */ 1988c2ecf20Sopenharmony_ci#define TX_STATUS_UR BIT(1) /* Tx Underrun */ 1998c2ecf20Sopenharmony_ci#define TX_STATUS_BE BIT(3) /* Bus Error */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define AG71XX_REG_RX_CTRL 0x018c 2028c2ecf20Sopenharmony_ci#define RX_CTRL_RXE BIT(0) /* Rx Enable */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define AG71XX_DMA_RETRY 10 2058c2ecf20Sopenharmony_ci#define AG71XX_DMA_DELAY 1 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define AG71XX_REG_RX_DESC 0x0190 2088c2ecf20Sopenharmony_ci#define AG71XX_REG_RX_STATUS 0x0194 2098c2ecf20Sopenharmony_ci#define RX_STATUS_PR BIT(0) /* Packet Received */ 2108c2ecf20Sopenharmony_ci#define RX_STATUS_OF BIT(2) /* Rx Overflow */ 2118c2ecf20Sopenharmony_ci#define RX_STATUS_BE BIT(3) /* Bus Error */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#define AG71XX_REG_INT_ENABLE 0x0198 2148c2ecf20Sopenharmony_ci#define AG71XX_REG_INT_STATUS 0x019c 2158c2ecf20Sopenharmony_ci#define AG71XX_INT_TX_PS BIT(0) 2168c2ecf20Sopenharmony_ci#define AG71XX_INT_TX_UR BIT(1) 2178c2ecf20Sopenharmony_ci#define AG71XX_INT_TX_BE BIT(3) 2188c2ecf20Sopenharmony_ci#define AG71XX_INT_RX_PR BIT(4) 2198c2ecf20Sopenharmony_ci#define AG71XX_INT_RX_OF BIT(6) 2208c2ecf20Sopenharmony_ci#define AG71XX_INT_RX_BE BIT(7) 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#define AG71XX_REG_FIFO_DEPTH 0x01a8 2238c2ecf20Sopenharmony_ci#define AG71XX_REG_RX_SM 0x01b0 2248c2ecf20Sopenharmony_ci#define AG71XX_REG_TX_SM 0x01b4 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define AG71XX_DEFAULT_MSG_ENABLE \ 2278c2ecf20Sopenharmony_ci (NETIF_MSG_DRV \ 2288c2ecf20Sopenharmony_ci | NETIF_MSG_PROBE \ 2298c2ecf20Sopenharmony_ci | NETIF_MSG_LINK \ 2308c2ecf20Sopenharmony_ci | NETIF_MSG_TIMER \ 2318c2ecf20Sopenharmony_ci | NETIF_MSG_IFDOWN \ 2328c2ecf20Sopenharmony_ci | NETIF_MSG_IFUP \ 2338c2ecf20Sopenharmony_ci | NETIF_MSG_RX_ERR \ 2348c2ecf20Sopenharmony_ci | NETIF_MSG_TX_ERR) 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistruct ag71xx_statistic { 2378c2ecf20Sopenharmony_ci unsigned short offset; 2388c2ecf20Sopenharmony_ci u32 mask; 2398c2ecf20Sopenharmony_ci const char name[ETH_GSTRING_LEN]; 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic const struct ag71xx_statistic ag71xx_statistics[] = { 2438c2ecf20Sopenharmony_ci { 0x0080, GENMASK(17, 0), "Tx/Rx 64 Byte", }, 2448c2ecf20Sopenharmony_ci { 0x0084, GENMASK(17, 0), "Tx/Rx 65-127 Byte", }, 2458c2ecf20Sopenharmony_ci { 0x0088, GENMASK(17, 0), "Tx/Rx 128-255 Byte", }, 2468c2ecf20Sopenharmony_ci { 0x008C, GENMASK(17, 0), "Tx/Rx 256-511 Byte", }, 2478c2ecf20Sopenharmony_ci { 0x0090, GENMASK(17, 0), "Tx/Rx 512-1023 Byte", }, 2488c2ecf20Sopenharmony_ci { 0x0094, GENMASK(17, 0), "Tx/Rx 1024-1518 Byte", }, 2498c2ecf20Sopenharmony_ci { 0x0098, GENMASK(17, 0), "Tx/Rx 1519-1522 Byte VLAN", }, 2508c2ecf20Sopenharmony_ci { 0x009C, GENMASK(23, 0), "Rx Byte", }, 2518c2ecf20Sopenharmony_ci { 0x00A0, GENMASK(17, 0), "Rx Packet", }, 2528c2ecf20Sopenharmony_ci { 0x00A4, GENMASK(11, 0), "Rx FCS Error", }, 2538c2ecf20Sopenharmony_ci { 0x00A8, GENMASK(17, 0), "Rx Multicast Packet", }, 2548c2ecf20Sopenharmony_ci { 0x00AC, GENMASK(21, 0), "Rx Broadcast Packet", }, 2558c2ecf20Sopenharmony_ci { 0x00B0, GENMASK(17, 0), "Rx Control Frame Packet", }, 2568c2ecf20Sopenharmony_ci { 0x00B4, GENMASK(11, 0), "Rx Pause Frame Packet", }, 2578c2ecf20Sopenharmony_ci { 0x00B8, GENMASK(11, 0), "Rx Unknown OPCode Packet", }, 2588c2ecf20Sopenharmony_ci { 0x00BC, GENMASK(11, 0), "Rx Alignment Error", }, 2598c2ecf20Sopenharmony_ci { 0x00C0, GENMASK(15, 0), "Rx Frame Length Error", }, 2608c2ecf20Sopenharmony_ci { 0x00C4, GENMASK(11, 0), "Rx Code Error", }, 2618c2ecf20Sopenharmony_ci { 0x00C8, GENMASK(11, 0), "Rx Carrier Sense Error", }, 2628c2ecf20Sopenharmony_ci { 0x00CC, GENMASK(11, 0), "Rx Undersize Packet", }, 2638c2ecf20Sopenharmony_ci { 0x00D0, GENMASK(11, 0), "Rx Oversize Packet", }, 2648c2ecf20Sopenharmony_ci { 0x00D4, GENMASK(11, 0), "Rx Fragments", }, 2658c2ecf20Sopenharmony_ci { 0x00D8, GENMASK(11, 0), "Rx Jabber", }, 2668c2ecf20Sopenharmony_ci { 0x00DC, GENMASK(11, 0), "Rx Dropped Packet", }, 2678c2ecf20Sopenharmony_ci { 0x00E0, GENMASK(23, 0), "Tx Byte", }, 2688c2ecf20Sopenharmony_ci { 0x00E4, GENMASK(17, 0), "Tx Packet", }, 2698c2ecf20Sopenharmony_ci { 0x00E8, GENMASK(17, 0), "Tx Multicast Packet", }, 2708c2ecf20Sopenharmony_ci { 0x00EC, GENMASK(17, 0), "Tx Broadcast Packet", }, 2718c2ecf20Sopenharmony_ci { 0x00F0, GENMASK(11, 0), "Tx Pause Control Frame", }, 2728c2ecf20Sopenharmony_ci { 0x00F4, GENMASK(11, 0), "Tx Deferral Packet", }, 2738c2ecf20Sopenharmony_ci { 0x00F8, GENMASK(11, 0), "Tx Excessive Deferral Packet", }, 2748c2ecf20Sopenharmony_ci { 0x00FC, GENMASK(11, 0), "Tx Single Collision Packet", }, 2758c2ecf20Sopenharmony_ci { 0x0100, GENMASK(11, 0), "Tx Multiple Collision", }, 2768c2ecf20Sopenharmony_ci { 0x0104, GENMASK(11, 0), "Tx Late Collision Packet", }, 2778c2ecf20Sopenharmony_ci { 0x0108, GENMASK(11, 0), "Tx Excessive Collision Packet", }, 2788c2ecf20Sopenharmony_ci { 0x010C, GENMASK(12, 0), "Tx Total Collision", }, 2798c2ecf20Sopenharmony_ci { 0x0110, GENMASK(11, 0), "Tx Pause Frames Honored", }, 2808c2ecf20Sopenharmony_ci { 0x0114, GENMASK(11, 0), "Tx Drop Frame", }, 2818c2ecf20Sopenharmony_ci { 0x0118, GENMASK(11, 0), "Tx Jabber Frame", }, 2828c2ecf20Sopenharmony_ci { 0x011C, GENMASK(11, 0), "Tx FCS Error", }, 2838c2ecf20Sopenharmony_ci { 0x0120, GENMASK(11, 0), "Tx Control Frame", }, 2848c2ecf20Sopenharmony_ci { 0x0124, GENMASK(11, 0), "Tx Oversize Frame", }, 2858c2ecf20Sopenharmony_ci { 0x0128, GENMASK(11, 0), "Tx Undersize Frame", }, 2868c2ecf20Sopenharmony_ci { 0x012C, GENMASK(11, 0), "Tx Fragment", }, 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define DESC_EMPTY BIT(31) 2908c2ecf20Sopenharmony_ci#define DESC_MORE BIT(24) 2918c2ecf20Sopenharmony_ci#define DESC_PKTLEN_M 0xfff 2928c2ecf20Sopenharmony_cistruct ag71xx_desc { 2938c2ecf20Sopenharmony_ci u32 data; 2948c2ecf20Sopenharmony_ci u32 ctrl; 2958c2ecf20Sopenharmony_ci u32 next; 2968c2ecf20Sopenharmony_ci u32 pad; 2978c2ecf20Sopenharmony_ci} __aligned(4); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci#define AG71XX_DESC_SIZE roundup(sizeof(struct ag71xx_desc), \ 3008c2ecf20Sopenharmony_ci L1_CACHE_BYTES) 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistruct ag71xx_buf { 3038c2ecf20Sopenharmony_ci union { 3048c2ecf20Sopenharmony_ci struct { 3058c2ecf20Sopenharmony_ci struct sk_buff *skb; 3068c2ecf20Sopenharmony_ci unsigned int len; 3078c2ecf20Sopenharmony_ci } tx; 3088c2ecf20Sopenharmony_ci struct { 3098c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 3108c2ecf20Sopenharmony_ci void *rx_buf; 3118c2ecf20Sopenharmony_ci } rx; 3128c2ecf20Sopenharmony_ci }; 3138c2ecf20Sopenharmony_ci}; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistruct ag71xx_ring { 3168c2ecf20Sopenharmony_ci /* "Hot" fields in the data path. */ 3178c2ecf20Sopenharmony_ci unsigned int curr; 3188c2ecf20Sopenharmony_ci unsigned int dirty; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* "Cold" fields - not used in the data path. */ 3218c2ecf20Sopenharmony_ci struct ag71xx_buf *buf; 3228c2ecf20Sopenharmony_ci u16 order; 3238c2ecf20Sopenharmony_ci u16 desc_split; 3248c2ecf20Sopenharmony_ci dma_addr_t descs_dma; 3258c2ecf20Sopenharmony_ci u8 *descs_cpu; 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cienum ag71xx_type { 3298c2ecf20Sopenharmony_ci AR7100, 3308c2ecf20Sopenharmony_ci AR7240, 3318c2ecf20Sopenharmony_ci AR9130, 3328c2ecf20Sopenharmony_ci AR9330, 3338c2ecf20Sopenharmony_ci AR9340, 3348c2ecf20Sopenharmony_ci QCA9530, 3358c2ecf20Sopenharmony_ci QCA9550, 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistruct ag71xx_dcfg { 3398c2ecf20Sopenharmony_ci u32 max_frame_len; 3408c2ecf20Sopenharmony_ci const u32 *fifodata; 3418c2ecf20Sopenharmony_ci u16 desc_pktlen_mask; 3428c2ecf20Sopenharmony_ci bool tx_hang_workaround; 3438c2ecf20Sopenharmony_ci enum ag71xx_type type; 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistruct ag71xx { 3478c2ecf20Sopenharmony_ci /* Critical data related to the per-packet data path are clustered 3488c2ecf20Sopenharmony_ci * early in this structure to help improve the D-cache footprint. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci struct ag71xx_ring rx_ring ____cacheline_aligned; 3518c2ecf20Sopenharmony_ci struct ag71xx_ring tx_ring ____cacheline_aligned; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci u16 rx_buf_size; 3548c2ecf20Sopenharmony_ci u8 rx_buf_offset; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci struct net_device *ndev; 3578c2ecf20Sopenharmony_ci struct platform_device *pdev; 3588c2ecf20Sopenharmony_ci struct napi_struct napi; 3598c2ecf20Sopenharmony_ci u32 msg_enable; 3608c2ecf20Sopenharmony_ci const struct ag71xx_dcfg *dcfg; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* From this point onwards we're not looking at per-packet fields. */ 3638c2ecf20Sopenharmony_ci void __iomem *mac_base; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci struct ag71xx_desc *stop_desc; 3668c2ecf20Sopenharmony_ci dma_addr_t stop_desc_dma; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci phy_interface_t phy_if_mode; 3698c2ecf20Sopenharmony_ci struct phylink *phylink; 3708c2ecf20Sopenharmony_ci struct phylink_config phylink_config; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci struct delayed_work restart_work; 3738c2ecf20Sopenharmony_ci struct timer_list oom_timer; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci struct reset_control *mac_reset; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci u32 fifodata[3]; 3788c2ecf20Sopenharmony_ci int mac_idx; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci struct reset_control *mdio_reset; 3818c2ecf20Sopenharmony_ci struct mii_bus *mii_bus; 3828c2ecf20Sopenharmony_ci struct clk *clk_mdio; 3838c2ecf20Sopenharmony_ci struct clk *clk_eth; 3848c2ecf20Sopenharmony_ci}; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int ag71xx_desc_empty(struct ag71xx_desc *desc) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci return (desc->ctrl & DESC_EMPTY) != 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic struct ag71xx_desc *ag71xx_ring_desc(struct ag71xx_ring *ring, int idx) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci return (struct ag71xx_desc *)&ring->descs_cpu[idx * AG71XX_DESC_SIZE]; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int ag71xx_ring_size_order(int size) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci return fls(size - 1); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic bool ag71xx_is(struct ag71xx *ag, enum ag71xx_type type) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci return ag->dcfg->type == type; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void ag71xx_wr(struct ag71xx *ag, unsigned int reg, u32 value) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci iowrite32(value, ag->mac_base + reg); 4098c2ecf20Sopenharmony_ci /* flush write */ 4108c2ecf20Sopenharmony_ci (void)ioread32(ag->mac_base + reg); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic u32 ag71xx_rr(struct ag71xx *ag, unsigned int reg) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci return ioread32(ag->mac_base + reg); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void ag71xx_sb(struct ag71xx *ag, unsigned int reg, u32 mask) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci void __iomem *r; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci r = ag->mac_base + reg; 4238c2ecf20Sopenharmony_ci iowrite32(ioread32(r) | mask, r); 4248c2ecf20Sopenharmony_ci /* flush write */ 4258c2ecf20Sopenharmony_ci (void)ioread32(r); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void ag71xx_cb(struct ag71xx *ag, unsigned int reg, u32 mask) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci void __iomem *r; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci r = ag->mac_base + reg; 4338c2ecf20Sopenharmony_ci iowrite32(ioread32(r) & ~mask, r); 4348c2ecf20Sopenharmony_ci /* flush write */ 4358c2ecf20Sopenharmony_ci (void)ioread32(r); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void ag71xx_int_enable(struct ag71xx *ag, u32 ints) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void ag71xx_int_disable(struct ag71xx *ag, u32 ints) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void ag71xx_get_drvinfo(struct net_device *ndev, 4498c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci strlcpy(info->driver, "ag71xx", sizeof(info->driver)); 4548c2ecf20Sopenharmony_ci strlcpy(info->bus_info, of_node_full_name(ag->pdev->dev.of_node), 4558c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int ag71xx_get_link_ksettings(struct net_device *ndev, 4598c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *kset) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_get(ag->phylink, kset); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int ag71xx_set_link_ksettings(struct net_device *ndev, 4678c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *kset) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_set(ag->phylink, kset); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int ag71xx_ethtool_nway_reset(struct net_device *ndev) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return phylink_ethtool_nway_reset(ag->phylink); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void ag71xx_ethtool_get_pauseparam(struct net_device *ndev, 4828c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci phylink_ethtool_get_pauseparam(ag->phylink, pause); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int ag71xx_ethtool_set_pauseparam(struct net_device *ndev, 4908c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return phylink_ethtool_set_pauseparam(ag->phylink, pause); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void ag71xx_ethtool_get_strings(struct net_device *netdev, u32 sset, 4988c2ecf20Sopenharmony_ci u8 *data) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci if (sset == ETH_SS_STATS) { 5018c2ecf20Sopenharmony_ci int i; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++) 5048c2ecf20Sopenharmony_ci memcpy(data + i * ETH_GSTRING_LEN, 5058c2ecf20Sopenharmony_ci ag71xx_statistics[i].name, ETH_GSTRING_LEN); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic void ag71xx_ethtool_get_stats(struct net_device *ndev, 5108c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 5138c2ecf20Sopenharmony_ci int i; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++) 5168c2ecf20Sopenharmony_ci *data++ = ag71xx_rr(ag, ag71xx_statistics[i].offset) 5178c2ecf20Sopenharmony_ci & ag71xx_statistics[i].mask; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int ag71xx_ethtool_get_sset_count(struct net_device *ndev, int sset) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci if (sset == ETH_SS_STATS) 5238c2ecf20Sopenharmony_ci return ARRAY_SIZE(ag71xx_statistics); 5248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic const struct ethtool_ops ag71xx_ethtool_ops = { 5288c2ecf20Sopenharmony_ci .get_drvinfo = ag71xx_get_drvinfo, 5298c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 5308c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 5318c2ecf20Sopenharmony_ci .get_link_ksettings = ag71xx_get_link_ksettings, 5328c2ecf20Sopenharmony_ci .set_link_ksettings = ag71xx_set_link_ksettings, 5338c2ecf20Sopenharmony_ci .nway_reset = ag71xx_ethtool_nway_reset, 5348c2ecf20Sopenharmony_ci .get_pauseparam = ag71xx_ethtool_get_pauseparam, 5358c2ecf20Sopenharmony_ci .set_pauseparam = ag71xx_ethtool_set_pauseparam, 5368c2ecf20Sopenharmony_ci .get_strings = ag71xx_ethtool_get_strings, 5378c2ecf20Sopenharmony_ci .get_ethtool_stats = ag71xx_ethtool_get_stats, 5388c2ecf20Sopenharmony_ci .get_sset_count = ag71xx_ethtool_get_sset_count, 5398c2ecf20Sopenharmony_ci}; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int ag71xx_mdio_wait_busy(struct ag71xx *ag) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 5448c2ecf20Sopenharmony_ci int i; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci for (i = 0; i < AG71XX_MDIO_RETRY; i++) { 5478c2ecf20Sopenharmony_ci u32 busy; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci udelay(AG71XX_MDIO_DELAY); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci busy = ag71xx_rr(ag, AG71XX_REG_MII_IND); 5528c2ecf20Sopenharmony_ci if (!busy) 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci udelay(AG71XX_MDIO_DELAY); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci netif_err(ag, link, ndev, "MDIO operation timed out\n"); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct ag71xx *ag = bus->priv; 5668c2ecf20Sopenharmony_ci int err, val; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci err = ag71xx_mdio_wait_busy(ag); 5698c2ecf20Sopenharmony_ci if (err) 5708c2ecf20Sopenharmony_ci return err; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_ADDR, 5738c2ecf20Sopenharmony_ci ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff)); 5748c2ecf20Sopenharmony_ci /* enable read mode */ 5758c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci err = ag71xx_mdio_wait_busy(ag); 5788c2ecf20Sopenharmony_ci if (err) 5798c2ecf20Sopenharmony_ci return err; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci val = ag71xx_rr(ag, AG71XX_REG_MII_STATUS); 5828c2ecf20Sopenharmony_ci /* disable read mode */ 5838c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CMD, 0); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci netif_dbg(ag, link, ag->ndev, "mii_read: addr=%04x, reg=%04x, value=%04x\n", 5868c2ecf20Sopenharmony_ci addr, reg, val); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return val; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, 5928c2ecf20Sopenharmony_ci u16 val) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct ag71xx *ag = bus->priv; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci netif_dbg(ag, link, ag->ndev, "mii_write: addr=%04x, reg=%04x, value=%04x\n", 5978c2ecf20Sopenharmony_ci addr, reg, val); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_ADDR, 6008c2ecf20Sopenharmony_ci ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff)); 6018c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CTRL, val); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return ag71xx_mdio_wait_busy(ag); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic const u32 ar71xx_mdio_div_table[] = { 6078c2ecf20Sopenharmony_ci 4, 4, 6, 8, 10, 14, 20, 28, 6088c2ecf20Sopenharmony_ci}; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic const u32 ar7240_mdio_div_table[] = { 6118c2ecf20Sopenharmony_ci 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96, 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic const u32 ar933x_mdio_div_table[] = { 6158c2ecf20Sopenharmony_ci 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98, 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int ag71xx_mdio_get_divider(struct ag71xx *ag, u32 *div) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci unsigned long ref_clock; 6218c2ecf20Sopenharmony_ci const u32 *table; 6228c2ecf20Sopenharmony_ci int ndivs, i; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ref_clock = clk_get_rate(ag->clk_mdio); 6258c2ecf20Sopenharmony_ci if (!ref_clock) 6268c2ecf20Sopenharmony_ci return -EINVAL; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) { 6298c2ecf20Sopenharmony_ci table = ar933x_mdio_div_table; 6308c2ecf20Sopenharmony_ci ndivs = ARRAY_SIZE(ar933x_mdio_div_table); 6318c2ecf20Sopenharmony_ci } else if (ag71xx_is(ag, AR7240)) { 6328c2ecf20Sopenharmony_ci table = ar7240_mdio_div_table; 6338c2ecf20Sopenharmony_ci ndivs = ARRAY_SIZE(ar7240_mdio_div_table); 6348c2ecf20Sopenharmony_ci } else { 6358c2ecf20Sopenharmony_ci table = ar71xx_mdio_div_table; 6368c2ecf20Sopenharmony_ci ndivs = ARRAY_SIZE(ar71xx_mdio_div_table); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (i = 0; i < ndivs; i++) { 6408c2ecf20Sopenharmony_ci unsigned long t; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci t = ref_clock / table[i]; 6438c2ecf20Sopenharmony_ci if (t <= AG71XX_MDIO_MAX_CLK) { 6448c2ecf20Sopenharmony_ci *div = i; 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return -ENOENT; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int ag71xx_mdio_reset(struct mii_bus *bus) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct ag71xx *ag = bus->priv; 6558c2ecf20Sopenharmony_ci int err; 6568c2ecf20Sopenharmony_ci u32 t; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci err = ag71xx_mdio_get_divider(ag, &t); 6598c2ecf20Sopenharmony_ci if (err) 6608c2ecf20Sopenharmony_ci return err; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CFG, t | MII_CFG_RESET); 6638c2ecf20Sopenharmony_ci usleep_range(100, 200); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CFG, t); 6668c2ecf20Sopenharmony_ci usleep_range(100, 200); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return 0; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int ag71xx_mdio_probe(struct ag71xx *ag) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct device *dev = &ag->pdev->dev; 6748c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 6758c2ecf20Sopenharmony_ci static struct mii_bus *mii_bus; 6768c2ecf20Sopenharmony_ci struct device_node *np, *mnp; 6778c2ecf20Sopenharmony_ci int err; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci np = dev->of_node; 6808c2ecf20Sopenharmony_ci ag->mii_bus = NULL; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci ag->clk_mdio = devm_clk_get(dev, "mdio"); 6838c2ecf20Sopenharmony_ci if (IS_ERR(ag->clk_mdio)) { 6848c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "Failed to get mdio clk.\n"); 6858c2ecf20Sopenharmony_ci return PTR_ERR(ag->clk_mdio); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci err = clk_prepare_enable(ag->clk_mdio); 6898c2ecf20Sopenharmony_ci if (err) { 6908c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "Failed to enable mdio clk.\n"); 6918c2ecf20Sopenharmony_ci return err; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci mii_bus = devm_mdiobus_alloc(dev); 6958c2ecf20Sopenharmony_ci if (!mii_bus) { 6968c2ecf20Sopenharmony_ci err = -ENOMEM; 6978c2ecf20Sopenharmony_ci goto mdio_err_put_clk; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio"); 7018c2ecf20Sopenharmony_ci if (IS_ERR(ag->mdio_reset)) { 7028c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "Failed to get reset mdio.\n"); 7038c2ecf20Sopenharmony_ci err = PTR_ERR(ag->mdio_reset); 7048c2ecf20Sopenharmony_ci goto mdio_err_put_clk; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci mii_bus->name = "ag71xx_mdio"; 7088c2ecf20Sopenharmony_ci mii_bus->read = ag71xx_mdio_mii_read; 7098c2ecf20Sopenharmony_ci mii_bus->write = ag71xx_mdio_mii_write; 7108c2ecf20Sopenharmony_ci mii_bus->reset = ag71xx_mdio_reset; 7118c2ecf20Sopenharmony_ci mii_bus->priv = ag; 7128c2ecf20Sopenharmony_ci mii_bus->parent = dev; 7138c2ecf20Sopenharmony_ci snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, ag->mac_idx); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (!IS_ERR(ag->mdio_reset)) { 7168c2ecf20Sopenharmony_ci reset_control_assert(ag->mdio_reset); 7178c2ecf20Sopenharmony_ci msleep(100); 7188c2ecf20Sopenharmony_ci reset_control_deassert(ag->mdio_reset); 7198c2ecf20Sopenharmony_ci msleep(200); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci mnp = of_get_child_by_name(np, "mdio"); 7238c2ecf20Sopenharmony_ci err = of_mdiobus_register(mii_bus, mnp); 7248c2ecf20Sopenharmony_ci of_node_put(mnp); 7258c2ecf20Sopenharmony_ci if (err) 7268c2ecf20Sopenharmony_ci goto mdio_err_put_clk; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci ag->mii_bus = mii_bus; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cimdio_err_put_clk: 7338c2ecf20Sopenharmony_ci clk_disable_unprepare(ag->clk_mdio); 7348c2ecf20Sopenharmony_ci return err; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic void ag71xx_mdio_remove(struct ag71xx *ag) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci if (ag->mii_bus) 7408c2ecf20Sopenharmony_ci mdiobus_unregister(ag->mii_bus); 7418c2ecf20Sopenharmony_ci clk_disable_unprepare(ag->clk_mdio); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void ag71xx_hw_stop(struct ag71xx *ag) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci /* disable all interrupts and stop the rx/tx engine */ 7478c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); 7488c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); 7498c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic bool ag71xx_check_dma_stuck(struct ag71xx *ag) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci unsigned long timestamp; 7558c2ecf20Sopenharmony_ci u32 rx_sm, tx_sm, rx_fd; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci timestamp = netdev_get_tx_queue(ag->ndev, 0)->trans_start; 7588c2ecf20Sopenharmony_ci if (likely(time_before(jiffies, timestamp + HZ / 10))) 7598c2ecf20Sopenharmony_ci return false; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!netif_carrier_ok(ag->ndev)) 7628c2ecf20Sopenharmony_ci return false; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM); 7658c2ecf20Sopenharmony_ci if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6) 7668c2ecf20Sopenharmony_ci return true; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM); 7698c2ecf20Sopenharmony_ci rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH); 7708c2ecf20Sopenharmony_ci if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) && 7718c2ecf20Sopenharmony_ci ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0) 7728c2ecf20Sopenharmony_ci return true; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return false; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int ag71xx_tx_packets(struct ag71xx *ag, bool flush) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->tx_ring; 7808c2ecf20Sopenharmony_ci int sent = 0, bytes_compl = 0, n = 0; 7818c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 7828c2ecf20Sopenharmony_ci int ring_mask, ring_size; 7838c2ecf20Sopenharmony_ci bool dma_stuck = false; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci ring_mask = BIT(ring->order) - 1; 7868c2ecf20Sopenharmony_ci ring_size = BIT(ring->order); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci netif_dbg(ag, tx_queued, ndev, "processing TX ring\n"); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci while (ring->dirty + n != ring->curr) { 7918c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 7928c2ecf20Sopenharmony_ci struct sk_buff *skb; 7938c2ecf20Sopenharmony_ci unsigned int i; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci i = (ring->dirty + n) & ring_mask; 7968c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, i); 7978c2ecf20Sopenharmony_ci skb = ring->buf[i].tx.skb; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (!flush && !ag71xx_desc_empty(desc)) { 8008c2ecf20Sopenharmony_ci if (ag->dcfg->tx_hang_workaround && 8018c2ecf20Sopenharmony_ci ag71xx_check_dma_stuck(ag)) { 8028c2ecf20Sopenharmony_ci schedule_delayed_work(&ag->restart_work, 8038c2ecf20Sopenharmony_ci HZ / 2); 8048c2ecf20Sopenharmony_ci dma_stuck = true; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (flush) 8108c2ecf20Sopenharmony_ci desc->ctrl |= DESC_EMPTY; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci n++; 8138c2ecf20Sopenharmony_ci if (!skb) 8148c2ecf20Sopenharmony_ci continue; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8178c2ecf20Sopenharmony_ci ring->buf[i].tx.skb = NULL; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci bytes_compl += ring->buf[i].tx.len; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci sent++; 8228c2ecf20Sopenharmony_ci ring->dirty += n; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci while (n > 0) { 8258c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); 8268c2ecf20Sopenharmony_ci n--; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci netif_dbg(ag, tx_done, ndev, "%d packets sent out\n", sent); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (!sent) 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci ag->ndev->stats.tx_bytes += bytes_compl; 8368c2ecf20Sopenharmony_ci ag->ndev->stats.tx_packets += sent; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci netdev_completed_queue(ag->ndev, sent, bytes_compl); 8398c2ecf20Sopenharmony_ci if ((ring->curr - ring->dirty) < (ring_size * 3) / 4) 8408c2ecf20Sopenharmony_ci netif_wake_queue(ag->ndev); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!dma_stuck) 8438c2ecf20Sopenharmony_ci cancel_delayed_work(&ag->restart_work); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci return sent; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic void ag71xx_dma_wait_stop(struct ag71xx *ag) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 8518c2ecf20Sopenharmony_ci int i; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci for (i = 0; i < AG71XX_DMA_RETRY; i++) { 8548c2ecf20Sopenharmony_ci u32 rx, tx; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci mdelay(AG71XX_DMA_DELAY); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci rx = ag71xx_rr(ag, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE; 8598c2ecf20Sopenharmony_ci tx = ag71xx_rr(ag, AG71XX_REG_TX_CTRL) & TX_CTRL_TXE; 8608c2ecf20Sopenharmony_ci if (!rx && !tx) 8618c2ecf20Sopenharmony_ci return; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci netif_err(ag, hw, ndev, "DMA stop operation timed out\n"); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void ag71xx_dma_reset(struct ag71xx *ag) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 8708c2ecf20Sopenharmony_ci u32 val; 8718c2ecf20Sopenharmony_ci int i; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* stop RX and TX */ 8748c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); 8758c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* give the hardware some time to really stop all rx/tx activity 8788c2ecf20Sopenharmony_ci * clearing the descriptors too early causes random memory corruption 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci ag71xx_dma_wait_stop(ag); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* clear descriptor addresses */ 8838c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma); 8848c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* clear pending RX/TX interrupts */ 8878c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 8888c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); 8898c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* clear pending errors */ 8938c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); 8948c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); 8978c2ecf20Sopenharmony_ci if (val) 8988c2ecf20Sopenharmony_ci netif_err(ag, hw, ndev, "unable to clear DMA Rx status: %08x\n", 8998c2ecf20Sopenharmony_ci val); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* mask out reserved bits */ 9048c2ecf20Sopenharmony_ci val &= ~0xff000000; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (val) 9078c2ecf20Sopenharmony_ci netif_err(ag, hw, ndev, "unable to clear DMA Tx status: %08x\n", 9088c2ecf20Sopenharmony_ci val); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void ag71xx_hw_setup(struct ag71xx *ag) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci u32 init = MAC_CFG1_INIT; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* setup MAC configuration registers */ 9168c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, init); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci ag71xx_sb(ag, AG71XX_REG_MAC_CFG2, 9198c2ecf20Sopenharmony_ci MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* setup max frame length to zero */ 9228c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 0); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* setup FIFO configuration registers */ 9258c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT); 9268c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, ag->fifodata[0]); 9278c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, ag->fifodata[1]); 9288c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT); 9298c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT); 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic unsigned int ag71xx_max_frame_len(unsigned int mtu) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci return ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci u32 t; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci t = (((u32)mac[5]) << 24) | (((u32)mac[4]) << 16) 9428c2ecf20Sopenharmony_ci | (((u32)mac[3]) << 8) | ((u32)mac[2]); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci t = (((u32)mac[1]) << 24) | (((u32)mac[0]) << 16); 9478c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t); 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic void ag71xx_fast_reset(struct ag71xx *ag) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct net_device *dev = ag->ndev; 9538c2ecf20Sopenharmony_ci u32 rx_ds; 9548c2ecf20Sopenharmony_ci u32 mii_reg; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci ag71xx_hw_stop(ag); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG); 9598c2ecf20Sopenharmony_ci rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci ag71xx_tx_packets(ag, true); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci reset_control_assert(ag->mac_reset); 9648c2ecf20Sopenharmony_ci usleep_range(10, 20); 9658c2ecf20Sopenharmony_ci reset_control_deassert(ag->mac_reset); 9668c2ecf20Sopenharmony_ci usleep_range(10, 20); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci ag71xx_dma_reset(ag); 9698c2ecf20Sopenharmony_ci ag71xx_hw_setup(ag); 9708c2ecf20Sopenharmony_ci ag->tx_ring.curr = 0; 9718c2ecf20Sopenharmony_ci ag->tx_ring.dirty = 0; 9728c2ecf20Sopenharmony_ci netdev_reset_queue(ag->ndev); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* setup max frame length */ 9758c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 9768c2ecf20Sopenharmony_ci ag71xx_max_frame_len(ag->ndev->mtu)); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds); 9798c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma); 9808c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci ag71xx_hw_set_macaddr(ag, dev->dev_addr); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic void ag71xx_hw_start(struct ag71xx *ag) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci /* start RX engine */ 9888c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* enable interrupts */ 9918c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci netif_wake_queue(ag->ndev); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void ag71xx_mac_config(struct phylink_config *config, unsigned int mode, 9978c2ecf20Sopenharmony_ci const struct phylink_link_state *state) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (phylink_autoneg_inband(mode)) 10028c2ecf20Sopenharmony_ci return; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130)) 10058c2ecf20Sopenharmony_ci ag71xx_fast_reset(ag); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (ag->tx_ring.desc_split) { 10088c2ecf20Sopenharmony_ci ag->fifodata[2] &= 0xffff; 10098c2ecf20Sopenharmony_ci ag->fifodata[2] |= ((2048 - ag->tx_ring.desc_split) / 4) << 16; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic void ag71xx_mac_validate(struct phylink_config *config, 10168c2ecf20Sopenharmony_ci unsigned long *supported, 10178c2ecf20Sopenharmony_ci struct phylink_link_state *state) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); 10208c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci switch (state->interface) { 10238c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_NA: 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 10268c2ecf20Sopenharmony_ci if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 0) || 10278c2ecf20Sopenharmony_ci ag71xx_is(ag, AR9340) || 10288c2ecf20Sopenharmony_ci ag71xx_is(ag, QCA9530) || 10298c2ecf20Sopenharmony_ci (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1)) 10308c2ecf20Sopenharmony_ci break; 10318c2ecf20Sopenharmony_ci goto unsupported; 10328c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 10338c2ecf20Sopenharmony_ci if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 1) || 10348c2ecf20Sopenharmony_ci (ag71xx_is(ag, AR9340) && ag->mac_idx == 1) || 10358c2ecf20Sopenharmony_ci (ag71xx_is(ag, QCA9530) && ag->mac_idx == 1)) 10368c2ecf20Sopenharmony_ci break; 10378c2ecf20Sopenharmony_ci goto unsupported; 10388c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 10398c2ecf20Sopenharmony_ci if (ag71xx_is(ag, QCA9550) && ag->mac_idx == 0) 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci goto unsupported; 10428c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 10438c2ecf20Sopenharmony_ci if (ag71xx_is(ag, AR9340) && ag->mac_idx == 0) 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci goto unsupported; 10468c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII: 10478c2ecf20Sopenharmony_ci if ((ag71xx_is(ag, AR9340) && ag->mac_idx == 0) || 10488c2ecf20Sopenharmony_ci (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1)) 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci goto unsupported; 10518c2ecf20Sopenharmony_ci default: 10528c2ecf20Sopenharmony_ci goto unsupported; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci phylink_set(mask, MII); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci phylink_set(mask, Pause); 10588c2ecf20Sopenharmony_ci phylink_set(mask, Asym_Pause); 10598c2ecf20Sopenharmony_ci phylink_set(mask, Autoneg); 10608c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Half); 10618c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Full); 10628c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Half); 10638c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Full); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (state->interface == PHY_INTERFACE_MODE_NA || 10668c2ecf20Sopenharmony_ci state->interface == PHY_INTERFACE_MODE_SGMII || 10678c2ecf20Sopenharmony_ci state->interface == PHY_INTERFACE_MODE_RGMII || 10688c2ecf20Sopenharmony_ci state->interface == PHY_INTERFACE_MODE_GMII) { 10698c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 10708c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci bitmap_and(supported, supported, mask, 10748c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); 10758c2ecf20Sopenharmony_ci bitmap_and(state->advertising, state->advertising, mask, 10768c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return; 10798c2ecf20Sopenharmony_ciunsupported: 10808c2ecf20Sopenharmony_ci bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic void ag71xx_mac_pcs_get_state(struct phylink_config *config, 10848c2ecf20Sopenharmony_ci struct phylink_link_state *state) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci state->link = 0; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic void ag71xx_mac_an_restart(struct phylink_config *config) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci /* Not Supported */ 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic void ag71xx_mac_link_down(struct phylink_config *config, 10958c2ecf20Sopenharmony_ci unsigned int mode, phy_interface_t interface) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci ag71xx_hw_stop(ag); 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic void ag71xx_mac_link_up(struct phylink_config *config, 11038c2ecf20Sopenharmony_ci struct phy_device *phy, 11048c2ecf20Sopenharmony_ci unsigned int mode, phy_interface_t interface, 11058c2ecf20Sopenharmony_ci int speed, int duplex, 11068c2ecf20Sopenharmony_ci bool tx_pause, bool rx_pause) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); 11098c2ecf20Sopenharmony_ci u32 cfg1, cfg2; 11108c2ecf20Sopenharmony_ci u32 ifctl; 11118c2ecf20Sopenharmony_ci u32 fifo5; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); 11148c2ecf20Sopenharmony_ci cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); 11158c2ecf20Sopenharmony_ci cfg2 |= duplex ? MAC_CFG2_FDX : 0; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); 11188c2ecf20Sopenharmony_ci ifctl &= ~(MAC_IFCTL_SPEED); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); 11218c2ecf20Sopenharmony_ci fifo5 &= ~FIFO_CFG5_BM; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci switch (speed) { 11248c2ecf20Sopenharmony_ci case SPEED_1000: 11258c2ecf20Sopenharmony_ci cfg2 |= MAC_CFG2_IF_1000; 11268c2ecf20Sopenharmony_ci fifo5 |= FIFO_CFG5_BM; 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci case SPEED_100: 11298c2ecf20Sopenharmony_ci cfg2 |= MAC_CFG2_IF_10_100; 11308c2ecf20Sopenharmony_ci ifctl |= MAC_IFCTL_SPEED; 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci case SPEED_10: 11338c2ecf20Sopenharmony_ci cfg2 |= MAC_CFG2_IF_10_100; 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci default: 11368c2ecf20Sopenharmony_ci return; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); 11408c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); 11418c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci cfg1 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG1); 11448c2ecf20Sopenharmony_ci cfg1 &= ~(MAC_CFG1_TFC | MAC_CFG1_RFC); 11458c2ecf20Sopenharmony_ci if (tx_pause) 11468c2ecf20Sopenharmony_ci cfg1 |= MAC_CFG1_TFC; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (rx_pause) 11498c2ecf20Sopenharmony_ci cfg1 |= MAC_CFG1_RFC; 11508c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, cfg1); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci ag71xx_hw_start(ag); 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic const struct phylink_mac_ops ag71xx_phylink_mac_ops = { 11568c2ecf20Sopenharmony_ci .validate = ag71xx_mac_validate, 11578c2ecf20Sopenharmony_ci .mac_pcs_get_state = ag71xx_mac_pcs_get_state, 11588c2ecf20Sopenharmony_ci .mac_an_restart = ag71xx_mac_an_restart, 11598c2ecf20Sopenharmony_ci .mac_config = ag71xx_mac_config, 11608c2ecf20Sopenharmony_ci .mac_link_down = ag71xx_mac_link_down, 11618c2ecf20Sopenharmony_ci .mac_link_up = ag71xx_mac_link_up, 11628c2ecf20Sopenharmony_ci}; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic int ag71xx_phylink_setup(struct ag71xx *ag) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct phylink *phylink; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ag->phylink_config.dev = &ag->ndev->dev; 11698c2ecf20Sopenharmony_ci ag->phylink_config.type = PHYLINK_NETDEV; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci phylink = phylink_create(&ag->phylink_config, ag->pdev->dev.fwnode, 11728c2ecf20Sopenharmony_ci ag->phy_if_mode, &ag71xx_phylink_mac_ops); 11738c2ecf20Sopenharmony_ci if (IS_ERR(phylink)) 11748c2ecf20Sopenharmony_ci return PTR_ERR(phylink); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci ag->phylink = phylink; 11778c2ecf20Sopenharmony_ci return 0; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic void ag71xx_ring_tx_clean(struct ag71xx *ag) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->tx_ring; 11838c2ecf20Sopenharmony_ci int ring_mask = BIT(ring->order) - 1; 11848c2ecf20Sopenharmony_ci u32 bytes_compl = 0, pkts_compl = 0; 11858c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci while (ring->curr != ring->dirty) { 11888c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 11898c2ecf20Sopenharmony_ci u32 i = ring->dirty & ring_mask; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, i); 11928c2ecf20Sopenharmony_ci if (!ag71xx_desc_empty(desc)) { 11938c2ecf20Sopenharmony_ci desc->ctrl = 0; 11948c2ecf20Sopenharmony_ci ndev->stats.tx_errors++; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (ring->buf[i].tx.skb) { 11988c2ecf20Sopenharmony_ci bytes_compl += ring->buf[i].tx.len; 11998c2ecf20Sopenharmony_ci pkts_compl++; 12008c2ecf20Sopenharmony_ci dev_kfree_skb_any(ring->buf[i].tx.skb); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci ring->buf[i].tx.skb = NULL; 12038c2ecf20Sopenharmony_ci ring->dirty++; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* flush descriptors */ 12078c2ecf20Sopenharmony_ci wmb(); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci netdev_completed_queue(ndev, pkts_compl, bytes_compl); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic void ag71xx_ring_tx_init(struct ag71xx *ag) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->tx_ring; 12158c2ecf20Sopenharmony_ci int ring_size = BIT(ring->order); 12168c2ecf20Sopenharmony_ci int ring_mask = ring_size - 1; 12178c2ecf20Sopenharmony_ci int i; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci for (i = 0; i < ring_size; i++) { 12208c2ecf20Sopenharmony_ci struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci desc->next = (u32)(ring->descs_dma + 12238c2ecf20Sopenharmony_ci AG71XX_DESC_SIZE * ((i + 1) & ring_mask)); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci desc->ctrl = DESC_EMPTY; 12268c2ecf20Sopenharmony_ci ring->buf[i].tx.skb = NULL; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* flush descriptors */ 12308c2ecf20Sopenharmony_ci wmb(); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci ring->curr = 0; 12338c2ecf20Sopenharmony_ci ring->dirty = 0; 12348c2ecf20Sopenharmony_ci netdev_reset_queue(ag->ndev); 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic void ag71xx_ring_rx_clean(struct ag71xx *ag) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->rx_ring; 12408c2ecf20Sopenharmony_ci int ring_size = BIT(ring->order); 12418c2ecf20Sopenharmony_ci int i; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (!ring->buf) 12448c2ecf20Sopenharmony_ci return; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci for (i = 0; i < ring_size; i++) 12478c2ecf20Sopenharmony_ci if (ring->buf[i].rx.rx_buf) { 12488c2ecf20Sopenharmony_ci dma_unmap_single(&ag->pdev->dev, 12498c2ecf20Sopenharmony_ci ring->buf[i].rx.dma_addr, 12508c2ecf20Sopenharmony_ci ag->rx_buf_size, DMA_FROM_DEVICE); 12518c2ecf20Sopenharmony_ci skb_free_frag(ring->buf[i].rx.rx_buf); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic int ag71xx_buffer_size(struct ag71xx *ag) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci return ag->rx_buf_size + 12588c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf, 12628c2ecf20Sopenharmony_ci int offset, 12638c2ecf20Sopenharmony_ci void *(*alloc)(unsigned int size)) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->rx_ring; 12668c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 12678c2ecf20Sopenharmony_ci void *data; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci data = alloc(ag71xx_buffer_size(ag)); 12728c2ecf20Sopenharmony_ci if (!data) 12738c2ecf20Sopenharmony_ci return false; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci buf->rx.rx_buf = data; 12768c2ecf20Sopenharmony_ci buf->rx.dma_addr = dma_map_single(&ag->pdev->dev, data, ag->rx_buf_size, 12778c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12788c2ecf20Sopenharmony_ci desc->data = (u32)buf->rx.dma_addr + offset; 12798c2ecf20Sopenharmony_ci return true; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int ag71xx_ring_rx_init(struct ag71xx *ag) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->rx_ring; 12858c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 12868c2ecf20Sopenharmony_ci int ring_mask = BIT(ring->order) - 1; 12878c2ecf20Sopenharmony_ci int ring_size = BIT(ring->order); 12888c2ecf20Sopenharmony_ci unsigned int i; 12898c2ecf20Sopenharmony_ci int ret; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci ret = 0; 12928c2ecf20Sopenharmony_ci for (i = 0; i < ring_size; i++) { 12938c2ecf20Sopenharmony_ci struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci desc->next = (u32)(ring->descs_dma + 12968c2ecf20Sopenharmony_ci AG71XX_DESC_SIZE * ((i + 1) & ring_mask)); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "RX desc at %p, next is %08x\n", 12998c2ecf20Sopenharmony_ci desc, desc->next); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci for (i = 0; i < ring_size; i++) { 13038c2ecf20Sopenharmony_ci struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], ag->rx_buf_offset, 13068c2ecf20Sopenharmony_ci netdev_alloc_frag)) { 13078c2ecf20Sopenharmony_ci ret = -ENOMEM; 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci desc->ctrl = DESC_EMPTY; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* flush descriptors */ 13158c2ecf20Sopenharmony_ci wmb(); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci ring->curr = 0; 13188c2ecf20Sopenharmony_ci ring->dirty = 0; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci return ret; 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int ag71xx_ring_rx_refill(struct ag71xx *ag) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct ag71xx_ring *ring = &ag->rx_ring; 13268c2ecf20Sopenharmony_ci int ring_mask = BIT(ring->order) - 1; 13278c2ecf20Sopenharmony_ci int offset = ag->rx_buf_offset; 13288c2ecf20Sopenharmony_ci unsigned int count; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci count = 0; 13318c2ecf20Sopenharmony_ci for (; ring->curr - ring->dirty > 0; ring->dirty++) { 13328c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 13338c2ecf20Sopenharmony_ci unsigned int i; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci i = ring->dirty & ring_mask; 13368c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, i); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (!ring->buf[i].rx.rx_buf && 13398c2ecf20Sopenharmony_ci !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset, 13408c2ecf20Sopenharmony_ci napi_alloc_frag)) 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci desc->ctrl = DESC_EMPTY; 13448c2ecf20Sopenharmony_ci count++; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci /* flush descriptors */ 13488c2ecf20Sopenharmony_ci wmb(); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ag->ndev, "%u rx descriptors refilled\n", 13518c2ecf20Sopenharmony_ci count); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci return count; 13548c2ecf20Sopenharmony_ci} 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cistatic int ag71xx_rings_init(struct ag71xx *ag) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci struct ag71xx_ring *tx = &ag->tx_ring; 13598c2ecf20Sopenharmony_ci struct ag71xx_ring *rx = &ag->rx_ring; 13608c2ecf20Sopenharmony_ci int ring_size, tx_size; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ring_size = BIT(tx->order) + BIT(rx->order); 13638c2ecf20Sopenharmony_ci tx_size = BIT(tx->order); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci tx->buf = kcalloc(ring_size, sizeof(*tx->buf), GFP_KERNEL); 13668c2ecf20Sopenharmony_ci if (!tx->buf) 13678c2ecf20Sopenharmony_ci return -ENOMEM; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci tx->descs_cpu = dma_alloc_coherent(&ag->pdev->dev, 13708c2ecf20Sopenharmony_ci ring_size * AG71XX_DESC_SIZE, 13718c2ecf20Sopenharmony_ci &tx->descs_dma, GFP_KERNEL); 13728c2ecf20Sopenharmony_ci if (!tx->descs_cpu) { 13738c2ecf20Sopenharmony_ci kfree(tx->buf); 13748c2ecf20Sopenharmony_ci tx->buf = NULL; 13758c2ecf20Sopenharmony_ci return -ENOMEM; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci rx->buf = &tx->buf[tx_size]; 13798c2ecf20Sopenharmony_ci rx->descs_cpu = ((void *)tx->descs_cpu) + tx_size * AG71XX_DESC_SIZE; 13808c2ecf20Sopenharmony_ci rx->descs_dma = tx->descs_dma + tx_size * AG71XX_DESC_SIZE; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci ag71xx_ring_tx_init(ag); 13838c2ecf20Sopenharmony_ci return ag71xx_ring_rx_init(ag); 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic void ag71xx_rings_free(struct ag71xx *ag) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct ag71xx_ring *tx = &ag->tx_ring; 13898c2ecf20Sopenharmony_ci struct ag71xx_ring *rx = &ag->rx_ring; 13908c2ecf20Sopenharmony_ci int ring_size; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci ring_size = BIT(tx->order) + BIT(rx->order); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (tx->descs_cpu) 13958c2ecf20Sopenharmony_ci dma_free_coherent(&ag->pdev->dev, ring_size * AG71XX_DESC_SIZE, 13968c2ecf20Sopenharmony_ci tx->descs_cpu, tx->descs_dma); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci kfree(tx->buf); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci tx->descs_cpu = NULL; 14018c2ecf20Sopenharmony_ci rx->descs_cpu = NULL; 14028c2ecf20Sopenharmony_ci tx->buf = NULL; 14038c2ecf20Sopenharmony_ci rx->buf = NULL; 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_cistatic void ag71xx_rings_cleanup(struct ag71xx *ag) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci ag71xx_ring_rx_clean(ag); 14098c2ecf20Sopenharmony_ci ag71xx_ring_tx_clean(ag); 14108c2ecf20Sopenharmony_ci ag71xx_rings_free(ag); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci netdev_reset_queue(ag->ndev); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic void ag71xx_hw_init(struct ag71xx *ag) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci ag71xx_hw_stop(ag); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR); 14208c2ecf20Sopenharmony_ci usleep_range(20, 30); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci reset_control_assert(ag->mac_reset); 14238c2ecf20Sopenharmony_ci msleep(100); 14248c2ecf20Sopenharmony_ci reset_control_deassert(ag->mac_reset); 14258c2ecf20Sopenharmony_ci msleep(200); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci ag71xx_hw_setup(ag); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci ag71xx_dma_reset(ag); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistatic int ag71xx_hw_enable(struct ag71xx *ag) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci int ret; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci ret = ag71xx_rings_init(ag); 14378c2ecf20Sopenharmony_ci if (ret) 14388c2ecf20Sopenharmony_ci return ret; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci napi_enable(&ag->napi); 14418c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma); 14428c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma); 14438c2ecf20Sopenharmony_ci netif_start_queue(ag->ndev); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return 0; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic void ag71xx_hw_disable(struct ag71xx *ag) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci netif_stop_queue(ag->ndev); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci ag71xx_hw_stop(ag); 14538c2ecf20Sopenharmony_ci ag71xx_dma_reset(ag); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci napi_disable(&ag->napi); 14568c2ecf20Sopenharmony_ci del_timer_sync(&ag->oom_timer); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci ag71xx_rings_cleanup(ag); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic int ag71xx_open(struct net_device *ndev) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 14648c2ecf20Sopenharmony_ci unsigned int max_frame_len; 14658c2ecf20Sopenharmony_ci int ret; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci ret = phylink_of_phy_connect(ag->phylink, ag->pdev->dev.of_node, 0); 14688c2ecf20Sopenharmony_ci if (ret) { 14698c2ecf20Sopenharmony_ci netif_err(ag, link, ndev, "phylink_of_phy_connect filed with err: %i\n", 14708c2ecf20Sopenharmony_ci ret); 14718c2ecf20Sopenharmony_ci return ret; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci max_frame_len = ag71xx_max_frame_len(ndev->mtu); 14758c2ecf20Sopenharmony_ci ag->rx_buf_size = 14768c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* setup max frame length */ 14798c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len); 14808c2ecf20Sopenharmony_ci ag71xx_hw_set_macaddr(ag, ndev->dev_addr); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci ret = ag71xx_hw_enable(ag); 14838c2ecf20Sopenharmony_ci if (ret) 14848c2ecf20Sopenharmony_ci goto err; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci phylink_start(ag->phylink); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci return 0; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cierr: 14918c2ecf20Sopenharmony_ci ag71xx_rings_cleanup(ag); 14928c2ecf20Sopenharmony_ci phylink_disconnect_phy(ag->phylink); 14938c2ecf20Sopenharmony_ci return ret; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic int ag71xx_stop(struct net_device *ndev) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci phylink_stop(ag->phylink); 15018c2ecf20Sopenharmony_ci phylink_disconnect_phy(ag->phylink); 15028c2ecf20Sopenharmony_ci ag71xx_hw_disable(ag); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return 0; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int ag71xx_fill_dma_desc(struct ag71xx_ring *ring, u32 addr, int len) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci int i, ring_mask, ndesc, split; 15108c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci ring_mask = BIT(ring->order) - 1; 15138c2ecf20Sopenharmony_ci ndesc = 0; 15148c2ecf20Sopenharmony_ci split = ring->desc_split; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!split) 15178c2ecf20Sopenharmony_ci split = len; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci while (len > 0) { 15208c2ecf20Sopenharmony_ci unsigned int cur_len = len; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci i = (ring->curr + ndesc) & ring_mask; 15238c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, i); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (!ag71xx_desc_empty(desc)) 15268c2ecf20Sopenharmony_ci return -1; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (cur_len > split) { 15298c2ecf20Sopenharmony_ci cur_len = split; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* TX will hang if DMA transfers <= 4 bytes, 15328c2ecf20Sopenharmony_ci * make sure next segment is more than 4 bytes long. 15338c2ecf20Sopenharmony_ci */ 15348c2ecf20Sopenharmony_ci if (len <= split + 4) 15358c2ecf20Sopenharmony_ci cur_len -= 4; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci desc->data = addr; 15398c2ecf20Sopenharmony_ci addr += cur_len; 15408c2ecf20Sopenharmony_ci len -= cur_len; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (len > 0) 15438c2ecf20Sopenharmony_ci cur_len |= DESC_MORE; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* prevent early tx attempt of this descriptor */ 15468c2ecf20Sopenharmony_ci if (!ndesc) 15478c2ecf20Sopenharmony_ci cur_len |= DESC_EMPTY; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci desc->ctrl = cur_len; 15508c2ecf20Sopenharmony_ci ndesc++; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci return ndesc; 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb, 15578c2ecf20Sopenharmony_ci struct net_device *ndev) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci int i, n, ring_min, ring_mask, ring_size; 15608c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 15618c2ecf20Sopenharmony_ci struct ag71xx_ring *ring; 15628c2ecf20Sopenharmony_ci struct ag71xx_desc *desc; 15638c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci ring = &ag->tx_ring; 15668c2ecf20Sopenharmony_ci ring_mask = BIT(ring->order) - 1; 15678c2ecf20Sopenharmony_ci ring_size = BIT(ring->order); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (skb->len <= 4) { 15708c2ecf20Sopenharmony_ci netif_dbg(ag, tx_err, ndev, "packet len is too small\n"); 15718c2ecf20Sopenharmony_ci goto err_drop; 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci dma_addr = dma_map_single(&ag->pdev->dev, skb->data, skb->len, 15758c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci i = ring->curr & ring_mask; 15788c2ecf20Sopenharmony_ci desc = ag71xx_ring_desc(ring, i); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* setup descriptor fields */ 15818c2ecf20Sopenharmony_ci n = ag71xx_fill_dma_desc(ring, (u32)dma_addr, 15828c2ecf20Sopenharmony_ci skb->len & ag->dcfg->desc_pktlen_mask); 15838c2ecf20Sopenharmony_ci if (n < 0) 15848c2ecf20Sopenharmony_ci goto err_drop_unmap; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci i = (ring->curr + n - 1) & ring_mask; 15878c2ecf20Sopenharmony_ci ring->buf[i].tx.len = skb->len; 15888c2ecf20Sopenharmony_ci ring->buf[i].tx.skb = skb; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci netdev_sent_queue(ndev, skb->len); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci desc->ctrl &= ~DESC_EMPTY; 15958c2ecf20Sopenharmony_ci ring->curr += n; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci /* flush descriptor */ 15988c2ecf20Sopenharmony_ci wmb(); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci ring_min = 2; 16018c2ecf20Sopenharmony_ci if (ring->desc_split) 16028c2ecf20Sopenharmony_ci ring_min *= AG71XX_TX_RING_DS_PER_PKT; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (ring->curr - ring->dirty >= ring_size - ring_min) { 16058c2ecf20Sopenharmony_ci netif_dbg(ag, tx_err, ndev, "tx queue full\n"); 16068c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci netif_dbg(ag, tx_queued, ndev, "packet injected into TX queue\n"); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* enable TX engine */ 16128c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cierr_drop_unmap: 16178c2ecf20Sopenharmony_ci dma_unmap_single(&ag->pdev->dev, dma_addr, skb->len, DMA_TO_DEVICE); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cierr_drop: 16208c2ecf20Sopenharmony_ci ndev->stats.tx_dropped++; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 16238c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic void ag71xx_oom_timer_handler(struct timer_list *t) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci struct ag71xx *ag = from_timer(ag, t, oom_timer); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci napi_schedule(&ag->napi); 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic void ag71xx_tx_timeout(struct net_device *ndev, unsigned int txqueue) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci netif_err(ag, tx_err, ndev, "tx timeout\n"); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci schedule_delayed_work(&ag->restart_work, 1); 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_cistatic void ag71xx_restart_work_func(struct work_struct *work) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct ag71xx *ag = container_of(work, struct ag71xx, 16458c2ecf20Sopenharmony_ci restart_work.work); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci rtnl_lock(); 16488c2ecf20Sopenharmony_ci ag71xx_hw_disable(ag); 16498c2ecf20Sopenharmony_ci ag71xx_hw_enable(ag); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci phylink_stop(ag->phylink); 16528c2ecf20Sopenharmony_ci phylink_start(ag->phylink); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci rtnl_unlock(); 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic int ag71xx_rx_packets(struct ag71xx *ag, int limit) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 16608c2ecf20Sopenharmony_ci int ring_mask, ring_size, done = 0; 16618c2ecf20Sopenharmony_ci unsigned int pktlen_mask, offset; 16628c2ecf20Sopenharmony_ci struct sk_buff *next, *skb; 16638c2ecf20Sopenharmony_ci struct ag71xx_ring *ring; 16648c2ecf20Sopenharmony_ci struct list_head rx_list; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci ring = &ag->rx_ring; 16678c2ecf20Sopenharmony_ci pktlen_mask = ag->dcfg->desc_pktlen_mask; 16688c2ecf20Sopenharmony_ci offset = ag->rx_buf_offset; 16698c2ecf20Sopenharmony_ci ring_mask = BIT(ring->order) - 1; 16708c2ecf20Sopenharmony_ci ring_size = BIT(ring->order); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "rx packets, limit=%d, curr=%u, dirty=%u\n", 16738c2ecf20Sopenharmony_ci limit, ring->curr, ring->dirty); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rx_list); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci while (done < limit) { 16788c2ecf20Sopenharmony_ci unsigned int i = ring->curr & ring_mask; 16798c2ecf20Sopenharmony_ci struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); 16808c2ecf20Sopenharmony_ci int pktlen; 16818c2ecf20Sopenharmony_ci int err = 0; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (ag71xx_desc_empty(desc)) 16848c2ecf20Sopenharmony_ci break; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if ((ring->dirty + ring_size) == ring->curr) { 16878c2ecf20Sopenharmony_ci WARN_ONCE(1, "RX out of ring"); 16888c2ecf20Sopenharmony_ci break; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci pktlen = desc->ctrl & pktlen_mask; 16948c2ecf20Sopenharmony_ci pktlen -= ETH_FCS_LEN; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci dma_unmap_single(&ag->pdev->dev, ring->buf[i].rx.dma_addr, 16978c2ecf20Sopenharmony_ci ag->rx_buf_size, DMA_FROM_DEVICE); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci ndev->stats.rx_packets++; 17008c2ecf20Sopenharmony_ci ndev->stats.rx_bytes += pktlen; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci skb = build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag)); 17038c2ecf20Sopenharmony_ci if (!skb) { 17048c2ecf20Sopenharmony_ci skb_free_frag(ring->buf[i].rx.rx_buf); 17058c2ecf20Sopenharmony_ci goto next; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci skb_reserve(skb, offset); 17098c2ecf20Sopenharmony_ci skb_put(skb, pktlen); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (err) { 17128c2ecf20Sopenharmony_ci ndev->stats.rx_dropped++; 17138c2ecf20Sopenharmony_ci kfree_skb(skb); 17148c2ecf20Sopenharmony_ci } else { 17158c2ecf20Sopenharmony_ci skb->dev = ndev; 17168c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 17178c2ecf20Sopenharmony_ci list_add_tail(&skb->list, &rx_list); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cinext: 17218c2ecf20Sopenharmony_ci ring->buf[i].rx.rx_buf = NULL; 17228c2ecf20Sopenharmony_ci done++; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci ring->curr++; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci ag71xx_ring_rx_refill(ag); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci list_for_each_entry_safe(skb, next, &rx_list, list) 17308c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 17318c2ecf20Sopenharmony_ci netif_receive_skb_list(&rx_list); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "rx finish, curr=%u, dirty=%u, done=%d\n", 17348c2ecf20Sopenharmony_ci ring->curr, ring->dirty, done); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci return done; 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cistatic int ag71xx_poll(struct napi_struct *napi, int limit) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci struct ag71xx *ag = container_of(napi, struct ag71xx, napi); 17428c2ecf20Sopenharmony_ci struct ag71xx_ring *rx_ring = &ag->rx_ring; 17438c2ecf20Sopenharmony_ci int rx_ring_size = BIT(rx_ring->order); 17448c2ecf20Sopenharmony_ci struct net_device *ndev = ag->ndev; 17458c2ecf20Sopenharmony_ci int tx_done, rx_done; 17468c2ecf20Sopenharmony_ci u32 status; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci tx_done = ag71xx_tx_packets(ag, false); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "processing RX ring\n"); 17518c2ecf20Sopenharmony_ci rx_done = ag71xx_rx_packets(ag, limit); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (!rx_ring->buf[rx_ring->dirty % rx_ring_size].rx.rx_buf) 17548c2ecf20Sopenharmony_ci goto oom; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); 17578c2ecf20Sopenharmony_ci if (unlikely(status & RX_STATUS_OF)) { 17588c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF); 17598c2ecf20Sopenharmony_ci ndev->stats.rx_fifo_errors++; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* restart RX */ 17628c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (rx_done < limit) { 17668c2ecf20Sopenharmony_ci if (status & RX_STATUS_PR) 17678c2ecf20Sopenharmony_ci goto more; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); 17708c2ecf20Sopenharmony_ci if (status & TX_STATUS_PS) 17718c2ecf20Sopenharmony_ci goto more; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "disable polling mode, rx=%d, tx=%d,limit=%d\n", 17748c2ecf20Sopenharmony_ci rx_done, tx_done, limit); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci napi_complete(napi); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* enable interrupts */ 17798c2ecf20Sopenharmony_ci ag71xx_int_enable(ag, AG71XX_INT_POLL); 17808c2ecf20Sopenharmony_ci return rx_done; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cimore: 17848c2ecf20Sopenharmony_ci netif_dbg(ag, rx_status, ndev, "stay in polling mode, rx=%d, tx=%d, limit=%d\n", 17858c2ecf20Sopenharmony_ci rx_done, tx_done, limit); 17868c2ecf20Sopenharmony_ci return limit; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cioom: 17898c2ecf20Sopenharmony_ci netif_err(ag, rx_err, ndev, "out of memory\n"); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL); 17928c2ecf20Sopenharmony_ci napi_complete(napi); 17938c2ecf20Sopenharmony_ci return 0; 17948c2ecf20Sopenharmony_ci} 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic irqreturn_t ag71xx_interrupt(int irq, void *dev_id) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci struct net_device *ndev = dev_id; 17998c2ecf20Sopenharmony_ci struct ag71xx *ag; 18008c2ecf20Sopenharmony_ci u32 status; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci ag = netdev_priv(ndev); 18038c2ecf20Sopenharmony_ci status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (unlikely(!status)) 18068c2ecf20Sopenharmony_ci return IRQ_NONE; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (unlikely(status & AG71XX_INT_ERR)) { 18098c2ecf20Sopenharmony_ci if (status & AG71XX_INT_TX_BE) { 18108c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE); 18118c2ecf20Sopenharmony_ci netif_err(ag, intr, ndev, "TX BUS error\n"); 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci if (status & AG71XX_INT_RX_BE) { 18148c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE); 18158c2ecf20Sopenharmony_ci netif_err(ag, intr, ndev, "RX BUS error\n"); 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (likely(status & AG71XX_INT_POLL)) { 18208c2ecf20Sopenharmony_ci ag71xx_int_disable(ag, AG71XX_INT_POLL); 18218c2ecf20Sopenharmony_ci netif_dbg(ag, intr, ndev, "enable polling mode\n"); 18228c2ecf20Sopenharmony_ci napi_schedule(&ag->napi); 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic int ag71xx_change_mtu(struct net_device *ndev, int new_mtu) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci struct ag71xx *ag = netdev_priv(ndev); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci ndev->mtu = new_mtu; 18338c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 18348c2ecf20Sopenharmony_ci ag71xx_max_frame_len(ndev->mtu)); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci return 0; 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic const struct net_device_ops ag71xx_netdev_ops = { 18408c2ecf20Sopenharmony_ci .ndo_open = ag71xx_open, 18418c2ecf20Sopenharmony_ci .ndo_stop = ag71xx_stop, 18428c2ecf20Sopenharmony_ci .ndo_start_xmit = ag71xx_hard_start_xmit, 18438c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl, 18448c2ecf20Sopenharmony_ci .ndo_tx_timeout = ag71xx_tx_timeout, 18458c2ecf20Sopenharmony_ci .ndo_change_mtu = ag71xx_change_mtu, 18468c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 18478c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 18488c2ecf20Sopenharmony_ci}; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_cistatic const u32 ar71xx_addr_ar7100[] = { 18518c2ecf20Sopenharmony_ci 0x19000000, 0x1a000000, 18528c2ecf20Sopenharmony_ci}; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_cistatic int ag71xx_probe(struct platform_device *pdev) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 18578c2ecf20Sopenharmony_ci const struct ag71xx_dcfg *dcfg; 18588c2ecf20Sopenharmony_ci struct net_device *ndev; 18598c2ecf20Sopenharmony_ci struct resource *res; 18608c2ecf20Sopenharmony_ci const void *mac_addr; 18618c2ecf20Sopenharmony_ci int tx_size, err, i; 18628c2ecf20Sopenharmony_ci struct ag71xx *ag; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci if (!np) 18658c2ecf20Sopenharmony_ci return -ENODEV; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*ag)); 18688c2ecf20Sopenharmony_ci if (!ndev) 18698c2ecf20Sopenharmony_ci return -ENOMEM; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 18728c2ecf20Sopenharmony_ci if (!res) 18738c2ecf20Sopenharmony_ci return -EINVAL; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci dcfg = of_device_get_match_data(&pdev->dev); 18768c2ecf20Sopenharmony_ci if (!dcfg) 18778c2ecf20Sopenharmony_ci return -EINVAL; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci ag = netdev_priv(ndev); 18808c2ecf20Sopenharmony_ci ag->mac_idx = -1; 18818c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar71xx_addr_ar7100); i++) { 18828c2ecf20Sopenharmony_ci if (ar71xx_addr_ar7100[i] == res->start) 18838c2ecf20Sopenharmony_ci ag->mac_idx = i; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (ag->mac_idx < 0) { 18878c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "unknown mac idx\n"); 18888c2ecf20Sopenharmony_ci return -EINVAL; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ag->clk_eth = devm_clk_get(&pdev->dev, "eth"); 18928c2ecf20Sopenharmony_ci if (IS_ERR(ag->clk_eth)) { 18938c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "Failed to get eth clk.\n"); 18948c2ecf20Sopenharmony_ci return PTR_ERR(ag->clk_eth); 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci ag->pdev = pdev; 19008c2ecf20Sopenharmony_ci ag->ndev = ndev; 19018c2ecf20Sopenharmony_ci ag->dcfg = dcfg; 19028c2ecf20Sopenharmony_ci ag->msg_enable = netif_msg_init(-1, AG71XX_DEFAULT_MSG_ENABLE); 19038c2ecf20Sopenharmony_ci memcpy(ag->fifodata, dcfg->fifodata, sizeof(ag->fifodata)); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac"); 19068c2ecf20Sopenharmony_ci if (IS_ERR(ag->mac_reset)) { 19078c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "missing mac reset\n"); 19088c2ecf20Sopenharmony_ci return PTR_ERR(ag->mac_reset); 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 19128c2ecf20Sopenharmony_ci if (!ag->mac_base) 19138c2ecf20Sopenharmony_ci return -ENOMEM; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci ndev->irq = platform_get_irq(pdev, 0); 19168c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt, 19178c2ecf20Sopenharmony_ci 0x0, dev_name(&pdev->dev), ndev); 19188c2ecf20Sopenharmony_ci if (err) { 19198c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "unable to request IRQ %d\n", 19208c2ecf20Sopenharmony_ci ndev->irq); 19218c2ecf20Sopenharmony_ci return err; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci ndev->netdev_ops = &ag71xx_netdev_ops; 19258c2ecf20Sopenharmony_ci ndev->ethtool_ops = &ag71xx_ethtool_ops; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ag->restart_work, ag71xx_restart_work_func); 19288c2ecf20Sopenharmony_ci timer_setup(&ag->oom_timer, ag71xx_oom_timer_handler, 0); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci tx_size = AG71XX_TX_RING_SIZE_DEFAULT; 19318c2ecf20Sopenharmony_ci ag->rx_ring.order = ag71xx_ring_size_order(AG71XX_RX_RING_SIZE_DEFAULT); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci ndev->min_mtu = 68; 19348c2ecf20Sopenharmony_ci ndev->max_mtu = dcfg->max_frame_len - ag71xx_max_frame_len(0); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci ag->rx_buf_offset = NET_SKB_PAD; 19378c2ecf20Sopenharmony_ci if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130)) 19388c2ecf20Sopenharmony_ci ag->rx_buf_offset += NET_IP_ALIGN; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (ag71xx_is(ag, AR7100)) { 19418c2ecf20Sopenharmony_ci ag->tx_ring.desc_split = AG71XX_TX_RING_SPLIT; 19428c2ecf20Sopenharmony_ci tx_size *= AG71XX_TX_RING_DS_PER_PKT; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci ag->tx_ring.order = ag71xx_ring_size_order(tx_size); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci ag->stop_desc = dmam_alloc_coherent(&pdev->dev, 19478c2ecf20Sopenharmony_ci sizeof(struct ag71xx_desc), 19488c2ecf20Sopenharmony_ci &ag->stop_desc_dma, GFP_KERNEL); 19498c2ecf20Sopenharmony_ci if (!ag->stop_desc) 19508c2ecf20Sopenharmony_ci return -ENOMEM; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci ag->stop_desc->data = 0; 19538c2ecf20Sopenharmony_ci ag->stop_desc->ctrl = 0; 19548c2ecf20Sopenharmony_ci ag->stop_desc->next = (u32)ag->stop_desc_dma; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci mac_addr = of_get_mac_address(np); 19578c2ecf20Sopenharmony_ci if (!IS_ERR(mac_addr)) 19588c2ecf20Sopenharmony_ci memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); 19598c2ecf20Sopenharmony_ci if (IS_ERR(mac_addr) || !is_valid_ether_addr(ndev->dev_addr)) { 19608c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "invalid MAC address, using random address\n"); 19618c2ecf20Sopenharmony_ci eth_random_addr(ndev->dev_addr); 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci err = of_get_phy_mode(np, &ag->phy_if_mode); 19658c2ecf20Sopenharmony_ci if (err) { 19668c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "missing phy-mode property in DT\n"); 19678c2ecf20Sopenharmony_ci return err; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci netif_napi_add(ndev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci err = clk_prepare_enable(ag->clk_eth); 19738c2ecf20Sopenharmony_ci if (err) { 19748c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "Failed to enable eth clk.\n"); 19758c2ecf20Sopenharmony_ci return err; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0); 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci ag71xx_hw_init(ag); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci err = ag71xx_mdio_probe(ag); 19838c2ecf20Sopenharmony_ci if (err) 19848c2ecf20Sopenharmony_ci goto err_put_clk; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ndev); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci err = ag71xx_phylink_setup(ag); 19898c2ecf20Sopenharmony_ci if (err) { 19908c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err); 19918c2ecf20Sopenharmony_ci goto err_mdio_remove; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci err = register_netdev(ndev); 19958c2ecf20Sopenharmony_ci if (err) { 19968c2ecf20Sopenharmony_ci netif_err(ag, probe, ndev, "unable to register net device\n"); 19978c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 19988c2ecf20Sopenharmony_ci goto err_mdio_remove; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci netif_info(ag, probe, ndev, "Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n", 20028c2ecf20Sopenharmony_ci (unsigned long)ag->mac_base, ndev->irq, 20038c2ecf20Sopenharmony_ci phy_modes(ag->phy_if_mode)); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci return 0; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cierr_mdio_remove: 20088c2ecf20Sopenharmony_ci ag71xx_mdio_remove(ag); 20098c2ecf20Sopenharmony_cierr_put_clk: 20108c2ecf20Sopenharmony_ci clk_disable_unprepare(ag->clk_eth); 20118c2ecf20Sopenharmony_ci return err; 20128c2ecf20Sopenharmony_ci} 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_cistatic int ag71xx_remove(struct platform_device *pdev) 20158c2ecf20Sopenharmony_ci{ 20168c2ecf20Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 20178c2ecf20Sopenharmony_ci struct ag71xx *ag; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci if (!ndev) 20208c2ecf20Sopenharmony_ci return 0; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci ag = netdev_priv(ndev); 20238c2ecf20Sopenharmony_ci unregister_netdev(ndev); 20248c2ecf20Sopenharmony_ci ag71xx_mdio_remove(ag); 20258c2ecf20Sopenharmony_ci clk_disable_unprepare(ag->clk_eth); 20268c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci return 0; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic const u32 ar71xx_fifo_ar7100[] = { 20328c2ecf20Sopenharmony_ci 0x0fff0000, 0x00001fff, 0x00780fff, 20338c2ecf20Sopenharmony_ci}; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_cistatic const u32 ar71xx_fifo_ar9130[] = { 20368c2ecf20Sopenharmony_ci 0x0fff0000, 0x00001fff, 0x008001ff, 20378c2ecf20Sopenharmony_ci}; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_cistatic const u32 ar71xx_fifo_ar9330[] = { 20408c2ecf20Sopenharmony_ci 0x0010ffff, 0x015500aa, 0x01f00140, 20418c2ecf20Sopenharmony_ci}; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar7100 = { 20448c2ecf20Sopenharmony_ci .type = AR7100, 20458c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar7100, 20468c2ecf20Sopenharmony_ci .max_frame_len = 1540, 20478c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_4K - 1, 20488c2ecf20Sopenharmony_ci .tx_hang_workaround = false, 20498c2ecf20Sopenharmony_ci}; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar7240 = { 20528c2ecf20Sopenharmony_ci .type = AR7240, 20538c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar7100, 20548c2ecf20Sopenharmony_ci .max_frame_len = 1540, 20558c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_4K - 1, 20568c2ecf20Sopenharmony_ci .tx_hang_workaround = true, 20578c2ecf20Sopenharmony_ci}; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9130 = { 20608c2ecf20Sopenharmony_ci .type = AR9130, 20618c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar9130, 20628c2ecf20Sopenharmony_ci .max_frame_len = 1540, 20638c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_4K - 1, 20648c2ecf20Sopenharmony_ci .tx_hang_workaround = false, 20658c2ecf20Sopenharmony_ci}; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9330 = { 20688c2ecf20Sopenharmony_ci .type = AR9330, 20698c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar9330, 20708c2ecf20Sopenharmony_ci .max_frame_len = 1540, 20718c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_4K - 1, 20728c2ecf20Sopenharmony_ci .tx_hang_workaround = true, 20738c2ecf20Sopenharmony_ci}; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_ar9340 = { 20768c2ecf20Sopenharmony_ci .type = AR9340, 20778c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar9330, 20788c2ecf20Sopenharmony_ci .max_frame_len = SZ_16K - 1, 20798c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_16K - 1, 20808c2ecf20Sopenharmony_ci .tx_hang_workaround = true, 20818c2ecf20Sopenharmony_ci}; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_qca9530 = { 20848c2ecf20Sopenharmony_ci .type = QCA9530, 20858c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar9330, 20868c2ecf20Sopenharmony_ci .max_frame_len = SZ_16K - 1, 20878c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_16K - 1, 20888c2ecf20Sopenharmony_ci .tx_hang_workaround = true, 20898c2ecf20Sopenharmony_ci}; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_cistatic const struct ag71xx_dcfg ag71xx_dcfg_qca9550 = { 20928c2ecf20Sopenharmony_ci .type = QCA9550, 20938c2ecf20Sopenharmony_ci .fifodata = ar71xx_fifo_ar9330, 20948c2ecf20Sopenharmony_ci .max_frame_len = 1540, 20958c2ecf20Sopenharmony_ci .desc_pktlen_mask = SZ_16K - 1, 20968c2ecf20Sopenharmony_ci .tx_hang_workaround = true, 20978c2ecf20Sopenharmony_ci}; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic const struct of_device_id ag71xx_match[] = { 21008c2ecf20Sopenharmony_ci { .compatible = "qca,ar7100-eth", .data = &ag71xx_dcfg_ar7100 }, 21018c2ecf20Sopenharmony_ci { .compatible = "qca,ar7240-eth", .data = &ag71xx_dcfg_ar7240 }, 21028c2ecf20Sopenharmony_ci { .compatible = "qca,ar7241-eth", .data = &ag71xx_dcfg_ar7240 }, 21038c2ecf20Sopenharmony_ci { .compatible = "qca,ar7242-eth", .data = &ag71xx_dcfg_ar7240 }, 21048c2ecf20Sopenharmony_ci { .compatible = "qca,ar9130-eth", .data = &ag71xx_dcfg_ar9130 }, 21058c2ecf20Sopenharmony_ci { .compatible = "qca,ar9330-eth", .data = &ag71xx_dcfg_ar9330 }, 21068c2ecf20Sopenharmony_ci { .compatible = "qca,ar9340-eth", .data = &ag71xx_dcfg_ar9340 }, 21078c2ecf20Sopenharmony_ci { .compatible = "qca,qca9530-eth", .data = &ag71xx_dcfg_qca9530 }, 21088c2ecf20Sopenharmony_ci { .compatible = "qca,qca9550-eth", .data = &ag71xx_dcfg_qca9550 }, 21098c2ecf20Sopenharmony_ci { .compatible = "qca,qca9560-eth", .data = &ag71xx_dcfg_qca9550 }, 21108c2ecf20Sopenharmony_ci {} 21118c2ecf20Sopenharmony_ci}; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_cistatic struct platform_driver ag71xx_driver = { 21148c2ecf20Sopenharmony_ci .probe = ag71xx_probe, 21158c2ecf20Sopenharmony_ci .remove = ag71xx_remove, 21168c2ecf20Sopenharmony_ci .driver = { 21178c2ecf20Sopenharmony_ci .name = "ag71xx", 21188c2ecf20Sopenharmony_ci .of_match_table = ag71xx_match, 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci}; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_cimodule_platform_driver(ag71xx_driver); 21238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2124