18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/of_device.h> 108c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 118c2ecf20Sopenharmony_ci#include <linux/of_net.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 178c2ecf20Sopenharmony_ci#include <linux/reset.h> 188c2ecf20Sopenharmony_ci#include <linux/tcp.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/devinfo.h> 218c2ecf20Sopenharmony_ci#include <linux/phylink.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "mtk_eth_soc.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int mtk_msg_level = -1; 268c2ecf20Sopenharmony_cimodule_param_named(msg_level, mtk_msg_level, int, 0); 278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define MTK_ETHTOOL_STAT(x) { #x, \ 308c2ecf20Sopenharmony_ci offsetof(struct mtk_hw_stats, x) / sizeof(u64) } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* strings used by ethtool */ 338c2ecf20Sopenharmony_cistatic const struct mtk_ethtool_stats { 348c2ecf20Sopenharmony_ci char str[ETH_GSTRING_LEN]; 358c2ecf20Sopenharmony_ci u32 offset; 368c2ecf20Sopenharmony_ci} mtk_ethtool_stats[] = { 378c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(tx_bytes), 388c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(tx_packets), 398c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(tx_skip), 408c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(tx_collisions), 418c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_bytes), 428c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_packets), 438c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_overflow), 448c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_fcs_errors), 458c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_short_errors), 468c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_long_errors), 478c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_checksum_errors), 488c2ecf20Sopenharmony_ci MTK_ETHTOOL_STAT(rx_flow_control_packets), 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const char * const mtk_clks_source_name[] = { 528c2ecf20Sopenharmony_ci "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", 538c2ecf20Sopenharmony_ci "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", 548c2ecf20Sopenharmony_ci "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", 558c2ecf20Sopenharmony_ci "sgmii_ck", "eth2pll", 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_civoid mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci __raw_writel(val, eth->base + reg); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciu32 mtk_r32(struct mtk_eth *eth, unsigned reg) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return __raw_readl(eth->base + reg); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned reg) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci u32 val; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci val = mtk_r32(eth, reg); 738c2ecf20Sopenharmony_ci val &= ~mask; 748c2ecf20Sopenharmony_ci val |= set; 758c2ecf20Sopenharmony_ci mtk_w32(eth, val, reg); 768c2ecf20Sopenharmony_ci return reg; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int mtk_mdio_busy_wait(struct mtk_eth *eth) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned long t_start = jiffies; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci while (1) { 848c2ecf20Sopenharmony_ci if (!(mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_ACCESS)) 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci usleep_range(10, 20); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci dev_err(eth->dev, "mdio: MDIO timeout\n"); 928c2ecf20Sopenharmony_ci return -1; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, 968c2ecf20Sopenharmony_ci u32 phy_register, u32 write_data) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci if (mtk_mdio_busy_wait(eth)) 998c2ecf20Sopenharmony_ci return -1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci write_data &= 0xffff; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE | 1048c2ecf20Sopenharmony_ci (phy_register << PHY_IAC_REG_SHIFT) | 1058c2ecf20Sopenharmony_ci (phy_addr << PHY_IAC_ADDR_SHIFT) | write_data, 1068c2ecf20Sopenharmony_ci MTK_PHY_IAC); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (mtk_mdio_busy_wait(eth)) 1098c2ecf20Sopenharmony_ci return -1; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci u32 d; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (mtk_mdio_busy_wait(eth)) 1198c2ecf20Sopenharmony_ci return 0xffff; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ | 1228c2ecf20Sopenharmony_ci (phy_reg << PHY_IAC_REG_SHIFT) | 1238c2ecf20Sopenharmony_ci (phy_addr << PHY_IAC_ADDR_SHIFT), 1248c2ecf20Sopenharmony_ci MTK_PHY_IAC); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (mtk_mdio_busy_wait(eth)) 1278c2ecf20Sopenharmony_ci return 0xffff; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci d = mtk_r32(eth, MTK_PHY_IAC) & 0xffff; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return d; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int mtk_mdio_write(struct mii_bus *bus, int phy_addr, 1358c2ecf20Sopenharmony_ci int phy_reg, u16 val) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct mtk_eth *eth = bus->priv; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return _mtk_mdio_write(eth, phy_addr, phy_reg, val); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct mtk_eth *eth = bus->priv; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return _mtk_mdio_read(eth, phy_addr, phy_reg); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth, 1508c2ecf20Sopenharmony_ci phy_interface_t interface) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci u32 val; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Check DDR memory type. 1558c2ecf20Sopenharmony_ci * Currently TRGMII mode with DDR2 memory is not supported. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci regmap_read(eth->ethsys, ETHSYS_SYSCFG, &val); 1588c2ecf20Sopenharmony_ci if (interface == PHY_INTERFACE_MODE_TRGMII && 1598c2ecf20Sopenharmony_ci val & SYSCFG_DRAM_TYPE_DDR2) { 1608c2ecf20Sopenharmony_ci dev_err(eth->dev, 1618c2ecf20Sopenharmony_ci "TRGMII mode with DDR2 memory is not supported!\n"); 1628c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci val = (interface == PHY_INTERFACE_MODE_TRGMII) ? 1668c2ecf20Sopenharmony_ci ETHSYS_TRGMII_MT7621_DDR_PLL : 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0, 1698c2ecf20Sopenharmony_ci ETHSYS_TRGMII_MT7621_MASK, val); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, 1758c2ecf20Sopenharmony_ci phy_interface_t interface, int speed) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci u32 val; 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (interface == PHY_INTERFACE_MODE_TRGMII) { 1818c2ecf20Sopenharmony_ci mtk_w32(eth, TRGMII_MODE, INTF_MODE); 1828c2ecf20Sopenharmony_ci val = 500000000; 1838c2ecf20Sopenharmony_ci ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], val); 1848c2ecf20Sopenharmony_ci if (ret) 1858c2ecf20Sopenharmony_ci dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret); 1868c2ecf20Sopenharmony_ci return; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci val = (speed == SPEED_1000) ? 1908c2ecf20Sopenharmony_ci INTF_MODE_RGMII_1000 : INTF_MODE_RGMII_10_100; 1918c2ecf20Sopenharmony_ci mtk_w32(eth, val, INTF_MODE); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0, 1948c2ecf20Sopenharmony_ci ETHSYS_TRGMII_CLK_SEL362_5, 1958c2ecf20Sopenharmony_ci ETHSYS_TRGMII_CLK_SEL362_5); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci val = (speed == SPEED_1000) ? 250000000 : 500000000; 1988c2ecf20Sopenharmony_ci ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], val); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci val = (speed == SPEED_1000) ? 2038c2ecf20Sopenharmony_ci RCK_CTRL_RGMII_1000 : RCK_CTRL_RGMII_10_100; 2048c2ecf20Sopenharmony_ci mtk_w32(eth, val, TRGMII_RCK_CTRL); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci val = (speed == SPEED_1000) ? 2078c2ecf20Sopenharmony_ci TCK_CTRL_RGMII_1000 : TCK_CTRL_RGMII_10_100; 2088c2ecf20Sopenharmony_ci mtk_w32(eth, val, TRGMII_TCK_CTRL); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void mtk_mac_config(struct phylink_config *config, unsigned int mode, 2128c2ecf20Sopenharmony_ci const struct phylink_link_state *state) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 2158c2ecf20Sopenharmony_ci phylink_config); 2168c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 2178c2ecf20Sopenharmony_ci u32 mcr_cur, mcr_new, sid, i; 2188c2ecf20Sopenharmony_ci int val, ge_mode, err = 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* MT76x8 has no hardware settings between for the MAC */ 2218c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && 2228c2ecf20Sopenharmony_ci mac->interface != state->interface) { 2238c2ecf20Sopenharmony_ci /* Setup soc pin functions */ 2248c2ecf20Sopenharmony_ci switch (state->interface) { 2258c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_TRGMII: 2268c2ecf20Sopenharmony_ci if (mac->id) 2278c2ecf20Sopenharmony_ci goto err_phy; 2288c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(mac->hw->soc->caps, 2298c2ecf20Sopenharmony_ci MTK_GMAC1_TRGMII)) 2308c2ecf20Sopenharmony_ci goto err_phy; 2318c2ecf20Sopenharmony_ci fallthrough; 2328c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_TXID: 2338c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_RXID: 2348c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_ID: 2358c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII: 2368c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 2378c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_REVMII: 2388c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 2398c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) { 2408c2ecf20Sopenharmony_ci err = mtk_gmac_rgmii_path_setup(eth, mac->id); 2418c2ecf20Sopenharmony_ci if (err) 2428c2ecf20Sopenharmony_ci goto init_err; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 2468c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 2478c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 2488c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { 2498c2ecf20Sopenharmony_ci err = mtk_gmac_sgmii_path_setup(eth, mac->id); 2508c2ecf20Sopenharmony_ci if (err) 2518c2ecf20Sopenharmony_ci goto init_err; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 2558c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) { 2568c2ecf20Sopenharmony_ci err = mtk_gmac_gephy_path_setup(eth, mac->id); 2578c2ecf20Sopenharmony_ci if (err) 2588c2ecf20Sopenharmony_ci goto init_err; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci default: 2628c2ecf20Sopenharmony_ci goto err_phy; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Setup clock for 1st gmac */ 2668c2ecf20Sopenharmony_ci if (!mac->id && state->interface != PHY_INTERFACE_MODE_SGMII && 2678c2ecf20Sopenharmony_ci !phy_interface_mode_is_8023z(state->interface) && 2688c2ecf20Sopenharmony_ci MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII)) { 2698c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(mac->hw->soc->caps, 2708c2ecf20Sopenharmony_ci MTK_TRGMII_MT7621_CLK)) { 2718c2ecf20Sopenharmony_ci if (mt7621_gmac0_rgmii_adjust(mac->hw, 2728c2ecf20Sopenharmony_ci state->interface)) 2738c2ecf20Sopenharmony_ci goto err_phy; 2748c2ecf20Sopenharmony_ci } else { 2758c2ecf20Sopenharmony_ci mtk_gmac0_rgmii_adjust(mac->hw, 2768c2ecf20Sopenharmony_ci state->interface, 2778c2ecf20Sopenharmony_ci state->speed); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* mt7623_pad_clk_setup */ 2808c2ecf20Sopenharmony_ci for (i = 0 ; i < NUM_TRGMII_CTRL; i++) 2818c2ecf20Sopenharmony_ci mtk_w32(mac->hw, 2828c2ecf20Sopenharmony_ci TD_DM_DRVP(8) | TD_DM_DRVN(8), 2838c2ecf20Sopenharmony_ci TRGMII_TD_ODT(i)); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Assert/release MT7623 RXC reset */ 2868c2ecf20Sopenharmony_ci mtk_m32(mac->hw, 0, RXC_RST | RXC_DQSISEL, 2878c2ecf20Sopenharmony_ci TRGMII_RCK_CTRL); 2888c2ecf20Sopenharmony_ci mtk_m32(mac->hw, RXC_RST, 0, TRGMII_RCK_CTRL); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ge_mode = 0; 2938c2ecf20Sopenharmony_ci switch (state->interface) { 2948c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 2958c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 2968c2ecf20Sopenharmony_ci ge_mode = 1; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_REVMII: 2998c2ecf20Sopenharmony_ci ge_mode = 2; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 3028c2ecf20Sopenharmony_ci if (mac->id) 3038c2ecf20Sopenharmony_ci goto err_phy; 3048c2ecf20Sopenharmony_ci ge_mode = 3; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci default: 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* put the gmac into the right mode */ 3118c2ecf20Sopenharmony_ci regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 3128c2ecf20Sopenharmony_ci val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); 3138c2ecf20Sopenharmony_ci val |= SYSCFG0_GE_MODE(ge_mode, mac->id); 3148c2ecf20Sopenharmony_ci regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mac->interface = state->interface; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* SGMII */ 3208c2ecf20Sopenharmony_ci if (state->interface == PHY_INTERFACE_MODE_SGMII || 3218c2ecf20Sopenharmony_ci phy_interface_mode_is_8023z(state->interface)) { 3228c2ecf20Sopenharmony_ci /* The path GMAC to SGMII will be enabled once the SGMIISYS is 3238c2ecf20Sopenharmony_ci * being setup done. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 3288c2ecf20Sopenharmony_ci SYSCFG0_SGMII_MASK, 3298c2ecf20Sopenharmony_ci ~(u32)SYSCFG0_SGMII_MASK); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Decide how GMAC and SGMIISYS be mapped */ 3328c2ecf20Sopenharmony_ci sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 3338c2ecf20Sopenharmony_ci 0 : mac->id; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Setup SGMIISYS with the determined property */ 3368c2ecf20Sopenharmony_ci if (state->interface != PHY_INTERFACE_MODE_SGMII) 3378c2ecf20Sopenharmony_ci err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, 3388c2ecf20Sopenharmony_ci state); 3398c2ecf20Sopenharmony_ci else if (phylink_autoneg_inband(mode)) 3408c2ecf20Sopenharmony_ci err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (err) 3438c2ecf20Sopenharmony_ci goto init_err; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 3468c2ecf20Sopenharmony_ci SYSCFG0_SGMII_MASK, val); 3478c2ecf20Sopenharmony_ci } else if (phylink_autoneg_inband(mode)) { 3488c2ecf20Sopenharmony_ci dev_err(eth->dev, 3498c2ecf20Sopenharmony_ci "In-band mode not supported in non SGMII mode!\n"); 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Setup gmac */ 3548c2ecf20Sopenharmony_ci mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); 3558c2ecf20Sopenharmony_ci mcr_new = mcr_cur; 3568c2ecf20Sopenharmony_ci mcr_new |= MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | 3578c2ecf20Sopenharmony_ci MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK | 3588c2ecf20Sopenharmony_ci MAC_MCR_RX_FIFO_CLR_DIS; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Only update control register when needed! */ 3618c2ecf20Sopenharmony_ci if (mcr_new != mcr_cur) 3628c2ecf20Sopenharmony_ci mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cierr_phy: 3678c2ecf20Sopenharmony_ci dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, 3688c2ecf20Sopenharmony_ci mac->id, phy_modes(state->interface)); 3698c2ecf20Sopenharmony_ci return; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciinit_err: 3728c2ecf20Sopenharmony_ci dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, 3738c2ecf20Sopenharmony_ci mac->id, phy_modes(state->interface), err); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void mtk_mac_pcs_get_state(struct phylink_config *config, 3778c2ecf20Sopenharmony_ci struct phylink_link_state *state) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 3808c2ecf20Sopenharmony_ci phylink_config); 3818c2ecf20Sopenharmony_ci u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci state->link = (pmsr & MAC_MSR_LINK); 3848c2ecf20Sopenharmony_ci state->duplex = (pmsr & MAC_MSR_DPX) >> 1; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci switch (pmsr & (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)) { 3878c2ecf20Sopenharmony_ci case 0: 3888c2ecf20Sopenharmony_ci state->speed = SPEED_10; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case MAC_MSR_SPEED_100: 3918c2ecf20Sopenharmony_ci state->speed = SPEED_100; 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case MAC_MSR_SPEED_1000: 3948c2ecf20Sopenharmony_ci state->speed = SPEED_1000; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci default: 3978c2ecf20Sopenharmony_ci state->speed = SPEED_UNKNOWN; 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX); 4028c2ecf20Sopenharmony_ci if (pmsr & MAC_MSR_RX_FC) 4038c2ecf20Sopenharmony_ci state->pause |= MLO_PAUSE_RX; 4048c2ecf20Sopenharmony_ci if (pmsr & MAC_MSR_TX_FC) 4058c2ecf20Sopenharmony_ci state->pause |= MLO_PAUSE_TX; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void mtk_mac_an_restart(struct phylink_config *config) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 4118c2ecf20Sopenharmony_ci phylink_config); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci mtk_sgmii_restart_an(mac->hw, mac->id); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, 4178c2ecf20Sopenharmony_ci phy_interface_t interface) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 4208c2ecf20Sopenharmony_ci phylink_config); 4218c2ecf20Sopenharmony_ci u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN); 4248c2ecf20Sopenharmony_ci mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void mtk_mac_link_up(struct phylink_config *config, 4288c2ecf20Sopenharmony_ci struct phy_device *phy, 4298c2ecf20Sopenharmony_ci unsigned int mode, phy_interface_t interface, 4308c2ecf20Sopenharmony_ci int speed, int duplex, bool tx_pause, bool rx_pause) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 4338c2ecf20Sopenharmony_ci phylink_config); 4348c2ecf20Sopenharmony_ci u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | 4378c2ecf20Sopenharmony_ci MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | 4388c2ecf20Sopenharmony_ci MAC_MCR_FORCE_RX_FC); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Configure speed */ 4418c2ecf20Sopenharmony_ci switch (speed) { 4428c2ecf20Sopenharmony_ci case SPEED_2500: 4438c2ecf20Sopenharmony_ci case SPEED_1000: 4448c2ecf20Sopenharmony_ci mcr |= MAC_MCR_SPEED_1000; 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci case SPEED_100: 4478c2ecf20Sopenharmony_ci mcr |= MAC_MCR_SPEED_100; 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Configure duplex */ 4528c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) 4538c2ecf20Sopenharmony_ci mcr |= MAC_MCR_FORCE_DPX; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* Configure pause modes - phylink will avoid these for half duplex */ 4568c2ecf20Sopenharmony_ci if (tx_pause) 4578c2ecf20Sopenharmony_ci mcr |= MAC_MCR_FORCE_TX_FC; 4588c2ecf20Sopenharmony_ci if (rx_pause) 4598c2ecf20Sopenharmony_ci mcr |= MAC_MCR_FORCE_RX_FC; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN; 4628c2ecf20Sopenharmony_ci mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void mtk_validate(struct phylink_config *config, 4668c2ecf20Sopenharmony_ci unsigned long *supported, 4678c2ecf20Sopenharmony_ci struct phylink_link_state *state) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct mtk_mac *mac = container_of(config, struct mtk_mac, 4708c2ecf20Sopenharmony_ci phylink_config); 4718c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (state->interface != PHY_INTERFACE_MODE_NA && 4748c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_MII && 4758c2ecf20Sopenharmony_ci state->interface != PHY_INTERFACE_MODE_GMII && 4768c2ecf20Sopenharmony_ci !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) && 4778c2ecf20Sopenharmony_ci phy_interface_mode_is_rgmii(state->interface)) && 4788c2ecf20Sopenharmony_ci !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && 4798c2ecf20Sopenharmony_ci !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII) && 4808c2ecf20Sopenharmony_ci !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) && 4818c2ecf20Sopenharmony_ci (state->interface == PHY_INTERFACE_MODE_SGMII || 4828c2ecf20Sopenharmony_ci phy_interface_mode_is_8023z(state->interface)))) { 4838c2ecf20Sopenharmony_ci linkmode_zero(supported); 4848c2ecf20Sopenharmony_ci return; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci phylink_set_port_modes(mask); 4888c2ecf20Sopenharmony_ci phylink_set(mask, Autoneg); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci switch (state->interface) { 4918c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_TRGMII: 4928c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 4958c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 4968c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 4978c2ecf20Sopenharmony_ci phylink_set(mask, 2500baseX_Full); 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 5008c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII: 5018c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_ID: 5028c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_RXID: 5038c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_TXID: 5048c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Half); 5058c2ecf20Sopenharmony_ci fallthrough; 5068c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 5078c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 5088c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 5098c2ecf20Sopenharmony_ci fallthrough; 5108c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 5118c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 5128c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_REVMII: 5138c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_NA: 5148c2ecf20Sopenharmony_ci default: 5158c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Half); 5168c2ecf20Sopenharmony_ci phylink_set(mask, 10baseT_Full); 5178c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Half); 5188c2ecf20Sopenharmony_ci phylink_set(mask, 100baseT_Full); 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (state->interface == PHY_INTERFACE_MODE_NA) { 5238c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { 5248c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 5258c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 5268c2ecf20Sopenharmony_ci phylink_set(mask, 2500baseX_Full); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) { 5298c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 5308c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Half); 5318c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseX_Full); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) { 5348c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Full); 5358c2ecf20Sopenharmony_ci phylink_set(mask, 1000baseT_Half); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci phylink_set(mask, Pause); 5408c2ecf20Sopenharmony_ci phylink_set(mask, Asym_Pause); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci linkmode_and(supported, supported, mask); 5438c2ecf20Sopenharmony_ci linkmode_and(state->advertising, state->advertising, mask); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* We can only operate at 2500BaseX or 1000BaseX. If requested 5468c2ecf20Sopenharmony_ci * to advertise both, only report advertising at 2500BaseX. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_ci phylink_helper_basex_speed(state); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic const struct phylink_mac_ops mtk_phylink_ops = { 5528c2ecf20Sopenharmony_ci .validate = mtk_validate, 5538c2ecf20Sopenharmony_ci .mac_pcs_get_state = mtk_mac_pcs_get_state, 5548c2ecf20Sopenharmony_ci .mac_an_restart = mtk_mac_an_restart, 5558c2ecf20Sopenharmony_ci .mac_config = mtk_mac_config, 5568c2ecf20Sopenharmony_ci .mac_link_down = mtk_mac_link_down, 5578c2ecf20Sopenharmony_ci .mac_link_up = mtk_mac_link_up, 5588c2ecf20Sopenharmony_ci}; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int mtk_mdio_init(struct mtk_eth *eth) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct device_node *mii_np; 5638c2ecf20Sopenharmony_ci int ret; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); 5668c2ecf20Sopenharmony_ci if (!mii_np) { 5678c2ecf20Sopenharmony_ci dev_err(eth->dev, "no %s child node found", "mdio-bus"); 5688c2ecf20Sopenharmony_ci return -ENODEV; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!of_device_is_available(mii_np)) { 5728c2ecf20Sopenharmony_ci ret = -ENODEV; 5738c2ecf20Sopenharmony_ci goto err_put_node; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci eth->mii_bus = devm_mdiobus_alloc(eth->dev); 5778c2ecf20Sopenharmony_ci if (!eth->mii_bus) { 5788c2ecf20Sopenharmony_ci ret = -ENOMEM; 5798c2ecf20Sopenharmony_ci goto err_put_node; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci eth->mii_bus->name = "mdio"; 5838c2ecf20Sopenharmony_ci eth->mii_bus->read = mtk_mdio_read; 5848c2ecf20Sopenharmony_ci eth->mii_bus->write = mtk_mdio_write; 5858c2ecf20Sopenharmony_ci eth->mii_bus->priv = eth; 5868c2ecf20Sopenharmony_ci eth->mii_bus->parent = eth->dev; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); 5898c2ecf20Sopenharmony_ci ret = of_mdiobus_register(eth->mii_bus, mii_np); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cierr_put_node: 5928c2ecf20Sopenharmony_ci of_node_put(mii_np); 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void mtk_mdio_cleanup(struct mtk_eth *eth) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci if (!eth->mii_bus) 5998c2ecf20Sopenharmony_ci return; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci mdiobus_unregister(eth->mii_bus); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic inline void mtk_tx_irq_disable(struct mtk_eth *eth, u32 mask) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci unsigned long flags; 6078c2ecf20Sopenharmony_ci u32 val; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci spin_lock_irqsave(ð->tx_irq_lock, flags); 6108c2ecf20Sopenharmony_ci val = mtk_r32(eth, eth->tx_int_mask_reg); 6118c2ecf20Sopenharmony_ci mtk_w32(eth, val & ~mask, eth->tx_int_mask_reg); 6128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ð->tx_irq_lock, flags); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic inline void mtk_tx_irq_enable(struct mtk_eth *eth, u32 mask) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci unsigned long flags; 6188c2ecf20Sopenharmony_ci u32 val; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci spin_lock_irqsave(ð->tx_irq_lock, flags); 6218c2ecf20Sopenharmony_ci val = mtk_r32(eth, eth->tx_int_mask_reg); 6228c2ecf20Sopenharmony_ci mtk_w32(eth, val | mask, eth->tx_int_mask_reg); 6238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ð->tx_irq_lock, flags); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic inline void mtk_rx_irq_disable(struct mtk_eth *eth, u32 mask) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci unsigned long flags; 6298c2ecf20Sopenharmony_ci u32 val; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci spin_lock_irqsave(ð->rx_irq_lock, flags); 6328c2ecf20Sopenharmony_ci val = mtk_r32(eth, MTK_PDMA_INT_MASK); 6338c2ecf20Sopenharmony_ci mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK); 6348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ð->rx_irq_lock, flags); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic inline void mtk_rx_irq_enable(struct mtk_eth *eth, u32 mask) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci unsigned long flags; 6408c2ecf20Sopenharmony_ci u32 val; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci spin_lock_irqsave(ð->rx_irq_lock, flags); 6438c2ecf20Sopenharmony_ci val = mtk_r32(eth, MTK_PDMA_INT_MASK); 6448c2ecf20Sopenharmony_ci mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK); 6458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ð->rx_irq_lock, flags); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int mtk_set_mac_address(struct net_device *dev, void *p) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci int ret = eth_mac_addr(dev, p); 6518c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 6528c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 6538c2ecf20Sopenharmony_ci const char *macaddr = dev->dev_addr; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (ret) 6568c2ecf20Sopenharmony_ci return ret; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) 6598c2ecf20Sopenharmony_ci return -EBUSY; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci spin_lock_bh(&mac->hw->page_lock); 6628c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 6638c2ecf20Sopenharmony_ci mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1], 6648c2ecf20Sopenharmony_ci MT7628_SDM_MAC_ADRH); 6658c2ecf20Sopenharmony_ci mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) | 6668c2ecf20Sopenharmony_ci (macaddr[4] << 8) | macaddr[5], 6678c2ecf20Sopenharmony_ci MT7628_SDM_MAC_ADRL); 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1], 6708c2ecf20Sopenharmony_ci MTK_GDMA_MAC_ADRH(mac->id)); 6718c2ecf20Sopenharmony_ci mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) | 6728c2ecf20Sopenharmony_ci (macaddr[4] << 8) | macaddr[5], 6738c2ecf20Sopenharmony_ci MTK_GDMA_MAC_ADRL(mac->id)); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci spin_unlock_bh(&mac->hw->page_lock); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_civoid mtk_stats_update_mac(struct mtk_mac *mac) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct mtk_hw_stats *hw_stats = mac->hw_stats; 6838c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci u64_stats_update_begin(&hw_stats->syncp); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 6888c2ecf20Sopenharmony_ci hw_stats->tx_packets += mtk_r32(mac->hw, MT7628_SDM_TPCNT); 6898c2ecf20Sopenharmony_ci hw_stats->tx_bytes += mtk_r32(mac->hw, MT7628_SDM_TBCNT); 6908c2ecf20Sopenharmony_ci hw_stats->rx_packets += mtk_r32(mac->hw, MT7628_SDM_RPCNT); 6918c2ecf20Sopenharmony_ci hw_stats->rx_bytes += mtk_r32(mac->hw, MT7628_SDM_RBCNT); 6928c2ecf20Sopenharmony_ci hw_stats->rx_checksum_errors += 6938c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MT7628_SDM_CS_ERR); 6948c2ecf20Sopenharmony_ci } else { 6958c2ecf20Sopenharmony_ci unsigned int offs = hw_stats->reg_offset; 6968c2ecf20Sopenharmony_ci u64 stats; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci hw_stats->rx_bytes += mtk_r32(mac->hw, 6998c2ecf20Sopenharmony_ci MTK_GDM1_RX_GBCNT_L + offs); 7008c2ecf20Sopenharmony_ci stats = mtk_r32(mac->hw, MTK_GDM1_RX_GBCNT_H + offs); 7018c2ecf20Sopenharmony_ci if (stats) 7028c2ecf20Sopenharmony_ci hw_stats->rx_bytes += (stats << 32); 7038c2ecf20Sopenharmony_ci hw_stats->rx_packets += 7048c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_GPCNT + offs); 7058c2ecf20Sopenharmony_ci hw_stats->rx_overflow += 7068c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_OERCNT + offs); 7078c2ecf20Sopenharmony_ci hw_stats->rx_fcs_errors += 7088c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_FERCNT + offs); 7098c2ecf20Sopenharmony_ci hw_stats->rx_short_errors += 7108c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_SERCNT + offs); 7118c2ecf20Sopenharmony_ci hw_stats->rx_long_errors += 7128c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_LENCNT + offs); 7138c2ecf20Sopenharmony_ci hw_stats->rx_checksum_errors += 7148c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_CERCNT + offs); 7158c2ecf20Sopenharmony_ci hw_stats->rx_flow_control_packets += 7168c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_RX_FCCNT + offs); 7178c2ecf20Sopenharmony_ci hw_stats->tx_skip += 7188c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_TX_SKIPCNT + offs); 7198c2ecf20Sopenharmony_ci hw_stats->tx_collisions += 7208c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_TX_COLCNT + offs); 7218c2ecf20Sopenharmony_ci hw_stats->tx_bytes += 7228c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_L + offs); 7238c2ecf20Sopenharmony_ci stats = mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_H + offs); 7248c2ecf20Sopenharmony_ci if (stats) 7258c2ecf20Sopenharmony_ci hw_stats->tx_bytes += (stats << 32); 7268c2ecf20Sopenharmony_ci hw_stats->tx_packets += 7278c2ecf20Sopenharmony_ci mtk_r32(mac->hw, MTK_GDM1_TX_GPCNT + offs); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci u64_stats_update_end(&hw_stats->syncp); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void mtk_stats_update(struct mtk_eth *eth) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci int i; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 7388c2ecf20Sopenharmony_ci if (!eth->mac[i] || !eth->mac[i]->hw_stats) 7398c2ecf20Sopenharmony_ci continue; 7408c2ecf20Sopenharmony_ci if (spin_trylock(ð->mac[i]->hw_stats->stats_lock)) { 7418c2ecf20Sopenharmony_ci mtk_stats_update_mac(eth->mac[i]); 7428c2ecf20Sopenharmony_ci spin_unlock(ð->mac[i]->hw_stats->stats_lock); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic void mtk_get_stats64(struct net_device *dev, 7488c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *storage) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 7518c2ecf20Sopenharmony_ci struct mtk_hw_stats *hw_stats = mac->hw_stats; 7528c2ecf20Sopenharmony_ci unsigned int start; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (netif_running(dev) && netif_device_present(dev)) { 7558c2ecf20Sopenharmony_ci if (spin_trylock_bh(&hw_stats->stats_lock)) { 7568c2ecf20Sopenharmony_ci mtk_stats_update_mac(mac); 7578c2ecf20Sopenharmony_ci spin_unlock_bh(&hw_stats->stats_lock); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci do { 7628c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&hw_stats->syncp); 7638c2ecf20Sopenharmony_ci storage->rx_packets = hw_stats->rx_packets; 7648c2ecf20Sopenharmony_ci storage->tx_packets = hw_stats->tx_packets; 7658c2ecf20Sopenharmony_ci storage->rx_bytes = hw_stats->rx_bytes; 7668c2ecf20Sopenharmony_ci storage->tx_bytes = hw_stats->tx_bytes; 7678c2ecf20Sopenharmony_ci storage->collisions = hw_stats->tx_collisions; 7688c2ecf20Sopenharmony_ci storage->rx_length_errors = hw_stats->rx_short_errors + 7698c2ecf20Sopenharmony_ci hw_stats->rx_long_errors; 7708c2ecf20Sopenharmony_ci storage->rx_over_errors = hw_stats->rx_overflow; 7718c2ecf20Sopenharmony_ci storage->rx_crc_errors = hw_stats->rx_fcs_errors; 7728c2ecf20Sopenharmony_ci storage->rx_errors = hw_stats->rx_checksum_errors; 7738c2ecf20Sopenharmony_ci storage->tx_aborted_errors = hw_stats->tx_skip; 7748c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci storage->tx_errors = dev->stats.tx_errors; 7778c2ecf20Sopenharmony_ci storage->rx_dropped = dev->stats.rx_dropped; 7788c2ecf20Sopenharmony_ci storage->tx_dropped = dev->stats.tx_dropped; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic inline int mtk_max_frag_size(int mtu) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci /* make sure buf_size will be at least MTK_MAX_RX_LENGTH */ 7848c2ecf20Sopenharmony_ci if (mtu + MTK_RX_ETH_HLEN < MTK_MAX_RX_LENGTH) 7858c2ecf20Sopenharmony_ci mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return SKB_DATA_ALIGN(MTK_RX_HLEN + mtu) + 7888c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic inline int mtk_max_buf_size(int frag_size) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci int buf_size = frag_size - NET_SKB_PAD - NET_IP_ALIGN - 7948c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci WARN_ON(buf_size < MTK_MAX_RX_LENGTH); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return buf_size; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd, 8028c2ecf20Sopenharmony_ci struct mtk_rx_dma *dma_rxd) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); 8058c2ecf20Sopenharmony_ci rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); 8068c2ecf20Sopenharmony_ci rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); 8078c2ecf20Sopenharmony_ci rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic void *mtk_max_lro_buf_alloc(gfp_t gfp_mask) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci unsigned int size = mtk_max_frag_size(MTK_MAX_LRO_RX_LENGTH); 8138c2ecf20Sopenharmony_ci unsigned long data; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci data = __get_free_pages(gfp_mask | __GFP_COMP | __GFP_NOWARN, 8168c2ecf20Sopenharmony_ci get_order(size)); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci return (void *)data; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/* the qdma core needs scratch memory to be setup */ 8228c2ecf20Sopenharmony_cistatic int mtk_init_fq_dma(struct mtk_eth *eth) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci dma_addr_t phy_ring_tail; 8258c2ecf20Sopenharmony_ci int cnt = MTK_DMA_SIZE; 8268c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 8278c2ecf20Sopenharmony_ci int i; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci eth->scratch_ring = dma_alloc_coherent(eth->dev, 8308c2ecf20Sopenharmony_ci cnt * sizeof(struct mtk_tx_dma), 8318c2ecf20Sopenharmony_ci ð->phy_scratch_ring, 8328c2ecf20Sopenharmony_ci GFP_ATOMIC); 8338c2ecf20Sopenharmony_ci if (unlikely(!eth->scratch_ring)) 8348c2ecf20Sopenharmony_ci return -ENOMEM; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, 8378c2ecf20Sopenharmony_ci GFP_KERNEL); 8388c2ecf20Sopenharmony_ci if (unlikely(!eth->scratch_head)) 8398c2ecf20Sopenharmony_ci return -ENOMEM; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci dma_addr = dma_map_single(eth->dev, 8428c2ecf20Sopenharmony_ci eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE, 8438c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 8448c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(eth->dev, dma_addr))) 8458c2ecf20Sopenharmony_ci return -ENOMEM; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci phy_ring_tail = eth->phy_scratch_ring + 8488c2ecf20Sopenharmony_ci (sizeof(struct mtk_tx_dma) * (cnt - 1)); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 8518c2ecf20Sopenharmony_ci eth->scratch_ring[i].txd1 = 8528c2ecf20Sopenharmony_ci (dma_addr + (i * MTK_QDMA_PAGE_SIZE)); 8538c2ecf20Sopenharmony_ci if (i < cnt - 1) 8548c2ecf20Sopenharmony_ci eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring + 8558c2ecf20Sopenharmony_ci ((i + 1) * sizeof(struct mtk_tx_dma))); 8568c2ecf20Sopenharmony_ci eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); 8608c2ecf20Sopenharmony_ci mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL); 8618c2ecf20Sopenharmony_ci mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT); 8628c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic inline void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci void *ret = ring->dma; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return ret + (desc - ring->phys); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic inline struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, 8758c2ecf20Sopenharmony_ci struct mtk_tx_dma *txd) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci int idx = txd - ring->dma; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci return &ring->buf[idx]; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, 8838c2ecf20Sopenharmony_ci struct mtk_tx_dma *dma) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci return ring->dma_pdma - ring->dma + dma; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci return ((void *)dma - (void *)ring->dma) / sizeof(*dma); 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 8968c2ecf20Sopenharmony_ci if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { 8978c2ecf20Sopenharmony_ci dma_unmap_single(eth->dev, 8988c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, dma_addr0), 8998c2ecf20Sopenharmony_ci dma_unmap_len(tx_buf, dma_len0), 9008c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9018c2ecf20Sopenharmony_ci } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { 9028c2ecf20Sopenharmony_ci dma_unmap_page(eth->dev, 9038c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, dma_addr0), 9048c2ecf20Sopenharmony_ci dma_unmap_len(tx_buf, dma_len0), 9058c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci } else { 9088c2ecf20Sopenharmony_ci if (dma_unmap_len(tx_buf, dma_len0)) { 9098c2ecf20Sopenharmony_ci dma_unmap_page(eth->dev, 9108c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, dma_addr0), 9118c2ecf20Sopenharmony_ci dma_unmap_len(tx_buf, dma_len0), 9128c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (dma_unmap_len(tx_buf, dma_len1)) { 9168c2ecf20Sopenharmony_ci dma_unmap_page(eth->dev, 9178c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, dma_addr1), 9188c2ecf20Sopenharmony_ci dma_unmap_len(tx_buf, dma_len1), 9198c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci tx_buf->flags = 0; 9248c2ecf20Sopenharmony_ci if (tx_buf->skb && 9258c2ecf20Sopenharmony_ci (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) 9268c2ecf20Sopenharmony_ci dev_kfree_skb_any(tx_buf->skb); 9278c2ecf20Sopenharmony_ci tx_buf->skb = NULL; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, 9318c2ecf20Sopenharmony_ci struct mtk_tx_dma *txd, dma_addr_t mapped_addr, 9328c2ecf20Sopenharmony_ci size_t size, int idx) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 9358c2ecf20Sopenharmony_ci dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); 9368c2ecf20Sopenharmony_ci dma_unmap_len_set(tx_buf, dma_len0, size); 9378c2ecf20Sopenharmony_ci } else { 9388c2ecf20Sopenharmony_ci if (idx & 1) { 9398c2ecf20Sopenharmony_ci txd->txd3 = mapped_addr; 9408c2ecf20Sopenharmony_ci txd->txd2 |= TX_DMA_PLEN1(size); 9418c2ecf20Sopenharmony_ci dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); 9428c2ecf20Sopenharmony_ci dma_unmap_len_set(tx_buf, dma_len1, size); 9438c2ecf20Sopenharmony_ci } else { 9448c2ecf20Sopenharmony_ci tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; 9458c2ecf20Sopenharmony_ci txd->txd1 = mapped_addr; 9468c2ecf20Sopenharmony_ci txd->txd2 = TX_DMA_PLEN0(size); 9478c2ecf20Sopenharmony_ci dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); 9488c2ecf20Sopenharmony_ci dma_unmap_len_set(tx_buf, dma_len0, size); 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, 9548c2ecf20Sopenharmony_ci int tx_num, struct mtk_tx_ring *ring, bool gso) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 9578c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 9588c2ecf20Sopenharmony_ci struct mtk_tx_dma *itxd, *txd; 9598c2ecf20Sopenharmony_ci struct mtk_tx_dma *itxd_pdma, *txd_pdma; 9608c2ecf20Sopenharmony_ci struct mtk_tx_buf *itx_buf, *tx_buf; 9618c2ecf20Sopenharmony_ci dma_addr_t mapped_addr; 9628c2ecf20Sopenharmony_ci unsigned int nr_frags; 9638c2ecf20Sopenharmony_ci int i, n_desc = 1; 9648c2ecf20Sopenharmony_ci u32 txd4 = 0, fport; 9658c2ecf20Sopenharmony_ci int k = 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci itxd = ring->next_free; 9688c2ecf20Sopenharmony_ci itxd_pdma = qdma_to_pdma(ring, itxd); 9698c2ecf20Sopenharmony_ci if (itxd == ring->last_free) 9708c2ecf20Sopenharmony_ci return -ENOMEM; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* set the forward port */ 9738c2ecf20Sopenharmony_ci fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; 9748c2ecf20Sopenharmony_ci txd4 |= fport; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci itx_buf = mtk_desc_to_tx_buf(ring, itxd); 9778c2ecf20Sopenharmony_ci memset(itx_buf, 0, sizeof(*itx_buf)); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (gso) 9808c2ecf20Sopenharmony_ci txd4 |= TX_DMA_TSO; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* TX Checksum offload */ 9838c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 9848c2ecf20Sopenharmony_ci txd4 |= TX_DMA_CHKSUM; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* VLAN header offload */ 9878c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 9888c2ecf20Sopenharmony_ci txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci mapped_addr = dma_map_single(eth->dev, skb->data, 9918c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 9928c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) 9938c2ecf20Sopenharmony_ci return -ENOMEM; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci WRITE_ONCE(itxd->txd1, mapped_addr); 9968c2ecf20Sopenharmony_ci itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; 9978c2ecf20Sopenharmony_ci itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : 9988c2ecf20Sopenharmony_ci MTK_TX_FLAGS_FPORT1; 9998c2ecf20Sopenharmony_ci setup_tx_buf(eth, itx_buf, itxd_pdma, mapped_addr, skb_headlen(skb), 10008c2ecf20Sopenharmony_ci k++); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* TX SG offload */ 10038c2ecf20Sopenharmony_ci txd = itxd; 10048c2ecf20Sopenharmony_ci txd_pdma = qdma_to_pdma(ring, txd); 10058c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 10088c2ecf20Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 10098c2ecf20Sopenharmony_ci unsigned int offset = 0; 10108c2ecf20Sopenharmony_ci int frag_size = skb_frag_size(frag); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci while (frag_size) { 10138c2ecf20Sopenharmony_ci bool last_frag = false; 10148c2ecf20Sopenharmony_ci unsigned int frag_map_size; 10158c2ecf20Sopenharmony_ci bool new_desc = true; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || 10188c2ecf20Sopenharmony_ci (i & 0x1)) { 10198c2ecf20Sopenharmony_ci txd = mtk_qdma_phys_to_virt(ring, txd->txd2); 10208c2ecf20Sopenharmony_ci txd_pdma = qdma_to_pdma(ring, txd); 10218c2ecf20Sopenharmony_ci if (txd == ring->last_free) 10228c2ecf20Sopenharmony_ci goto err_dma; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci n_desc++; 10258c2ecf20Sopenharmony_ci } else { 10268c2ecf20Sopenharmony_ci new_desc = false; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); 10318c2ecf20Sopenharmony_ci mapped_addr = skb_frag_dma_map(eth->dev, frag, offset, 10328c2ecf20Sopenharmony_ci frag_map_size, 10338c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 10348c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) 10358c2ecf20Sopenharmony_ci goto err_dma; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (i == nr_frags - 1 && 10388c2ecf20Sopenharmony_ci (frag_size - frag_map_size) == 0) 10398c2ecf20Sopenharmony_ci last_frag = true; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci WRITE_ONCE(txd->txd1, mapped_addr); 10428c2ecf20Sopenharmony_ci WRITE_ONCE(txd->txd3, (TX_DMA_SWC | 10438c2ecf20Sopenharmony_ci TX_DMA_PLEN0(frag_map_size) | 10448c2ecf20Sopenharmony_ci last_frag * TX_DMA_LS0)); 10458c2ecf20Sopenharmony_ci WRITE_ONCE(txd->txd4, fport); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci tx_buf = mtk_desc_to_tx_buf(ring, txd); 10488c2ecf20Sopenharmony_ci if (new_desc) 10498c2ecf20Sopenharmony_ci memset(tx_buf, 0, sizeof(*tx_buf)); 10508c2ecf20Sopenharmony_ci tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; 10518c2ecf20Sopenharmony_ci tx_buf->flags |= MTK_TX_FLAGS_PAGE0; 10528c2ecf20Sopenharmony_ci tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : 10538c2ecf20Sopenharmony_ci MTK_TX_FLAGS_FPORT1; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci setup_tx_buf(eth, tx_buf, txd_pdma, mapped_addr, 10568c2ecf20Sopenharmony_ci frag_map_size, k++); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci frag_size -= frag_map_size; 10598c2ecf20Sopenharmony_ci offset += frag_map_size; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* store skb to cleanup */ 10648c2ecf20Sopenharmony_ci itx_buf->skb = skb; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci WRITE_ONCE(itxd->txd4, txd4); 10678c2ecf20Sopenharmony_ci WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | 10688c2ecf20Sopenharmony_ci (!nr_frags * TX_DMA_LS0))); 10698c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 10708c2ecf20Sopenharmony_ci if (k & 0x1) 10718c2ecf20Sopenharmony_ci txd_pdma->txd2 |= TX_DMA_LS0; 10728c2ecf20Sopenharmony_ci else 10738c2ecf20Sopenharmony_ci txd_pdma->txd2 |= TX_DMA_LS1; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci netdev_sent_queue(dev, skb->len); 10778c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); 10808c2ecf20Sopenharmony_ci atomic_sub(n_desc, &ring->free_count); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* make sure that all changes to the dma ring are flushed before we 10838c2ecf20Sopenharmony_ci * continue 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci wmb(); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 10888c2ecf20Sopenharmony_ci if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || 10898c2ecf20Sopenharmony_ci !netdev_xmit_more()) 10908c2ecf20Sopenharmony_ci mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); 10918c2ecf20Sopenharmony_ci } else { 10928c2ecf20Sopenharmony_ci int next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd), 10938c2ecf20Sopenharmony_ci ring->dma_size); 10948c2ecf20Sopenharmony_ci mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci return 0; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cierr_dma: 11008c2ecf20Sopenharmony_ci do { 11018c2ecf20Sopenharmony_ci tx_buf = mtk_desc_to_tx_buf(ring, itxd); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci /* unmap dma */ 11048c2ecf20Sopenharmony_ci mtk_tx_unmap(eth, tx_buf); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; 11078c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) 11088c2ecf20Sopenharmony_ci itxd_pdma->txd2 = TX_DMA_DESP2_DEF; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); 11118c2ecf20Sopenharmony_ci itxd_pdma = qdma_to_pdma(ring, itxd); 11128c2ecf20Sopenharmony_ci } while (itxd != txd); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci return -ENOMEM; 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic inline int mtk_cal_txd_req(struct sk_buff *skb) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci int i, nfrags; 11208c2ecf20Sopenharmony_ci skb_frag_t *frag; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci nfrags = 1; 11238c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 11248c2ecf20Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 11258c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 11268c2ecf20Sopenharmony_ci nfrags += DIV_ROUND_UP(skb_frag_size(frag), 11278c2ecf20Sopenharmony_ci MTK_TX_DMA_BUF_LEN); 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci nfrags += skb_shinfo(skb)->nr_frags; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci return nfrags; 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic int mtk_queue_stopped(struct mtk_eth *eth) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci int i; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 11418c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 11428c2ecf20Sopenharmony_ci continue; 11438c2ecf20Sopenharmony_ci if (netif_queue_stopped(eth->netdev[i])) 11448c2ecf20Sopenharmony_ci return 1; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return 0; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic void mtk_wake_queue(struct mtk_eth *eth) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci int i; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 11558c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 11568c2ecf20Sopenharmony_ci continue; 11578c2ecf20Sopenharmony_ci netif_wake_queue(eth->netdev[i]); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cistatic void mtk_stop_queue(struct mtk_eth *eth) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci int i; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 11668c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 11678c2ecf20Sopenharmony_ci continue; 11688c2ecf20Sopenharmony_ci netif_stop_queue(eth->netdev[i]); 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 11758c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 11768c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 11778c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 11788c2ecf20Sopenharmony_ci bool gso = false; 11798c2ecf20Sopenharmony_ci int tx_num; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* normally we can rely on the stack not calling this more than once, 11828c2ecf20Sopenharmony_ci * however we have 2 queues running on the same ring so we need to lock 11838c2ecf20Sopenharmony_ci * the ring access 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ci spin_lock(ð->page_lock); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, ð->state))) 11888c2ecf20Sopenharmony_ci goto drop; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci tx_num = mtk_cal_txd_req(skb); 11918c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { 11928c2ecf20Sopenharmony_ci mtk_stop_queue(eth); 11938c2ecf20Sopenharmony_ci netif_err(eth, tx_queued, dev, 11948c2ecf20Sopenharmony_ci "Tx Ring full when queue awake!\n"); 11958c2ecf20Sopenharmony_ci spin_unlock(ð->page_lock); 11968c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* TSO: fill MSS info in tcp checksum field */ 12008c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 12018c2ecf20Sopenharmony_ci if (skb_cow_head(skb, 0)) { 12028c2ecf20Sopenharmony_ci netif_warn(eth, tx_err, dev, 12038c2ecf20Sopenharmony_ci "GSO expand head fail.\n"); 12048c2ecf20Sopenharmony_ci goto drop; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_type & 12088c2ecf20Sopenharmony_ci (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { 12098c2ecf20Sopenharmony_ci gso = true; 12108c2ecf20Sopenharmony_ci tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size); 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) 12158c2ecf20Sopenharmony_ci goto drop; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) 12188c2ecf20Sopenharmony_ci mtk_stop_queue(eth); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci spin_unlock(ð->page_lock); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cidrop: 12258c2ecf20Sopenharmony_ci spin_unlock(ð->page_lock); 12268c2ecf20Sopenharmony_ci stats->tx_dropped++; 12278c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12288c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci int i; 12348c2ecf20Sopenharmony_ci struct mtk_rx_ring *ring; 12358c2ecf20Sopenharmony_ci int idx; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (!eth->hwlro) 12388c2ecf20Sopenharmony_ci return ð->rx_ring[0]; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) { 12418c2ecf20Sopenharmony_ci ring = ð->rx_ring[i]; 12428c2ecf20Sopenharmony_ci idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); 12438c2ecf20Sopenharmony_ci if (ring->dma[idx].rxd2 & RX_DMA_DONE) { 12448c2ecf20Sopenharmony_ci ring->calc_idx_update = true; 12458c2ecf20Sopenharmony_ci return ring; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return NULL; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic void mtk_update_rx_cpu_idx(struct mtk_eth *eth) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct mtk_rx_ring *ring; 12558c2ecf20Sopenharmony_ci int i; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (!eth->hwlro) { 12588c2ecf20Sopenharmony_ci ring = ð->rx_ring[0]; 12598c2ecf20Sopenharmony_ci mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); 12608c2ecf20Sopenharmony_ci } else { 12618c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) { 12628c2ecf20Sopenharmony_ci ring = ð->rx_ring[i]; 12638c2ecf20Sopenharmony_ci if (ring->calc_idx_update) { 12648c2ecf20Sopenharmony_ci ring->calc_idx_update = false; 12658c2ecf20Sopenharmony_ci mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic int mtk_poll_rx(struct napi_struct *napi, int budget, 12728c2ecf20Sopenharmony_ci struct mtk_eth *eth) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct mtk_rx_ring *ring; 12758c2ecf20Sopenharmony_ci int idx; 12768c2ecf20Sopenharmony_ci struct sk_buff *skb; 12778c2ecf20Sopenharmony_ci u8 *data, *new_data; 12788c2ecf20Sopenharmony_ci struct mtk_rx_dma *rxd, trxd; 12798c2ecf20Sopenharmony_ci int done = 0; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci while (done < budget) { 12828c2ecf20Sopenharmony_ci struct net_device *netdev; 12838c2ecf20Sopenharmony_ci unsigned int pktlen; 12848c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 12858c2ecf20Sopenharmony_ci int mac; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci ring = mtk_get_rx_ring(eth); 12888c2ecf20Sopenharmony_ci if (unlikely(!ring)) 12898c2ecf20Sopenharmony_ci goto rx_done; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); 12928c2ecf20Sopenharmony_ci rxd = &ring->dma[idx]; 12938c2ecf20Sopenharmony_ci data = ring->data[idx]; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci mtk_rx_get_desc(&trxd, rxd); 12968c2ecf20Sopenharmony_ci if (!(trxd.rxd2 & RX_DMA_DONE)) 12978c2ecf20Sopenharmony_ci break; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* find out which mac the packet come from. values start at 1 */ 13008c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 13018c2ecf20Sopenharmony_ci mac = 0; 13028c2ecf20Sopenharmony_ci } else { 13038c2ecf20Sopenharmony_ci mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & 13048c2ecf20Sopenharmony_ci RX_DMA_FPORT_MASK; 13058c2ecf20Sopenharmony_ci mac--; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || 13098c2ecf20Sopenharmony_ci !eth->netdev[mac])) 13108c2ecf20Sopenharmony_ci goto release_desc; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci netdev = eth->netdev[mac]; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, ð->state))) 13158c2ecf20Sopenharmony_ci goto release_desc; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* alloc new buffer */ 13188c2ecf20Sopenharmony_ci if (ring->frag_size <= PAGE_SIZE) 13198c2ecf20Sopenharmony_ci new_data = napi_alloc_frag(ring->frag_size); 13208c2ecf20Sopenharmony_ci else 13218c2ecf20Sopenharmony_ci new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); 13228c2ecf20Sopenharmony_ci if (unlikely(!new_data)) { 13238c2ecf20Sopenharmony_ci netdev->stats.rx_dropped++; 13248c2ecf20Sopenharmony_ci goto release_desc; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci dma_addr = dma_map_single(eth->dev, 13278c2ecf20Sopenharmony_ci new_data + NET_SKB_PAD + 13288c2ecf20Sopenharmony_ci eth->ip_align, 13298c2ecf20Sopenharmony_ci ring->buf_size, 13308c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 13318c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(eth->dev, dma_addr))) { 13328c2ecf20Sopenharmony_ci skb_free_frag(new_data); 13338c2ecf20Sopenharmony_ci netdev->stats.rx_dropped++; 13348c2ecf20Sopenharmony_ci goto release_desc; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* receive data */ 13388c2ecf20Sopenharmony_ci skb = build_skb(data, ring->frag_size); 13398c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 13408c2ecf20Sopenharmony_ci skb_free_frag(new_data); 13418c2ecf20Sopenharmony_ci netdev->stats.rx_dropped++; 13428c2ecf20Sopenharmony_ci goto release_desc; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci dma_unmap_single(eth->dev, trxd.rxd1, 13478c2ecf20Sopenharmony_ci ring->buf_size, DMA_FROM_DEVICE); 13488c2ecf20Sopenharmony_ci pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); 13498c2ecf20Sopenharmony_ci skb->dev = netdev; 13508c2ecf20Sopenharmony_ci skb_put(skb, pktlen); 13518c2ecf20Sopenharmony_ci if (trxd.rxd4 & eth->rx_dma_l4_valid) 13528c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 13538c2ecf20Sopenharmony_ci else 13548c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 13558c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && 13588c2ecf20Sopenharmony_ci (trxd.rxd2 & RX_DMA_VTAG)) 13598c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 13608c2ecf20Sopenharmony_ci RX_DMA_VID(trxd.rxd3)); 13618c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, 0); 13628c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci ring->data[idx] = new_data; 13658c2ecf20Sopenharmony_ci rxd->rxd1 = (unsigned int)dma_addr; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_cirelease_desc: 13688c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) 13698c2ecf20Sopenharmony_ci rxd->rxd2 = RX_DMA_LSO; 13708c2ecf20Sopenharmony_ci else 13718c2ecf20Sopenharmony_ci rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci ring->calc_idx = idx; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci done++; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_cirx_done: 13798c2ecf20Sopenharmony_ci if (done) { 13808c2ecf20Sopenharmony_ci /* make sure that all changes to the dma ring are flushed before 13818c2ecf20Sopenharmony_ci * we continue 13828c2ecf20Sopenharmony_ci */ 13838c2ecf20Sopenharmony_ci wmb(); 13848c2ecf20Sopenharmony_ci mtk_update_rx_cpu_idx(eth); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci return done; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cistatic int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, 13918c2ecf20Sopenharmony_ci unsigned int *done, unsigned int *bytes) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 13948c2ecf20Sopenharmony_ci struct mtk_tx_dma *desc; 13958c2ecf20Sopenharmony_ci struct sk_buff *skb; 13968c2ecf20Sopenharmony_ci struct mtk_tx_buf *tx_buf; 13978c2ecf20Sopenharmony_ci u32 cpu, dma; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); 14008c2ecf20Sopenharmony_ci dma = mtk_r32(eth, MTK_QTX_DRX_PTR); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci desc = mtk_qdma_phys_to_virt(ring, cpu); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci while ((cpu != dma) && budget) { 14058c2ecf20Sopenharmony_ci u32 next_cpu = desc->txd2; 14068c2ecf20Sopenharmony_ci int mac = 0; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci desc = mtk_qdma_phys_to_virt(ring, desc->txd2); 14098c2ecf20Sopenharmony_ci if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0) 14108c2ecf20Sopenharmony_ci break; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci tx_buf = mtk_desc_to_tx_buf(ring, desc); 14138c2ecf20Sopenharmony_ci if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) 14148c2ecf20Sopenharmony_ci mac = 1; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci skb = tx_buf->skb; 14178c2ecf20Sopenharmony_ci if (!skb) 14188c2ecf20Sopenharmony_ci break; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { 14218c2ecf20Sopenharmony_ci bytes[mac] += skb->len; 14228c2ecf20Sopenharmony_ci done[mac]++; 14238c2ecf20Sopenharmony_ci budget--; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci mtk_tx_unmap(eth, tx_buf); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci ring->last_free = desc; 14288c2ecf20Sopenharmony_ci atomic_inc(&ring->free_count); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci cpu = next_cpu; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return budget; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, 14398c2ecf20Sopenharmony_ci unsigned int *done, unsigned int *bytes) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 14428c2ecf20Sopenharmony_ci struct mtk_tx_dma *desc; 14438c2ecf20Sopenharmony_ci struct sk_buff *skb; 14448c2ecf20Sopenharmony_ci struct mtk_tx_buf *tx_buf; 14458c2ecf20Sopenharmony_ci u32 cpu, dma; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci cpu = ring->cpu_idx; 14488c2ecf20Sopenharmony_ci dma = mtk_r32(eth, MT7628_TX_DTX_IDX0); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci while ((cpu != dma) && budget) { 14518c2ecf20Sopenharmony_ci tx_buf = &ring->buf[cpu]; 14528c2ecf20Sopenharmony_ci skb = tx_buf->skb; 14538c2ecf20Sopenharmony_ci if (!skb) 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { 14578c2ecf20Sopenharmony_ci bytes[0] += skb->len; 14588c2ecf20Sopenharmony_ci done[0]++; 14598c2ecf20Sopenharmony_ci budget--; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci mtk_tx_unmap(eth, tx_buf); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci desc = &ring->dma[cpu]; 14658c2ecf20Sopenharmony_ci ring->last_free = desc; 14668c2ecf20Sopenharmony_ci atomic_inc(&ring->free_count); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci cpu = NEXT_DESP_IDX(cpu, ring->dma_size); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci ring->cpu_idx = cpu; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci return budget; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int mtk_poll_tx(struct mtk_eth *eth, int budget) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 14798c2ecf20Sopenharmony_ci unsigned int done[MTK_MAX_DEVS]; 14808c2ecf20Sopenharmony_ci unsigned int bytes[MTK_MAX_DEVS]; 14818c2ecf20Sopenharmony_ci int total = 0, i; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci memset(done, 0, sizeof(done)); 14848c2ecf20Sopenharmony_ci memset(bytes, 0, sizeof(bytes)); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) 14878c2ecf20Sopenharmony_ci budget = mtk_poll_tx_qdma(eth, budget, done, bytes); 14888c2ecf20Sopenharmony_ci else 14898c2ecf20Sopenharmony_ci budget = mtk_poll_tx_pdma(eth, budget, done, bytes); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 14928c2ecf20Sopenharmony_ci if (!eth->netdev[i] || !done[i]) 14938c2ecf20Sopenharmony_ci continue; 14948c2ecf20Sopenharmony_ci netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); 14958c2ecf20Sopenharmony_ci total += done[i]; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (mtk_queue_stopped(eth) && 14998c2ecf20Sopenharmony_ci (atomic_read(&ring->free_count) > ring->thresh)) 15008c2ecf20Sopenharmony_ci mtk_wake_queue(eth); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci return total; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic void mtk_handle_status_irq(struct mtk_eth *eth) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci u32 status2 = mtk_r32(eth, MTK_INT_STATUS2); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) { 15108c2ecf20Sopenharmony_ci mtk_stats_update(eth); 15118c2ecf20Sopenharmony_ci mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF), 15128c2ecf20Sopenharmony_ci MTK_INT_STATUS2); 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic int mtk_napi_tx(struct napi_struct *napi, int budget) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); 15198c2ecf20Sopenharmony_ci u32 status, mask; 15208c2ecf20Sopenharmony_ci int tx_done = 0; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) 15238c2ecf20Sopenharmony_ci mtk_handle_status_irq(eth); 15248c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_TX_DONE_INT, eth->tx_int_status_reg); 15258c2ecf20Sopenharmony_ci tx_done = mtk_poll_tx(eth, budget); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (unlikely(netif_msg_intr(eth))) { 15288c2ecf20Sopenharmony_ci status = mtk_r32(eth, eth->tx_int_status_reg); 15298c2ecf20Sopenharmony_ci mask = mtk_r32(eth, eth->tx_int_mask_reg); 15308c2ecf20Sopenharmony_ci dev_info(eth->dev, 15318c2ecf20Sopenharmony_ci "done tx %d, intr 0x%08x/0x%x\n", 15328c2ecf20Sopenharmony_ci tx_done, status, mask); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (tx_done == budget) 15368c2ecf20Sopenharmony_ci return budget; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci status = mtk_r32(eth, eth->tx_int_status_reg); 15398c2ecf20Sopenharmony_ci if (status & MTK_TX_DONE_INT) 15408c2ecf20Sopenharmony_ci return budget; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci napi_complete(napi); 15438c2ecf20Sopenharmony_ci mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return tx_done; 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic int mtk_napi_rx(struct napi_struct *napi, int budget) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); 15518c2ecf20Sopenharmony_ci u32 status, mask; 15528c2ecf20Sopenharmony_ci int rx_done = 0; 15538c2ecf20Sopenharmony_ci int remain_budget = budget; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci mtk_handle_status_irq(eth); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cipoll_again: 15588c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS); 15598c2ecf20Sopenharmony_ci rx_done = mtk_poll_rx(napi, remain_budget, eth); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (unlikely(netif_msg_intr(eth))) { 15628c2ecf20Sopenharmony_ci status = mtk_r32(eth, MTK_PDMA_INT_STATUS); 15638c2ecf20Sopenharmony_ci mask = mtk_r32(eth, MTK_PDMA_INT_MASK); 15648c2ecf20Sopenharmony_ci dev_info(eth->dev, 15658c2ecf20Sopenharmony_ci "done rx %d, intr 0x%08x/0x%x\n", 15668c2ecf20Sopenharmony_ci rx_done, status, mask); 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci if (rx_done == remain_budget) 15698c2ecf20Sopenharmony_ci return budget; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci status = mtk_r32(eth, MTK_PDMA_INT_STATUS); 15728c2ecf20Sopenharmony_ci if (status & MTK_RX_DONE_INT) { 15738c2ecf20Sopenharmony_ci remain_budget -= rx_done; 15748c2ecf20Sopenharmony_ci goto poll_again; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci napi_complete(napi); 15778c2ecf20Sopenharmony_ci mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci return rx_done + budget - remain_budget; 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cistatic int mtk_tx_alloc(struct mtk_eth *eth) 15838c2ecf20Sopenharmony_ci{ 15848c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 15858c2ecf20Sopenharmony_ci int i, sz = sizeof(*ring->dma); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), 15888c2ecf20Sopenharmony_ci GFP_KERNEL); 15898c2ecf20Sopenharmony_ci if (!ring->buf) 15908c2ecf20Sopenharmony_ci goto no_tx_mem; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, 15938c2ecf20Sopenharmony_ci &ring->phys, GFP_ATOMIC); 15948c2ecf20Sopenharmony_ci if (!ring->dma) 15958c2ecf20Sopenharmony_ci goto no_tx_mem; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci for (i = 0; i < MTK_DMA_SIZE; i++) { 15988c2ecf20Sopenharmony_ci int next = (i + 1) % MTK_DMA_SIZE; 15998c2ecf20Sopenharmony_ci u32 next_ptr = ring->phys + next * sz; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci ring->dma[i].txd2 = next_ptr; 16028c2ecf20Sopenharmony_ci ring->dma[i].txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* On MT7688 (PDMA only) this driver uses the ring->dma structs 16068c2ecf20Sopenharmony_ci * only as the framework. The real HW descriptors are the PDMA 16078c2ecf20Sopenharmony_ci * descriptors in ring->dma_pdma. 16088c2ecf20Sopenharmony_ci */ 16098c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 16108c2ecf20Sopenharmony_ci ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, 16118c2ecf20Sopenharmony_ci &ring->phys_pdma, 16128c2ecf20Sopenharmony_ci GFP_ATOMIC); 16138c2ecf20Sopenharmony_ci if (!ring->dma_pdma) 16148c2ecf20Sopenharmony_ci goto no_tx_mem; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci for (i = 0; i < MTK_DMA_SIZE; i++) { 16178c2ecf20Sopenharmony_ci ring->dma_pdma[i].txd2 = TX_DMA_DESP2_DEF; 16188c2ecf20Sopenharmony_ci ring->dma_pdma[i].txd4 = 0; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci ring->dma_size = MTK_DMA_SIZE; 16238c2ecf20Sopenharmony_ci atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); 16248c2ecf20Sopenharmony_ci ring->next_free = &ring->dma[0]; 16258c2ecf20Sopenharmony_ci ring->last_free = &ring->dma[MTK_DMA_SIZE - 1]; 16268c2ecf20Sopenharmony_ci ring->thresh = MAX_SKB_FRAGS; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* make sure that all changes to the dma ring are flushed before we 16298c2ecf20Sopenharmony_ci * continue 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ci wmb(); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 16348c2ecf20Sopenharmony_ci mtk_w32(eth, ring->phys, MTK_QTX_CTX_PTR); 16358c2ecf20Sopenharmony_ci mtk_w32(eth, ring->phys, MTK_QTX_DTX_PTR); 16368c2ecf20Sopenharmony_ci mtk_w32(eth, 16378c2ecf20Sopenharmony_ci ring->phys + ((MTK_DMA_SIZE - 1) * sz), 16388c2ecf20Sopenharmony_ci MTK_QTX_CRX_PTR); 16398c2ecf20Sopenharmony_ci mtk_w32(eth, 16408c2ecf20Sopenharmony_ci ring->phys + ((MTK_DMA_SIZE - 1) * sz), 16418c2ecf20Sopenharmony_ci MTK_QTX_DRX_PTR); 16428c2ecf20Sopenharmony_ci mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, 16438c2ecf20Sopenharmony_ci MTK_QTX_CFG(0)); 16448c2ecf20Sopenharmony_ci } else { 16458c2ecf20Sopenharmony_ci mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); 16468c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0); 16478c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); 16488c2ecf20Sopenharmony_ci mtk_w32(eth, MT7628_PST_DTX_IDX0, MTK_PDMA_RST_IDX); 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci return 0; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_cino_tx_mem: 16548c2ecf20Sopenharmony_ci return -ENOMEM; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic void mtk_tx_clean(struct mtk_eth *eth) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct mtk_tx_ring *ring = ð->tx_ring; 16608c2ecf20Sopenharmony_ci int i; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (ring->buf) { 16638c2ecf20Sopenharmony_ci for (i = 0; i < MTK_DMA_SIZE; i++) 16648c2ecf20Sopenharmony_ci mtk_tx_unmap(eth, &ring->buf[i]); 16658c2ecf20Sopenharmony_ci kfree(ring->buf); 16668c2ecf20Sopenharmony_ci ring->buf = NULL; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (ring->dma) { 16708c2ecf20Sopenharmony_ci dma_free_coherent(eth->dev, 16718c2ecf20Sopenharmony_ci MTK_DMA_SIZE * sizeof(*ring->dma), 16728c2ecf20Sopenharmony_ci ring->dma, 16738c2ecf20Sopenharmony_ci ring->phys); 16748c2ecf20Sopenharmony_ci ring->dma = NULL; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (ring->dma_pdma) { 16788c2ecf20Sopenharmony_ci dma_free_coherent(eth->dev, 16798c2ecf20Sopenharmony_ci MTK_DMA_SIZE * sizeof(*ring->dma_pdma), 16808c2ecf20Sopenharmony_ci ring->dma_pdma, 16818c2ecf20Sopenharmony_ci ring->phys_pdma); 16828c2ecf20Sopenharmony_ci ring->dma_pdma = NULL; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci struct mtk_rx_ring *ring; 16898c2ecf20Sopenharmony_ci int rx_data_len, rx_dma_size; 16908c2ecf20Sopenharmony_ci int i; 16918c2ecf20Sopenharmony_ci u32 offset = 0; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci if (rx_flag == MTK_RX_FLAGS_QDMA) { 16948c2ecf20Sopenharmony_ci if (ring_no) 16958c2ecf20Sopenharmony_ci return -EINVAL; 16968c2ecf20Sopenharmony_ci ring = ð->rx_ring_qdma; 16978c2ecf20Sopenharmony_ci offset = 0x1000; 16988c2ecf20Sopenharmony_ci } else { 16998c2ecf20Sopenharmony_ci ring = ð->rx_ring[ring_no]; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (rx_flag == MTK_RX_FLAGS_HWLRO) { 17038c2ecf20Sopenharmony_ci rx_data_len = MTK_MAX_LRO_RX_LENGTH; 17048c2ecf20Sopenharmony_ci rx_dma_size = MTK_HW_LRO_DMA_SIZE; 17058c2ecf20Sopenharmony_ci } else { 17068c2ecf20Sopenharmony_ci rx_data_len = ETH_DATA_LEN; 17078c2ecf20Sopenharmony_ci rx_dma_size = MTK_DMA_SIZE; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci ring->frag_size = mtk_max_frag_size(rx_data_len); 17118c2ecf20Sopenharmony_ci ring->buf_size = mtk_max_buf_size(ring->frag_size); 17128c2ecf20Sopenharmony_ci ring->data = kcalloc(rx_dma_size, sizeof(*ring->data), 17138c2ecf20Sopenharmony_ci GFP_KERNEL); 17148c2ecf20Sopenharmony_ci if (!ring->data) 17158c2ecf20Sopenharmony_ci return -ENOMEM; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci for (i = 0; i < rx_dma_size; i++) { 17188c2ecf20Sopenharmony_ci if (ring->frag_size <= PAGE_SIZE) 17198c2ecf20Sopenharmony_ci ring->data[i] = netdev_alloc_frag(ring->frag_size); 17208c2ecf20Sopenharmony_ci else 17218c2ecf20Sopenharmony_ci ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); 17228c2ecf20Sopenharmony_ci if (!ring->data[i]) 17238c2ecf20Sopenharmony_ci return -ENOMEM; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci ring->dma = dma_alloc_coherent(eth->dev, 17278c2ecf20Sopenharmony_ci rx_dma_size * sizeof(*ring->dma), 17288c2ecf20Sopenharmony_ci &ring->phys, GFP_ATOMIC); 17298c2ecf20Sopenharmony_ci if (!ring->dma) 17308c2ecf20Sopenharmony_ci return -ENOMEM; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci for (i = 0; i < rx_dma_size; i++) { 17338c2ecf20Sopenharmony_ci dma_addr_t dma_addr = dma_map_single(eth->dev, 17348c2ecf20Sopenharmony_ci ring->data[i] + NET_SKB_PAD + eth->ip_align, 17358c2ecf20Sopenharmony_ci ring->buf_size, 17368c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 17378c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(eth->dev, dma_addr))) 17388c2ecf20Sopenharmony_ci return -ENOMEM; 17398c2ecf20Sopenharmony_ci ring->dma[i].rxd1 = (unsigned int)dma_addr; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) 17428c2ecf20Sopenharmony_ci ring->dma[i].rxd2 = RX_DMA_LSO; 17438c2ecf20Sopenharmony_ci else 17448c2ecf20Sopenharmony_ci ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size); 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci ring->dma_size = rx_dma_size; 17478c2ecf20Sopenharmony_ci ring->calc_idx_update = false; 17488c2ecf20Sopenharmony_ci ring->calc_idx = rx_dma_size - 1; 17498c2ecf20Sopenharmony_ci ring->crx_idx_reg = MTK_PRX_CRX_IDX_CFG(ring_no); 17508c2ecf20Sopenharmony_ci /* make sure that all changes to the dma ring are flushed before we 17518c2ecf20Sopenharmony_ci * continue 17528c2ecf20Sopenharmony_ci */ 17538c2ecf20Sopenharmony_ci wmb(); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); 17568c2ecf20Sopenharmony_ci mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); 17578c2ecf20Sopenharmony_ci mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); 17588c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return 0; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci int i; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci if (ring->data && ring->dma) { 17688c2ecf20Sopenharmony_ci for (i = 0; i < ring->dma_size; i++) { 17698c2ecf20Sopenharmony_ci if (!ring->data[i]) 17708c2ecf20Sopenharmony_ci continue; 17718c2ecf20Sopenharmony_ci if (!ring->dma[i].rxd1) 17728c2ecf20Sopenharmony_ci continue; 17738c2ecf20Sopenharmony_ci dma_unmap_single(eth->dev, 17748c2ecf20Sopenharmony_ci ring->dma[i].rxd1, 17758c2ecf20Sopenharmony_ci ring->buf_size, 17768c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 17778c2ecf20Sopenharmony_ci skb_free_frag(ring->data[i]); 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci kfree(ring->data); 17808c2ecf20Sopenharmony_ci ring->data = NULL; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (ring->dma) { 17848c2ecf20Sopenharmony_ci dma_free_coherent(eth->dev, 17858c2ecf20Sopenharmony_ci ring->dma_size * sizeof(*ring->dma), 17868c2ecf20Sopenharmony_ci ring->dma, 17878c2ecf20Sopenharmony_ci ring->phys); 17888c2ecf20Sopenharmony_ci ring->dma = NULL; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic int mtk_hwlro_rx_init(struct mtk_eth *eth) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci int i; 17958c2ecf20Sopenharmony_ci u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0; 17968c2ecf20Sopenharmony_ci u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* set LRO rings to auto-learn modes */ 17998c2ecf20Sopenharmony_ci ring_ctrl_dw2 |= MTK_RING_AUTO_LERAN_MODE; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* validate LRO ring */ 18028c2ecf20Sopenharmony_ci ring_ctrl_dw2 |= MTK_RING_VLD; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* set AGE timer (unit: 20us) */ 18058c2ecf20Sopenharmony_ci ring_ctrl_dw2 |= MTK_RING_AGE_TIME_H; 18068c2ecf20Sopenharmony_ci ring_ctrl_dw1 |= MTK_RING_AGE_TIME_L; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* set max AGG timer (unit: 20us) */ 18098c2ecf20Sopenharmony_ci ring_ctrl_dw2 |= MTK_RING_MAX_AGG_TIME; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* set max LRO AGG count */ 18128c2ecf20Sopenharmony_ci ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L; 18138c2ecf20Sopenharmony_ci ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) { 18168c2ecf20Sopenharmony_ci mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i)); 18178c2ecf20Sopenharmony_ci mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i)); 18188c2ecf20Sopenharmony_ci mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i)); 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* IPv4 checksum update enable */ 18228c2ecf20Sopenharmony_ci lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* switch priority comparison to packet count mode */ 18258c2ecf20Sopenharmony_ci lro_ctrl_dw0 |= MTK_LRO_ALT_PKT_CNT_MODE; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* bandwidth threshold setting */ 18288c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci /* auto-learn score delta setting */ 18318c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_PDMA_LRO_ALT_SCORE_DELTA); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci /* set refresh timer for altering flows to 1 sec. (unit: 20us) */ 18348c2ecf20Sopenharmony_ci mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME, 18358c2ecf20Sopenharmony_ci MTK_PDMA_LRO_ALT_REFRESH_TIMER); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci /* set HW LRO mode & the max aggregation count for rx packets */ 18388c2ecf20Sopenharmony_ci lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci /* the minimal remaining room of SDL0 in RXD for lro aggregation */ 18418c2ecf20Sopenharmony_ci lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci /* enable HW LRO */ 18448c2ecf20Sopenharmony_ci lro_ctrl_dw0 |= MTK_LRO_EN; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3); 18478c2ecf20Sopenharmony_ci mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci return 0; 18508c2ecf20Sopenharmony_ci} 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_cistatic void mtk_hwlro_rx_uninit(struct mtk_eth *eth) 18538c2ecf20Sopenharmony_ci{ 18548c2ecf20Sopenharmony_ci int i; 18558c2ecf20Sopenharmony_ci u32 val; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci /* relinquish lro rings, flush aggregated packets */ 18588c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_LRO_RING_RELINQUISH_REQ, MTK_PDMA_LRO_CTRL_DW0); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci /* wait for relinquishments done */ 18618c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 18628c2ecf20Sopenharmony_ci val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0); 18638c2ecf20Sopenharmony_ci if (val & MTK_LRO_RING_RELINQUISH_DONE) { 18648c2ecf20Sopenharmony_ci msleep(20); 18658c2ecf20Sopenharmony_ci continue; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci break; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* invalidate lro rings */ 18718c2ecf20Sopenharmony_ci for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) 18728c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i)); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci /* disable HW LRO */ 18758c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0); 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci u32 reg_val; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx)); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* invalidate the IP setting */ 18858c2ecf20Sopenharmony_ci mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx)); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx)); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* validate the IP setting */ 18908c2ecf20Sopenharmony_ci mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx)); 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci u32 reg_val; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx)); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci /* invalidate the IP setting */ 19008c2ecf20Sopenharmony_ci mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx)); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx)); 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_cistatic int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci int cnt = 0; 19088c2ecf20Sopenharmony_ci int i; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) { 19118c2ecf20Sopenharmony_ci if (mac->hwlro_ip[i]) 19128c2ecf20Sopenharmony_ci cnt++; 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci return cnt; 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic int mtk_hwlro_add_ipaddr(struct net_device *dev, 19198c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 19228c2ecf20Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 19238c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 19248c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 19258c2ecf20Sopenharmony_ci int hwlro_idx; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if ((fsp->flow_type != TCP_V4_FLOW) || 19288c2ecf20Sopenharmony_ci (!fsp->h_u.tcp_ip4_spec.ip4dst) || 19298c2ecf20Sopenharmony_ci (fsp->location > 1)) 19308c2ecf20Sopenharmony_ci return -EINVAL; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst); 19338c2ecf20Sopenharmony_ci hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci return 0; 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic int mtk_hwlro_del_ipaddr(struct net_device *dev, 19438c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 19468c2ecf20Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 19478c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 19488c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 19498c2ecf20Sopenharmony_ci int hwlro_idx; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (fsp->location > 1) 19528c2ecf20Sopenharmony_ci return -EINVAL; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci mac->hwlro_ip[fsp->location] = 0; 19558c2ecf20Sopenharmony_ci hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci mtk_hwlro_inval_ipaddr(eth, hwlro_idx); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci return 0; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic void mtk_hwlro_netdev_disable(struct net_device *dev) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 19678c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 19688c2ecf20Sopenharmony_ci int i, hwlro_idx; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) { 19718c2ecf20Sopenharmony_ci mac->hwlro_ip[i] = 0; 19728c2ecf20Sopenharmony_ci hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci mtk_hwlro_inval_ipaddr(eth, hwlro_idx); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci mac->hwlro_ip_cnt = 0; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int mtk_hwlro_get_fdir_entry(struct net_device *dev, 19818c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 19848c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fsp = 19858c2ecf20Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if (fsp->location >= ARRAY_SIZE(mac->hwlro_ip)) 19888c2ecf20Sopenharmony_ci return -EINVAL; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* only tcp dst ipv4 is meaningful, others are meaningless */ 19918c2ecf20Sopenharmony_ci fsp->flow_type = TCP_V4_FLOW; 19928c2ecf20Sopenharmony_ci fsp->h_u.tcp_ip4_spec.ip4dst = ntohl(mac->hwlro_ip[fsp->location]); 19938c2ecf20Sopenharmony_ci fsp->m_u.tcp_ip4_spec.ip4dst = 0; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci fsp->h_u.tcp_ip4_spec.ip4src = 0; 19968c2ecf20Sopenharmony_ci fsp->m_u.tcp_ip4_spec.ip4src = 0xffffffff; 19978c2ecf20Sopenharmony_ci fsp->h_u.tcp_ip4_spec.psrc = 0; 19988c2ecf20Sopenharmony_ci fsp->m_u.tcp_ip4_spec.psrc = 0xffff; 19998c2ecf20Sopenharmony_ci fsp->h_u.tcp_ip4_spec.pdst = 0; 20008c2ecf20Sopenharmony_ci fsp->m_u.tcp_ip4_spec.pdst = 0xffff; 20018c2ecf20Sopenharmony_ci fsp->h_u.tcp_ip4_spec.tos = 0; 20028c2ecf20Sopenharmony_ci fsp->m_u.tcp_ip4_spec.tos = 0xff; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci return 0; 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cistatic int mtk_hwlro_get_fdir_all(struct net_device *dev, 20088c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 20098c2ecf20Sopenharmony_ci u32 *rule_locs) 20108c2ecf20Sopenharmony_ci{ 20118c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 20128c2ecf20Sopenharmony_ci int cnt = 0; 20138c2ecf20Sopenharmony_ci int i; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) { 20168c2ecf20Sopenharmony_ci if (cnt == cmd->rule_cnt) 20178c2ecf20Sopenharmony_ci return -EMSGSIZE; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci if (mac->hwlro_ip[i]) { 20208c2ecf20Sopenharmony_ci rule_locs[cnt] = i; 20218c2ecf20Sopenharmony_ci cnt++; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci cmd->rule_cnt = cnt; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci return 0; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_cistatic netdev_features_t mtk_fix_features(struct net_device *dev, 20318c2ecf20Sopenharmony_ci netdev_features_t features) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci if (!(features & NETIF_F_LRO)) { 20348c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 20358c2ecf20Sopenharmony_ci int ip_cnt = mtk_hwlro_get_ip_cnt(mac); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (ip_cnt) { 20388c2ecf20Sopenharmony_ci netdev_info(dev, "RX flow is programmed, LRO should keep on\n"); 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci features |= NETIF_F_LRO; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci return features; 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic int mtk_set_features(struct net_device *dev, netdev_features_t features) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci int err = 0; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (!((dev->features ^ features) & NETIF_F_LRO)) 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci if (!(features & NETIF_F_LRO)) 20558c2ecf20Sopenharmony_ci mtk_hwlro_netdev_disable(dev); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci return err; 20588c2ecf20Sopenharmony_ci} 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci/* wait for DMA to finish whatever it is doing before we start using it again */ 20618c2ecf20Sopenharmony_cistatic int mtk_dma_busy_wait(struct mtk_eth *eth) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci unsigned long t_start = jiffies; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci while (1) { 20668c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 20678c2ecf20Sopenharmony_ci if (!(mtk_r32(eth, MTK_QDMA_GLO_CFG) & 20688c2ecf20Sopenharmony_ci (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY))) 20698c2ecf20Sopenharmony_ci return 0; 20708c2ecf20Sopenharmony_ci } else { 20718c2ecf20Sopenharmony_ci if (!(mtk_r32(eth, MTK_PDMA_GLO_CFG) & 20728c2ecf20Sopenharmony_ci (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY))) 20738c2ecf20Sopenharmony_ci return 0; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if (time_after(jiffies, t_start + MTK_DMA_BUSY_TIMEOUT)) 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci dev_err(eth->dev, "DMA init timeout\n"); 20818c2ecf20Sopenharmony_ci return -1; 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic int mtk_dma_init(struct mtk_eth *eth) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci int err; 20878c2ecf20Sopenharmony_ci u32 i; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (mtk_dma_busy_wait(eth)) 20908c2ecf20Sopenharmony_ci return -EBUSY; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 20938c2ecf20Sopenharmony_ci /* QDMA needs scratch memory for internal reordering of the 20948c2ecf20Sopenharmony_ci * descriptors 20958c2ecf20Sopenharmony_ci */ 20968c2ecf20Sopenharmony_ci err = mtk_init_fq_dma(eth); 20978c2ecf20Sopenharmony_ci if (err) 20988c2ecf20Sopenharmony_ci return err; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci err = mtk_tx_alloc(eth); 21028c2ecf20Sopenharmony_ci if (err) 21038c2ecf20Sopenharmony_ci return err; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 21068c2ecf20Sopenharmony_ci err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA); 21078c2ecf20Sopenharmony_ci if (err) 21088c2ecf20Sopenharmony_ci return err; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_NORMAL); 21128c2ecf20Sopenharmony_ci if (err) 21138c2ecf20Sopenharmony_ci return err; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (eth->hwlro) { 21168c2ecf20Sopenharmony_ci for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) { 21178c2ecf20Sopenharmony_ci err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO); 21188c2ecf20Sopenharmony_ci if (err) 21198c2ecf20Sopenharmony_ci return err; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci err = mtk_hwlro_rx_init(eth); 21228c2ecf20Sopenharmony_ci if (err) 21238c2ecf20Sopenharmony_ci return err; 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 21278c2ecf20Sopenharmony_ci /* Enable random early drop and set drop threshold 21288c2ecf20Sopenharmony_ci * automatically 21298c2ecf20Sopenharmony_ci */ 21308c2ecf20Sopenharmony_ci mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | 21318c2ecf20Sopenharmony_ci FC_THRES_MIN, MTK_QDMA_FC_THRES); 21328c2ecf20Sopenharmony_ci mtk_w32(eth, 0x0, MTK_QDMA_HRED2); 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci return 0; 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_cistatic void mtk_dma_free(struct mtk_eth *eth) 21398c2ecf20Sopenharmony_ci{ 21408c2ecf20Sopenharmony_ci int i; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) 21438c2ecf20Sopenharmony_ci if (eth->netdev[i]) 21448c2ecf20Sopenharmony_ci netdev_reset_queue(eth->netdev[i]); 21458c2ecf20Sopenharmony_ci if (eth->scratch_ring) { 21468c2ecf20Sopenharmony_ci dma_free_coherent(eth->dev, 21478c2ecf20Sopenharmony_ci MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), 21488c2ecf20Sopenharmony_ci eth->scratch_ring, 21498c2ecf20Sopenharmony_ci eth->phy_scratch_ring); 21508c2ecf20Sopenharmony_ci eth->scratch_ring = NULL; 21518c2ecf20Sopenharmony_ci eth->phy_scratch_ring = 0; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci mtk_tx_clean(eth); 21548c2ecf20Sopenharmony_ci mtk_rx_clean(eth, ð->rx_ring[0]); 21558c2ecf20Sopenharmony_ci mtk_rx_clean(eth, ð->rx_ring_qdma); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (eth->hwlro) { 21588c2ecf20Sopenharmony_ci mtk_hwlro_rx_uninit(eth); 21598c2ecf20Sopenharmony_ci for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) 21608c2ecf20Sopenharmony_ci mtk_rx_clean(eth, ð->rx_ring[i]); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci kfree(eth->scratch_head); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue) 21678c2ecf20Sopenharmony_ci{ 21688c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 21698c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci eth->netdev[mac->id]->stats.tx_errors++; 21728c2ecf20Sopenharmony_ci netif_err(eth, tx_err, dev, 21738c2ecf20Sopenharmony_ci "transmit timed out\n"); 21748c2ecf20Sopenharmony_ci schedule_work(ð->pending_work); 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_cistatic irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci struct mtk_eth *eth = _eth; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (likely(napi_schedule_prep(ð->rx_napi))) { 21828c2ecf20Sopenharmony_ci __napi_schedule(ð->rx_napi); 21838c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); 21848c2ecf20Sopenharmony_ci } 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci return IRQ_HANDLED; 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic irqreturn_t mtk_handle_irq_tx(int irq, void *_eth) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci struct mtk_eth *eth = _eth; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (likely(napi_schedule_prep(ð->tx_napi))) { 21948c2ecf20Sopenharmony_ci __napi_schedule(ð->tx_napi); 21958c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic irqreturn_t mtk_handle_irq(int irq, void *_eth) 22028c2ecf20Sopenharmony_ci{ 22038c2ecf20Sopenharmony_ci struct mtk_eth *eth = _eth; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (mtk_r32(eth, MTK_PDMA_INT_MASK) & MTK_RX_DONE_INT) { 22068c2ecf20Sopenharmony_ci if (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT) 22078c2ecf20Sopenharmony_ci mtk_handle_irq_rx(irq, _eth); 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci if (mtk_r32(eth, eth->tx_int_mask_reg) & MTK_TX_DONE_INT) { 22108c2ecf20Sopenharmony_ci if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT) 22118c2ecf20Sopenharmony_ci mtk_handle_irq_tx(irq, _eth); 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22158c2ecf20Sopenharmony_ci} 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 22188c2ecf20Sopenharmony_cistatic void mtk_poll_controller(struct net_device *dev) 22198c2ecf20Sopenharmony_ci{ 22208c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 22218c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); 22248c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); 22258c2ecf20Sopenharmony_ci mtk_handle_irq_rx(eth->irq[2], dev); 22268c2ecf20Sopenharmony_ci mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); 22278c2ecf20Sopenharmony_ci mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci#endif 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_cistatic int mtk_start_dma(struct mtk_eth *eth) 22328c2ecf20Sopenharmony_ci{ 22338c2ecf20Sopenharmony_ci u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; 22348c2ecf20Sopenharmony_ci int err; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci err = mtk_dma_init(eth); 22378c2ecf20Sopenharmony_ci if (err) { 22388c2ecf20Sopenharmony_ci mtk_dma_free(eth); 22398c2ecf20Sopenharmony_ci return err; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 22438c2ecf20Sopenharmony_ci mtk_w32(eth, 22448c2ecf20Sopenharmony_ci MTK_TX_WB_DDONE | MTK_TX_DMA_EN | 22458c2ecf20Sopenharmony_ci MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO | 22468c2ecf20Sopenharmony_ci MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | 22478c2ecf20Sopenharmony_ci MTK_RX_BT_32DWORDS, 22488c2ecf20Sopenharmony_ci MTK_QDMA_GLO_CFG); 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci mtk_w32(eth, 22518c2ecf20Sopenharmony_ci MTK_RX_DMA_EN | rx_2b_offset | 22528c2ecf20Sopenharmony_ci MTK_RX_BT_32DWORDS | MTK_MULTI_EN, 22538c2ecf20Sopenharmony_ci MTK_PDMA_GLO_CFG); 22548c2ecf20Sopenharmony_ci } else { 22558c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN | 22568c2ecf20Sopenharmony_ci MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS, 22578c2ecf20Sopenharmony_ci MTK_PDMA_GLO_CFG); 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci return 0; 22618c2ecf20Sopenharmony_ci} 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_cistatic void mtk_gdm_config(struct mtk_eth *eth, u32 config) 22648c2ecf20Sopenharmony_ci{ 22658c2ecf20Sopenharmony_ci int i; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) 22688c2ecf20Sopenharmony_ci return; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 22718c2ecf20Sopenharmony_ci u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci /* default setup the forward port to send frame to PDMA */ 22748c2ecf20Sopenharmony_ci val &= ~0xffff; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci /* Enable RX checksum */ 22778c2ecf20Sopenharmony_ci val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci val |= config; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci /* Reset and enable PSE */ 22848c2ecf20Sopenharmony_ci mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); 22858c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MTK_RST_GL); 22868c2ecf20Sopenharmony_ci} 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_cistatic int mtk_open(struct net_device *dev) 22898c2ecf20Sopenharmony_ci{ 22908c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 22918c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 22928c2ecf20Sopenharmony_ci int err; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); 22958c2ecf20Sopenharmony_ci if (err) { 22968c2ecf20Sopenharmony_ci netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, 22978c2ecf20Sopenharmony_ci err); 22988c2ecf20Sopenharmony_ci return err; 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci /* we run 2 netdevs on the same dma ring so we only bring it up once */ 23028c2ecf20Sopenharmony_ci if (!refcount_read(ð->dma_refcnt)) { 23038c2ecf20Sopenharmony_ci int err = mtk_start_dma(eth); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (err) { 23068c2ecf20Sopenharmony_ci phylink_disconnect_phy(mac->phylink); 23078c2ecf20Sopenharmony_ci return err; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci napi_enable(ð->tx_napi); 23138c2ecf20Sopenharmony_ci napi_enable(ð->rx_napi); 23148c2ecf20Sopenharmony_ci mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); 23158c2ecf20Sopenharmony_ci mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); 23168c2ecf20Sopenharmony_ci refcount_set(ð->dma_refcnt, 1); 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci else 23198c2ecf20Sopenharmony_ci refcount_inc(ð->dma_refcnt); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci phylink_start(mac->phylink); 23228c2ecf20Sopenharmony_ci netif_start_queue(dev); 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg) 23278c2ecf20Sopenharmony_ci{ 23288c2ecf20Sopenharmony_ci u32 val; 23298c2ecf20Sopenharmony_ci int i; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci /* stop the dma engine */ 23328c2ecf20Sopenharmony_ci spin_lock_bh(ð->page_lock); 23338c2ecf20Sopenharmony_ci val = mtk_r32(eth, glo_cfg); 23348c2ecf20Sopenharmony_ci mtk_w32(eth, val & ~(MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN), 23358c2ecf20Sopenharmony_ci glo_cfg); 23368c2ecf20Sopenharmony_ci spin_unlock_bh(ð->page_lock); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci /* wait for dma stop */ 23398c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 23408c2ecf20Sopenharmony_ci val = mtk_r32(eth, glo_cfg); 23418c2ecf20Sopenharmony_ci if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) { 23428c2ecf20Sopenharmony_ci msleep(20); 23438c2ecf20Sopenharmony_ci continue; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci break; 23468c2ecf20Sopenharmony_ci } 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic int mtk_stop(struct net_device *dev) 23508c2ecf20Sopenharmony_ci{ 23518c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 23528c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci phylink_stop(mac->phylink); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci netif_tx_disable(dev); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci phylink_disconnect_phy(mac->phylink); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci /* only shutdown DMA if this is the last user */ 23618c2ecf20Sopenharmony_ci if (!refcount_dec_and_test(ð->dma_refcnt)) 23628c2ecf20Sopenharmony_ci return 0; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); 23678c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); 23688c2ecf20Sopenharmony_ci napi_disable(ð->tx_napi); 23698c2ecf20Sopenharmony_ci napi_disable(ð->rx_napi); 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) 23728c2ecf20Sopenharmony_ci mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); 23738c2ecf20Sopenharmony_ci mtk_stop_dma(eth, MTK_PDMA_GLO_CFG); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci mtk_dma_free(eth); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci return 0; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_cistatic void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) 23818c2ecf20Sopenharmony_ci{ 23828c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, 23838c2ecf20Sopenharmony_ci reset_bits, 23848c2ecf20Sopenharmony_ci reset_bits); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 23878c2ecf20Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, 23888c2ecf20Sopenharmony_ci reset_bits, 23898c2ecf20Sopenharmony_ci ~reset_bits); 23908c2ecf20Sopenharmony_ci mdelay(10); 23918c2ecf20Sopenharmony_ci} 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_cistatic void mtk_clk_disable(struct mtk_eth *eth) 23948c2ecf20Sopenharmony_ci{ 23958c2ecf20Sopenharmony_ci int clk; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci for (clk = MTK_CLK_MAX - 1; clk >= 0; clk--) 23988c2ecf20Sopenharmony_ci clk_disable_unprepare(eth->clks[clk]); 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cistatic int mtk_clk_enable(struct mtk_eth *eth) 24028c2ecf20Sopenharmony_ci{ 24038c2ecf20Sopenharmony_ci int clk, ret; 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci for (clk = 0; clk < MTK_CLK_MAX ; clk++) { 24068c2ecf20Sopenharmony_ci ret = clk_prepare_enable(eth->clks[clk]); 24078c2ecf20Sopenharmony_ci if (ret) 24088c2ecf20Sopenharmony_ci goto err_disable_clks; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci return 0; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_cierr_disable_clks: 24148c2ecf20Sopenharmony_ci while (--clk >= 0) 24158c2ecf20Sopenharmony_ci clk_disable_unprepare(eth->clks[clk]); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return ret; 24188c2ecf20Sopenharmony_ci} 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_cistatic int mtk_hw_init(struct mtk_eth *eth) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci int i, val, ret; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (test_and_set_bit(MTK_HW_INIT, ð->state)) 24258c2ecf20Sopenharmony_ci return 0; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci pm_runtime_enable(eth->dev); 24288c2ecf20Sopenharmony_ci pm_runtime_get_sync(eth->dev); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci ret = mtk_clk_enable(eth); 24318c2ecf20Sopenharmony_ci if (ret) 24328c2ecf20Sopenharmony_ci goto err_disable_pm; 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 24358c2ecf20Sopenharmony_ci ret = device_reset(eth->dev); 24368c2ecf20Sopenharmony_ci if (ret) { 24378c2ecf20Sopenharmony_ci dev_err(eth->dev, "MAC reset failed!\n"); 24388c2ecf20Sopenharmony_ci goto err_disable_pm; 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci /* enable interrupt delay for RX */ 24428c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci /* disable delay and normal interrupt */ 24458c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, ~0); 24468c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, ~0); 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci return 0; 24498c2ecf20Sopenharmony_ci } 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci /* Non-MT7628 handling... */ 24528c2ecf20Sopenharmony_ci ethsys_reset(eth, RSTCTRL_FE); 24538c2ecf20Sopenharmony_ci ethsys_reset(eth, RSTCTRL_PPE); 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci if (eth->pctl) { 24568c2ecf20Sopenharmony_ci /* Set GE2 driving and slew rate */ 24578c2ecf20Sopenharmony_ci regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci /* set GE2 TDSEL */ 24608c2ecf20Sopenharmony_ci regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5); 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci /* set GE2 TUNE */ 24638c2ecf20Sopenharmony_ci regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0); 24648c2ecf20Sopenharmony_ci } 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci /* Set linkdown as the default for each GMAC. Its own MCR would be set 24678c2ecf20Sopenharmony_ci * up with the more appropriate value when mtk_mac_config call is being 24688c2ecf20Sopenharmony_ci * invoked. 24698c2ecf20Sopenharmony_ci */ 24708c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) 24718c2ecf20Sopenharmony_ci mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i)); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci /* Indicates CDM to parse the MTK special tag from CPU 24748c2ecf20Sopenharmony_ci * which also is working out for untag packets. 24758c2ecf20Sopenharmony_ci */ 24768c2ecf20Sopenharmony_ci val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); 24778c2ecf20Sopenharmony_ci mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci /* Enable RX VLan Offloading */ 24808c2ecf20Sopenharmony_ci mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci /* enable interrupt delay for RX */ 24838c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci /* disable delay and normal interrupt */ 24868c2ecf20Sopenharmony_ci mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); 24878c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, ~0); 24888c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, ~0); 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci /* FE int grouping */ 24918c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); 24928c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); 24938c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); 24948c2ecf20Sopenharmony_ci mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); 24958c2ecf20Sopenharmony_ci mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci return 0; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_cierr_disable_pm: 25008c2ecf20Sopenharmony_ci pm_runtime_put_sync(eth->dev); 25018c2ecf20Sopenharmony_ci pm_runtime_disable(eth->dev); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci return ret; 25048c2ecf20Sopenharmony_ci} 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_cistatic int mtk_hw_deinit(struct mtk_eth *eth) 25078c2ecf20Sopenharmony_ci{ 25088c2ecf20Sopenharmony_ci if (!test_and_clear_bit(MTK_HW_INIT, ð->state)) 25098c2ecf20Sopenharmony_ci return 0; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci mtk_clk_disable(eth); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci pm_runtime_put_sync(eth->dev); 25148c2ecf20Sopenharmony_ci pm_runtime_disable(eth->dev); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci return 0; 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_cistatic int __init mtk_init(struct net_device *dev) 25208c2ecf20Sopenharmony_ci{ 25218c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 25228c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 25238c2ecf20Sopenharmony_ci const char *mac_addr; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci mac_addr = of_get_mac_address(mac->of_node); 25268c2ecf20Sopenharmony_ci if (!IS_ERR(mac_addr)) 25278c2ecf20Sopenharmony_ci ether_addr_copy(dev->dev_addr, mac_addr); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci /* If the mac address is invalid, use random mac address */ 25308c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 25318c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 25328c2ecf20Sopenharmony_ci dev_err(eth->dev, "generated random MAC address %pM\n", 25338c2ecf20Sopenharmony_ci dev->dev_addr); 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci return 0; 25378c2ecf20Sopenharmony_ci} 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_cistatic void mtk_uninit(struct net_device *dev) 25408c2ecf20Sopenharmony_ci{ 25418c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 25428c2ecf20Sopenharmony_ci struct mtk_eth *eth = mac->hw; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci phylink_disconnect_phy(mac->phylink); 25458c2ecf20Sopenharmony_ci mtk_tx_irq_disable(eth, ~0); 25468c2ecf20Sopenharmony_ci mtk_rx_irq_disable(eth, ~0); 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_cistatic int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci switch (cmd) { 25548c2ecf20Sopenharmony_ci case SIOCGMIIPHY: 25558c2ecf20Sopenharmony_ci case SIOCGMIIREG: 25568c2ecf20Sopenharmony_ci case SIOCSMIIREG: 25578c2ecf20Sopenharmony_ci return phylink_mii_ioctl(mac->phylink, ifr, cmd); 25588c2ecf20Sopenharmony_ci default: 25598c2ecf20Sopenharmony_ci break; 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25638c2ecf20Sopenharmony_ci} 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_cistatic void mtk_pending_work(struct work_struct *work) 25668c2ecf20Sopenharmony_ci{ 25678c2ecf20Sopenharmony_ci struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work); 25688c2ecf20Sopenharmony_ci int err, i; 25698c2ecf20Sopenharmony_ci unsigned long restart = 0; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci rtnl_lock(); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci while (test_and_set_bit_lock(MTK_RESETTING, ð->state)) 25768c2ecf20Sopenharmony_ci cpu_relax(); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci dev_dbg(eth->dev, "[%s][%d] mtk_stop starts\n", __func__, __LINE__); 25798c2ecf20Sopenharmony_ci /* stop all devices to make sure that dma is properly shut down */ 25808c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 25818c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 25828c2ecf20Sopenharmony_ci continue; 25838c2ecf20Sopenharmony_ci mtk_stop(eth->netdev[i]); 25848c2ecf20Sopenharmony_ci __set_bit(i, &restart); 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci dev_dbg(eth->dev, "[%s][%d] mtk_stop ends\n", __func__, __LINE__); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci /* restart underlying hardware such as power, clock, pin mux 25898c2ecf20Sopenharmony_ci * and the connected phy 25908c2ecf20Sopenharmony_ci */ 25918c2ecf20Sopenharmony_ci mtk_hw_deinit(eth); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci if (eth->dev->pins) 25948c2ecf20Sopenharmony_ci pinctrl_select_state(eth->dev->pins->p, 25958c2ecf20Sopenharmony_ci eth->dev->pins->default_state); 25968c2ecf20Sopenharmony_ci mtk_hw_init(eth); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci /* restart DMA and enable IRQs */ 25998c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 26008c2ecf20Sopenharmony_ci if (!test_bit(i, &restart)) 26018c2ecf20Sopenharmony_ci continue; 26028c2ecf20Sopenharmony_ci err = mtk_open(eth->netdev[i]); 26038c2ecf20Sopenharmony_ci if (err) { 26048c2ecf20Sopenharmony_ci netif_alert(eth, ifup, eth->netdev[i], 26058c2ecf20Sopenharmony_ci "Driver up/down cycle failed, closing device.\n"); 26068c2ecf20Sopenharmony_ci dev_close(eth->netdev[i]); 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci clear_bit_unlock(MTK_RESETTING, ð->state); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci rtnl_unlock(); 26158c2ecf20Sopenharmony_ci} 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_cistatic int mtk_free_dev(struct mtk_eth *eth) 26188c2ecf20Sopenharmony_ci{ 26198c2ecf20Sopenharmony_ci int i; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 26228c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 26238c2ecf20Sopenharmony_ci continue; 26248c2ecf20Sopenharmony_ci free_netdev(eth->netdev[i]); 26258c2ecf20Sopenharmony_ci } 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci return 0; 26288c2ecf20Sopenharmony_ci} 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_cistatic int mtk_unreg_dev(struct mtk_eth *eth) 26318c2ecf20Sopenharmony_ci{ 26328c2ecf20Sopenharmony_ci int i; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 26358c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 26368c2ecf20Sopenharmony_ci continue; 26378c2ecf20Sopenharmony_ci unregister_netdev(eth->netdev[i]); 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci return 0; 26418c2ecf20Sopenharmony_ci} 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_cistatic int mtk_cleanup(struct mtk_eth *eth) 26448c2ecf20Sopenharmony_ci{ 26458c2ecf20Sopenharmony_ci mtk_unreg_dev(eth); 26468c2ecf20Sopenharmony_ci mtk_free_dev(eth); 26478c2ecf20Sopenharmony_ci cancel_work_sync(ð->pending_work); 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci return 0; 26508c2ecf20Sopenharmony_ci} 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_cistatic int mtk_get_link_ksettings(struct net_device *ndev, 26538c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 26548c2ecf20Sopenharmony_ci{ 26558c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(ndev); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) 26588c2ecf20Sopenharmony_ci return -EBUSY; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_get(mac->phylink, cmd); 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cistatic int mtk_set_link_ksettings(struct net_device *ndev, 26648c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(ndev); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) 26698c2ecf20Sopenharmony_ci return -EBUSY; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci return phylink_ethtool_ksettings_set(mac->phylink, cmd); 26728c2ecf20Sopenharmony_ci} 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_cistatic void mtk_get_drvinfo(struct net_device *dev, 26758c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 26768c2ecf20Sopenharmony_ci{ 26778c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver)); 26808c2ecf20Sopenharmony_ci strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info)); 26818c2ecf20Sopenharmony_ci info->n_stats = ARRAY_SIZE(mtk_ethtool_stats); 26828c2ecf20Sopenharmony_ci} 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_cistatic u32 mtk_get_msglevel(struct net_device *dev) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci return mac->hw->msg_enable; 26898c2ecf20Sopenharmony_ci} 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cistatic void mtk_set_msglevel(struct net_device *dev, u32 value) 26928c2ecf20Sopenharmony_ci{ 26938c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci mac->hw->msg_enable = value; 26968c2ecf20Sopenharmony_ci} 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_cistatic int mtk_nway_reset(struct net_device *dev) 26998c2ecf20Sopenharmony_ci{ 27008c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) 27038c2ecf20Sopenharmony_ci return -EBUSY; 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci if (!mac->phylink) 27068c2ecf20Sopenharmony_ci return -ENOTSUPP; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return phylink_ethtool_nway_reset(mac->phylink); 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) 27128c2ecf20Sopenharmony_ci{ 27138c2ecf20Sopenharmony_ci int i; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci switch (stringset) { 27168c2ecf20Sopenharmony_ci case ETH_SS_STATS: 27178c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { 27188c2ecf20Sopenharmony_ci memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); 27198c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci break; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_cistatic int mtk_get_sset_count(struct net_device *dev, int sset) 27268c2ecf20Sopenharmony_ci{ 27278c2ecf20Sopenharmony_ci switch (sset) { 27288c2ecf20Sopenharmony_ci case ETH_SS_STATS: 27298c2ecf20Sopenharmony_ci return ARRAY_SIZE(mtk_ethtool_stats); 27308c2ecf20Sopenharmony_ci default: 27318c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic void mtk_get_ethtool_stats(struct net_device *dev, 27368c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 27378c2ecf20Sopenharmony_ci{ 27388c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 27398c2ecf20Sopenharmony_ci struct mtk_hw_stats *hwstats = mac->hw_stats; 27408c2ecf20Sopenharmony_ci u64 *data_src, *data_dst; 27418c2ecf20Sopenharmony_ci unsigned int start; 27428c2ecf20Sopenharmony_ci int i; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) 27458c2ecf20Sopenharmony_ci return; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci if (netif_running(dev) && netif_device_present(dev)) { 27488c2ecf20Sopenharmony_ci if (spin_trylock_bh(&hwstats->stats_lock)) { 27498c2ecf20Sopenharmony_ci mtk_stats_update_mac(mac); 27508c2ecf20Sopenharmony_ci spin_unlock_bh(&hwstats->stats_lock); 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci data_src = (u64 *)hwstats; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci do { 27578c2ecf20Sopenharmony_ci data_dst = data; 27588c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&hwstats->syncp); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) 27618c2ecf20Sopenharmony_ci *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); 27628c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); 27638c2ecf20Sopenharmony_ci} 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_cistatic int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 27668c2ecf20Sopenharmony_ci u32 *rule_locs) 27678c2ecf20Sopenharmony_ci{ 27688c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci switch (cmd->cmd) { 27718c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 27728c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) { 27738c2ecf20Sopenharmony_ci cmd->data = MTK_MAX_RX_RING_NUM; 27748c2ecf20Sopenharmony_ci ret = 0; 27758c2ecf20Sopenharmony_ci } 27768c2ecf20Sopenharmony_ci break; 27778c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 27788c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) { 27798c2ecf20Sopenharmony_ci struct mtk_mac *mac = netdev_priv(dev); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci cmd->rule_cnt = mac->hwlro_ip_cnt; 27828c2ecf20Sopenharmony_ci ret = 0; 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci break; 27858c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 27868c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) 27878c2ecf20Sopenharmony_ci ret = mtk_hwlro_get_fdir_entry(dev, cmd); 27888c2ecf20Sopenharmony_ci break; 27898c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 27908c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) 27918c2ecf20Sopenharmony_ci ret = mtk_hwlro_get_fdir_all(dev, cmd, 27928c2ecf20Sopenharmony_ci rule_locs); 27938c2ecf20Sopenharmony_ci break; 27948c2ecf20Sopenharmony_ci default: 27958c2ecf20Sopenharmony_ci break; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci return ret; 27998c2ecf20Sopenharmony_ci} 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_cistatic int mtk_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 28028c2ecf20Sopenharmony_ci{ 28038c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci switch (cmd->cmd) { 28068c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 28078c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) 28088c2ecf20Sopenharmony_ci ret = mtk_hwlro_add_ipaddr(dev, cmd); 28098c2ecf20Sopenharmony_ci break; 28108c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 28118c2ecf20Sopenharmony_ci if (dev->hw_features & NETIF_F_LRO) 28128c2ecf20Sopenharmony_ci ret = mtk_hwlro_del_ipaddr(dev, cmd); 28138c2ecf20Sopenharmony_ci break; 28148c2ecf20Sopenharmony_ci default: 28158c2ecf20Sopenharmony_ci break; 28168c2ecf20Sopenharmony_ci } 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci return ret; 28198c2ecf20Sopenharmony_ci} 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_cistatic const struct ethtool_ops mtk_ethtool_ops = { 28228c2ecf20Sopenharmony_ci .get_link_ksettings = mtk_get_link_ksettings, 28238c2ecf20Sopenharmony_ci .set_link_ksettings = mtk_set_link_ksettings, 28248c2ecf20Sopenharmony_ci .get_drvinfo = mtk_get_drvinfo, 28258c2ecf20Sopenharmony_ci .get_msglevel = mtk_get_msglevel, 28268c2ecf20Sopenharmony_ci .set_msglevel = mtk_set_msglevel, 28278c2ecf20Sopenharmony_ci .nway_reset = mtk_nway_reset, 28288c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 28298c2ecf20Sopenharmony_ci .get_strings = mtk_get_strings, 28308c2ecf20Sopenharmony_ci .get_sset_count = mtk_get_sset_count, 28318c2ecf20Sopenharmony_ci .get_ethtool_stats = mtk_get_ethtool_stats, 28328c2ecf20Sopenharmony_ci .get_rxnfc = mtk_get_rxnfc, 28338c2ecf20Sopenharmony_ci .set_rxnfc = mtk_set_rxnfc, 28348c2ecf20Sopenharmony_ci}; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_cistatic const struct net_device_ops mtk_netdev_ops = { 28378c2ecf20Sopenharmony_ci .ndo_init = mtk_init, 28388c2ecf20Sopenharmony_ci .ndo_uninit = mtk_uninit, 28398c2ecf20Sopenharmony_ci .ndo_open = mtk_open, 28408c2ecf20Sopenharmony_ci .ndo_stop = mtk_stop, 28418c2ecf20Sopenharmony_ci .ndo_start_xmit = mtk_start_xmit, 28428c2ecf20Sopenharmony_ci .ndo_set_mac_address = mtk_set_mac_address, 28438c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 28448c2ecf20Sopenharmony_ci .ndo_do_ioctl = mtk_do_ioctl, 28458c2ecf20Sopenharmony_ci .ndo_tx_timeout = mtk_tx_timeout, 28468c2ecf20Sopenharmony_ci .ndo_get_stats64 = mtk_get_stats64, 28478c2ecf20Sopenharmony_ci .ndo_fix_features = mtk_fix_features, 28488c2ecf20Sopenharmony_ci .ndo_set_features = mtk_set_features, 28498c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 28508c2ecf20Sopenharmony_ci .ndo_poll_controller = mtk_poll_controller, 28518c2ecf20Sopenharmony_ci#endif 28528c2ecf20Sopenharmony_ci}; 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cistatic int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) 28558c2ecf20Sopenharmony_ci{ 28568c2ecf20Sopenharmony_ci const __be32 *_id = of_get_property(np, "reg", NULL); 28578c2ecf20Sopenharmony_ci phy_interface_t phy_mode; 28588c2ecf20Sopenharmony_ci struct phylink *phylink; 28598c2ecf20Sopenharmony_ci struct mtk_mac *mac; 28608c2ecf20Sopenharmony_ci int id, err; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci if (!_id) { 28638c2ecf20Sopenharmony_ci dev_err(eth->dev, "missing mac id\n"); 28648c2ecf20Sopenharmony_ci return -EINVAL; 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci id = be32_to_cpup(_id); 28688c2ecf20Sopenharmony_ci if (id >= MTK_MAC_COUNT) { 28698c2ecf20Sopenharmony_ci dev_err(eth->dev, "%d is not a valid mac id\n", id); 28708c2ecf20Sopenharmony_ci return -EINVAL; 28718c2ecf20Sopenharmony_ci } 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci if (eth->netdev[id]) { 28748c2ecf20Sopenharmony_ci dev_err(eth->dev, "duplicate mac id found: %d\n", id); 28758c2ecf20Sopenharmony_ci return -EINVAL; 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci eth->netdev[id] = alloc_etherdev(sizeof(*mac)); 28798c2ecf20Sopenharmony_ci if (!eth->netdev[id]) { 28808c2ecf20Sopenharmony_ci dev_err(eth->dev, "alloc_etherdev failed\n"); 28818c2ecf20Sopenharmony_ci return -ENOMEM; 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci mac = netdev_priv(eth->netdev[id]); 28848c2ecf20Sopenharmony_ci eth->mac[id] = mac; 28858c2ecf20Sopenharmony_ci mac->id = id; 28868c2ecf20Sopenharmony_ci mac->hw = eth; 28878c2ecf20Sopenharmony_ci mac->of_node = np; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci memset(mac->hwlro_ip, 0, sizeof(mac->hwlro_ip)); 28908c2ecf20Sopenharmony_ci mac->hwlro_ip_cnt = 0; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci mac->hw_stats = devm_kzalloc(eth->dev, 28938c2ecf20Sopenharmony_ci sizeof(*mac->hw_stats), 28948c2ecf20Sopenharmony_ci GFP_KERNEL); 28958c2ecf20Sopenharmony_ci if (!mac->hw_stats) { 28968c2ecf20Sopenharmony_ci dev_err(eth->dev, "failed to allocate counter memory\n"); 28978c2ecf20Sopenharmony_ci err = -ENOMEM; 28988c2ecf20Sopenharmony_ci goto free_netdev; 28998c2ecf20Sopenharmony_ci } 29008c2ecf20Sopenharmony_ci spin_lock_init(&mac->hw_stats->stats_lock); 29018c2ecf20Sopenharmony_ci u64_stats_init(&mac->hw_stats->syncp); 29028c2ecf20Sopenharmony_ci mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci /* phylink create */ 29058c2ecf20Sopenharmony_ci err = of_get_phy_mode(np, &phy_mode); 29068c2ecf20Sopenharmony_ci if (err) { 29078c2ecf20Sopenharmony_ci dev_err(eth->dev, "incorrect phy-mode\n"); 29088c2ecf20Sopenharmony_ci goto free_netdev; 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci /* mac config is not set */ 29128c2ecf20Sopenharmony_ci mac->interface = PHY_INTERFACE_MODE_NA; 29138c2ecf20Sopenharmony_ci mac->mode = MLO_AN_PHY; 29148c2ecf20Sopenharmony_ci mac->speed = SPEED_UNKNOWN; 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci mac->phylink_config.dev = ð->netdev[id]->dev; 29178c2ecf20Sopenharmony_ci mac->phylink_config.type = PHYLINK_NETDEV; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci phylink = phylink_create(&mac->phylink_config, 29208c2ecf20Sopenharmony_ci of_fwnode_handle(mac->of_node), 29218c2ecf20Sopenharmony_ci phy_mode, &mtk_phylink_ops); 29228c2ecf20Sopenharmony_ci if (IS_ERR(phylink)) { 29238c2ecf20Sopenharmony_ci err = PTR_ERR(phylink); 29248c2ecf20Sopenharmony_ci goto free_netdev; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci mac->phylink = phylink; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci SET_NETDEV_DEV(eth->netdev[id], eth->dev); 29308c2ecf20Sopenharmony_ci eth->netdev[id]->watchdog_timeo = 5 * HZ; 29318c2ecf20Sopenharmony_ci eth->netdev[id]->netdev_ops = &mtk_netdev_ops; 29328c2ecf20Sopenharmony_ci eth->netdev[id]->base_addr = (unsigned long)eth->base; 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci eth->netdev[id]->hw_features = eth->soc->hw_features; 29358c2ecf20Sopenharmony_ci if (eth->hwlro) 29368c2ecf20Sopenharmony_ci eth->netdev[id]->hw_features |= NETIF_F_LRO; 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci eth->netdev[id]->vlan_features = eth->soc->hw_features & 29398c2ecf20Sopenharmony_ci ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); 29408c2ecf20Sopenharmony_ci eth->netdev[id]->features |= eth->soc->hw_features; 29418c2ecf20Sopenharmony_ci eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci eth->netdev[id]->irq = eth->irq[0]; 29448c2ecf20Sopenharmony_ci eth->netdev[id]->dev.of_node = np; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci return 0; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_cifree_netdev: 29518c2ecf20Sopenharmony_ci free_netdev(eth->netdev[id]); 29528c2ecf20Sopenharmony_ci return err; 29538c2ecf20Sopenharmony_ci} 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_cistatic int mtk_probe(struct platform_device *pdev) 29568c2ecf20Sopenharmony_ci{ 29578c2ecf20Sopenharmony_ci struct device_node *mac_np; 29588c2ecf20Sopenharmony_ci struct mtk_eth *eth; 29598c2ecf20Sopenharmony_ci int err, i; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL); 29628c2ecf20Sopenharmony_ci if (!eth) 29638c2ecf20Sopenharmony_ci return -ENOMEM; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci eth->soc = of_device_get_match_data(&pdev->dev); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci eth->dev = &pdev->dev; 29688c2ecf20Sopenharmony_ci eth->base = devm_platform_ioremap_resource(pdev, 0); 29698c2ecf20Sopenharmony_ci if (IS_ERR(eth->base)) 29708c2ecf20Sopenharmony_ci return PTR_ERR(eth->base); 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { 29738c2ecf20Sopenharmony_ci eth->tx_int_mask_reg = MTK_QDMA_INT_MASK; 29748c2ecf20Sopenharmony_ci eth->tx_int_status_reg = MTK_QDMA_INT_STATUS; 29758c2ecf20Sopenharmony_ci } else { 29768c2ecf20Sopenharmony_ci eth->tx_int_mask_reg = MTK_PDMA_INT_MASK; 29778c2ecf20Sopenharmony_ci eth->tx_int_status_reg = MTK_PDMA_INT_STATUS; 29788c2ecf20Sopenharmony_ci } 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 29818c2ecf20Sopenharmony_ci eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; 29828c2ecf20Sopenharmony_ci eth->ip_align = NET_IP_ALIGN; 29838c2ecf20Sopenharmony_ci } else { 29848c2ecf20Sopenharmony_ci eth->rx_dma_l4_valid = RX_DMA_L4_VALID; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci spin_lock_init(ð->page_lock); 29888c2ecf20Sopenharmony_ci spin_lock_init(ð->tx_irq_lock); 29898c2ecf20Sopenharmony_ci spin_lock_init(ð->rx_irq_lock); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 29928c2ecf20Sopenharmony_ci eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 29938c2ecf20Sopenharmony_ci "mediatek,ethsys"); 29948c2ecf20Sopenharmony_ci if (IS_ERR(eth->ethsys)) { 29958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no ethsys regmap found\n"); 29968c2ecf20Sopenharmony_ci return PTR_ERR(eth->ethsys); 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) { 30018c2ecf20Sopenharmony_ci eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 30028c2ecf20Sopenharmony_ci "mediatek,infracfg"); 30038c2ecf20Sopenharmony_ci if (IS_ERR(eth->infra)) { 30048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no infracfg regmap found\n"); 30058c2ecf20Sopenharmony_ci return PTR_ERR(eth->infra); 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { 30108c2ecf20Sopenharmony_ci eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), 30118c2ecf20Sopenharmony_ci GFP_KERNEL); 30128c2ecf20Sopenharmony_ci if (!eth->sgmii) 30138c2ecf20Sopenharmony_ci return -ENOMEM; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, 30168c2ecf20Sopenharmony_ci eth->soc->ana_rgc3); 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci if (err) 30198c2ecf20Sopenharmony_ci return err; 30208c2ecf20Sopenharmony_ci } 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (eth->soc->required_pctl) { 30238c2ecf20Sopenharmony_ci eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 30248c2ecf20Sopenharmony_ci "mediatek,pctl"); 30258c2ecf20Sopenharmony_ci if (IS_ERR(eth->pctl)) { 30268c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no pctl regmap found\n"); 30278c2ecf20Sopenharmony_ci return PTR_ERR(eth->pctl); 30288c2ecf20Sopenharmony_ci } 30298c2ecf20Sopenharmony_ci } 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 30328c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0) 30338c2ecf20Sopenharmony_ci eth->irq[i] = eth->irq[0]; 30348c2ecf20Sopenharmony_ci else 30358c2ecf20Sopenharmony_ci eth->irq[i] = platform_get_irq(pdev, i); 30368c2ecf20Sopenharmony_ci if (eth->irq[i] < 0) { 30378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no IRQ%d resource found\n", i); 30388c2ecf20Sopenharmony_ci return -ENXIO; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(eth->clks); i++) { 30428c2ecf20Sopenharmony_ci eth->clks[i] = devm_clk_get(eth->dev, 30438c2ecf20Sopenharmony_ci mtk_clks_source_name[i]); 30448c2ecf20Sopenharmony_ci if (IS_ERR(eth->clks[i])) { 30458c2ecf20Sopenharmony_ci if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) 30468c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 30478c2ecf20Sopenharmony_ci if (eth->soc->required_clks & BIT(i)) { 30488c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "clock %s not found\n", 30498c2ecf20Sopenharmony_ci mtk_clks_source_name[i]); 30508c2ecf20Sopenharmony_ci return -EINVAL; 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci eth->clks[i] = NULL; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); 30578c2ecf20Sopenharmony_ci INIT_WORK(ð->pending_work, mtk_pending_work); 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci err = mtk_hw_init(eth); 30608c2ecf20Sopenharmony_ci if (err) 30618c2ecf20Sopenharmony_ci return err; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO); 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci for_each_child_of_node(pdev->dev.of_node, mac_np) { 30668c2ecf20Sopenharmony_ci if (!of_device_is_compatible(mac_np, 30678c2ecf20Sopenharmony_ci "mediatek,eth-mac")) 30688c2ecf20Sopenharmony_ci continue; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci if (!of_device_is_available(mac_np)) 30718c2ecf20Sopenharmony_ci continue; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci err = mtk_add_mac(eth, mac_np); 30748c2ecf20Sopenharmony_ci if (err) { 30758c2ecf20Sopenharmony_ci of_node_put(mac_np); 30768c2ecf20Sopenharmony_ci goto err_deinit_hw; 30778c2ecf20Sopenharmony_ci } 30788c2ecf20Sopenharmony_ci } 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { 30818c2ecf20Sopenharmony_ci err = devm_request_irq(eth->dev, eth->irq[0], 30828c2ecf20Sopenharmony_ci mtk_handle_irq, 0, 30838c2ecf20Sopenharmony_ci dev_name(eth->dev), eth); 30848c2ecf20Sopenharmony_ci } else { 30858c2ecf20Sopenharmony_ci err = devm_request_irq(eth->dev, eth->irq[1], 30868c2ecf20Sopenharmony_ci mtk_handle_irq_tx, 0, 30878c2ecf20Sopenharmony_ci dev_name(eth->dev), eth); 30888c2ecf20Sopenharmony_ci if (err) 30898c2ecf20Sopenharmony_ci goto err_free_dev; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci err = devm_request_irq(eth->dev, eth->irq[2], 30928c2ecf20Sopenharmony_ci mtk_handle_irq_rx, 0, 30938c2ecf20Sopenharmony_ci dev_name(eth->dev), eth); 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci if (err) 30968c2ecf20Sopenharmony_ci goto err_free_dev; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci /* No MT7628/88 support yet */ 30998c2ecf20Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { 31008c2ecf20Sopenharmony_ci err = mtk_mdio_init(eth); 31018c2ecf20Sopenharmony_ci if (err) 31028c2ecf20Sopenharmony_ci goto err_free_dev; 31038c2ecf20Sopenharmony_ci } 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAX_DEVS; i++) { 31068c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 31078c2ecf20Sopenharmony_ci continue; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci err = register_netdev(eth->netdev[i]); 31108c2ecf20Sopenharmony_ci if (err) { 31118c2ecf20Sopenharmony_ci dev_err(eth->dev, "error bringing up device\n"); 31128c2ecf20Sopenharmony_ci goto err_deinit_mdio; 31138c2ecf20Sopenharmony_ci } else 31148c2ecf20Sopenharmony_ci netif_info(eth, probe, eth->netdev[i], 31158c2ecf20Sopenharmony_ci "mediatek frame engine at 0x%08lx, irq %d\n", 31168c2ecf20Sopenharmony_ci eth->netdev[i]->base_addr, eth->irq[0]); 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci /* we run 2 devices on the same DMA ring so we need a dummy device 31208c2ecf20Sopenharmony_ci * for NAPI to work 31218c2ecf20Sopenharmony_ci */ 31228c2ecf20Sopenharmony_ci init_dummy_netdev(ð->dummy_dev); 31238c2ecf20Sopenharmony_ci netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, 31248c2ecf20Sopenharmony_ci MTK_NAPI_WEIGHT); 31258c2ecf20Sopenharmony_ci netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, 31268c2ecf20Sopenharmony_ci MTK_NAPI_WEIGHT); 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, eth); 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci return 0; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_cierr_deinit_mdio: 31338c2ecf20Sopenharmony_ci mtk_mdio_cleanup(eth); 31348c2ecf20Sopenharmony_cierr_free_dev: 31358c2ecf20Sopenharmony_ci mtk_free_dev(eth); 31368c2ecf20Sopenharmony_cierr_deinit_hw: 31378c2ecf20Sopenharmony_ci mtk_hw_deinit(eth); 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci return err; 31408c2ecf20Sopenharmony_ci} 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_cistatic int mtk_remove(struct platform_device *pdev) 31438c2ecf20Sopenharmony_ci{ 31448c2ecf20Sopenharmony_ci struct mtk_eth *eth = platform_get_drvdata(pdev); 31458c2ecf20Sopenharmony_ci struct mtk_mac *mac; 31468c2ecf20Sopenharmony_ci int i; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci /* stop all devices to make sure that dma is properly shut down */ 31498c2ecf20Sopenharmony_ci for (i = 0; i < MTK_MAC_COUNT; i++) { 31508c2ecf20Sopenharmony_ci if (!eth->netdev[i]) 31518c2ecf20Sopenharmony_ci continue; 31528c2ecf20Sopenharmony_ci mtk_stop(eth->netdev[i]); 31538c2ecf20Sopenharmony_ci mac = netdev_priv(eth->netdev[i]); 31548c2ecf20Sopenharmony_ci phylink_disconnect_phy(mac->phylink); 31558c2ecf20Sopenharmony_ci } 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci mtk_hw_deinit(eth); 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci netif_napi_del(ð->tx_napi); 31608c2ecf20Sopenharmony_ci netif_napi_del(ð->rx_napi); 31618c2ecf20Sopenharmony_ci mtk_cleanup(eth); 31628c2ecf20Sopenharmony_ci mtk_mdio_cleanup(eth); 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci return 0; 31658c2ecf20Sopenharmony_ci} 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_cistatic const struct mtk_soc_data mt2701_data = { 31688c2ecf20Sopenharmony_ci .caps = MT7623_CAPS | MTK_HWLRO, 31698c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES, 31708c2ecf20Sopenharmony_ci .required_clks = MT7623_CLKS_BITMAP, 31718c2ecf20Sopenharmony_ci .required_pctl = true, 31728c2ecf20Sopenharmony_ci}; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_cistatic const struct mtk_soc_data mt7621_data = { 31758c2ecf20Sopenharmony_ci .caps = MT7621_CAPS, 31768c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES, 31778c2ecf20Sopenharmony_ci .required_clks = MT7621_CLKS_BITMAP, 31788c2ecf20Sopenharmony_ci .required_pctl = false, 31798c2ecf20Sopenharmony_ci}; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_cistatic const struct mtk_soc_data mt7622_data = { 31828c2ecf20Sopenharmony_ci .ana_rgc3 = 0x2028, 31838c2ecf20Sopenharmony_ci .caps = MT7622_CAPS | MTK_HWLRO, 31848c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES, 31858c2ecf20Sopenharmony_ci .required_clks = MT7622_CLKS_BITMAP, 31868c2ecf20Sopenharmony_ci .required_pctl = false, 31878c2ecf20Sopenharmony_ci}; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_cistatic const struct mtk_soc_data mt7623_data = { 31908c2ecf20Sopenharmony_ci .caps = MT7623_CAPS | MTK_HWLRO, 31918c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES, 31928c2ecf20Sopenharmony_ci .required_clks = MT7623_CLKS_BITMAP, 31938c2ecf20Sopenharmony_ci .required_pctl = true, 31948c2ecf20Sopenharmony_ci}; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_cistatic const struct mtk_soc_data mt7629_data = { 31978c2ecf20Sopenharmony_ci .ana_rgc3 = 0x128, 31988c2ecf20Sopenharmony_ci .caps = MT7629_CAPS | MTK_HWLRO, 31998c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES, 32008c2ecf20Sopenharmony_ci .required_clks = MT7629_CLKS_BITMAP, 32018c2ecf20Sopenharmony_ci .required_pctl = false, 32028c2ecf20Sopenharmony_ci}; 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_cistatic const struct mtk_soc_data rt5350_data = { 32058c2ecf20Sopenharmony_ci .caps = MT7628_CAPS, 32068c2ecf20Sopenharmony_ci .hw_features = MTK_HW_FEATURES_MT7628, 32078c2ecf20Sopenharmony_ci .required_clks = MT7628_CLKS_BITMAP, 32088c2ecf20Sopenharmony_ci .required_pctl = false, 32098c2ecf20Sopenharmony_ci}; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ciconst struct of_device_id of_mtk_match[] = { 32128c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, 32138c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, 32148c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, 32158c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, 32168c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, 32178c2ecf20Sopenharmony_ci { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, 32188c2ecf20Sopenharmony_ci {}, 32198c2ecf20Sopenharmony_ci}; 32208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_mtk_match); 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_cistatic struct platform_driver mtk_driver = { 32238c2ecf20Sopenharmony_ci .probe = mtk_probe, 32248c2ecf20Sopenharmony_ci .remove = mtk_remove, 32258c2ecf20Sopenharmony_ci .driver = { 32268c2ecf20Sopenharmony_ci .name = "mtk_soc_eth", 32278c2ecf20Sopenharmony_ci .of_match_table = of_mtk_match, 32288c2ecf20Sopenharmony_ci }, 32298c2ecf20Sopenharmony_ci}; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_cimodule_platform_driver(mtk_driver); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 32348c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 32358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ethernet driver for MediaTek SoC"); 3236