18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/signal.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/mii.h> 128c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 138c2ecf20Sopenharmony_ci#include <linux/usb.h> 148c2ecf20Sopenharmony_ci#include <linux/crc32.h> 158c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 168c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 178c2ecf20Sopenharmony_ci#include <linux/list.h> 188c2ecf20Sopenharmony_ci#include <linux/ip.h> 198c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 208c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 218c2ecf20Sopenharmony_ci#include <uapi/linux/mdio.h> 228c2ecf20Sopenharmony_ci#include <linux/mdio.h> 238c2ecf20Sopenharmony_ci#include <linux/usb/cdc.h> 248c2ecf20Sopenharmony_ci#include <linux/suspend.h> 258c2ecf20Sopenharmony_ci#include <linux/atomic.h> 268c2ecf20Sopenharmony_ci#include <linux/acpi.h> 278c2ecf20Sopenharmony_ci#include <linux/firmware.h> 288c2ecf20Sopenharmony_ci#include <crypto/hash.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Information for net-next */ 318c2ecf20Sopenharmony_ci#define NETNEXT_VERSION "11" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Information for net */ 348c2ecf20Sopenharmony_ci#define NET_VERSION "11" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION 378c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" 388c2ecf20Sopenharmony_ci#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" 398c2ecf20Sopenharmony_ci#define MODULENAME "r8152" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define R8152_PHY_ID 32 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define PLA_IDR 0xc000 448c2ecf20Sopenharmony_ci#define PLA_RCR 0xc010 458c2ecf20Sopenharmony_ci#define PLA_RMS 0xc016 468c2ecf20Sopenharmony_ci#define PLA_RXFIFO_CTRL0 0xc0a0 478c2ecf20Sopenharmony_ci#define PLA_RXFIFO_CTRL1 0xc0a4 488c2ecf20Sopenharmony_ci#define PLA_RXFIFO_CTRL2 0xc0a8 498c2ecf20Sopenharmony_ci#define PLA_DMY_REG0 0xc0b0 508c2ecf20Sopenharmony_ci#define PLA_FMC 0xc0b4 518c2ecf20Sopenharmony_ci#define PLA_CFG_WOL 0xc0b6 528c2ecf20Sopenharmony_ci#define PLA_TEREDO_CFG 0xc0bc 538c2ecf20Sopenharmony_ci#define PLA_TEREDO_WAKE_BASE 0xc0c4 548c2ecf20Sopenharmony_ci#define PLA_MAR 0xcd00 558c2ecf20Sopenharmony_ci#define PLA_BACKUP 0xd000 568c2ecf20Sopenharmony_ci#define PLA_BDC_CR 0xd1a0 578c2ecf20Sopenharmony_ci#define PLA_TEREDO_TIMER 0xd2cc 588c2ecf20Sopenharmony_ci#define PLA_REALWOW_TIMER 0xd2e8 598c2ecf20Sopenharmony_ci#define PLA_UPHY_TIMER 0xd388 608c2ecf20Sopenharmony_ci#define PLA_SUSPEND_FLAG 0xd38a 618c2ecf20Sopenharmony_ci#define PLA_INDICATE_FALG 0xd38c 628c2ecf20Sopenharmony_ci#define PLA_MACDBG_PRE 0xd38c /* RTL_VER_04 only */ 638c2ecf20Sopenharmony_ci#define PLA_MACDBG_POST 0xd38e /* RTL_VER_04 only */ 648c2ecf20Sopenharmony_ci#define PLA_EXTRA_STATUS 0xd398 658c2ecf20Sopenharmony_ci#define PLA_EFUSE_DATA 0xdd00 668c2ecf20Sopenharmony_ci#define PLA_EFUSE_CMD 0xdd02 678c2ecf20Sopenharmony_ci#define PLA_LEDSEL 0xdd90 688c2ecf20Sopenharmony_ci#define PLA_LED_FEATURE 0xdd92 698c2ecf20Sopenharmony_ci#define PLA_PHYAR 0xde00 708c2ecf20Sopenharmony_ci#define PLA_BOOT_CTRL 0xe004 718c2ecf20Sopenharmony_ci#define PLA_LWAKE_CTRL_REG 0xe007 728c2ecf20Sopenharmony_ci#define PLA_GPHY_INTR_IMR 0xe022 738c2ecf20Sopenharmony_ci#define PLA_EEE_CR 0xe040 748c2ecf20Sopenharmony_ci#define PLA_EEEP_CR 0xe080 758c2ecf20Sopenharmony_ci#define PLA_MAC_PWR_CTRL 0xe0c0 768c2ecf20Sopenharmony_ci#define PLA_MAC_PWR_CTRL2 0xe0ca 778c2ecf20Sopenharmony_ci#define PLA_MAC_PWR_CTRL3 0xe0cc 788c2ecf20Sopenharmony_ci#define PLA_MAC_PWR_CTRL4 0xe0ce 798c2ecf20Sopenharmony_ci#define PLA_WDT6_CTRL 0xe428 808c2ecf20Sopenharmony_ci#define PLA_TCR0 0xe610 818c2ecf20Sopenharmony_ci#define PLA_TCR1 0xe612 828c2ecf20Sopenharmony_ci#define PLA_MTPS 0xe615 838c2ecf20Sopenharmony_ci#define PLA_TXFIFO_CTRL 0xe618 848c2ecf20Sopenharmony_ci#define PLA_RSTTALLY 0xe800 858c2ecf20Sopenharmony_ci#define PLA_CR 0xe813 868c2ecf20Sopenharmony_ci#define PLA_CRWECR 0xe81c 878c2ecf20Sopenharmony_ci#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ 888c2ecf20Sopenharmony_ci#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */ 898c2ecf20Sopenharmony_ci#define PLA_CONFIG5 0xe822 908c2ecf20Sopenharmony_ci#define PLA_PHY_PWR 0xe84c 918c2ecf20Sopenharmony_ci#define PLA_OOB_CTRL 0xe84f 928c2ecf20Sopenharmony_ci#define PLA_CPCR 0xe854 938c2ecf20Sopenharmony_ci#define PLA_MISC_0 0xe858 948c2ecf20Sopenharmony_ci#define PLA_MISC_1 0xe85a 958c2ecf20Sopenharmony_ci#define PLA_OCP_GPHY_BASE 0xe86c 968c2ecf20Sopenharmony_ci#define PLA_TALLYCNT 0xe890 978c2ecf20Sopenharmony_ci#define PLA_SFF_STS_7 0xe8de 988c2ecf20Sopenharmony_ci#define PLA_PHYSTATUS 0xe908 998c2ecf20Sopenharmony_ci#define PLA_CONFIG6 0xe90a /* CONFIG6 */ 1008c2ecf20Sopenharmony_ci#define PLA_BP_BA 0xfc26 1018c2ecf20Sopenharmony_ci#define PLA_BP_0 0xfc28 1028c2ecf20Sopenharmony_ci#define PLA_BP_1 0xfc2a 1038c2ecf20Sopenharmony_ci#define PLA_BP_2 0xfc2c 1048c2ecf20Sopenharmony_ci#define PLA_BP_3 0xfc2e 1058c2ecf20Sopenharmony_ci#define PLA_BP_4 0xfc30 1068c2ecf20Sopenharmony_ci#define PLA_BP_5 0xfc32 1078c2ecf20Sopenharmony_ci#define PLA_BP_6 0xfc34 1088c2ecf20Sopenharmony_ci#define PLA_BP_7 0xfc36 1098c2ecf20Sopenharmony_ci#define PLA_BP_EN 0xfc38 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define USB_USB2PHY 0xb41e 1128c2ecf20Sopenharmony_ci#define USB_SSPHYLINK1 0xb426 1138c2ecf20Sopenharmony_ci#define USB_SSPHYLINK2 0xb428 1148c2ecf20Sopenharmony_ci#define USB_U2P3_CTRL 0xb460 1158c2ecf20Sopenharmony_ci#define USB_CSR_DUMMY1 0xb464 1168c2ecf20Sopenharmony_ci#define USB_CSR_DUMMY2 0xb466 1178c2ecf20Sopenharmony_ci#define USB_DEV_STAT 0xb808 1188c2ecf20Sopenharmony_ci#define USB_CONNECT_TIMER 0xcbf8 1198c2ecf20Sopenharmony_ci#define USB_MSC_TIMER 0xcbfc 1208c2ecf20Sopenharmony_ci#define USB_BURST_SIZE 0xcfc0 1218c2ecf20Sopenharmony_ci#define USB_FW_FIX_EN0 0xcfca 1228c2ecf20Sopenharmony_ci#define USB_FW_FIX_EN1 0xcfcc 1238c2ecf20Sopenharmony_ci#define USB_LPM_CONFIG 0xcfd8 1248c2ecf20Sopenharmony_ci#define USB_CSTMR 0xcfef /* RTL8153A */ 1258c2ecf20Sopenharmony_ci#define USB_FW_CTRL 0xd334 /* RTL8153B */ 1268c2ecf20Sopenharmony_ci#define USB_FC_TIMER 0xd340 1278c2ecf20Sopenharmony_ci#define USB_USB_CTRL 0xd406 1288c2ecf20Sopenharmony_ci#define USB_PHY_CTRL 0xd408 1298c2ecf20Sopenharmony_ci#define USB_TX_AGG 0xd40a 1308c2ecf20Sopenharmony_ci#define USB_RX_BUF_TH 0xd40c 1318c2ecf20Sopenharmony_ci#define USB_USB_TIMER 0xd428 1328c2ecf20Sopenharmony_ci#define USB_RX_EARLY_TIMEOUT 0xd42c 1338c2ecf20Sopenharmony_ci#define USB_RX_EARLY_SIZE 0xd42e 1348c2ecf20Sopenharmony_ci#define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */ 1358c2ecf20Sopenharmony_ci#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */ 1368c2ecf20Sopenharmony_ci#define USB_TX_DMA 0xd434 1378c2ecf20Sopenharmony_ci#define USB_UPT_RXDMA_OWN 0xd437 1388c2ecf20Sopenharmony_ci#define USB_TOLERANCE 0xd490 1398c2ecf20Sopenharmony_ci#define USB_LPM_CTRL 0xd41a 1408c2ecf20Sopenharmony_ci#define USB_BMU_RESET 0xd4b0 1418c2ecf20Sopenharmony_ci#define USB_U1U2_TIMER 0xd4da 1428c2ecf20Sopenharmony_ci#define USB_FW_TASK 0xd4e8 /* RTL8153B */ 1438c2ecf20Sopenharmony_ci#define USB_UPS_CTRL 0xd800 1448c2ecf20Sopenharmony_ci#define USB_POWER_CUT 0xd80a 1458c2ecf20Sopenharmony_ci#define USB_MISC_0 0xd81a 1468c2ecf20Sopenharmony_ci#define USB_MISC_1 0xd81f 1478c2ecf20Sopenharmony_ci#define USB_AFE_CTRL2 0xd824 1488c2ecf20Sopenharmony_ci#define USB_UPS_CFG 0xd842 1498c2ecf20Sopenharmony_ci#define USB_UPS_FLAGS 0xd848 1508c2ecf20Sopenharmony_ci#define USB_WDT1_CTRL 0xe404 1518c2ecf20Sopenharmony_ci#define USB_WDT11_CTRL 0xe43c 1528c2ecf20Sopenharmony_ci#define USB_BP_BA PLA_BP_BA 1538c2ecf20Sopenharmony_ci#define USB_BP_0 PLA_BP_0 1548c2ecf20Sopenharmony_ci#define USB_BP_1 PLA_BP_1 1558c2ecf20Sopenharmony_ci#define USB_BP_2 PLA_BP_2 1568c2ecf20Sopenharmony_ci#define USB_BP_3 PLA_BP_3 1578c2ecf20Sopenharmony_ci#define USB_BP_4 PLA_BP_4 1588c2ecf20Sopenharmony_ci#define USB_BP_5 PLA_BP_5 1598c2ecf20Sopenharmony_ci#define USB_BP_6 PLA_BP_6 1608c2ecf20Sopenharmony_ci#define USB_BP_7 PLA_BP_7 1618c2ecf20Sopenharmony_ci#define USB_BP_EN PLA_BP_EN /* RTL8153A */ 1628c2ecf20Sopenharmony_ci#define USB_BP_8 0xfc38 /* RTL8153B */ 1638c2ecf20Sopenharmony_ci#define USB_BP_9 0xfc3a 1648c2ecf20Sopenharmony_ci#define USB_BP_10 0xfc3c 1658c2ecf20Sopenharmony_ci#define USB_BP_11 0xfc3e 1668c2ecf20Sopenharmony_ci#define USB_BP_12 0xfc40 1678c2ecf20Sopenharmony_ci#define USB_BP_13 0xfc42 1688c2ecf20Sopenharmony_ci#define USB_BP_14 0xfc44 1698c2ecf20Sopenharmony_ci#define USB_BP_15 0xfc46 1708c2ecf20Sopenharmony_ci#define USB_BP2_EN 0xfc48 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* OCP Registers */ 1738c2ecf20Sopenharmony_ci#define OCP_ALDPS_CONFIG 0x2010 1748c2ecf20Sopenharmony_ci#define OCP_EEE_CONFIG1 0x2080 1758c2ecf20Sopenharmony_ci#define OCP_EEE_CONFIG2 0x2092 1768c2ecf20Sopenharmony_ci#define OCP_EEE_CONFIG3 0x2094 1778c2ecf20Sopenharmony_ci#define OCP_BASE_MII 0xa400 1788c2ecf20Sopenharmony_ci#define OCP_EEE_AR 0xa41a 1798c2ecf20Sopenharmony_ci#define OCP_EEE_DATA 0xa41c 1808c2ecf20Sopenharmony_ci#define OCP_PHY_STATUS 0xa420 1818c2ecf20Sopenharmony_ci#define OCP_NCTL_CFG 0xa42c 1828c2ecf20Sopenharmony_ci#define OCP_POWER_CFG 0xa430 1838c2ecf20Sopenharmony_ci#define OCP_EEE_CFG 0xa432 1848c2ecf20Sopenharmony_ci#define OCP_SRAM_ADDR 0xa436 1858c2ecf20Sopenharmony_ci#define OCP_SRAM_DATA 0xa438 1868c2ecf20Sopenharmony_ci#define OCP_DOWN_SPEED 0xa442 1878c2ecf20Sopenharmony_ci#define OCP_EEE_ABLE 0xa5c4 1888c2ecf20Sopenharmony_ci#define OCP_EEE_ADV 0xa5d0 1898c2ecf20Sopenharmony_ci#define OCP_EEE_LPABLE 0xa5d2 1908c2ecf20Sopenharmony_ci#define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ 1918c2ecf20Sopenharmony_ci#define OCP_PHY_PATCH_STAT 0xb800 1928c2ecf20Sopenharmony_ci#define OCP_PHY_PATCH_CMD 0xb820 1938c2ecf20Sopenharmony_ci#define OCP_PHY_LOCK 0xb82e 1948c2ecf20Sopenharmony_ci#define OCP_ADC_IOFFSET 0xbcfc 1958c2ecf20Sopenharmony_ci#define OCP_ADC_CFG 0xbc06 1968c2ecf20Sopenharmony_ci#define OCP_SYSCLK_CFG 0xc416 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* SRAM Register */ 1998c2ecf20Sopenharmony_ci#define SRAM_GREEN_CFG 0x8011 2008c2ecf20Sopenharmony_ci#define SRAM_LPF_CFG 0x8012 2018c2ecf20Sopenharmony_ci#define SRAM_10M_AMP1 0x8080 2028c2ecf20Sopenharmony_ci#define SRAM_10M_AMP2 0x8082 2038c2ecf20Sopenharmony_ci#define SRAM_IMPEDANCE 0x8084 2048c2ecf20Sopenharmony_ci#define SRAM_PHY_LOCK 0xb82e 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* PLA_RCR */ 2078c2ecf20Sopenharmony_ci#define RCR_AAP 0x00000001 2088c2ecf20Sopenharmony_ci#define RCR_APM 0x00000002 2098c2ecf20Sopenharmony_ci#define RCR_AM 0x00000004 2108c2ecf20Sopenharmony_ci#define RCR_AB 0x00000008 2118c2ecf20Sopenharmony_ci#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB) 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* PLA_RXFIFO_CTRL0 */ 2148c2ecf20Sopenharmony_ci#define RXFIFO_THR1_NORMAL 0x00080002 2158c2ecf20Sopenharmony_ci#define RXFIFO_THR1_OOB 0x01800003 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* PLA_RXFIFO_CTRL1 */ 2188c2ecf20Sopenharmony_ci#define RXFIFO_THR2_FULL 0x00000060 2198c2ecf20Sopenharmony_ci#define RXFIFO_THR2_HIGH 0x00000038 2208c2ecf20Sopenharmony_ci#define RXFIFO_THR2_OOB 0x0000004a 2218c2ecf20Sopenharmony_ci#define RXFIFO_THR2_NORMAL 0x00a0 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* PLA_RXFIFO_CTRL2 */ 2248c2ecf20Sopenharmony_ci#define RXFIFO_THR3_FULL 0x00000078 2258c2ecf20Sopenharmony_ci#define RXFIFO_THR3_HIGH 0x00000048 2268c2ecf20Sopenharmony_ci#define RXFIFO_THR3_OOB 0x0000005a 2278c2ecf20Sopenharmony_ci#define RXFIFO_THR3_NORMAL 0x0110 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* PLA_TXFIFO_CTRL */ 2308c2ecf20Sopenharmony_ci#define TXFIFO_THR_NORMAL 0x00400008 2318c2ecf20Sopenharmony_ci#define TXFIFO_THR_NORMAL2 0x01000008 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* PLA_DMY_REG0 */ 2348c2ecf20Sopenharmony_ci#define ECM_ALDPS 0x0002 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* PLA_FMC */ 2378c2ecf20Sopenharmony_ci#define FMC_FCR_MCU_EN 0x0001 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* PLA_EEEP_CR */ 2408c2ecf20Sopenharmony_ci#define EEEP_CR_EEEP_TX 0x0002 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* PLA_WDT6_CTRL */ 2438c2ecf20Sopenharmony_ci#define WDT6_SET_MODE 0x0010 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/* PLA_TCR0 */ 2468c2ecf20Sopenharmony_ci#define TCR0_TX_EMPTY 0x0800 2478c2ecf20Sopenharmony_ci#define TCR0_AUTO_FIFO 0x0080 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* PLA_TCR1 */ 2508c2ecf20Sopenharmony_ci#define VERSION_MASK 0x7cf0 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* PLA_MTPS */ 2538c2ecf20Sopenharmony_ci#define MTPS_JUMBO (12 * 1024 / 64) 2548c2ecf20Sopenharmony_ci#define MTPS_DEFAULT (6 * 1024 / 64) 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* PLA_RSTTALLY */ 2578c2ecf20Sopenharmony_ci#define TALLY_RESET 0x0001 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* PLA_CR */ 2608c2ecf20Sopenharmony_ci#define CR_RST 0x10 2618c2ecf20Sopenharmony_ci#define CR_RE 0x08 2628c2ecf20Sopenharmony_ci#define CR_TE 0x04 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* PLA_CRWECR */ 2658c2ecf20Sopenharmony_ci#define CRWECR_NORAML 0x00 2668c2ecf20Sopenharmony_ci#define CRWECR_CONFIG 0xc0 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* PLA_OOB_CTRL */ 2698c2ecf20Sopenharmony_ci#define NOW_IS_OOB 0x80 2708c2ecf20Sopenharmony_ci#define TXFIFO_EMPTY 0x20 2718c2ecf20Sopenharmony_ci#define RXFIFO_EMPTY 0x10 2728c2ecf20Sopenharmony_ci#define LINK_LIST_READY 0x02 2738c2ecf20Sopenharmony_ci#define DIS_MCU_CLROOB 0x01 2748c2ecf20Sopenharmony_ci#define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY) 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* PLA_MISC_1 */ 2778c2ecf20Sopenharmony_ci#define RXDY_GATED_EN 0x0008 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* PLA_SFF_STS_7 */ 2808c2ecf20Sopenharmony_ci#define RE_INIT_LL 0x8000 2818c2ecf20Sopenharmony_ci#define MCU_BORW_EN 0x4000 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* PLA_CPCR */ 2848c2ecf20Sopenharmony_ci#define CPCR_RX_VLAN 0x0040 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* PLA_CFG_WOL */ 2878c2ecf20Sopenharmony_ci#define MAGIC_EN 0x0001 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* PLA_TEREDO_CFG */ 2908c2ecf20Sopenharmony_ci#define TEREDO_SEL 0x8000 2918c2ecf20Sopenharmony_ci#define TEREDO_WAKE_MASK 0x7f00 2928c2ecf20Sopenharmony_ci#define TEREDO_RS_EVENT_MASK 0x00fe 2938c2ecf20Sopenharmony_ci#define OOB_TEREDO_EN 0x0001 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* PLA_BDC_CR */ 2968c2ecf20Sopenharmony_ci#define ALDPS_PROXY_MODE 0x0001 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* PLA_EFUSE_CMD */ 2998c2ecf20Sopenharmony_ci#define EFUSE_READ_CMD BIT(15) 3008c2ecf20Sopenharmony_ci#define EFUSE_DATA_BIT16 BIT(7) 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* PLA_CONFIG34 */ 3038c2ecf20Sopenharmony_ci#define LINK_ON_WAKE_EN 0x0010 3048c2ecf20Sopenharmony_ci#define LINK_OFF_WAKE_EN 0x0008 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* PLA_CONFIG6 */ 3078c2ecf20Sopenharmony_ci#define LANWAKE_CLR_EN BIT(0) 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* PLA_CONFIG5 */ 3108c2ecf20Sopenharmony_ci#define BWF_EN 0x0040 3118c2ecf20Sopenharmony_ci#define MWF_EN 0x0020 3128c2ecf20Sopenharmony_ci#define UWF_EN 0x0010 3138c2ecf20Sopenharmony_ci#define LAN_WAKE_EN 0x0002 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* PLA_LED_FEATURE */ 3168c2ecf20Sopenharmony_ci#define LED_MODE_MASK 0x0700 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/* PLA_PHY_PWR */ 3198c2ecf20Sopenharmony_ci#define TX_10M_IDLE_EN 0x0080 3208c2ecf20Sopenharmony_ci#define PFM_PWM_SWITCH 0x0040 3218c2ecf20Sopenharmony_ci#define TEST_IO_OFF BIT(4) 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* PLA_MAC_PWR_CTRL */ 3248c2ecf20Sopenharmony_ci#define D3_CLK_GATED_EN 0x00004000 3258c2ecf20Sopenharmony_ci#define MCU_CLK_RATIO 0x07010f07 3268c2ecf20Sopenharmony_ci#define MCU_CLK_RATIO_MASK 0x0f0f0f0f 3278c2ecf20Sopenharmony_ci#define ALDPS_SPDWN_RATIO 0x0f87 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* PLA_MAC_PWR_CTRL2 */ 3308c2ecf20Sopenharmony_ci#define EEE_SPDWN_RATIO 0x8007 3318c2ecf20Sopenharmony_ci#define MAC_CLK_SPDWN_EN BIT(15) 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* PLA_MAC_PWR_CTRL3 */ 3348c2ecf20Sopenharmony_ci#define PLA_MCU_SPDWN_EN BIT(14) 3358c2ecf20Sopenharmony_ci#define PKT_AVAIL_SPDWN_EN 0x0100 3368c2ecf20Sopenharmony_ci#define SUSPEND_SPDWN_EN 0x0004 3378c2ecf20Sopenharmony_ci#define U1U2_SPDWN_EN 0x0002 3388c2ecf20Sopenharmony_ci#define L1_SPDWN_EN 0x0001 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* PLA_MAC_PWR_CTRL4 */ 3418c2ecf20Sopenharmony_ci#define PWRSAVE_SPDWN_EN 0x1000 3428c2ecf20Sopenharmony_ci#define RXDV_SPDWN_EN 0x0800 3438c2ecf20Sopenharmony_ci#define TX10MIDLE_EN 0x0100 3448c2ecf20Sopenharmony_ci#define TP100_SPDWN_EN 0x0020 3458c2ecf20Sopenharmony_ci#define TP500_SPDWN_EN 0x0010 3468c2ecf20Sopenharmony_ci#define TP1000_SPDWN_EN 0x0008 3478c2ecf20Sopenharmony_ci#define EEE_SPDWN_EN 0x0001 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* PLA_GPHY_INTR_IMR */ 3508c2ecf20Sopenharmony_ci#define GPHY_STS_MSK 0x0001 3518c2ecf20Sopenharmony_ci#define SPEED_DOWN_MSK 0x0002 3528c2ecf20Sopenharmony_ci#define SPDWN_RXDV_MSK 0x0004 3538c2ecf20Sopenharmony_ci#define SPDWN_LINKCHG_MSK 0x0008 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/* PLA_PHYAR */ 3568c2ecf20Sopenharmony_ci#define PHYAR_FLAG 0x80000000 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* PLA_EEE_CR */ 3598c2ecf20Sopenharmony_ci#define EEE_RX_EN 0x0001 3608c2ecf20Sopenharmony_ci#define EEE_TX_EN 0x0002 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* PLA_BOOT_CTRL */ 3638c2ecf20Sopenharmony_ci#define AUTOLOAD_DONE 0x0002 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/* PLA_LWAKE_CTRL_REG */ 3668c2ecf20Sopenharmony_ci#define LANWAKE_PIN BIT(7) 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* PLA_SUSPEND_FLAG */ 3698c2ecf20Sopenharmony_ci#define LINK_CHG_EVENT BIT(0) 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/* PLA_INDICATE_FALG */ 3728c2ecf20Sopenharmony_ci#define UPCOMING_RUNTIME_D3 BIT(0) 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/* PLA_MACDBG_PRE and PLA_MACDBG_POST */ 3758c2ecf20Sopenharmony_ci#define DEBUG_OE BIT(0) 3768c2ecf20Sopenharmony_ci#define DEBUG_LTSSM 0x0082 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/* PLA_EXTRA_STATUS */ 3798c2ecf20Sopenharmony_ci#define CUR_LINK_OK BIT(15) 3808c2ecf20Sopenharmony_ci#define U3P3_CHECK_EN BIT(7) /* RTL_VER_05 only */ 3818c2ecf20Sopenharmony_ci#define LINK_CHANGE_FLAG BIT(8) 3828c2ecf20Sopenharmony_ci#define POLL_LINK_CHG BIT(0) 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/* USB_USB2PHY */ 3858c2ecf20Sopenharmony_ci#define USB2PHY_SUSPEND 0x0001 3868c2ecf20Sopenharmony_ci#define USB2PHY_L1 0x0002 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* USB_SSPHYLINK1 */ 3898c2ecf20Sopenharmony_ci#define DELAY_PHY_PWR_CHG BIT(1) 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/* USB_SSPHYLINK2 */ 3928c2ecf20Sopenharmony_ci#define pwd_dn_scale_mask 0x3ffe 3938c2ecf20Sopenharmony_ci#define pwd_dn_scale(x) ((x) << 1) 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* USB_CSR_DUMMY1 */ 3968c2ecf20Sopenharmony_ci#define DYNAMIC_BURST 0x0001 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/* USB_CSR_DUMMY2 */ 3998c2ecf20Sopenharmony_ci#define EP4_FULL_FC 0x0001 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* USB_DEV_STAT */ 4028c2ecf20Sopenharmony_ci#define STAT_SPEED_MASK 0x0006 4038c2ecf20Sopenharmony_ci#define STAT_SPEED_HIGH 0x0000 4048c2ecf20Sopenharmony_ci#define STAT_SPEED_FULL 0x0002 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/* USB_FW_FIX_EN0 */ 4078c2ecf20Sopenharmony_ci#define FW_FIX_SUSPEND BIT(14) 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* USB_FW_FIX_EN1 */ 4108c2ecf20Sopenharmony_ci#define FW_IP_RESET_EN BIT(9) 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/* USB_LPM_CONFIG */ 4138c2ecf20Sopenharmony_ci#define LPM_U1U2_EN BIT(0) 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/* USB_TX_AGG */ 4168c2ecf20Sopenharmony_ci#define TX_AGG_MAX_THRESHOLD 0x03 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* USB_RX_BUF_TH */ 4198c2ecf20Sopenharmony_ci#define RX_THR_SUPPER 0x0c350180 4208c2ecf20Sopenharmony_ci#define RX_THR_HIGH 0x7a120180 4218c2ecf20Sopenharmony_ci#define RX_THR_SLOW 0xffff0180 4228c2ecf20Sopenharmony_ci#define RX_THR_B 0x00010001 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* USB_TX_DMA */ 4258c2ecf20Sopenharmony_ci#define TEST_MODE_DISABLE 0x00000001 4268c2ecf20Sopenharmony_ci#define TX_SIZE_ADJUST1 0x00000100 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* USB_BMU_RESET */ 4298c2ecf20Sopenharmony_ci#define BMU_RESET_EP_IN 0x01 4308c2ecf20Sopenharmony_ci#define BMU_RESET_EP_OUT 0x02 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/* USB_UPT_RXDMA_OWN */ 4338c2ecf20Sopenharmony_ci#define OWN_UPDATE BIT(0) 4348c2ecf20Sopenharmony_ci#define OWN_CLEAR BIT(1) 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/* USB_FW_TASK */ 4378c2ecf20Sopenharmony_ci#define FC_PATCH_TASK BIT(1) 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* USB_UPS_CTRL */ 4408c2ecf20Sopenharmony_ci#define POWER_CUT 0x0100 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/* USB_PM_CTRL_STATUS */ 4438c2ecf20Sopenharmony_ci#define RESUME_INDICATE 0x0001 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* USB_CSTMR */ 4468c2ecf20Sopenharmony_ci#define FORCE_SUPER BIT(0) 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* USB_FW_CTRL */ 4498c2ecf20Sopenharmony_ci#define FLOW_CTRL_PATCH_OPT BIT(1) 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci/* USB_FC_TIMER */ 4528c2ecf20Sopenharmony_ci#define CTRL_TIMER_EN BIT(15) 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* USB_USB_CTRL */ 4558c2ecf20Sopenharmony_ci#define RX_AGG_DISABLE 0x0010 4568c2ecf20Sopenharmony_ci#define RX_ZERO_EN 0x0080 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* USB_U2P3_CTRL */ 4598c2ecf20Sopenharmony_ci#define U2P3_ENABLE 0x0001 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/* USB_POWER_CUT */ 4628c2ecf20Sopenharmony_ci#define PWR_EN 0x0001 4638c2ecf20Sopenharmony_ci#define PHASE2_EN 0x0008 4648c2ecf20Sopenharmony_ci#define UPS_EN BIT(4) 4658c2ecf20Sopenharmony_ci#define USP_PREWAKE BIT(5) 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/* USB_MISC_0 */ 4688c2ecf20Sopenharmony_ci#define PCUT_STATUS 0x0001 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci/* USB_RX_EARLY_TIMEOUT */ 4718c2ecf20Sopenharmony_ci#define COALESCE_SUPER 85000U 4728c2ecf20Sopenharmony_ci#define COALESCE_HIGH 250000U 4738c2ecf20Sopenharmony_ci#define COALESCE_SLOW 524280U 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* USB_WDT1_CTRL */ 4768c2ecf20Sopenharmony_ci#define WTD1_EN BIT(0) 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* USB_WDT11_CTRL */ 4798c2ecf20Sopenharmony_ci#define TIMER11_EN 0x0001 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* USB_LPM_CTRL */ 4828c2ecf20Sopenharmony_ci/* bit 4 ~ 5: fifo empty boundary */ 4838c2ecf20Sopenharmony_ci#define FIFO_EMPTY_1FB 0x30 /* 0x1fb * 64 = 32448 bytes */ 4848c2ecf20Sopenharmony_ci/* bit 2 ~ 3: LMP timer */ 4858c2ecf20Sopenharmony_ci#define LPM_TIMER_MASK 0x0c 4868c2ecf20Sopenharmony_ci#define LPM_TIMER_500MS 0x04 /* 500 ms */ 4878c2ecf20Sopenharmony_ci#define LPM_TIMER_500US 0x0c /* 500 us */ 4888c2ecf20Sopenharmony_ci#define ROK_EXIT_LPM 0x02 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* USB_AFE_CTRL2 */ 4918c2ecf20Sopenharmony_ci#define SEN_VAL_MASK 0xf800 4928c2ecf20Sopenharmony_ci#define SEN_VAL_NORMAL 0xa000 4938c2ecf20Sopenharmony_ci#define SEL_RXIDLE 0x0100 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* USB_UPS_CFG */ 4968c2ecf20Sopenharmony_ci#define SAW_CNT_1MS_MASK 0x0fff 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/* USB_UPS_FLAGS */ 4998c2ecf20Sopenharmony_ci#define UPS_FLAGS_R_TUNE BIT(0) 5008c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_10M_CKDIV BIT(1) 5018c2ecf20Sopenharmony_ci#define UPS_FLAGS_250M_CKDIV BIT(2) 5028c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_ALDPS BIT(3) 5038c2ecf20Sopenharmony_ci#define UPS_FLAGS_CTAP_SHORT_DIS BIT(4) 5048c2ecf20Sopenharmony_ci#define ups_flags_speed(x) ((x) << 16) 5058c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_EEE BIT(20) 5068c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_500M_EEE BIT(21) 5078c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_EEE_CKDIV BIT(22) 5088c2ecf20Sopenharmony_ci#define UPS_FLAGS_EEE_PLLOFF_100 BIT(23) 5098c2ecf20Sopenharmony_ci#define UPS_FLAGS_EEE_PLLOFF_GIGA BIT(24) 5108c2ecf20Sopenharmony_ci#define UPS_FLAGS_EEE_CMOD_LV_EN BIT(25) 5118c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_GREEN BIT(26) 5128c2ecf20Sopenharmony_ci#define UPS_FLAGS_EN_FLOW_CTR BIT(27) 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cienum spd_duplex { 5158c2ecf20Sopenharmony_ci NWAY_10M_HALF, 5168c2ecf20Sopenharmony_ci NWAY_10M_FULL, 5178c2ecf20Sopenharmony_ci NWAY_100M_HALF, 5188c2ecf20Sopenharmony_ci NWAY_100M_FULL, 5198c2ecf20Sopenharmony_ci NWAY_1000M_FULL, 5208c2ecf20Sopenharmony_ci FORCE_10M_HALF, 5218c2ecf20Sopenharmony_ci FORCE_10M_FULL, 5228c2ecf20Sopenharmony_ci FORCE_100M_HALF, 5238c2ecf20Sopenharmony_ci FORCE_100M_FULL, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/* OCP_ALDPS_CONFIG */ 5278c2ecf20Sopenharmony_ci#define ENPWRSAVE 0x8000 5288c2ecf20Sopenharmony_ci#define ENPDNPS 0x0200 5298c2ecf20Sopenharmony_ci#define LINKENA 0x0100 5308c2ecf20Sopenharmony_ci#define DIS_SDSAVE 0x0010 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* OCP_PHY_STATUS */ 5338c2ecf20Sopenharmony_ci#define PHY_STAT_MASK 0x0007 5348c2ecf20Sopenharmony_ci#define PHY_STAT_EXT_INIT 2 5358c2ecf20Sopenharmony_ci#define PHY_STAT_LAN_ON 3 5368c2ecf20Sopenharmony_ci#define PHY_STAT_PWRDN 5 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* OCP_NCTL_CFG */ 5398c2ecf20Sopenharmony_ci#define PGA_RETURN_EN BIT(1) 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* OCP_POWER_CFG */ 5428c2ecf20Sopenharmony_ci#define EEE_CLKDIV_EN 0x8000 5438c2ecf20Sopenharmony_ci#define EN_ALDPS 0x0004 5448c2ecf20Sopenharmony_ci#define EN_10M_PLLOFF 0x0001 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci/* OCP_EEE_CONFIG1 */ 5478c2ecf20Sopenharmony_ci#define RG_TXLPI_MSK_HFDUP 0x8000 5488c2ecf20Sopenharmony_ci#define RG_MATCLR_EN 0x4000 5498c2ecf20Sopenharmony_ci#define EEE_10_CAP 0x2000 5508c2ecf20Sopenharmony_ci#define EEE_NWAY_EN 0x1000 5518c2ecf20Sopenharmony_ci#define TX_QUIET_EN 0x0200 5528c2ecf20Sopenharmony_ci#define RX_QUIET_EN 0x0100 5538c2ecf20Sopenharmony_ci#define sd_rise_time_mask 0x0070 5548c2ecf20Sopenharmony_ci#define sd_rise_time(x) (min(x, 7) << 4) /* bit 4 ~ 6 */ 5558c2ecf20Sopenharmony_ci#define RG_RXLPI_MSK_HFDUP 0x0008 5568c2ecf20Sopenharmony_ci#define SDFALLTIME 0x0007 /* bit 0 ~ 2 */ 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/* OCP_EEE_CONFIG2 */ 5598c2ecf20Sopenharmony_ci#define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */ 5608c2ecf20Sopenharmony_ci#define RG_DACQUIET_EN 0x0400 5618c2ecf20Sopenharmony_ci#define RG_LDVQUIET_EN 0x0200 5628c2ecf20Sopenharmony_ci#define RG_CKRSEL 0x0020 5638c2ecf20Sopenharmony_ci#define RG_EEEPRG_EN 0x0010 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/* OCP_EEE_CONFIG3 */ 5668c2ecf20Sopenharmony_ci#define fast_snr_mask 0xff80 5678c2ecf20Sopenharmony_ci#define fast_snr(x) (min(x, 0x1ff) << 7) /* bit 7 ~ 15 */ 5688c2ecf20Sopenharmony_ci#define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */ 5698c2ecf20Sopenharmony_ci#define MSK_PH 0x0006 /* bit 0 ~ 3 */ 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* OCP_EEE_AR */ 5728c2ecf20Sopenharmony_ci/* bit[15:14] function */ 5738c2ecf20Sopenharmony_ci#define FUN_ADDR 0x0000 5748c2ecf20Sopenharmony_ci#define FUN_DATA 0x4000 5758c2ecf20Sopenharmony_ci/* bit[4:0] device addr */ 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* OCP_EEE_CFG */ 5788c2ecf20Sopenharmony_ci#define CTAP_SHORT_EN 0x0040 5798c2ecf20Sopenharmony_ci#define EEE10_EN 0x0010 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/* OCP_DOWN_SPEED */ 5828c2ecf20Sopenharmony_ci#define EN_EEE_CMODE BIT(14) 5838c2ecf20Sopenharmony_ci#define EN_EEE_1000 BIT(13) 5848c2ecf20Sopenharmony_ci#define EN_EEE_100 BIT(12) 5858c2ecf20Sopenharmony_ci#define EN_10M_CLKDIV BIT(11) 5868c2ecf20Sopenharmony_ci#define EN_10M_BGOFF 0x0080 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/* OCP_PHY_STATE */ 5898c2ecf20Sopenharmony_ci#define TXDIS_STATE 0x01 5908c2ecf20Sopenharmony_ci#define ABD_STATE 0x02 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/* OCP_PHY_PATCH_STAT */ 5938c2ecf20Sopenharmony_ci#define PATCH_READY BIT(6) 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci/* OCP_PHY_PATCH_CMD */ 5968c2ecf20Sopenharmony_ci#define PATCH_REQUEST BIT(4) 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* OCP_PHY_LOCK */ 5998c2ecf20Sopenharmony_ci#define PATCH_LOCK BIT(0) 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* OCP_ADC_CFG */ 6028c2ecf20Sopenharmony_ci#define CKADSEL_L 0x0100 6038c2ecf20Sopenharmony_ci#define ADC_EN 0x0080 6048c2ecf20Sopenharmony_ci#define EN_EMI_L 0x0040 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/* OCP_SYSCLK_CFG */ 6078c2ecf20Sopenharmony_ci#define clk_div_expo(x) (min(x, 5) << 8) 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/* SRAM_GREEN_CFG */ 6108c2ecf20Sopenharmony_ci#define GREEN_ETH_EN BIT(15) 6118c2ecf20Sopenharmony_ci#define R_TUNE_EN BIT(11) 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* SRAM_LPF_CFG */ 6148c2ecf20Sopenharmony_ci#define LPF_AUTO_TUNE 0x8000 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci/* SRAM_10M_AMP1 */ 6178c2ecf20Sopenharmony_ci#define GDAC_IB_UPALL 0x0008 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* SRAM_10M_AMP2 */ 6208c2ecf20Sopenharmony_ci#define AMP_DN 0x0200 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* SRAM_IMPEDANCE */ 6238c2ecf20Sopenharmony_ci#define RX_DRIVING_MASK 0x6000 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/* SRAM_PHY_LOCK */ 6268c2ecf20Sopenharmony_ci#define PHY_PATCH_LOCK 0x0001 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/* MAC PASSTHRU */ 6298c2ecf20Sopenharmony_ci#define AD_MASK 0xfee0 6308c2ecf20Sopenharmony_ci#define BND_MASK 0x0004 6318c2ecf20Sopenharmony_ci#define BD_MASK 0x0001 6328c2ecf20Sopenharmony_ci#define EFUSE 0xcfdb 6338c2ecf20Sopenharmony_ci#define PASS_THRU_MASK 0x1 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci#define BP4_SUPER_ONLY 0x1578 /* RTL_VER_04 only */ 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cienum rtl_register_content { 6388c2ecf20Sopenharmony_ci _1000bps = 0x10, 6398c2ecf20Sopenharmony_ci _100bps = 0x08, 6408c2ecf20Sopenharmony_ci _10bps = 0x04, 6418c2ecf20Sopenharmony_ci LINK_STATUS = 0x02, 6428c2ecf20Sopenharmony_ci FULL_DUP = 0x01, 6438c2ecf20Sopenharmony_ci}; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci#define RTL8152_MAX_TX 4 6468c2ecf20Sopenharmony_ci#define RTL8152_MAX_RX 10 6478c2ecf20Sopenharmony_ci#define INTBUFSIZE 2 6488c2ecf20Sopenharmony_ci#define TX_ALIGN 4 6498c2ecf20Sopenharmony_ci#define RX_ALIGN 8 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci#define RTL8152_RX_MAX_PENDING 4096 6528c2ecf20Sopenharmony_ci#define RTL8152_RXFG_HEADSZ 256 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci#define INTR_LINK 0x0004 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci#define RTL8152_REQT_READ 0xc0 6578c2ecf20Sopenharmony_ci#define RTL8152_REQT_WRITE 0x40 6588c2ecf20Sopenharmony_ci#define RTL8152_REQ_GET_REGS 0x05 6598c2ecf20Sopenharmony_ci#define RTL8152_REQ_SET_REGS 0x05 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci#define BYTE_EN_DWORD 0xff 6628c2ecf20Sopenharmony_ci#define BYTE_EN_WORD 0x33 6638c2ecf20Sopenharmony_ci#define BYTE_EN_BYTE 0x11 6648c2ecf20Sopenharmony_ci#define BYTE_EN_SIX_BYTES 0x3f 6658c2ecf20Sopenharmony_ci#define BYTE_EN_START_MASK 0x0f 6668c2ecf20Sopenharmony_ci#define BYTE_EN_END_MASK 0xf0 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci#define RTL8153_MAX_PACKET 9216 /* 9K */ 6698c2ecf20Sopenharmony_ci#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - \ 6708c2ecf20Sopenharmony_ci ETH_FCS_LEN) 6718c2ecf20Sopenharmony_ci#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) 6728c2ecf20Sopenharmony_ci#define RTL8153_RMS RTL8153_MAX_PACKET 6738c2ecf20Sopenharmony_ci#define RTL8152_TX_TIMEOUT (5 * HZ) 6748c2ecf20Sopenharmony_ci#define RTL8152_NAPI_WEIGHT 64 6758c2ecf20Sopenharmony_ci#define rx_reserved_size(x) ((x) + VLAN_ETH_HLEN + ETH_FCS_LEN + \ 6768c2ecf20Sopenharmony_ci sizeof(struct rx_desc) + RX_ALIGN) 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/* rtl8152 flags */ 6798c2ecf20Sopenharmony_cienum rtl8152_flags { 6808c2ecf20Sopenharmony_ci RTL8152_UNPLUG = 0, 6818c2ecf20Sopenharmony_ci RTL8152_SET_RX_MODE, 6828c2ecf20Sopenharmony_ci WORK_ENABLE, 6838c2ecf20Sopenharmony_ci RTL8152_LINK_CHG, 6848c2ecf20Sopenharmony_ci SELECTIVE_SUSPEND, 6858c2ecf20Sopenharmony_ci PHY_RESET, 6868c2ecf20Sopenharmony_ci SCHEDULE_TASKLET, 6878c2ecf20Sopenharmony_ci GREEN_ETHERNET, 6888c2ecf20Sopenharmony_ci DELL_TB_RX_AGG_BUG, 6898c2ecf20Sopenharmony_ci LENOVO_MACPASSTHRU, 6908c2ecf20Sopenharmony_ci}; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* Define these values to match your device */ 6938c2ecf20Sopenharmony_ci#define VENDOR_ID_REALTEK 0x0bda 6948c2ecf20Sopenharmony_ci#define VENDOR_ID_MICROSOFT 0x045e 6958c2ecf20Sopenharmony_ci#define VENDOR_ID_SAMSUNG 0x04e8 6968c2ecf20Sopenharmony_ci#define VENDOR_ID_LENOVO 0x17ef 6978c2ecf20Sopenharmony_ci#define VENDOR_ID_LINKSYS 0x13b1 6988c2ecf20Sopenharmony_ci#define VENDOR_ID_NVIDIA 0x0955 6998c2ecf20Sopenharmony_ci#define VENDOR_ID_TPLINK 0x2357 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci#define DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2 0x3082 7028c2ecf20Sopenharmony_ci#define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2 0xa387 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci#define MCU_TYPE_PLA 0x0100 7058c2ecf20Sopenharmony_ci#define MCU_TYPE_USB 0x0000 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistruct tally_counter { 7088c2ecf20Sopenharmony_ci __le64 tx_packets; 7098c2ecf20Sopenharmony_ci __le64 rx_packets; 7108c2ecf20Sopenharmony_ci __le64 tx_errors; 7118c2ecf20Sopenharmony_ci __le32 rx_errors; 7128c2ecf20Sopenharmony_ci __le16 rx_missed; 7138c2ecf20Sopenharmony_ci __le16 align_errors; 7148c2ecf20Sopenharmony_ci __le32 tx_one_collision; 7158c2ecf20Sopenharmony_ci __le32 tx_multi_collision; 7168c2ecf20Sopenharmony_ci __le64 rx_unicast; 7178c2ecf20Sopenharmony_ci __le64 rx_broadcast; 7188c2ecf20Sopenharmony_ci __le32 rx_multicast; 7198c2ecf20Sopenharmony_ci __le16 tx_aborted; 7208c2ecf20Sopenharmony_ci __le16 tx_underrun; 7218c2ecf20Sopenharmony_ci}; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistruct rx_desc { 7248c2ecf20Sopenharmony_ci __le32 opts1; 7258c2ecf20Sopenharmony_ci#define RX_LEN_MASK 0x7fff 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci __le32 opts2; 7288c2ecf20Sopenharmony_ci#define RD_UDP_CS BIT(23) 7298c2ecf20Sopenharmony_ci#define RD_TCP_CS BIT(22) 7308c2ecf20Sopenharmony_ci#define RD_IPV6_CS BIT(20) 7318c2ecf20Sopenharmony_ci#define RD_IPV4_CS BIT(19) 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci __le32 opts3; 7348c2ecf20Sopenharmony_ci#define IPF BIT(23) /* IP checksum fail */ 7358c2ecf20Sopenharmony_ci#define UDPF BIT(22) /* UDP checksum fail */ 7368c2ecf20Sopenharmony_ci#define TCPF BIT(21) /* TCP checksum fail */ 7378c2ecf20Sopenharmony_ci#define RX_VLAN_TAG BIT(16) 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci __le32 opts4; 7408c2ecf20Sopenharmony_ci __le32 opts5; 7418c2ecf20Sopenharmony_ci __le32 opts6; 7428c2ecf20Sopenharmony_ci}; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistruct tx_desc { 7458c2ecf20Sopenharmony_ci __le32 opts1; 7468c2ecf20Sopenharmony_ci#define TX_FS BIT(31) /* First segment of a packet */ 7478c2ecf20Sopenharmony_ci#define TX_LS BIT(30) /* Final segment of a packet */ 7488c2ecf20Sopenharmony_ci#define GTSENDV4 BIT(28) 7498c2ecf20Sopenharmony_ci#define GTSENDV6 BIT(27) 7508c2ecf20Sopenharmony_ci#define GTTCPHO_SHIFT 18 7518c2ecf20Sopenharmony_ci#define GTTCPHO_MAX 0x7fU 7528c2ecf20Sopenharmony_ci#define TX_LEN_MAX 0x3ffffU 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci __le32 opts2; 7558c2ecf20Sopenharmony_ci#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */ 7568c2ecf20Sopenharmony_ci#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */ 7578c2ecf20Sopenharmony_ci#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */ 7588c2ecf20Sopenharmony_ci#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */ 7598c2ecf20Sopenharmony_ci#define MSS_SHIFT 17 7608c2ecf20Sopenharmony_ci#define MSS_MAX 0x7ffU 7618c2ecf20Sopenharmony_ci#define TCPHO_SHIFT 17 7628c2ecf20Sopenharmony_ci#define TCPHO_MAX 0x7ffU 7638c2ecf20Sopenharmony_ci#define TX_VLAN_TAG BIT(16) 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistruct r8152; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistruct rx_agg { 7698c2ecf20Sopenharmony_ci struct list_head list, info_list; 7708c2ecf20Sopenharmony_ci struct urb *urb; 7718c2ecf20Sopenharmony_ci struct r8152 *context; 7728c2ecf20Sopenharmony_ci struct page *page; 7738c2ecf20Sopenharmony_ci void *buffer; 7748c2ecf20Sopenharmony_ci}; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistruct tx_agg { 7778c2ecf20Sopenharmony_ci struct list_head list; 7788c2ecf20Sopenharmony_ci struct urb *urb; 7798c2ecf20Sopenharmony_ci struct r8152 *context; 7808c2ecf20Sopenharmony_ci void *buffer; 7818c2ecf20Sopenharmony_ci void *head; 7828c2ecf20Sopenharmony_ci u32 skb_num; 7838c2ecf20Sopenharmony_ci u32 skb_len; 7848c2ecf20Sopenharmony_ci}; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistruct r8152 { 7878c2ecf20Sopenharmony_ci unsigned long flags; 7888c2ecf20Sopenharmony_ci struct usb_device *udev; 7898c2ecf20Sopenharmony_ci struct napi_struct napi; 7908c2ecf20Sopenharmony_ci struct usb_interface *intf; 7918c2ecf20Sopenharmony_ci struct net_device *netdev; 7928c2ecf20Sopenharmony_ci struct urb *intr_urb; 7938c2ecf20Sopenharmony_ci struct tx_agg tx_info[RTL8152_MAX_TX]; 7948c2ecf20Sopenharmony_ci struct list_head rx_info, rx_used; 7958c2ecf20Sopenharmony_ci struct list_head rx_done, tx_free; 7968c2ecf20Sopenharmony_ci struct sk_buff_head tx_queue, rx_queue; 7978c2ecf20Sopenharmony_ci spinlock_t rx_lock, tx_lock; 7988c2ecf20Sopenharmony_ci struct delayed_work schedule, hw_phy_work; 7998c2ecf20Sopenharmony_ci struct mii_if_info mii; 8008c2ecf20Sopenharmony_ci struct mutex control; /* use for hw setting */ 8018c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8028c2ecf20Sopenharmony_ci struct notifier_block pm_notifier; 8038c2ecf20Sopenharmony_ci#endif 8048c2ecf20Sopenharmony_ci struct tasklet_struct tx_tl; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci struct rtl_ops { 8078c2ecf20Sopenharmony_ci void (*init)(struct r8152 *tp); 8088c2ecf20Sopenharmony_ci int (*enable)(struct r8152 *tp); 8098c2ecf20Sopenharmony_ci void (*disable)(struct r8152 *tp); 8108c2ecf20Sopenharmony_ci void (*up)(struct r8152 *tp); 8118c2ecf20Sopenharmony_ci void (*down)(struct r8152 *tp); 8128c2ecf20Sopenharmony_ci void (*unload)(struct r8152 *tp); 8138c2ecf20Sopenharmony_ci int (*eee_get)(struct r8152 *tp, struct ethtool_eee *eee); 8148c2ecf20Sopenharmony_ci int (*eee_set)(struct r8152 *tp, struct ethtool_eee *eee); 8158c2ecf20Sopenharmony_ci bool (*in_nway)(struct r8152 *tp); 8168c2ecf20Sopenharmony_ci void (*hw_phy_cfg)(struct r8152 *tp); 8178c2ecf20Sopenharmony_ci void (*autosuspend_en)(struct r8152 *tp, bool enable); 8188c2ecf20Sopenharmony_ci } rtl_ops; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci struct ups_info { 8218c2ecf20Sopenharmony_ci u32 _10m_ckdiv:1; 8228c2ecf20Sopenharmony_ci u32 _250m_ckdiv:1; 8238c2ecf20Sopenharmony_ci u32 aldps:1; 8248c2ecf20Sopenharmony_ci u32 lite_mode:2; 8258c2ecf20Sopenharmony_ci u32 speed_duplex:4; 8268c2ecf20Sopenharmony_ci u32 eee:1; 8278c2ecf20Sopenharmony_ci u32 eee_lite:1; 8288c2ecf20Sopenharmony_ci u32 eee_ckdiv:1; 8298c2ecf20Sopenharmony_ci u32 eee_plloff_100:1; 8308c2ecf20Sopenharmony_ci u32 eee_plloff_giga:1; 8318c2ecf20Sopenharmony_ci u32 eee_cmod_lv:1; 8328c2ecf20Sopenharmony_ci u32 green:1; 8338c2ecf20Sopenharmony_ci u32 flow_control:1; 8348c2ecf20Sopenharmony_ci u32 ctap_short_off:1; 8358c2ecf20Sopenharmony_ci } ups_info; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci#define RTL_VER_SIZE 32 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci struct rtl_fw { 8408c2ecf20Sopenharmony_ci const char *fw_name; 8418c2ecf20Sopenharmony_ci const struct firmware *fw; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci char version[RTL_VER_SIZE]; 8448c2ecf20Sopenharmony_ci int (*pre_fw)(struct r8152 *tp); 8458c2ecf20Sopenharmony_ci int (*post_fw)(struct r8152 *tp); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci bool retry; 8488c2ecf20Sopenharmony_ci } rtl_fw; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci atomic_t rx_count; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci bool eee_en; 8538c2ecf20Sopenharmony_ci int intr_interval; 8548c2ecf20Sopenharmony_ci u32 saved_wolopts; 8558c2ecf20Sopenharmony_ci u32 msg_enable; 8568c2ecf20Sopenharmony_ci u32 tx_qlen; 8578c2ecf20Sopenharmony_ci u32 coalesce; 8588c2ecf20Sopenharmony_ci u32 advertising; 8598c2ecf20Sopenharmony_ci u32 rx_buf_sz; 8608c2ecf20Sopenharmony_ci u32 rx_copybreak; 8618c2ecf20Sopenharmony_ci u32 rx_pending; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci u16 ocp_base; 8648c2ecf20Sopenharmony_ci u16 speed; 8658c2ecf20Sopenharmony_ci u16 eee_adv; 8668c2ecf20Sopenharmony_ci u8 *intr_buff; 8678c2ecf20Sopenharmony_ci u8 version; 8688c2ecf20Sopenharmony_ci u8 duplex; 8698c2ecf20Sopenharmony_ci u8 autoneg; 8708c2ecf20Sopenharmony_ci}; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci/** 8738c2ecf20Sopenharmony_ci * struct fw_block - block type and total length 8748c2ecf20Sopenharmony_ci * @type: type of the current block, such as RTL_FW_END, RTL_FW_PLA, 8758c2ecf20Sopenharmony_ci * RTL_FW_USB and so on. 8768c2ecf20Sopenharmony_ci * @length: total length of the current block. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_cistruct fw_block { 8798c2ecf20Sopenharmony_ci __le32 type; 8808c2ecf20Sopenharmony_ci __le32 length; 8818c2ecf20Sopenharmony_ci} __packed; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/** 8848c2ecf20Sopenharmony_ci * struct fw_header - header of the firmware file 8858c2ecf20Sopenharmony_ci * @checksum: checksum of sha256 which is calculated from the whole file 8868c2ecf20Sopenharmony_ci * except the checksum field of the file. That is, calculate sha256 8878c2ecf20Sopenharmony_ci * from the version field to the end of the file. 8888c2ecf20Sopenharmony_ci * @version: version of this firmware. 8898c2ecf20Sopenharmony_ci * @blocks: the first firmware block of the file 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_cistruct fw_header { 8928c2ecf20Sopenharmony_ci u8 checksum[32]; 8938c2ecf20Sopenharmony_ci char version[RTL_VER_SIZE]; 8948c2ecf20Sopenharmony_ci struct fw_block blocks[]; 8958c2ecf20Sopenharmony_ci} __packed; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/** 8988c2ecf20Sopenharmony_ci * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB. 8998c2ecf20Sopenharmony_ci * The layout of the firmware block is: 9008c2ecf20Sopenharmony_ci * <struct fw_mac> + <info> + <firmware data>. 9018c2ecf20Sopenharmony_ci * @fw_offset: offset of the firmware binary data. The start address of 9028c2ecf20Sopenharmony_ci * the data would be the address of struct fw_mac + @fw_offset. 9038c2ecf20Sopenharmony_ci * @fw_reg: the register to load the firmware. Depends on chip. 9048c2ecf20Sopenharmony_ci * @bp_ba_addr: the register to write break point base address. Depends on 9058c2ecf20Sopenharmony_ci * chip. 9068c2ecf20Sopenharmony_ci * @bp_ba_value: break point base address. Depends on chip. 9078c2ecf20Sopenharmony_ci * @bp_en_addr: the register to write break point enabled mask. Depends 9088c2ecf20Sopenharmony_ci * on chip. 9098c2ecf20Sopenharmony_ci * @bp_en_value: break point enabled mask. Depends on the firmware. 9108c2ecf20Sopenharmony_ci * @bp_start: the start register of break points. Depends on chip. 9118c2ecf20Sopenharmony_ci * @bp_num: the break point number which needs to be set for this firmware. 9128c2ecf20Sopenharmony_ci * Depends on the firmware. 9138c2ecf20Sopenharmony_ci * @bp: break points. Depends on firmware. 9148c2ecf20Sopenharmony_ci * @fw_ver_reg: the register to store the fw version. 9158c2ecf20Sopenharmony_ci * @fw_ver_data: the firmware version of the current type. 9168c2ecf20Sopenharmony_ci * @info: additional information for debugging, and is followed by the 9178c2ecf20Sopenharmony_ci * binary data of firmware. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_cistruct fw_mac { 9208c2ecf20Sopenharmony_ci struct fw_block blk_hdr; 9218c2ecf20Sopenharmony_ci __le16 fw_offset; 9228c2ecf20Sopenharmony_ci __le16 fw_reg; 9238c2ecf20Sopenharmony_ci __le16 bp_ba_addr; 9248c2ecf20Sopenharmony_ci __le16 bp_ba_value; 9258c2ecf20Sopenharmony_ci __le16 bp_en_addr; 9268c2ecf20Sopenharmony_ci __le16 bp_en_value; 9278c2ecf20Sopenharmony_ci __le16 bp_start; 9288c2ecf20Sopenharmony_ci __le16 bp_num; 9298c2ecf20Sopenharmony_ci __le16 bp[16]; /* any value determined by firmware */ 9308c2ecf20Sopenharmony_ci __le32 reserved; 9318c2ecf20Sopenharmony_ci __le16 fw_ver_reg; 9328c2ecf20Sopenharmony_ci u8 fw_ver_data; 9338c2ecf20Sopenharmony_ci char info[]; 9348c2ecf20Sopenharmony_ci} __packed; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/** 9378c2ecf20Sopenharmony_ci * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START. 9388c2ecf20Sopenharmony_ci * This is used to set patch key when loading the firmware of PHY. 9398c2ecf20Sopenharmony_ci * @key_reg: the register to write the patch key. 9408c2ecf20Sopenharmony_ci * @key_data: patch key. 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_cistruct fw_phy_patch_key { 9438c2ecf20Sopenharmony_ci struct fw_block blk_hdr; 9448c2ecf20Sopenharmony_ci __le16 key_reg; 9458c2ecf20Sopenharmony_ci __le16 key_data; 9468c2ecf20Sopenharmony_ci __le32 reserved; 9478c2ecf20Sopenharmony_ci} __packed; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci/** 9508c2ecf20Sopenharmony_ci * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC. 9518c2ecf20Sopenharmony_ci * The layout of the firmware block is: 9528c2ecf20Sopenharmony_ci * <struct fw_phy_nc> + <info> + <firmware data>. 9538c2ecf20Sopenharmony_ci * @fw_offset: offset of the firmware binary data. The start address of 9548c2ecf20Sopenharmony_ci * the data would be the address of struct fw_phy_nc + @fw_offset. 9558c2ecf20Sopenharmony_ci * @fw_reg: the register to load the firmware. Depends on chip. 9568c2ecf20Sopenharmony_ci * @ba_reg: the register to write the base address. Depends on chip. 9578c2ecf20Sopenharmony_ci * @ba_data: base address. Depends on chip. 9588c2ecf20Sopenharmony_ci * @patch_en_addr: the register of enabling patch mode. Depends on chip. 9598c2ecf20Sopenharmony_ci * @patch_en_value: patch mode enabled mask. Depends on the firmware. 9608c2ecf20Sopenharmony_ci * @mode_reg: the regitster of switching the mode. 9618c2ecf20Sopenharmony_ci * @mod_pre: the mode needing to be set before loading the firmware. 9628c2ecf20Sopenharmony_ci * @mod_post: the mode to be set when finishing to load the firmware. 9638c2ecf20Sopenharmony_ci * @bp_start: the start register of break points. Depends on chip. 9648c2ecf20Sopenharmony_ci * @bp_num: the break point number which needs to be set for this firmware. 9658c2ecf20Sopenharmony_ci * Depends on the firmware. 9668c2ecf20Sopenharmony_ci * @bp: break points. Depends on firmware. 9678c2ecf20Sopenharmony_ci * @info: additional information for debugging, and is followed by the 9688c2ecf20Sopenharmony_ci * binary data of firmware. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_cistruct fw_phy_nc { 9718c2ecf20Sopenharmony_ci struct fw_block blk_hdr; 9728c2ecf20Sopenharmony_ci __le16 fw_offset; 9738c2ecf20Sopenharmony_ci __le16 fw_reg; 9748c2ecf20Sopenharmony_ci __le16 ba_reg; 9758c2ecf20Sopenharmony_ci __le16 ba_data; 9768c2ecf20Sopenharmony_ci __le16 patch_en_addr; 9778c2ecf20Sopenharmony_ci __le16 patch_en_value; 9788c2ecf20Sopenharmony_ci __le16 mode_reg; 9798c2ecf20Sopenharmony_ci __le16 mode_pre; 9808c2ecf20Sopenharmony_ci __le16 mode_post; 9818c2ecf20Sopenharmony_ci __le16 reserved; 9828c2ecf20Sopenharmony_ci __le16 bp_start; 9838c2ecf20Sopenharmony_ci __le16 bp_num; 9848c2ecf20Sopenharmony_ci __le16 bp[4]; 9858c2ecf20Sopenharmony_ci char info[]; 9868c2ecf20Sopenharmony_ci} __packed; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cienum rtl_fw_type { 9898c2ecf20Sopenharmony_ci RTL_FW_END = 0, 9908c2ecf20Sopenharmony_ci RTL_FW_PLA, 9918c2ecf20Sopenharmony_ci RTL_FW_USB, 9928c2ecf20Sopenharmony_ci RTL_FW_PHY_START, 9938c2ecf20Sopenharmony_ci RTL_FW_PHY_STOP, 9948c2ecf20Sopenharmony_ci RTL_FW_PHY_NC, 9958c2ecf20Sopenharmony_ci}; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cienum rtl_version { 9988c2ecf20Sopenharmony_ci RTL_VER_UNKNOWN = 0, 9998c2ecf20Sopenharmony_ci RTL_VER_01, 10008c2ecf20Sopenharmony_ci RTL_VER_02, 10018c2ecf20Sopenharmony_ci RTL_VER_03, 10028c2ecf20Sopenharmony_ci RTL_VER_04, 10038c2ecf20Sopenharmony_ci RTL_VER_05, 10048c2ecf20Sopenharmony_ci RTL_VER_06, 10058c2ecf20Sopenharmony_ci RTL_VER_07, 10068c2ecf20Sopenharmony_ci RTL_VER_08, 10078c2ecf20Sopenharmony_ci RTL_VER_09, 10088c2ecf20Sopenharmony_ci RTL_VER_MAX 10098c2ecf20Sopenharmony_ci}; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cienum tx_csum_stat { 10128c2ecf20Sopenharmony_ci TX_CSUM_SUCCESS = 0, 10138c2ecf20Sopenharmony_ci TX_CSUM_TSO, 10148c2ecf20Sopenharmony_ci TX_CSUM_NONE 10158c2ecf20Sopenharmony_ci}; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_10_HALF BIT(0) 10188c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_10_FULL BIT(1) 10198c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_100_HALF BIT(2) 10208c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_100_FULL BIT(3) 10218c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_1000_HALF BIT(4) 10228c2ecf20Sopenharmony_ci#define RTL_ADVERTISED_1000_FULL BIT(5) 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). 10258c2ecf20Sopenharmony_ci * The RTL chips use a 64 element hash table based on the Ethernet CRC. 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_cistatic const int multicast_filter_limit = 32; 10288c2ecf20Sopenharmony_cistatic unsigned int agg_buf_sz = 16384; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci#define RTL_LIMITED_TSO_SIZE (agg_buf_sz - sizeof(struct tx_desc) - \ 10318c2ecf20Sopenharmony_ci VLAN_ETH_HLEN - ETH_FCS_LEN) 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic 10348c2ecf20Sopenharmony_ciint get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci int ret; 10378c2ecf20Sopenharmony_ci void *tmp; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci tmp = kmalloc(size, GFP_KERNEL); 10408c2ecf20Sopenharmony_ci if (!tmp) 10418c2ecf20Sopenharmony_ci return -ENOMEM; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), 10448c2ecf20Sopenharmony_ci RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, 10458c2ecf20Sopenharmony_ci value, index, tmp, size, USB_CTRL_GET_TIMEOUT); 10468c2ecf20Sopenharmony_ci if (ret < 0) 10478c2ecf20Sopenharmony_ci memset(data, 0xff, size); 10488c2ecf20Sopenharmony_ci else 10498c2ecf20Sopenharmony_ci memcpy(data, tmp, size); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci kfree(tmp); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return ret; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic 10578c2ecf20Sopenharmony_ciint set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci int ret; 10608c2ecf20Sopenharmony_ci void *tmp; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci tmp = kmemdup(data, size, GFP_KERNEL); 10638c2ecf20Sopenharmony_ci if (!tmp) 10648c2ecf20Sopenharmony_ci return -ENOMEM; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), 10678c2ecf20Sopenharmony_ci RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, 10688c2ecf20Sopenharmony_ci value, index, tmp, size, USB_CTRL_SET_TIMEOUT); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci kfree(tmp); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return ret; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic void rtl_set_unplug(struct r8152 *tp) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci if (tp->udev->state == USB_STATE_NOTATTACHED) { 10788c2ecf20Sopenharmony_ci set_bit(RTL8152_UNPLUG, &tp->flags); 10798c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, 10848c2ecf20Sopenharmony_ci void *data, u16 type) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci u16 limit = 64; 10878c2ecf20Sopenharmony_ci int ret = 0; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 10908c2ecf20Sopenharmony_ci return -ENODEV; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* both size and indix must be 4 bytes align */ 10938c2ecf20Sopenharmony_ci if ((size & 3) || !size || (index & 3) || !data) 10948c2ecf20Sopenharmony_ci return -EPERM; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if ((u32)index + (u32)size > 0xffff) 10978c2ecf20Sopenharmony_ci return -EPERM; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci while (size) { 11008c2ecf20Sopenharmony_ci if (size > limit) { 11018c2ecf20Sopenharmony_ci ret = get_registers(tp, index, type, limit, data); 11028c2ecf20Sopenharmony_ci if (ret < 0) 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci index += limit; 11068c2ecf20Sopenharmony_ci data += limit; 11078c2ecf20Sopenharmony_ci size -= limit; 11088c2ecf20Sopenharmony_ci } else { 11098c2ecf20Sopenharmony_ci ret = get_registers(tp, index, type, size, data); 11108c2ecf20Sopenharmony_ci if (ret < 0) 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci index += size; 11148c2ecf20Sopenharmony_ci data += size; 11158c2ecf20Sopenharmony_ci size = 0; 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (ret == -ENODEV) 11218c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci return ret; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen, 11278c2ecf20Sopenharmony_ci u16 size, void *data, u16 type) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci int ret; 11308c2ecf20Sopenharmony_ci u16 byteen_start, byteen_end, byen; 11318c2ecf20Sopenharmony_ci u16 limit = 512; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 11348c2ecf20Sopenharmony_ci return -ENODEV; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* both size and indix must be 4 bytes align */ 11378c2ecf20Sopenharmony_ci if ((size & 3) || !size || (index & 3) || !data) 11388c2ecf20Sopenharmony_ci return -EPERM; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if ((u32)index + (u32)size > 0xffff) 11418c2ecf20Sopenharmony_ci return -EPERM; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci byteen_start = byteen & BYTE_EN_START_MASK; 11448c2ecf20Sopenharmony_ci byteen_end = byteen & BYTE_EN_END_MASK; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci byen = byteen_start | (byteen_start << 4); 11478c2ecf20Sopenharmony_ci ret = set_registers(tp, index, type | byen, 4, data); 11488c2ecf20Sopenharmony_ci if (ret < 0) 11498c2ecf20Sopenharmony_ci goto error1; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci index += 4; 11528c2ecf20Sopenharmony_ci data += 4; 11538c2ecf20Sopenharmony_ci size -= 4; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (size) { 11568c2ecf20Sopenharmony_ci size -= 4; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci while (size) { 11598c2ecf20Sopenharmony_ci if (size > limit) { 11608c2ecf20Sopenharmony_ci ret = set_registers(tp, index, 11618c2ecf20Sopenharmony_ci type | BYTE_EN_DWORD, 11628c2ecf20Sopenharmony_ci limit, data); 11638c2ecf20Sopenharmony_ci if (ret < 0) 11648c2ecf20Sopenharmony_ci goto error1; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci index += limit; 11678c2ecf20Sopenharmony_ci data += limit; 11688c2ecf20Sopenharmony_ci size -= limit; 11698c2ecf20Sopenharmony_ci } else { 11708c2ecf20Sopenharmony_ci ret = set_registers(tp, index, 11718c2ecf20Sopenharmony_ci type | BYTE_EN_DWORD, 11728c2ecf20Sopenharmony_ci size, data); 11738c2ecf20Sopenharmony_ci if (ret < 0) 11748c2ecf20Sopenharmony_ci goto error1; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci index += size; 11778c2ecf20Sopenharmony_ci data += size; 11788c2ecf20Sopenharmony_ci size = 0; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci byen = byteen_end | (byteen_end >> 4); 11848c2ecf20Sopenharmony_ci ret = set_registers(tp, index, type | byen, 4, data); 11858c2ecf20Sopenharmony_ci if (ret < 0) 11868c2ecf20Sopenharmony_ci goto error1; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cierror1: 11908c2ecf20Sopenharmony_ci if (ret == -ENODEV) 11918c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return ret; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic inline 11978c2ecf20Sopenharmony_ciint pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic inline 12038c2ecf20Sopenharmony_ciint pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA); 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic inline 12098c2ecf20Sopenharmony_ciint usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB); 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci __le32 data; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci generic_ocp_read(tp, index, sizeof(data), &data, type); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return __le32_to_cpu(data); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci __le32 tmp = __cpu_to_le32(data); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci u32 data; 12338c2ecf20Sopenharmony_ci __le32 tmp; 12348c2ecf20Sopenharmony_ci u16 byen = BYTE_EN_WORD; 12358c2ecf20Sopenharmony_ci u8 shift = index & 2; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci index &= ~3; 12388c2ecf20Sopenharmony_ci byen <<= shift; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci data = __le32_to_cpu(tmp); 12438c2ecf20Sopenharmony_ci data >>= (shift * 8); 12448c2ecf20Sopenharmony_ci data &= 0xffff; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return (u16)data; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci u32 mask = 0xffff; 12528c2ecf20Sopenharmony_ci __le32 tmp; 12538c2ecf20Sopenharmony_ci u16 byen = BYTE_EN_WORD; 12548c2ecf20Sopenharmony_ci u8 shift = index & 2; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci data &= mask; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (index & 2) { 12598c2ecf20Sopenharmony_ci byen <<= shift; 12608c2ecf20Sopenharmony_ci mask <<= (shift * 8); 12618c2ecf20Sopenharmony_ci data <<= (shift * 8); 12628c2ecf20Sopenharmony_ci index &= ~3; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci tmp = __cpu_to_le32(data); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci u32 data; 12738c2ecf20Sopenharmony_ci __le32 tmp; 12748c2ecf20Sopenharmony_ci u8 shift = index & 3; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci index &= ~3; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci data = __le32_to_cpu(tmp); 12818c2ecf20Sopenharmony_ci data >>= (shift * 8); 12828c2ecf20Sopenharmony_ci data &= 0xff; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return (u8)data; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci u32 mask = 0xff; 12908c2ecf20Sopenharmony_ci __le32 tmp; 12918c2ecf20Sopenharmony_ci u16 byen = BYTE_EN_BYTE; 12928c2ecf20Sopenharmony_ci u8 shift = index & 3; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci data &= mask; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (index & 3) { 12978c2ecf20Sopenharmony_ci byen <<= shift; 12988c2ecf20Sopenharmony_ci mask <<= (shift * 8); 12998c2ecf20Sopenharmony_ci data <<= (shift * 8); 13008c2ecf20Sopenharmony_ci index &= ~3; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci tmp = __cpu_to_le32(data); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic u16 ocp_reg_read(struct r8152 *tp, u16 addr) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci u16 ocp_base, ocp_index; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci ocp_base = addr & 0xf000; 13138c2ecf20Sopenharmony_ci if (ocp_base != tp->ocp_base) { 13148c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); 13158c2ecf20Sopenharmony_ci tp->ocp_base = ocp_base; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci ocp_index = (addr & 0x0fff) | 0xb000; 13198c2ecf20Sopenharmony_ci return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index); 13208c2ecf20Sopenharmony_ci} 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistatic void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci u16 ocp_base, ocp_index; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci ocp_base = addr & 0xf000; 13278c2ecf20Sopenharmony_ci if (ocp_base != tp->ocp_base) { 13288c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); 13298c2ecf20Sopenharmony_ci tp->ocp_base = ocp_base; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci ocp_index = (addr & 0x0fff) | 0xb000; 13338c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2); 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic void sram_write(struct r8152 *tp, u16 addr, u16 data) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SRAM_ADDR, addr); 13498c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SRAM_DATA, data); 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic u16 sram_read(struct r8152 *tp, u16 addr) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SRAM_ADDR, addr); 13558c2ecf20Sopenharmony_ci return ocp_reg_read(tp, OCP_SRAM_DATA); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int read_mii_word(struct net_device *netdev, int phy_id, int reg) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 13618c2ecf20Sopenharmony_ci int ret; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 13648c2ecf20Sopenharmony_ci return -ENODEV; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (phy_id != R8152_PHY_ID) 13678c2ecf20Sopenharmony_ci return -EINVAL; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci ret = r8152_mdio_read(tp, reg); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return ret; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic 13758c2ecf20Sopenharmony_civoid write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 13808c2ecf20Sopenharmony_ci return; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (phy_id != R8152_PHY_ID) 13838c2ecf20Sopenharmony_ci return; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci r8152_mdio_write(tp, reg, val); 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic int 13898c2ecf20Sopenharmony_cir8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic int rtl8152_set_mac_address(struct net_device *netdev, void *p) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 13948c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 13958c2ecf20Sopenharmony_ci int ret = -EADDRNOTAVAIL; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 13988c2ecf20Sopenharmony_ci goto out1; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 14018c2ecf20Sopenharmony_ci if (ret < 0) 14028c2ecf20Sopenharmony_ci goto out1; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); 14098c2ecf20Sopenharmony_ci pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data); 14108c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 14158c2ecf20Sopenharmony_ciout1: 14168c2ecf20Sopenharmony_ci return ret; 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci/* Devices containing proper chips can support a persistent 14208c2ecf20Sopenharmony_ci * host system provided MAC address. 14218c2ecf20Sopenharmony_ci * Examples of this are Dell TB15 and Dell WD15 docks 14228c2ecf20Sopenharmony_ci */ 14238c2ecf20Sopenharmony_cistatic int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci acpi_status status; 14268c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 14278c2ecf20Sopenharmony_ci union acpi_object *obj; 14288c2ecf20Sopenharmony_ci int ret = -EINVAL; 14298c2ecf20Sopenharmony_ci u32 ocp_data; 14308c2ecf20Sopenharmony_ci unsigned char buf[6]; 14318c2ecf20Sopenharmony_ci char *mac_obj_name; 14328c2ecf20Sopenharmony_ci acpi_object_type mac_obj_type; 14338c2ecf20Sopenharmony_ci int mac_strlen; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (test_bit(LENOVO_MACPASSTHRU, &tp->flags)) { 14368c2ecf20Sopenharmony_ci mac_obj_name = "\\MACA"; 14378c2ecf20Sopenharmony_ci mac_obj_type = ACPI_TYPE_STRING; 14388c2ecf20Sopenharmony_ci mac_strlen = 0x16; 14398c2ecf20Sopenharmony_ci } else { 14408c2ecf20Sopenharmony_ci /* test for -AD variant of RTL8153 */ 14418c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); 14428c2ecf20Sopenharmony_ci if ((ocp_data & AD_MASK) == 0x1000) { 14438c2ecf20Sopenharmony_ci /* test for MAC address pass-through bit */ 14448c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); 14458c2ecf20Sopenharmony_ci if ((ocp_data & PASS_THRU_MASK) != 1) { 14468c2ecf20Sopenharmony_ci netif_dbg(tp, probe, tp->netdev, 14478c2ecf20Sopenharmony_ci "No efuse for RTL8153-AD MAC pass through\n"); 14488c2ecf20Sopenharmony_ci return -ENODEV; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci } else { 14518c2ecf20Sopenharmony_ci /* test for RTL8153-BND and RTL8153-BD */ 14528c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); 14538c2ecf20Sopenharmony_ci if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) { 14548c2ecf20Sopenharmony_ci netif_dbg(tp, probe, tp->netdev, 14558c2ecf20Sopenharmony_ci "Invalid variant for MAC pass through\n"); 14568c2ecf20Sopenharmony_ci return -ENODEV; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci mac_obj_name = "\\_SB.AMAC"; 14618c2ecf20Sopenharmony_ci mac_obj_type = ACPI_TYPE_BUFFER; 14628c2ecf20Sopenharmony_ci mac_strlen = 0x17; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* returns _AUXMAC_#AABBCCDDEEFF# */ 14668c2ecf20Sopenharmony_ci status = acpi_evaluate_object(NULL, mac_obj_name, NULL, &buffer); 14678c2ecf20Sopenharmony_ci obj = (union acpi_object *)buffer.pointer; 14688c2ecf20Sopenharmony_ci if (!ACPI_SUCCESS(status)) 14698c2ecf20Sopenharmony_ci return -ENODEV; 14708c2ecf20Sopenharmony_ci if (obj->type != mac_obj_type || obj->string.length != mac_strlen) { 14718c2ecf20Sopenharmony_ci netif_warn(tp, probe, tp->netdev, 14728c2ecf20Sopenharmony_ci "Invalid buffer for pass-thru MAC addr: (%d, %d)\n", 14738c2ecf20Sopenharmony_ci obj->type, obj->string.length); 14748c2ecf20Sopenharmony_ci goto amacout; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 || 14788c2ecf20Sopenharmony_ci strncmp(obj->string.pointer + 0x15, "#", 1) != 0) { 14798c2ecf20Sopenharmony_ci netif_warn(tp, probe, tp->netdev, 14808c2ecf20Sopenharmony_ci "Invalid header when reading pass-thru MAC addr\n"); 14818c2ecf20Sopenharmony_ci goto amacout; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci ret = hex2bin(buf, obj->string.pointer + 9, 6); 14848c2ecf20Sopenharmony_ci if (!(ret == 0 && is_valid_ether_addr(buf))) { 14858c2ecf20Sopenharmony_ci netif_warn(tp, probe, tp->netdev, 14868c2ecf20Sopenharmony_ci "Invalid MAC for pass-thru MAC addr: %d, %pM\n", 14878c2ecf20Sopenharmony_ci ret, buf); 14888c2ecf20Sopenharmony_ci ret = -EINVAL; 14898c2ecf20Sopenharmony_ci goto amacout; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci memcpy(sa->sa_data, buf, 6); 14928c2ecf20Sopenharmony_ci netif_info(tp, probe, tp->netdev, 14938c2ecf20Sopenharmony_ci "Using pass-thru MAC addr %pM\n", sa->sa_data); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ciamacout: 14968c2ecf20Sopenharmony_ci kfree(obj); 14978c2ecf20Sopenharmony_ci return ret; 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_cistatic int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci struct net_device *dev = tp->netdev; 15038c2ecf20Sopenharmony_ci int ret; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci sa->sa_family = dev->type; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci ret = eth_platform_get_mac_address(&tp->udev->dev, sa->sa_data); 15088c2ecf20Sopenharmony_ci if (ret < 0) { 15098c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_01) { 15108c2ecf20Sopenharmony_ci ret = pla_ocp_read(tp, PLA_IDR, 8, sa->sa_data); 15118c2ecf20Sopenharmony_ci } else { 15128c2ecf20Sopenharmony_ci /* if device doesn't support MAC pass through this will 15138c2ecf20Sopenharmony_ci * be expected to be non-zero 15148c2ecf20Sopenharmony_ci */ 15158c2ecf20Sopenharmony_ci ret = vendor_mac_passthru_addr_read(tp, sa); 15168c2ecf20Sopenharmony_ci if (ret < 0) 15178c2ecf20Sopenharmony_ci ret = pla_ocp_read(tp, PLA_BACKUP, 8, 15188c2ecf20Sopenharmony_ci sa->sa_data); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (ret < 0) { 15238c2ecf20Sopenharmony_ci netif_err(tp, probe, dev, "Get ether addr fail\n"); 15248c2ecf20Sopenharmony_ci } else if (!is_valid_ether_addr(sa->sa_data)) { 15258c2ecf20Sopenharmony_ci netif_err(tp, probe, dev, "Invalid ether addr %pM\n", 15268c2ecf20Sopenharmony_ci sa->sa_data); 15278c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 15288c2ecf20Sopenharmony_ci ether_addr_copy(sa->sa_data, dev->dev_addr); 15298c2ecf20Sopenharmony_ci netif_info(tp, probe, dev, "Random ether addr %pM\n", 15308c2ecf20Sopenharmony_ci sa->sa_data); 15318c2ecf20Sopenharmony_ci return 0; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci return ret; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic int set_ethernet_addr(struct r8152 *tp) 15388c2ecf20Sopenharmony_ci{ 15398c2ecf20Sopenharmony_ci struct net_device *dev = tp->netdev; 15408c2ecf20Sopenharmony_ci struct sockaddr sa; 15418c2ecf20Sopenharmony_ci int ret; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci ret = determine_ethernet_addr(tp, &sa); 15448c2ecf20Sopenharmony_ci if (ret < 0) 15458c2ecf20Sopenharmony_ci return ret; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_01) 15488c2ecf20Sopenharmony_ci ether_addr_copy(dev->dev_addr, sa.sa_data); 15498c2ecf20Sopenharmony_ci else 15508c2ecf20Sopenharmony_ci ret = rtl8152_set_mac_address(dev, &sa); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return ret; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_cistatic void read_bulk_callback(struct urb *urb) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct net_device *netdev; 15588c2ecf20Sopenharmony_ci int status = urb->status; 15598c2ecf20Sopenharmony_ci struct rx_agg *agg; 15608c2ecf20Sopenharmony_ci struct r8152 *tp; 15618c2ecf20Sopenharmony_ci unsigned long flags; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci agg = urb->context; 15648c2ecf20Sopenharmony_ci if (!agg) 15658c2ecf20Sopenharmony_ci return; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci tp = agg->context; 15688c2ecf20Sopenharmony_ci if (!tp) 15698c2ecf20Sopenharmony_ci return; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 15728c2ecf20Sopenharmony_ci return; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (!test_bit(WORK_ENABLE, &tp->flags)) 15758c2ecf20Sopenharmony_ci return; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci netdev = tp->netdev; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* When link down, the driver would cancel all bulks. */ 15808c2ecf20Sopenharmony_ci /* This avoid the re-submitting bulk */ 15818c2ecf20Sopenharmony_ci if (!netif_carrier_ok(netdev)) 15828c2ecf20Sopenharmony_ci return; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci usb_mark_last_busy(tp->udev); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci switch (status) { 15878c2ecf20Sopenharmony_ci case 0: 15888c2ecf20Sopenharmony_ci if (urb->actual_length < ETH_ZLEN) 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 15928c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->rx_done); 15938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 15948c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 15958c2ecf20Sopenharmony_ci return; 15968c2ecf20Sopenharmony_ci case -ESHUTDOWN: 15978c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 15988c2ecf20Sopenharmony_ci netif_device_detach(tp->netdev); 15998c2ecf20Sopenharmony_ci return; 16008c2ecf20Sopenharmony_ci case -ENOENT: 16018c2ecf20Sopenharmony_ci return; /* the urb is in unlink state */ 16028c2ecf20Sopenharmony_ci case -ETIME: 16038c2ecf20Sopenharmony_ci if (net_ratelimit()) 16048c2ecf20Sopenharmony_ci netdev_warn(netdev, "maybe reset is needed?\n"); 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci default: 16078c2ecf20Sopenharmony_ci if (net_ratelimit()) 16088c2ecf20Sopenharmony_ci netdev_warn(netdev, "Rx status %d\n", status); 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci r8152_submit_rx(tp, agg, GFP_ATOMIC); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic void write_bulk_callback(struct urb *urb) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct net_device_stats *stats; 16188c2ecf20Sopenharmony_ci struct net_device *netdev; 16198c2ecf20Sopenharmony_ci struct tx_agg *agg; 16208c2ecf20Sopenharmony_ci struct r8152 *tp; 16218c2ecf20Sopenharmony_ci unsigned long flags; 16228c2ecf20Sopenharmony_ci int status = urb->status; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci agg = urb->context; 16258c2ecf20Sopenharmony_ci if (!agg) 16268c2ecf20Sopenharmony_ci return; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci tp = agg->context; 16298c2ecf20Sopenharmony_ci if (!tp) 16308c2ecf20Sopenharmony_ci return; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci netdev = tp->netdev; 16338c2ecf20Sopenharmony_ci stats = &netdev->stats; 16348c2ecf20Sopenharmony_ci if (status) { 16358c2ecf20Sopenharmony_ci if (net_ratelimit()) 16368c2ecf20Sopenharmony_ci netdev_warn(netdev, "Tx status %d\n", status); 16378c2ecf20Sopenharmony_ci stats->tx_errors += agg->skb_num; 16388c2ecf20Sopenharmony_ci } else { 16398c2ecf20Sopenharmony_ci stats->tx_packets += agg->skb_num; 16408c2ecf20Sopenharmony_ci stats->tx_bytes += agg->skb_len; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->tx_lock, flags); 16448c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->tx_free); 16458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->tx_lock, flags); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(tp->intf); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (!netif_carrier_ok(netdev)) 16508c2ecf20Sopenharmony_ci return; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (!test_bit(WORK_ENABLE, &tp->flags)) 16538c2ecf20Sopenharmony_ci return; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 16568c2ecf20Sopenharmony_ci return; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (!skb_queue_empty(&tp->tx_queue)) 16598c2ecf20Sopenharmony_ci tasklet_schedule(&tp->tx_tl); 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cistatic void intr_callback(struct urb *urb) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci struct r8152 *tp; 16658c2ecf20Sopenharmony_ci __le16 *d; 16668c2ecf20Sopenharmony_ci int status = urb->status; 16678c2ecf20Sopenharmony_ci int res; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci tp = urb->context; 16708c2ecf20Sopenharmony_ci if (!tp) 16718c2ecf20Sopenharmony_ci return; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (!test_bit(WORK_ENABLE, &tp->flags)) 16748c2ecf20Sopenharmony_ci return; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 16778c2ecf20Sopenharmony_ci return; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci switch (status) { 16808c2ecf20Sopenharmony_ci case 0: /* success */ 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci case -ECONNRESET: /* unlink */ 16838c2ecf20Sopenharmony_ci case -ESHUTDOWN: 16848c2ecf20Sopenharmony_ci netif_device_detach(tp->netdev); 16858c2ecf20Sopenharmony_ci fallthrough; 16868c2ecf20Sopenharmony_ci case -ENOENT: 16878c2ecf20Sopenharmony_ci case -EPROTO: 16888c2ecf20Sopenharmony_ci netif_info(tp, intr, tp->netdev, 16898c2ecf20Sopenharmony_ci "Stop submitting intr, status %d\n", status); 16908c2ecf20Sopenharmony_ci return; 16918c2ecf20Sopenharmony_ci case -EOVERFLOW: 16928c2ecf20Sopenharmony_ci if (net_ratelimit()) 16938c2ecf20Sopenharmony_ci netif_info(tp, intr, tp->netdev, 16948c2ecf20Sopenharmony_ci "intr status -EOVERFLOW\n"); 16958c2ecf20Sopenharmony_ci goto resubmit; 16968c2ecf20Sopenharmony_ci /* -EPIPE: should clear the halt */ 16978c2ecf20Sopenharmony_ci default: 16988c2ecf20Sopenharmony_ci netif_info(tp, intr, tp->netdev, "intr status %d\n", status); 16998c2ecf20Sopenharmony_ci goto resubmit; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci d = urb->transfer_buffer; 17038c2ecf20Sopenharmony_ci if (INTR_LINK & __le16_to_cpu(d[0])) { 17048c2ecf20Sopenharmony_ci if (!netif_carrier_ok(tp->netdev)) { 17058c2ecf20Sopenharmony_ci set_bit(RTL8152_LINK_CHG, &tp->flags); 17068c2ecf20Sopenharmony_ci schedule_delayed_work(&tp->schedule, 0); 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci } else { 17098c2ecf20Sopenharmony_ci if (netif_carrier_ok(tp->netdev)) { 17108c2ecf20Sopenharmony_ci netif_stop_queue(tp->netdev); 17118c2ecf20Sopenharmony_ci set_bit(RTL8152_LINK_CHG, &tp->flags); 17128c2ecf20Sopenharmony_ci schedule_delayed_work(&tp->schedule, 0); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ciresubmit: 17178c2ecf20Sopenharmony_ci res = usb_submit_urb(urb, GFP_ATOMIC); 17188c2ecf20Sopenharmony_ci if (res == -ENODEV) { 17198c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 17208c2ecf20Sopenharmony_ci netif_device_detach(tp->netdev); 17218c2ecf20Sopenharmony_ci } else if (res) { 17228c2ecf20Sopenharmony_ci netif_err(tp, intr, tp->netdev, 17238c2ecf20Sopenharmony_ci "can't resubmit intr, status %d\n", res); 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic inline void *rx_agg_align(void *data) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci return (void *)ALIGN((uintptr_t)data, RX_ALIGN); 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic inline void *tx_agg_align(void *data) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci return (void *)ALIGN((uintptr_t)data, TX_ALIGN); 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic void free_rx_agg(struct r8152 *tp, struct rx_agg *agg) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci list_del(&agg->info_list); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci usb_free_urb(agg->urb); 17428c2ecf20Sopenharmony_ci put_page(agg->page); 17438c2ecf20Sopenharmony_ci kfree(agg); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci atomic_dec(&tp->rx_count); 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 17518c2ecf20Sopenharmony_ci int node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1; 17528c2ecf20Sopenharmony_ci unsigned int order = get_order(tp->rx_buf_sz); 17538c2ecf20Sopenharmony_ci struct rx_agg *rx_agg; 17548c2ecf20Sopenharmony_ci unsigned long flags; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci rx_agg = kmalloc_node(sizeof(*rx_agg), mflags, node); 17578c2ecf20Sopenharmony_ci if (!rx_agg) 17588c2ecf20Sopenharmony_ci return NULL; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci rx_agg->page = alloc_pages(mflags | __GFP_COMP, order); 17618c2ecf20Sopenharmony_ci if (!rx_agg->page) 17628c2ecf20Sopenharmony_ci goto free_rx; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci rx_agg->buffer = page_address(rx_agg->page); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci rx_agg->urb = usb_alloc_urb(0, mflags); 17678c2ecf20Sopenharmony_ci if (!rx_agg->urb) 17688c2ecf20Sopenharmony_ci goto free_buf; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci rx_agg->context = tp; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rx_agg->list); 17738c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rx_agg->info_list); 17748c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 17758c2ecf20Sopenharmony_ci list_add_tail(&rx_agg->info_list, &tp->rx_info); 17768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci atomic_inc(&tp->rx_count); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return rx_agg; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_cifree_buf: 17838c2ecf20Sopenharmony_ci __free_pages(rx_agg->page, order); 17848c2ecf20Sopenharmony_cifree_rx: 17858c2ecf20Sopenharmony_ci kfree(rx_agg); 17868c2ecf20Sopenharmony_ci return NULL; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_cistatic void free_all_mem(struct r8152 *tp) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci struct rx_agg *agg, *agg_next; 17928c2ecf20Sopenharmony_ci unsigned long flags; 17938c2ecf20Sopenharmony_ci int i; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci list_for_each_entry_safe(agg, agg_next, &tp->rx_info, info_list) 17988c2ecf20Sopenharmony_ci free_rx_agg(tp, agg); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci WARN_ON(atomic_read(&tp->rx_count)); 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci for (i = 0; i < RTL8152_MAX_TX; i++) { 18058c2ecf20Sopenharmony_ci usb_free_urb(tp->tx_info[i].urb); 18068c2ecf20Sopenharmony_ci tp->tx_info[i].urb = NULL; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci kfree(tp->tx_info[i].buffer); 18098c2ecf20Sopenharmony_ci tp->tx_info[i].buffer = NULL; 18108c2ecf20Sopenharmony_ci tp->tx_info[i].head = NULL; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci usb_free_urb(tp->intr_urb); 18148c2ecf20Sopenharmony_ci tp->intr_urb = NULL; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci kfree(tp->intr_buff); 18178c2ecf20Sopenharmony_ci tp->intr_buff = NULL; 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic int alloc_all_mem(struct r8152 *tp) 18218c2ecf20Sopenharmony_ci{ 18228c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 18238c2ecf20Sopenharmony_ci struct usb_interface *intf = tp->intf; 18248c2ecf20Sopenharmony_ci struct usb_host_interface *alt = intf->cur_altsetting; 18258c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep_intr = alt->endpoint + 2; 18268c2ecf20Sopenharmony_ci int node, i; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci spin_lock_init(&tp->rx_lock); 18318c2ecf20Sopenharmony_ci spin_lock_init(&tp->tx_lock); 18328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->rx_info); 18338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->tx_free); 18348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->rx_done); 18358c2ecf20Sopenharmony_ci skb_queue_head_init(&tp->tx_queue); 18368c2ecf20Sopenharmony_ci skb_queue_head_init(&tp->rx_queue); 18378c2ecf20Sopenharmony_ci atomic_set(&tp->rx_count, 0); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci for (i = 0; i < RTL8152_MAX_RX; i++) { 18408c2ecf20Sopenharmony_ci if (!alloc_rx_agg(tp, GFP_KERNEL)) 18418c2ecf20Sopenharmony_ci goto err1; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci for (i = 0; i < RTL8152_MAX_TX; i++) { 18458c2ecf20Sopenharmony_ci struct urb *urb; 18468c2ecf20Sopenharmony_ci u8 *buf; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); 18498c2ecf20Sopenharmony_ci if (!buf) 18508c2ecf20Sopenharmony_ci goto err1; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (buf != tx_agg_align(buf)) { 18538c2ecf20Sopenharmony_ci kfree(buf); 18548c2ecf20Sopenharmony_ci buf = kmalloc_node(agg_buf_sz + TX_ALIGN, GFP_KERNEL, 18558c2ecf20Sopenharmony_ci node); 18568c2ecf20Sopenharmony_ci if (!buf) 18578c2ecf20Sopenharmony_ci goto err1; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 18618c2ecf20Sopenharmony_ci if (!urb) { 18628c2ecf20Sopenharmony_ci kfree(buf); 18638c2ecf20Sopenharmony_ci goto err1; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->tx_info[i].list); 18678c2ecf20Sopenharmony_ci tp->tx_info[i].context = tp; 18688c2ecf20Sopenharmony_ci tp->tx_info[i].urb = urb; 18698c2ecf20Sopenharmony_ci tp->tx_info[i].buffer = buf; 18708c2ecf20Sopenharmony_ci tp->tx_info[i].head = tx_agg_align(buf); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci list_add_tail(&tp->tx_info[i].list, &tp->tx_free); 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL); 18768c2ecf20Sopenharmony_ci if (!tp->intr_urb) 18778c2ecf20Sopenharmony_ci goto err1; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); 18808c2ecf20Sopenharmony_ci if (!tp->intr_buff) 18818c2ecf20Sopenharmony_ci goto err1; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci tp->intr_interval = (int)ep_intr->desc.bInterval; 18848c2ecf20Sopenharmony_ci usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3), 18858c2ecf20Sopenharmony_ci tp->intr_buff, INTBUFSIZE, intr_callback, 18868c2ecf20Sopenharmony_ci tp, tp->intr_interval); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci return 0; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cierr1: 18918c2ecf20Sopenharmony_ci free_all_mem(tp); 18928c2ecf20Sopenharmony_ci return -ENOMEM; 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_cistatic struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct tx_agg *agg = NULL; 18988c2ecf20Sopenharmony_ci unsigned long flags; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci if (list_empty(&tp->tx_free)) 19018c2ecf20Sopenharmony_ci return NULL; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->tx_lock, flags); 19048c2ecf20Sopenharmony_ci if (!list_empty(&tp->tx_free)) { 19058c2ecf20Sopenharmony_ci struct list_head *cursor; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci cursor = tp->tx_free.next; 19088c2ecf20Sopenharmony_ci list_del_init(cursor); 19098c2ecf20Sopenharmony_ci agg = list_entry(cursor, struct tx_agg, list); 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->tx_lock, flags); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci return agg; 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci/* r8152_csum_workaround() 19178c2ecf20Sopenharmony_ci * The hw limits the value of the transport offset. When the offset is out of 19188c2ecf20Sopenharmony_ci * range, calculate the checksum by sw. 19198c2ecf20Sopenharmony_ci */ 19208c2ecf20Sopenharmony_cistatic void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, 19218c2ecf20Sopenharmony_ci struct sk_buff_head *list) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 19248c2ecf20Sopenharmony_ci netdev_features_t features = tp->netdev->features; 19258c2ecf20Sopenharmony_ci struct sk_buff *segs, *seg, *next; 19268c2ecf20Sopenharmony_ci struct sk_buff_head seg_list; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); 19298c2ecf20Sopenharmony_ci segs = skb_gso_segment(skb, features); 19308c2ecf20Sopenharmony_ci if (IS_ERR(segs) || !segs) 19318c2ecf20Sopenharmony_ci goto drop; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci __skb_queue_head_init(&seg_list); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci skb_list_walk_safe(segs, seg, next) { 19368c2ecf20Sopenharmony_ci skb_mark_not_on_list(seg); 19378c2ecf20Sopenharmony_ci __skb_queue_tail(&seg_list, seg); 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci skb_queue_splice(&seg_list, list); 19418c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 19428c2ecf20Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 19438c2ecf20Sopenharmony_ci if (skb_checksum_help(skb) < 0) 19448c2ecf20Sopenharmony_ci goto drop; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci __skb_queue_head(list, skb); 19478c2ecf20Sopenharmony_ci } else { 19488c2ecf20Sopenharmony_ci struct net_device_stats *stats; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cidrop: 19518c2ecf20Sopenharmony_ci stats = &tp->netdev->stats; 19528c2ecf20Sopenharmony_ci stats->tx_dropped++; 19538c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 19548c2ecf20Sopenharmony_ci } 19558c2ecf20Sopenharmony_ci} 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_cistatic inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 19608c2ecf20Sopenharmony_ci u32 opts2; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb)); 19638c2ecf20Sopenharmony_ci desc->opts2 |= cpu_to_le32(opts2); 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci u32 opts2 = le32_to_cpu(desc->opts2); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci if (opts2 & RX_VLAN_TAG) 19728c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 19738c2ecf20Sopenharmony_ci swab16(opts2 & 0xffff)); 19748c2ecf20Sopenharmony_ci} 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_cistatic int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, 19778c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 len, u32 transport_offset) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci u32 mss = skb_shinfo(skb)->gso_size; 19808c2ecf20Sopenharmony_ci u32 opts1, opts2 = 0; 19818c2ecf20Sopenharmony_ci int ret = TX_CSUM_SUCCESS; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci WARN_ON_ONCE(len > TX_LEN_MAX); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci opts1 = len | TX_FS | TX_LS; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if (mss) { 19888c2ecf20Sopenharmony_ci if (transport_offset > GTTCPHO_MAX) { 19898c2ecf20Sopenharmony_ci netif_warn(tp, tx_err, tp->netdev, 19908c2ecf20Sopenharmony_ci "Invalid transport offset 0x%x for TSO\n", 19918c2ecf20Sopenharmony_ci transport_offset); 19928c2ecf20Sopenharmony_ci ret = TX_CSUM_TSO; 19938c2ecf20Sopenharmony_ci goto unavailable; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci switch (vlan_get_protocol(skb)) { 19978c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 19988c2ecf20Sopenharmony_ci opts1 |= GTSENDV4; 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 20028c2ecf20Sopenharmony_ci if (skb_cow_head(skb, 0)) { 20038c2ecf20Sopenharmony_ci ret = TX_CSUM_TSO; 20048c2ecf20Sopenharmony_ci goto unavailable; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci tcp_v6_gso_csum_prep(skb); 20078c2ecf20Sopenharmony_ci opts1 |= GTSENDV6; 20088c2ecf20Sopenharmony_ci break; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci default: 20118c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 20128c2ecf20Sopenharmony_ci break; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci opts1 |= transport_offset << GTTCPHO_SHIFT; 20168c2ecf20Sopenharmony_ci opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; 20178c2ecf20Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 20188c2ecf20Sopenharmony_ci u8 ip_protocol; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (transport_offset > TCPHO_MAX) { 20218c2ecf20Sopenharmony_ci netif_warn(tp, tx_err, tp->netdev, 20228c2ecf20Sopenharmony_ci "Invalid transport offset 0x%x\n", 20238c2ecf20Sopenharmony_ci transport_offset); 20248c2ecf20Sopenharmony_ci ret = TX_CSUM_NONE; 20258c2ecf20Sopenharmony_ci goto unavailable; 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci switch (vlan_get_protocol(skb)) { 20298c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 20308c2ecf20Sopenharmony_ci opts2 |= IPV4_CS; 20318c2ecf20Sopenharmony_ci ip_protocol = ip_hdr(skb)->protocol; 20328c2ecf20Sopenharmony_ci break; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 20358c2ecf20Sopenharmony_ci opts2 |= IPV6_CS; 20368c2ecf20Sopenharmony_ci ip_protocol = ipv6_hdr(skb)->nexthdr; 20378c2ecf20Sopenharmony_ci break; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci default: 20408c2ecf20Sopenharmony_ci ip_protocol = IPPROTO_RAW; 20418c2ecf20Sopenharmony_ci break; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (ip_protocol == IPPROTO_TCP) 20458c2ecf20Sopenharmony_ci opts2 |= TCP_CS; 20468c2ecf20Sopenharmony_ci else if (ip_protocol == IPPROTO_UDP) 20478c2ecf20Sopenharmony_ci opts2 |= UDP_CS; 20488c2ecf20Sopenharmony_ci else 20498c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci opts2 |= transport_offset << TCPHO_SHIFT; 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci desc->opts2 = cpu_to_le32(opts2); 20558c2ecf20Sopenharmony_ci desc->opts1 = cpu_to_le32(opts1); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ciunavailable: 20588c2ecf20Sopenharmony_ci return ret; 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; 20648c2ecf20Sopenharmony_ci int remain, ret; 20658c2ecf20Sopenharmony_ci u8 *tx_data; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci __skb_queue_head_init(&skb_head); 20688c2ecf20Sopenharmony_ci spin_lock(&tx_queue->lock); 20698c2ecf20Sopenharmony_ci skb_queue_splice_init(tx_queue, &skb_head); 20708c2ecf20Sopenharmony_ci spin_unlock(&tx_queue->lock); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci tx_data = agg->head; 20738c2ecf20Sopenharmony_ci agg->skb_num = 0; 20748c2ecf20Sopenharmony_ci agg->skb_len = 0; 20758c2ecf20Sopenharmony_ci remain = agg_buf_sz; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) { 20788c2ecf20Sopenharmony_ci struct tx_desc *tx_desc; 20798c2ecf20Sopenharmony_ci struct sk_buff *skb; 20808c2ecf20Sopenharmony_ci unsigned int len; 20818c2ecf20Sopenharmony_ci u32 offset; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci skb = __skb_dequeue(&skb_head); 20848c2ecf20Sopenharmony_ci if (!skb) 20858c2ecf20Sopenharmony_ci break; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci len = skb->len + sizeof(*tx_desc); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (len > remain) { 20908c2ecf20Sopenharmony_ci __skb_queue_head(&skb_head, skb); 20918c2ecf20Sopenharmony_ci break; 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci tx_data = tx_agg_align(tx_data); 20958c2ecf20Sopenharmony_ci tx_desc = (struct tx_desc *)tx_data; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci offset = (u32)skb_transport_offset(skb); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) { 21008c2ecf20Sopenharmony_ci r8152_csum_workaround(tp, skb, &skb_head); 21018c2ecf20Sopenharmony_ci continue; 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci rtl_tx_vlan_tag(tx_desc, skb); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci tx_data += sizeof(*tx_desc); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci len = skb->len; 21098c2ecf20Sopenharmony_ci if (skb_copy_bits(skb, 0, tx_data, len) < 0) { 21108c2ecf20Sopenharmony_ci struct net_device_stats *stats = &tp->netdev->stats; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci stats->tx_dropped++; 21138c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 21148c2ecf20Sopenharmony_ci tx_data -= sizeof(*tx_desc); 21158c2ecf20Sopenharmony_ci continue; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci tx_data += len; 21198c2ecf20Sopenharmony_ci agg->skb_len += len; 21208c2ecf20Sopenharmony_ci agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags)) 21278c2ecf20Sopenharmony_ci break; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (!skb_queue_empty(&skb_head)) { 21318c2ecf20Sopenharmony_ci spin_lock(&tx_queue->lock); 21328c2ecf20Sopenharmony_ci skb_queue_splice(&skb_head, tx_queue); 21338c2ecf20Sopenharmony_ci spin_unlock(&tx_queue->lock); 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci netif_tx_lock(tp->netdev); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci if (netif_queue_stopped(tp->netdev) && 21398c2ecf20Sopenharmony_ci skb_queue_len(&tp->tx_queue) < tp->tx_qlen) 21408c2ecf20Sopenharmony_ci netif_wake_queue(tp->netdev); 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci netif_tx_unlock(tp->netdev); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface_async(tp->intf); 21458c2ecf20Sopenharmony_ci if (ret < 0) 21468c2ecf20Sopenharmony_ci goto out_tx_fill; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), 21498c2ecf20Sopenharmony_ci agg->head, (int)(tx_data - (u8 *)agg->head), 21508c2ecf20Sopenharmony_ci (usb_complete_t)write_bulk_callback, agg); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci ret = usb_submit_urb(agg->urb, GFP_ATOMIC); 21538c2ecf20Sopenharmony_ci if (ret < 0) 21548c2ecf20Sopenharmony_ci usb_autopm_put_interface_async(tp->intf); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ciout_tx_fill: 21578c2ecf20Sopenharmony_ci return ret; 21588c2ecf20Sopenharmony_ci} 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_cistatic u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) 21618c2ecf20Sopenharmony_ci{ 21628c2ecf20Sopenharmony_ci u8 checksum = CHECKSUM_NONE; 21638c2ecf20Sopenharmony_ci u32 opts2, opts3; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (!(tp->netdev->features & NETIF_F_RXCSUM)) 21668c2ecf20Sopenharmony_ci goto return_result; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci opts2 = le32_to_cpu(rx_desc->opts2); 21698c2ecf20Sopenharmony_ci opts3 = le32_to_cpu(rx_desc->opts3); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci if (opts2 & RD_IPV4_CS) { 21728c2ecf20Sopenharmony_ci if (opts3 & IPF) 21738c2ecf20Sopenharmony_ci checksum = CHECKSUM_NONE; 21748c2ecf20Sopenharmony_ci else if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) 21758c2ecf20Sopenharmony_ci checksum = CHECKSUM_UNNECESSARY; 21768c2ecf20Sopenharmony_ci else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) 21778c2ecf20Sopenharmony_ci checksum = CHECKSUM_UNNECESSARY; 21788c2ecf20Sopenharmony_ci } else if (opts2 & RD_IPV6_CS) { 21798c2ecf20Sopenharmony_ci if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) 21808c2ecf20Sopenharmony_ci checksum = CHECKSUM_UNNECESSARY; 21818c2ecf20Sopenharmony_ci else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) 21828c2ecf20Sopenharmony_ci checksum = CHECKSUM_UNNECESSARY; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cireturn_result: 21868c2ecf20Sopenharmony_ci return checksum; 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic inline bool rx_count_exceed(struct r8152 *tp) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci return atomic_read(&tp->rx_count) > RTL8152_MAX_RX; 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_cistatic inline int agg_offset(struct rx_agg *agg, void *addr) 21958c2ecf20Sopenharmony_ci{ 21968c2ecf20Sopenharmony_ci return (int)(addr - agg->buffer); 21978c2ecf20Sopenharmony_ci} 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_cistatic struct rx_agg *rtl_get_free_rx(struct r8152 *tp, gfp_t mflags) 22008c2ecf20Sopenharmony_ci{ 22018c2ecf20Sopenharmony_ci struct rx_agg *agg, *agg_next, *agg_free = NULL; 22028c2ecf20Sopenharmony_ci unsigned long flags; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci list_for_each_entry_safe(agg, agg_next, &tp->rx_used, list) { 22078c2ecf20Sopenharmony_ci if (page_count(agg->page) == 1) { 22088c2ecf20Sopenharmony_ci if (!agg_free) { 22098c2ecf20Sopenharmony_ci list_del_init(&agg->list); 22108c2ecf20Sopenharmony_ci agg_free = agg; 22118c2ecf20Sopenharmony_ci continue; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci if (rx_count_exceed(tp)) { 22148c2ecf20Sopenharmony_ci list_del_init(&agg->list); 22158c2ecf20Sopenharmony_ci free_rx_agg(tp, agg); 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci break; 22188c2ecf20Sopenharmony_ci } 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci if (!agg_free && atomic_read(&tp->rx_count) < tp->rx_pending) 22248c2ecf20Sopenharmony_ci agg_free = alloc_rx_agg(tp, mflags); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci return agg_free; 22278c2ecf20Sopenharmony_ci} 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_cistatic int rx_bottom(struct r8152 *tp, int budget) 22308c2ecf20Sopenharmony_ci{ 22318c2ecf20Sopenharmony_ci unsigned long flags; 22328c2ecf20Sopenharmony_ci struct list_head *cursor, *next, rx_queue; 22338c2ecf20Sopenharmony_ci int ret = 0, work_done = 0; 22348c2ecf20Sopenharmony_ci struct napi_struct *napi = &tp->napi; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if (!skb_queue_empty(&tp->rx_queue)) { 22378c2ecf20Sopenharmony_ci while (work_done < budget) { 22388c2ecf20Sopenharmony_ci struct sk_buff *skb = __skb_dequeue(&tp->rx_queue); 22398c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 22408c2ecf20Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 22418c2ecf20Sopenharmony_ci unsigned int pkt_len; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (!skb) 22448c2ecf20Sopenharmony_ci break; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci pkt_len = skb->len; 22478c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 22488c2ecf20Sopenharmony_ci work_done++; 22498c2ecf20Sopenharmony_ci stats->rx_packets++; 22508c2ecf20Sopenharmony_ci stats->rx_bytes += pkt_len; 22518c2ecf20Sopenharmony_ci } 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (list_empty(&tp->rx_done)) 22558c2ecf20Sopenharmony_ci goto out1; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rx_queue); 22588c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 22598c2ecf20Sopenharmony_ci list_splice_init(&tp->rx_done, &rx_queue); 22608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci list_for_each_safe(cursor, next, &rx_queue) { 22638c2ecf20Sopenharmony_ci struct rx_desc *rx_desc; 22648c2ecf20Sopenharmony_ci struct rx_agg *agg, *agg_free; 22658c2ecf20Sopenharmony_ci int len_used = 0; 22668c2ecf20Sopenharmony_ci struct urb *urb; 22678c2ecf20Sopenharmony_ci u8 *rx_data; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci list_del_init(cursor); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci agg = list_entry(cursor, struct rx_agg, list); 22728c2ecf20Sopenharmony_ci urb = agg->urb; 22738c2ecf20Sopenharmony_ci if (urb->actual_length < ETH_ZLEN) 22748c2ecf20Sopenharmony_ci goto submit; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci agg_free = rtl_get_free_rx(tp, GFP_ATOMIC); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci rx_desc = agg->buffer; 22798c2ecf20Sopenharmony_ci rx_data = agg->buffer; 22808c2ecf20Sopenharmony_ci len_used += sizeof(struct rx_desc); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci while (urb->actual_length > len_used) { 22838c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 22848c2ecf20Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 22858c2ecf20Sopenharmony_ci unsigned int pkt_len, rx_frag_head_sz; 22868c2ecf20Sopenharmony_ci struct sk_buff *skb; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci /* limite the skb numbers for rx_queue */ 22898c2ecf20Sopenharmony_ci if (unlikely(skb_queue_len(&tp->rx_queue) >= 1000)) 22908c2ecf20Sopenharmony_ci break; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; 22938c2ecf20Sopenharmony_ci if (pkt_len < ETH_ZLEN) 22948c2ecf20Sopenharmony_ci break; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci len_used += pkt_len; 22978c2ecf20Sopenharmony_ci if (urb->actual_length < len_used) 22988c2ecf20Sopenharmony_ci break; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci pkt_len -= ETH_FCS_LEN; 23018c2ecf20Sopenharmony_ci rx_data += sizeof(struct rx_desc); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci if (!agg_free || tp->rx_copybreak > pkt_len) 23048c2ecf20Sopenharmony_ci rx_frag_head_sz = pkt_len; 23058c2ecf20Sopenharmony_ci else 23068c2ecf20Sopenharmony_ci rx_frag_head_sz = tp->rx_copybreak; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci skb = napi_alloc_skb(napi, rx_frag_head_sz); 23098c2ecf20Sopenharmony_ci if (!skb) { 23108c2ecf20Sopenharmony_ci stats->rx_dropped++; 23118c2ecf20Sopenharmony_ci goto find_next_rx; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci skb->ip_summed = r8152_rx_csum(tp, rx_desc); 23158c2ecf20Sopenharmony_ci memcpy(skb->data, rx_data, rx_frag_head_sz); 23168c2ecf20Sopenharmony_ci skb_put(skb, rx_frag_head_sz); 23178c2ecf20Sopenharmony_ci pkt_len -= rx_frag_head_sz; 23188c2ecf20Sopenharmony_ci rx_data += rx_frag_head_sz; 23198c2ecf20Sopenharmony_ci if (pkt_len) { 23208c2ecf20Sopenharmony_ci skb_add_rx_frag(skb, 0, agg->page, 23218c2ecf20Sopenharmony_ci agg_offset(agg, rx_data), 23228c2ecf20Sopenharmony_ci pkt_len, 23238c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(pkt_len)); 23248c2ecf20Sopenharmony_ci get_page(agg->page); 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 23288c2ecf20Sopenharmony_ci rtl_rx_vlan_tag(rx_desc, skb); 23298c2ecf20Sopenharmony_ci if (work_done < budget) { 23308c2ecf20Sopenharmony_ci work_done++; 23318c2ecf20Sopenharmony_ci stats->rx_packets++; 23328c2ecf20Sopenharmony_ci stats->rx_bytes += skb->len; 23338c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 23348c2ecf20Sopenharmony_ci } else { 23358c2ecf20Sopenharmony_ci __skb_queue_tail(&tp->rx_queue, skb); 23368c2ecf20Sopenharmony_ci } 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_cifind_next_rx: 23398c2ecf20Sopenharmony_ci rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN); 23408c2ecf20Sopenharmony_ci rx_desc = (struct rx_desc *)rx_data; 23418c2ecf20Sopenharmony_ci len_used = agg_offset(agg, rx_data); 23428c2ecf20Sopenharmony_ci len_used += sizeof(struct rx_desc); 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci WARN_ON(!agg_free && page_count(agg->page) > 1); 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (agg_free) { 23488c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 23498c2ecf20Sopenharmony_ci if (page_count(agg->page) == 1) { 23508c2ecf20Sopenharmony_ci list_add(&agg_free->list, &tp->rx_used); 23518c2ecf20Sopenharmony_ci } else { 23528c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->rx_used); 23538c2ecf20Sopenharmony_ci agg = agg_free; 23548c2ecf20Sopenharmony_ci urb = agg->urb; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cisubmit: 23608c2ecf20Sopenharmony_ci if (!ret) { 23618c2ecf20Sopenharmony_ci ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); 23628c2ecf20Sopenharmony_ci } else { 23638c2ecf20Sopenharmony_ci urb->actual_length = 0; 23648c2ecf20Sopenharmony_ci list_add_tail(&agg->list, next); 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (!list_empty(&rx_queue)) { 23698c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 23708c2ecf20Sopenharmony_ci list_splice_tail(&rx_queue, &tp->rx_done); 23718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ciout1: 23758c2ecf20Sopenharmony_ci return work_done; 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_cistatic void tx_bottom(struct r8152 *tp) 23798c2ecf20Sopenharmony_ci{ 23808c2ecf20Sopenharmony_ci int res; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci do { 23838c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 23848c2ecf20Sopenharmony_ci struct tx_agg *agg; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (skb_queue_empty(&tp->tx_queue)) 23878c2ecf20Sopenharmony_ci break; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci agg = r8152_get_tx_agg(tp); 23908c2ecf20Sopenharmony_ci if (!agg) 23918c2ecf20Sopenharmony_ci break; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci res = r8152_tx_agg_fill(tp, agg); 23948c2ecf20Sopenharmony_ci if (!res) 23958c2ecf20Sopenharmony_ci continue; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (res == -ENODEV) { 23988c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 23998c2ecf20Sopenharmony_ci netif_device_detach(netdev); 24008c2ecf20Sopenharmony_ci } else { 24018c2ecf20Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 24028c2ecf20Sopenharmony_ci unsigned long flags; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci netif_warn(tp, tx_err, netdev, 24058c2ecf20Sopenharmony_ci "failed tx_urb %d\n", res); 24068c2ecf20Sopenharmony_ci stats->tx_dropped += agg->skb_num; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->tx_lock, flags); 24098c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->tx_free); 24108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->tx_lock, flags); 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci } while (res == 0); 24138c2ecf20Sopenharmony_ci} 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_cistatic void bottom_half(unsigned long data) 24168c2ecf20Sopenharmony_ci{ 24178c2ecf20Sopenharmony_ci struct r8152 *tp; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci tp = (struct r8152 *)data; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 24228c2ecf20Sopenharmony_ci return; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (!test_bit(WORK_ENABLE, &tp->flags)) 24258c2ecf20Sopenharmony_ci return; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* When link down, the driver would cancel all bulks. */ 24288c2ecf20Sopenharmony_ci /* This avoid the re-submitting bulk */ 24298c2ecf20Sopenharmony_ci if (!netif_carrier_ok(tp->netdev)) 24308c2ecf20Sopenharmony_ci return; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci clear_bit(SCHEDULE_TASKLET, &tp->flags); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci tx_bottom(tp); 24358c2ecf20Sopenharmony_ci} 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistatic int r8152_poll(struct napi_struct *napi, int budget) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct r8152 *tp = container_of(napi, struct r8152, napi); 24408c2ecf20Sopenharmony_ci int work_done; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci if (!budget) 24438c2ecf20Sopenharmony_ci return 0; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci work_done = rx_bottom(tp, budget); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (work_done < budget) { 24488c2ecf20Sopenharmony_ci if (!napi_complete_done(napi, work_done)) 24498c2ecf20Sopenharmony_ci goto out; 24508c2ecf20Sopenharmony_ci if (!list_empty(&tp->rx_done)) 24518c2ecf20Sopenharmony_ci napi_schedule(napi); 24528c2ecf20Sopenharmony_ci } 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ciout: 24558c2ecf20Sopenharmony_ci return work_done; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cistatic 24598c2ecf20Sopenharmony_ciint r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) 24608c2ecf20Sopenharmony_ci{ 24618c2ecf20Sopenharmony_ci int ret; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci /* The rx would be stopped, so skip submitting */ 24648c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags) || 24658c2ecf20Sopenharmony_ci !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev)) 24668c2ecf20Sopenharmony_ci return 0; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), 24698c2ecf20Sopenharmony_ci agg->buffer, tp->rx_buf_sz, 24708c2ecf20Sopenharmony_ci (usb_complete_t)read_bulk_callback, agg); 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci ret = usb_submit_urb(agg->urb, mem_flags); 24738c2ecf20Sopenharmony_ci if (ret == -ENODEV) { 24748c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 24758c2ecf20Sopenharmony_ci netif_device_detach(tp->netdev); 24768c2ecf20Sopenharmony_ci } else if (ret) { 24778c2ecf20Sopenharmony_ci struct urb *urb = agg->urb; 24788c2ecf20Sopenharmony_ci unsigned long flags; 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci urb->actual_length = 0; 24818c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 24828c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->rx_done); 24838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci netif_err(tp, rx_err, tp->netdev, 24868c2ecf20Sopenharmony_ci "Couldn't submit rx[%p], ret = %d\n", agg, ret); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci return ret; 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_cistatic void rtl_drop_queued_tx(struct r8152 *tp) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci struct net_device_stats *stats = &tp->netdev->stats; 24978c2ecf20Sopenharmony_ci struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; 24988c2ecf20Sopenharmony_ci struct sk_buff *skb; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci if (skb_queue_empty(tx_queue)) 25018c2ecf20Sopenharmony_ci return; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci __skb_queue_head_init(&skb_head); 25048c2ecf20Sopenharmony_ci spin_lock_bh(&tx_queue->lock); 25058c2ecf20Sopenharmony_ci skb_queue_splice_init(tx_queue, &skb_head); 25068c2ecf20Sopenharmony_ci spin_unlock_bh(&tx_queue->lock); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&skb_head))) { 25098c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 25108c2ecf20Sopenharmony_ci stats->tx_dropped++; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_cistatic void rtl8152_tx_timeout(struct net_device *netdev, unsigned int txqueue) 25158c2ecf20Sopenharmony_ci{ 25168c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci netif_warn(tp, tx_err, netdev, "Tx timeout\n"); 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci usb_queue_reset_device(tp->intf); 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic void rtl8152_set_rx_mode(struct net_device *netdev) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 25288c2ecf20Sopenharmony_ci set_bit(RTL8152_SET_RX_MODE, &tp->flags); 25298c2ecf20Sopenharmony_ci schedule_delayed_work(&tp->schedule, 0); 25308c2ecf20Sopenharmony_ci } 25318c2ecf20Sopenharmony_ci} 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_cistatic void _rtl8152_set_rx_mode(struct net_device *netdev) 25348c2ecf20Sopenharmony_ci{ 25358c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 25368c2ecf20Sopenharmony_ci u32 mc_filter[2]; /* Multicast hash filter */ 25378c2ecf20Sopenharmony_ci __le32 tmp[2]; 25388c2ecf20Sopenharmony_ci u32 ocp_data; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 25418c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 25428c2ecf20Sopenharmony_ci ocp_data &= ~RCR_ACPT_ALL; 25438c2ecf20Sopenharmony_ci ocp_data |= RCR_AB | RCR_APM; 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 25468c2ecf20Sopenharmony_ci /* Unconditionally log net taps. */ 25478c2ecf20Sopenharmony_ci netif_notice(tp, link, netdev, "Promiscuous mode enabled\n"); 25488c2ecf20Sopenharmony_ci ocp_data |= RCR_AM | RCR_AAP; 25498c2ecf20Sopenharmony_ci mc_filter[1] = 0xffffffff; 25508c2ecf20Sopenharmony_ci mc_filter[0] = 0xffffffff; 25518c2ecf20Sopenharmony_ci } else if ((netdev_mc_count(netdev) > multicast_filter_limit) || 25528c2ecf20Sopenharmony_ci (netdev->flags & IFF_ALLMULTI)) { 25538c2ecf20Sopenharmony_ci /* Too many to filter perfectly -- accept all multicasts. */ 25548c2ecf20Sopenharmony_ci ocp_data |= RCR_AM; 25558c2ecf20Sopenharmony_ci mc_filter[1] = 0xffffffff; 25568c2ecf20Sopenharmony_ci mc_filter[0] = 0xffffffff; 25578c2ecf20Sopenharmony_ci } else { 25588c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci mc_filter[1] = 0; 25618c2ecf20Sopenharmony_ci mc_filter[0] = 0; 25628c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 25638c2ecf20Sopenharmony_ci int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); 25668c2ecf20Sopenharmony_ci ocp_data |= RCR_AM; 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci } 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci tmp[0] = __cpu_to_le32(swab32(mc_filter[1])); 25718c2ecf20Sopenharmony_ci tmp[1] = __cpu_to_le32(swab32(mc_filter[0])); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp); 25748c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 25758c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_cistatic netdev_features_t 25798c2ecf20Sopenharmony_cirtl8152_features_check(struct sk_buff *skb, struct net_device *dev, 25808c2ecf20Sopenharmony_ci netdev_features_t features) 25818c2ecf20Sopenharmony_ci{ 25828c2ecf20Sopenharmony_ci u32 mss = skb_shinfo(skb)->gso_size; 25838c2ecf20Sopenharmony_ci int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX; 25848c2ecf20Sopenharmony_ci int offset = skb_transport_offset(skb); 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset) 25878c2ecf20Sopenharmony_ci features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 25888c2ecf20Sopenharmony_ci else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz) 25898c2ecf20Sopenharmony_ci features &= ~NETIF_F_GSO_MASK; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci return features; 25928c2ecf20Sopenharmony_ci} 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_cistatic netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, 25958c2ecf20Sopenharmony_ci struct net_device *netdev) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci skb_queue_tail(&tp->tx_queue, skb); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (!list_empty(&tp->tx_free)) { 26048c2ecf20Sopenharmony_ci if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { 26058c2ecf20Sopenharmony_ci set_bit(SCHEDULE_TASKLET, &tp->flags); 26068c2ecf20Sopenharmony_ci schedule_delayed_work(&tp->schedule, 0); 26078c2ecf20Sopenharmony_ci } else { 26088c2ecf20Sopenharmony_ci usb_mark_last_busy(tp->udev); 26098c2ecf20Sopenharmony_ci tasklet_schedule(&tp->tx_tl); 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { 26128c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 26168c2ecf20Sopenharmony_ci} 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_cistatic void r8152b_reset_packet_filter(struct r8152 *tp) 26198c2ecf20Sopenharmony_ci{ 26208c2ecf20Sopenharmony_ci u32 ocp_data; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC); 26238c2ecf20Sopenharmony_ci ocp_data &= ~FMC_FCR_MCU_EN; 26248c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); 26258c2ecf20Sopenharmony_ci ocp_data |= FMC_FCR_MCU_EN; 26268c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); 26278c2ecf20Sopenharmony_ci} 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_cistatic void rtl8152_nic_reset(struct r8152 *tp) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci int i; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 26368c2ecf20Sopenharmony_ci if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST)) 26378c2ecf20Sopenharmony_ci break; 26388c2ecf20Sopenharmony_ci usleep_range(100, 400); 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic void set_tx_qlen(struct r8152 *tp) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN + 26478c2ecf20Sopenharmony_ci sizeof(struct tx_desc)); 26488c2ecf20Sopenharmony_ci} 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_cistatic inline u8 rtl8152_get_speed(struct r8152 *tp) 26518c2ecf20Sopenharmony_ci{ 26528c2ecf20Sopenharmony_ci return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS); 26538c2ecf20Sopenharmony_ci} 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_cistatic void rtl_set_eee_plus(struct r8152 *tp) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci u32 ocp_data; 26588c2ecf20Sopenharmony_ci u8 speed; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci speed = rtl8152_get_speed(tp); 26618c2ecf20Sopenharmony_ci if (speed & _10bps) { 26628c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); 26638c2ecf20Sopenharmony_ci ocp_data |= EEEP_CR_EEEP_TX; 26648c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); 26658c2ecf20Sopenharmony_ci } else { 26668c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); 26678c2ecf20Sopenharmony_ci ocp_data &= ~EEEP_CR_EEEP_TX; 26688c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci} 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_cistatic void rxdy_gated_en(struct r8152 *tp, bool enable) 26738c2ecf20Sopenharmony_ci{ 26748c2ecf20Sopenharmony_ci u32 ocp_data; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); 26778c2ecf20Sopenharmony_ci if (enable) 26788c2ecf20Sopenharmony_ci ocp_data |= RXDY_GATED_EN; 26798c2ecf20Sopenharmony_ci else 26808c2ecf20Sopenharmony_ci ocp_data &= ~RXDY_GATED_EN; 26818c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); 26828c2ecf20Sopenharmony_ci} 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_cistatic int rtl_start_rx(struct r8152 *tp) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci struct rx_agg *agg, *agg_next; 26878c2ecf20Sopenharmony_ci struct list_head tmp_list; 26888c2ecf20Sopenharmony_ci unsigned long flags; 26898c2ecf20Sopenharmony_ci int ret = 0, i = 0; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_list); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->rx_done); 26968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tp->rx_used); 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci list_splice_init(&tp->rx_info, &tmp_list); 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) { 27038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&agg->list); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci /* Only RTL8152_MAX_RX rx_agg need to be submitted. */ 27068c2ecf20Sopenharmony_ci if (++i > RTL8152_MAX_RX) { 27078c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 27088c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->rx_used); 27098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27108c2ecf20Sopenharmony_ci } else if (unlikely(ret < 0)) { 27118c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 27128c2ecf20Sopenharmony_ci list_add_tail(&agg->list, &tp->rx_done); 27138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27148c2ecf20Sopenharmony_ci } else { 27158c2ecf20Sopenharmony_ci ret = r8152_submit_rx(tp, agg, GFP_KERNEL); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 27208c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&tp->rx_info)); 27218c2ecf20Sopenharmony_ci list_splice(&tmp_list, &tp->rx_info); 27228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci return ret; 27258c2ecf20Sopenharmony_ci} 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_cistatic int rtl_stop_rx(struct r8152 *tp) 27288c2ecf20Sopenharmony_ci{ 27298c2ecf20Sopenharmony_ci struct rx_agg *agg, *agg_next; 27308c2ecf20Sopenharmony_ci struct list_head tmp_list; 27318c2ecf20Sopenharmony_ci unsigned long flags; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_list); 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci /* The usb_kill_urb() couldn't be used in atomic. 27368c2ecf20Sopenharmony_ci * Therefore, move the list of rx_info to a tmp one. 27378c2ecf20Sopenharmony_ci * Then, list_for_each_entry_safe could be used without 27388c2ecf20Sopenharmony_ci * spin lock. 27398c2ecf20Sopenharmony_ci */ 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 27428c2ecf20Sopenharmony_ci list_splice_init(&tp->rx_info, &tmp_list); 27438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) { 27468c2ecf20Sopenharmony_ci /* At least RTL8152_MAX_RX rx_agg have the page_count being 27478c2ecf20Sopenharmony_ci * equal to 1, so the other ones could be freed safely. 27488c2ecf20Sopenharmony_ci */ 27498c2ecf20Sopenharmony_ci if (page_count(agg->page) > 1) 27508c2ecf20Sopenharmony_ci free_rx_agg(tp, agg); 27518c2ecf20Sopenharmony_ci else 27528c2ecf20Sopenharmony_ci usb_kill_urb(agg->urb); 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci /* Move back the list of temp to the rx_info */ 27568c2ecf20Sopenharmony_ci spin_lock_irqsave(&tp->rx_lock, flags); 27578c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&tp->rx_info)); 27588c2ecf20Sopenharmony_ci list_splice(&tmp_list, &tp->rx_info); 27598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tp->rx_lock, flags); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci while (!skb_queue_empty(&tp->rx_queue)) 27628c2ecf20Sopenharmony_ci dev_kfree_skb(__skb_dequeue(&tp->rx_queue)); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci return 0; 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_cistatic inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp) 27688c2ecf20Sopenharmony_ci{ 27698c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN, 27708c2ecf20Sopenharmony_ci OWN_UPDATE | OWN_CLEAR); 27718c2ecf20Sopenharmony_ci} 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_cistatic int rtl_enable(struct r8152 *tp) 27748c2ecf20Sopenharmony_ci{ 27758c2ecf20Sopenharmony_ci u32 ocp_data; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci r8152b_reset_packet_filter(tp); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR); 27808c2ecf20Sopenharmony_ci ocp_data |= CR_RE | CR_TE; 27818c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci switch (tp->version) { 27848c2ecf20Sopenharmony_ci case RTL_VER_08: 27858c2ecf20Sopenharmony_ci case RTL_VER_09: 27868c2ecf20Sopenharmony_ci r8153b_rx_agg_chg_indicate(tp); 27878c2ecf20Sopenharmony_ci break; 27888c2ecf20Sopenharmony_ci default: 27898c2ecf20Sopenharmony_ci break; 27908c2ecf20Sopenharmony_ci } 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci rxdy_gated_en(tp, false); 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci return 0; 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_cistatic int rtl8152_enable(struct r8152 *tp) 27988c2ecf20Sopenharmony_ci{ 27998c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 28008c2ecf20Sopenharmony_ci return -ENODEV; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci set_tx_qlen(tp); 28038c2ecf20Sopenharmony_ci rtl_set_eee_plus(tp); 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci return rtl_enable(tp); 28068c2ecf20Sopenharmony_ci} 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_cistatic void r8153_set_rx_early_timeout(struct r8152 *tp) 28098c2ecf20Sopenharmony_ci{ 28108c2ecf20Sopenharmony_ci u32 ocp_data = tp->coalesce / 8; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci switch (tp->version) { 28138c2ecf20Sopenharmony_ci case RTL_VER_03: 28148c2ecf20Sopenharmony_ci case RTL_VER_04: 28158c2ecf20Sopenharmony_ci case RTL_VER_05: 28168c2ecf20Sopenharmony_ci case RTL_VER_06: 28178c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, 28188c2ecf20Sopenharmony_ci ocp_data); 28198c2ecf20Sopenharmony_ci break; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci case RTL_VER_08: 28228c2ecf20Sopenharmony_ci case RTL_VER_09: 28238c2ecf20Sopenharmony_ci /* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout 28248c2ecf20Sopenharmony_ci * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 128ns. 28258c2ecf20Sopenharmony_ci */ 28268c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, 28278c2ecf20Sopenharmony_ci 128 / 8); 28288c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR, 28298c2ecf20Sopenharmony_ci ocp_data); 28308c2ecf20Sopenharmony_ci break; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci default: 28338c2ecf20Sopenharmony_ci break; 28348c2ecf20Sopenharmony_ci } 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_cistatic void r8153_set_rx_early_size(struct r8152 *tp) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci u32 ocp_data = tp->rx_buf_sz - rx_reserved_size(tp->netdev->mtu); 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci switch (tp->version) { 28428c2ecf20Sopenharmony_ci case RTL_VER_03: 28438c2ecf20Sopenharmony_ci case RTL_VER_04: 28448c2ecf20Sopenharmony_ci case RTL_VER_05: 28458c2ecf20Sopenharmony_ci case RTL_VER_06: 28468c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, 28478c2ecf20Sopenharmony_ci ocp_data / 4); 28488c2ecf20Sopenharmony_ci break; 28498c2ecf20Sopenharmony_ci case RTL_VER_08: 28508c2ecf20Sopenharmony_ci case RTL_VER_09: 28518c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, 28528c2ecf20Sopenharmony_ci ocp_data / 8); 28538c2ecf20Sopenharmony_ci break; 28548c2ecf20Sopenharmony_ci default: 28558c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 28568c2ecf20Sopenharmony_ci break; 28578c2ecf20Sopenharmony_ci } 28588c2ecf20Sopenharmony_ci} 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_cistatic int rtl8153_enable(struct r8152 *tp) 28618c2ecf20Sopenharmony_ci{ 28628c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 28638c2ecf20Sopenharmony_ci return -ENODEV; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci set_tx_qlen(tp); 28668c2ecf20Sopenharmony_ci rtl_set_eee_plus(tp); 28678c2ecf20Sopenharmony_ci r8153_set_rx_early_timeout(tp); 28688c2ecf20Sopenharmony_ci r8153_set_rx_early_size(tp); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_09) { 28718c2ecf20Sopenharmony_ci u32 ocp_data; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK); 28748c2ecf20Sopenharmony_ci ocp_data &= ~FC_PATCH_TASK; 28758c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); 28768c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 28778c2ecf20Sopenharmony_ci ocp_data |= FC_PATCH_TASK; 28788c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci return rtl_enable(tp); 28828c2ecf20Sopenharmony_ci} 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_cistatic void rtl_disable(struct r8152 *tp) 28858c2ecf20Sopenharmony_ci{ 28868c2ecf20Sopenharmony_ci u32 ocp_data; 28878c2ecf20Sopenharmony_ci int i; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) { 28908c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 28918c2ecf20Sopenharmony_ci return; 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 28958c2ecf20Sopenharmony_ci ocp_data &= ~RCR_ACPT_ALL; 28968c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci for (i = 0; i < RTL8152_MAX_TX; i++) 29018c2ecf20Sopenharmony_ci usb_kill_urb(tp->tx_info[i].urb); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci rxdy_gated_en(tp, true); 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 29068c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 29078c2ecf20Sopenharmony_ci if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY) 29088c2ecf20Sopenharmony_ci break; 29098c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 29108c2ecf20Sopenharmony_ci } 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 29138c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY) 29148c2ecf20Sopenharmony_ci break; 29158c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci rtl_stop_rx(tp); 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci rtl8152_nic_reset(tp); 29218c2ecf20Sopenharmony_ci} 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_cistatic void r8152_power_cut_en(struct r8152 *tp, bool enable) 29248c2ecf20Sopenharmony_ci{ 29258c2ecf20Sopenharmony_ci u32 ocp_data; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); 29288c2ecf20Sopenharmony_ci if (enable) 29298c2ecf20Sopenharmony_ci ocp_data |= POWER_CUT; 29308c2ecf20Sopenharmony_ci else 29318c2ecf20Sopenharmony_ci ocp_data &= ~POWER_CUT; 29328c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); 29358c2ecf20Sopenharmony_ci ocp_data &= ~RESUME_INDICATE; 29368c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); 29378c2ecf20Sopenharmony_ci} 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_cistatic void rtl_rx_vlan_en(struct r8152 *tp, bool enable) 29408c2ecf20Sopenharmony_ci{ 29418c2ecf20Sopenharmony_ci u32 ocp_data; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); 29448c2ecf20Sopenharmony_ci if (enable) 29458c2ecf20Sopenharmony_ci ocp_data |= CPCR_RX_VLAN; 29468c2ecf20Sopenharmony_ci else 29478c2ecf20Sopenharmony_ci ocp_data &= ~CPCR_RX_VLAN; 29488c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); 29498c2ecf20Sopenharmony_ci} 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_cistatic int rtl8152_set_features(struct net_device *dev, 29528c2ecf20Sopenharmony_ci netdev_features_t features) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci netdev_features_t changed = features ^ dev->features; 29558c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 29568c2ecf20Sopenharmony_ci int ret; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 29598c2ecf20Sopenharmony_ci if (ret < 0) 29608c2ecf20Sopenharmony_ci goto out; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_RX) { 29658c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 29668c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, true); 29678c2ecf20Sopenharmony_ci else 29688c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, false); 29698c2ecf20Sopenharmony_ci } 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ciout: 29768c2ecf20Sopenharmony_ci return ret; 29778c2ecf20Sopenharmony_ci} 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_cistatic u32 __rtl_get_wol(struct r8152 *tp) 29828c2ecf20Sopenharmony_ci{ 29838c2ecf20Sopenharmony_ci u32 ocp_data; 29848c2ecf20Sopenharmony_ci u32 wolopts = 0; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); 29878c2ecf20Sopenharmony_ci if (ocp_data & LINK_ON_WAKE_EN) 29888c2ecf20Sopenharmony_ci wolopts |= WAKE_PHY; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); 29918c2ecf20Sopenharmony_ci if (ocp_data & UWF_EN) 29928c2ecf20Sopenharmony_ci wolopts |= WAKE_UCAST; 29938c2ecf20Sopenharmony_ci if (ocp_data & BWF_EN) 29948c2ecf20Sopenharmony_ci wolopts |= WAKE_BCAST; 29958c2ecf20Sopenharmony_ci if (ocp_data & MWF_EN) 29968c2ecf20Sopenharmony_ci wolopts |= WAKE_MCAST; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); 29998c2ecf20Sopenharmony_ci if (ocp_data & MAGIC_EN) 30008c2ecf20Sopenharmony_ci wolopts |= WAKE_MAGIC; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci return wolopts; 30038c2ecf20Sopenharmony_ci} 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_cistatic void __rtl_set_wol(struct r8152 *tp, u32 wolopts) 30068c2ecf20Sopenharmony_ci{ 30078c2ecf20Sopenharmony_ci u32 ocp_data; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); 30128c2ecf20Sopenharmony_ci ocp_data &= ~LINK_ON_WAKE_EN; 30138c2ecf20Sopenharmony_ci if (wolopts & WAKE_PHY) 30148c2ecf20Sopenharmony_ci ocp_data |= LINK_ON_WAKE_EN; 30158c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); 30188c2ecf20Sopenharmony_ci ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN); 30198c2ecf20Sopenharmony_ci if (wolopts & WAKE_UCAST) 30208c2ecf20Sopenharmony_ci ocp_data |= UWF_EN; 30218c2ecf20Sopenharmony_ci if (wolopts & WAKE_BCAST) 30228c2ecf20Sopenharmony_ci ocp_data |= BWF_EN; 30238c2ecf20Sopenharmony_ci if (wolopts & WAKE_MCAST) 30248c2ecf20Sopenharmony_ci ocp_data |= MWF_EN; 30258c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data); 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); 30308c2ecf20Sopenharmony_ci ocp_data &= ~MAGIC_EN; 30318c2ecf20Sopenharmony_ci if (wolopts & WAKE_MAGIC) 30328c2ecf20Sopenharmony_ci ocp_data |= MAGIC_EN; 30338c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci if (wolopts & WAKE_ANY) 30368c2ecf20Sopenharmony_ci device_set_wakeup_enable(&tp->udev->dev, true); 30378c2ecf20Sopenharmony_ci else 30388c2ecf20Sopenharmony_ci device_set_wakeup_enable(&tp->udev->dev, false); 30398c2ecf20Sopenharmony_ci} 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_cistatic void r8153_u1u2en(struct r8152 *tp, bool enable) 30428c2ecf20Sopenharmony_ci{ 30438c2ecf20Sopenharmony_ci u8 u1u2[8]; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci if (enable) 30468c2ecf20Sopenharmony_ci memset(u1u2, 0xff, sizeof(u1u2)); 30478c2ecf20Sopenharmony_ci else 30488c2ecf20Sopenharmony_ci memset(u1u2, 0x00, sizeof(u1u2)); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); 30518c2ecf20Sopenharmony_ci} 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_cistatic void r8153b_u1u2en(struct r8152 *tp, bool enable) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci u32 ocp_data; 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG); 30588c2ecf20Sopenharmony_ci if (enable) 30598c2ecf20Sopenharmony_ci ocp_data |= LPM_U1U2_EN; 30608c2ecf20Sopenharmony_ci else 30618c2ecf20Sopenharmony_ci ocp_data &= ~LPM_U1U2_EN; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data); 30648c2ecf20Sopenharmony_ci} 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_cistatic void r8153_u2p3en(struct r8152 *tp, bool enable) 30678c2ecf20Sopenharmony_ci{ 30688c2ecf20Sopenharmony_ci u32 ocp_data; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); 30718c2ecf20Sopenharmony_ci if (enable) 30728c2ecf20Sopenharmony_ci ocp_data |= U2P3_ENABLE; 30738c2ecf20Sopenharmony_ci else 30748c2ecf20Sopenharmony_ci ocp_data &= ~U2P3_ENABLE; 30758c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); 30768c2ecf20Sopenharmony_ci} 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_cistatic void r8153b_ups_flags(struct r8152 *tp) 30798c2ecf20Sopenharmony_ci{ 30808c2ecf20Sopenharmony_ci u32 ups_flags = 0; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci if (tp->ups_info.green) 30838c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_GREEN; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci if (tp->ups_info.aldps) 30868c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_ALDPS; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci if (tp->ups_info.eee) 30898c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_EEE; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci if (tp->ups_info.flow_control) 30928c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_FLOW_CTR; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci if (tp->ups_info.eee_ckdiv) 30958c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_EEE_CKDIV; 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci if (tp->ups_info.eee_cmod_lv) 30988c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EEE_CMOD_LV_EN; 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci if (tp->ups_info._10m_ckdiv) 31018c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EN_10M_CKDIV; 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci if (tp->ups_info.eee_plloff_100) 31048c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EEE_PLLOFF_100; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci if (tp->ups_info.eee_plloff_giga) 31078c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_EEE_PLLOFF_GIGA; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci if (tp->ups_info._250m_ckdiv) 31108c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_250M_CKDIV; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci if (tp->ups_info.ctap_short_off) 31138c2ecf20Sopenharmony_ci ups_flags |= UPS_FLAGS_CTAP_SHORT_DIS; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci switch (tp->ups_info.speed_duplex) { 31168c2ecf20Sopenharmony_ci case NWAY_10M_HALF: 31178c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(1); 31188c2ecf20Sopenharmony_ci break; 31198c2ecf20Sopenharmony_ci case NWAY_10M_FULL: 31208c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(2); 31218c2ecf20Sopenharmony_ci break; 31228c2ecf20Sopenharmony_ci case NWAY_100M_HALF: 31238c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(3); 31248c2ecf20Sopenharmony_ci break; 31258c2ecf20Sopenharmony_ci case NWAY_100M_FULL: 31268c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(4); 31278c2ecf20Sopenharmony_ci break; 31288c2ecf20Sopenharmony_ci case NWAY_1000M_FULL: 31298c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(5); 31308c2ecf20Sopenharmony_ci break; 31318c2ecf20Sopenharmony_ci case FORCE_10M_HALF: 31328c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(6); 31338c2ecf20Sopenharmony_ci break; 31348c2ecf20Sopenharmony_ci case FORCE_10M_FULL: 31358c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(7); 31368c2ecf20Sopenharmony_ci break; 31378c2ecf20Sopenharmony_ci case FORCE_100M_HALF: 31388c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(8); 31398c2ecf20Sopenharmony_ci break; 31408c2ecf20Sopenharmony_ci case FORCE_100M_FULL: 31418c2ecf20Sopenharmony_ci ups_flags |= ups_flags_speed(9); 31428c2ecf20Sopenharmony_ci break; 31438c2ecf20Sopenharmony_ci default: 31448c2ecf20Sopenharmony_ci break; 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ups_flags); 31488c2ecf20Sopenharmony_ci} 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_cistatic void r8153b_green_en(struct r8152 *tp, bool enable) 31518c2ecf20Sopenharmony_ci{ 31528c2ecf20Sopenharmony_ci u16 data; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci if (enable) { 31558c2ecf20Sopenharmony_ci sram_write(tp, 0x8045, 0); /* 10M abiq&ldvbias */ 31568c2ecf20Sopenharmony_ci sram_write(tp, 0x804d, 0x1222); /* 100M short abiq&ldvbias */ 31578c2ecf20Sopenharmony_ci sram_write(tp, 0x805d, 0x0022); /* 1000M short abiq&ldvbias */ 31588c2ecf20Sopenharmony_ci } else { 31598c2ecf20Sopenharmony_ci sram_write(tp, 0x8045, 0x2444); /* 10M abiq&ldvbias */ 31608c2ecf20Sopenharmony_ci sram_write(tp, 0x804d, 0x2444); /* 100M short abiq&ldvbias */ 31618c2ecf20Sopenharmony_ci sram_write(tp, 0x805d, 0x2444); /* 1000M short abiq&ldvbias */ 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci data = sram_read(tp, SRAM_GREEN_CFG); 31658c2ecf20Sopenharmony_ci data |= GREEN_ETH_EN; 31668c2ecf20Sopenharmony_ci sram_write(tp, SRAM_GREEN_CFG, data); 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci tp->ups_info.green = enable; 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_cistatic u16 r8153_phy_status(struct r8152 *tp, u16 desired) 31728c2ecf20Sopenharmony_ci{ 31738c2ecf20Sopenharmony_ci u16 data; 31748c2ecf20Sopenharmony_ci int i; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci for (i = 0; i < 500; i++) { 31778c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_PHY_STATUS); 31788c2ecf20Sopenharmony_ci data &= PHY_STAT_MASK; 31798c2ecf20Sopenharmony_ci if (desired) { 31808c2ecf20Sopenharmony_ci if (data == desired) 31818c2ecf20Sopenharmony_ci break; 31828c2ecf20Sopenharmony_ci } else if (data == PHY_STAT_LAN_ON || data == PHY_STAT_PWRDN || 31838c2ecf20Sopenharmony_ci data == PHY_STAT_EXT_INIT) { 31848c2ecf20Sopenharmony_ci break; 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci msleep(20); 31888c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 31898c2ecf20Sopenharmony_ci break; 31908c2ecf20Sopenharmony_ci } 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci return data; 31938c2ecf20Sopenharmony_ci} 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_cistatic void r8153b_ups_en(struct r8152 *tp, bool enable) 31968c2ecf20Sopenharmony_ci{ 31978c2ecf20Sopenharmony_ci u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT); 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci if (enable) { 32008c2ecf20Sopenharmony_ci r8153b_ups_flags(tp); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN; 32038c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); 32068c2ecf20Sopenharmony_ci ocp_data |= BIT(0); 32078c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); 32088c2ecf20Sopenharmony_ci } else { 32098c2ecf20Sopenharmony_ci u16 data; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci ocp_data &= ~(UPS_EN | USP_PREWAKE); 32128c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); 32158c2ecf20Sopenharmony_ci ocp_data &= ~BIT(0); 32168c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); 32198c2ecf20Sopenharmony_ci ocp_data &= ~PCUT_STATUS; 32208c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, 0); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci switch (data) { 32258c2ecf20Sopenharmony_ci case PHY_STAT_PWRDN: 32268c2ecf20Sopenharmony_ci case PHY_STAT_EXT_INIT: 32278c2ecf20Sopenharmony_ci r8153b_green_en(tp, 32288c2ecf20Sopenharmony_ci test_bit(GREEN_ETHERNET, &tp->flags)); 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci data = r8152_mdio_read(tp, MII_BMCR); 32318c2ecf20Sopenharmony_ci data &= ~BMCR_PDOWN; 32328c2ecf20Sopenharmony_ci data |= BMCR_RESET; 32338c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_BMCR, data); 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, PHY_STAT_LAN_ON); 32368c2ecf20Sopenharmony_ci fallthrough; 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci default: 32398c2ecf20Sopenharmony_ci if (data != PHY_STAT_LAN_ON) 32408c2ecf20Sopenharmony_ci netif_warn(tp, link, tp->netdev, 32418c2ecf20Sopenharmony_ci "PHY not ready"); 32428c2ecf20Sopenharmony_ci break; 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci} 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_cistatic void r8153_power_cut_en(struct r8152 *tp, bool enable) 32488c2ecf20Sopenharmony_ci{ 32498c2ecf20Sopenharmony_ci u32 ocp_data; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); 32528c2ecf20Sopenharmony_ci if (enable) 32538c2ecf20Sopenharmony_ci ocp_data |= PWR_EN | PHASE2_EN; 32548c2ecf20Sopenharmony_ci else 32558c2ecf20Sopenharmony_ci ocp_data &= ~(PWR_EN | PHASE2_EN); 32568c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); 32598c2ecf20Sopenharmony_ci ocp_data &= ~PCUT_STATUS; 32608c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); 32618c2ecf20Sopenharmony_ci} 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_cistatic void r8153b_power_cut_en(struct r8152 *tp, bool enable) 32648c2ecf20Sopenharmony_ci{ 32658c2ecf20Sopenharmony_ci u32 ocp_data; 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); 32688c2ecf20Sopenharmony_ci if (enable) 32698c2ecf20Sopenharmony_ci ocp_data |= PWR_EN | PHASE2_EN; 32708c2ecf20Sopenharmony_ci else 32718c2ecf20Sopenharmony_ci ocp_data &= ~PWR_EN; 32728c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); 32758c2ecf20Sopenharmony_ci ocp_data &= ~PCUT_STATUS; 32768c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_cistatic void r8153_queue_wake(struct r8152 *tp, bool enable) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci u32 ocp_data; 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG); 32848c2ecf20Sopenharmony_ci if (enable) 32858c2ecf20Sopenharmony_ci ocp_data |= UPCOMING_RUNTIME_D3; 32868c2ecf20Sopenharmony_ci else 32878c2ecf20Sopenharmony_ci ocp_data &= ~UPCOMING_RUNTIME_D3; 32888c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG, ocp_data); 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG); 32918c2ecf20Sopenharmony_ci ocp_data &= ~LINK_CHG_EVENT; 32928c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG, ocp_data); 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS); 32958c2ecf20Sopenharmony_ci ocp_data &= ~LINK_CHANGE_FLAG; 32968c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data); 32978c2ecf20Sopenharmony_ci} 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_cistatic bool rtl_can_wakeup(struct r8152 *tp) 33008c2ecf20Sopenharmony_ci{ 33018c2ecf20Sopenharmony_ci struct usb_device *udev = tp->udev; 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci return (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP); 33048c2ecf20Sopenharmony_ci} 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_cistatic void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) 33078c2ecf20Sopenharmony_ci{ 33088c2ecf20Sopenharmony_ci if (enable) { 33098c2ecf20Sopenharmony_ci u32 ocp_data; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci __rtl_set_wol(tp, WAKE_ANY); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); 33168c2ecf20Sopenharmony_ci ocp_data |= LINK_OFF_WAKE_EN; 33178c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); 33208c2ecf20Sopenharmony_ci } else { 33218c2ecf20Sopenharmony_ci u32 ocp_data; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci __rtl_set_wol(tp, tp->saved_wolopts); 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); 33288c2ecf20Sopenharmony_ci ocp_data &= ~LINK_OFF_WAKE_EN; 33298c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci} 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_cistatic void rtl8153_runtime_enable(struct r8152 *tp, bool enable) 33368c2ecf20Sopenharmony_ci{ 33378c2ecf20Sopenharmony_ci if (enable) { 33388c2ecf20Sopenharmony_ci r8153_u1u2en(tp, false); 33398c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 33408c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, true); 33418c2ecf20Sopenharmony_ci } else { 33428c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, false); 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci switch (tp->version) { 33458c2ecf20Sopenharmony_ci case RTL_VER_03: 33468c2ecf20Sopenharmony_ci case RTL_VER_04: 33478c2ecf20Sopenharmony_ci break; 33488c2ecf20Sopenharmony_ci case RTL_VER_05: 33498c2ecf20Sopenharmony_ci case RTL_VER_06: 33508c2ecf20Sopenharmony_ci default: 33518c2ecf20Sopenharmony_ci r8153_u2p3en(tp, true); 33528c2ecf20Sopenharmony_ci break; 33538c2ecf20Sopenharmony_ci } 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci r8153_u1u2en(tp, true); 33568c2ecf20Sopenharmony_ci } 33578c2ecf20Sopenharmony_ci} 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_cistatic void rtl8153b_runtime_enable(struct r8152 *tp, bool enable) 33608c2ecf20Sopenharmony_ci{ 33618c2ecf20Sopenharmony_ci if (enable) { 33628c2ecf20Sopenharmony_ci r8153_queue_wake(tp, true); 33638c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, false); 33648c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 33658c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, true); 33668c2ecf20Sopenharmony_ci r8153b_ups_en(tp, true); 33678c2ecf20Sopenharmony_ci } else { 33688c2ecf20Sopenharmony_ci r8153b_ups_en(tp, false); 33698c2ecf20Sopenharmony_ci r8153_queue_wake(tp, false); 33708c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, false); 33718c2ecf20Sopenharmony_ci if (tp->udev->speed != USB_SPEED_HIGH) 33728c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, true); 33738c2ecf20Sopenharmony_ci } 33748c2ecf20Sopenharmony_ci} 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_cistatic void r8153_teredo_off(struct r8152 *tp) 33778c2ecf20Sopenharmony_ci{ 33788c2ecf20Sopenharmony_ci u32 ocp_data; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci switch (tp->version) { 33818c2ecf20Sopenharmony_ci case RTL_VER_01: 33828c2ecf20Sopenharmony_ci case RTL_VER_02: 33838c2ecf20Sopenharmony_ci case RTL_VER_03: 33848c2ecf20Sopenharmony_ci case RTL_VER_04: 33858c2ecf20Sopenharmony_ci case RTL_VER_05: 33868c2ecf20Sopenharmony_ci case RTL_VER_06: 33878c2ecf20Sopenharmony_ci case RTL_VER_07: 33888c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); 33898c2ecf20Sopenharmony_ci ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | 33908c2ecf20Sopenharmony_ci OOB_TEREDO_EN); 33918c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); 33928c2ecf20Sopenharmony_ci break; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci case RTL_VER_08: 33958c2ecf20Sopenharmony_ci case RTL_VER_09: 33968c2ecf20Sopenharmony_ci /* The bit 0 ~ 7 are relative with teredo settings. They are 33978c2ecf20Sopenharmony_ci * W1C (write 1 to clear), so set all 1 to disable it. 33988c2ecf20Sopenharmony_ci */ 33998c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff); 34008c2ecf20Sopenharmony_ci break; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci default: 34038c2ecf20Sopenharmony_ci break; 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); 34078c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); 34088c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); 34098c2ecf20Sopenharmony_ci} 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_cistatic void rtl_reset_bmu(struct r8152 *tp) 34128c2ecf20Sopenharmony_ci{ 34138c2ecf20Sopenharmony_ci u32 ocp_data; 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_RESET); 34168c2ecf20Sopenharmony_ci ocp_data &= ~(BMU_RESET_EP_IN | BMU_RESET_EP_OUT); 34178c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data); 34188c2ecf20Sopenharmony_ci ocp_data |= BMU_RESET_EP_IN | BMU_RESET_EP_OUT; 34198c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data); 34208c2ecf20Sopenharmony_ci} 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci/* Clear the bp to stop the firmware before loading a new one */ 34238c2ecf20Sopenharmony_cistatic void rtl_clear_bp(struct r8152 *tp, u16 type) 34248c2ecf20Sopenharmony_ci{ 34258c2ecf20Sopenharmony_ci switch (tp->version) { 34268c2ecf20Sopenharmony_ci case RTL_VER_01: 34278c2ecf20Sopenharmony_ci case RTL_VER_02: 34288c2ecf20Sopenharmony_ci case RTL_VER_07: 34298c2ecf20Sopenharmony_ci break; 34308c2ecf20Sopenharmony_ci case RTL_VER_03: 34318c2ecf20Sopenharmony_ci case RTL_VER_04: 34328c2ecf20Sopenharmony_ci case RTL_VER_05: 34338c2ecf20Sopenharmony_ci case RTL_VER_06: 34348c2ecf20Sopenharmony_ci ocp_write_byte(tp, type, PLA_BP_EN, 0); 34358c2ecf20Sopenharmony_ci break; 34368c2ecf20Sopenharmony_ci case RTL_VER_08: 34378c2ecf20Sopenharmony_ci case RTL_VER_09: 34388c2ecf20Sopenharmony_ci default: 34398c2ecf20Sopenharmony_ci if (type == MCU_TYPE_USB) { 34408c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0); 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0); 34438c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0); 34448c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_10, 0); 34458c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_11, 0); 34468c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_12, 0); 34478c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_13, 0); 34488c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_14, 0); 34498c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_15, 0); 34508c2ecf20Sopenharmony_ci } else { 34518c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); 34528c2ecf20Sopenharmony_ci } 34538c2ecf20Sopenharmony_ci break; 34548c2ecf20Sopenharmony_ci } 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_0, 0); 34578c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_1, 0); 34588c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_2, 0); 34598c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_3, 0); 34608c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_4, 0); 34618c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_5, 0); 34628c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_6, 0); 34638c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_7, 0); 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci /* wait 3 ms to make sure the firmware is stopped */ 34668c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 34678c2ecf20Sopenharmony_ci ocp_write_word(tp, type, PLA_BP_BA, 0); 34688c2ecf20Sopenharmony_ci} 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_cistatic int r8153_patch_request(struct r8152 *tp, bool request) 34718c2ecf20Sopenharmony_ci{ 34728c2ecf20Sopenharmony_ci u16 data; 34738c2ecf20Sopenharmony_ci int i; 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); 34768c2ecf20Sopenharmony_ci if (request) 34778c2ecf20Sopenharmony_ci data |= PATCH_REQUEST; 34788c2ecf20Sopenharmony_ci else 34798c2ecf20Sopenharmony_ci data &= ~PATCH_REQUEST; 34808c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci for (i = 0; request && i < 5000; i++) { 34838c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 34848c2ecf20Sopenharmony_ci if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) 34858c2ecf20Sopenharmony_ci break; 34868c2ecf20Sopenharmony_ci } 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { 34898c2ecf20Sopenharmony_ci netif_err(tp, drv, tp->netdev, "patch request fail\n"); 34908c2ecf20Sopenharmony_ci r8153_patch_request(tp, false); 34918c2ecf20Sopenharmony_ci return -ETIME; 34928c2ecf20Sopenharmony_ci } else { 34938c2ecf20Sopenharmony_ci return 0; 34948c2ecf20Sopenharmony_ci } 34958c2ecf20Sopenharmony_ci} 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_cistatic int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key) 34988c2ecf20Sopenharmony_ci{ 34998c2ecf20Sopenharmony_ci if (r8153_patch_request(tp, true)) { 35008c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "patch request fail\n"); 35018c2ecf20Sopenharmony_ci return -ETIME; 35028c2ecf20Sopenharmony_ci } 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci sram_write(tp, key_addr, patch_key); 35058c2ecf20Sopenharmony_ci sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK); 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci return 0; 35088c2ecf20Sopenharmony_ci} 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_cistatic int r8153_post_ram_code(struct r8152 *tp, u16 key_addr) 35118c2ecf20Sopenharmony_ci{ 35128c2ecf20Sopenharmony_ci u16 data; 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci sram_write(tp, 0x0000, 0x0000); 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_PHY_LOCK); 35178c2ecf20Sopenharmony_ci data &= ~PATCH_LOCK; 35188c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_PHY_LOCK, data); 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci sram_write(tp, key_addr, 0x0000); 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci r8153_patch_request(tp, false); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base); 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci return 0; 35278c2ecf20Sopenharmony_ci} 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_cistatic bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy) 35308c2ecf20Sopenharmony_ci{ 35318c2ecf20Sopenharmony_ci u32 length; 35328c2ecf20Sopenharmony_ci u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start; 35338c2ecf20Sopenharmony_ci bool rc = false; 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci switch (tp->version) { 35368c2ecf20Sopenharmony_ci case RTL_VER_04: 35378c2ecf20Sopenharmony_ci case RTL_VER_05: 35388c2ecf20Sopenharmony_ci case RTL_VER_06: 35398c2ecf20Sopenharmony_ci fw_reg = 0xa014; 35408c2ecf20Sopenharmony_ci ba_reg = 0xa012; 35418c2ecf20Sopenharmony_ci patch_en_addr = 0xa01a; 35428c2ecf20Sopenharmony_ci mode_reg = 0xb820; 35438c2ecf20Sopenharmony_ci bp_start = 0xa000; 35448c2ecf20Sopenharmony_ci break; 35458c2ecf20Sopenharmony_ci default: 35468c2ecf20Sopenharmony_ci goto out; 35478c2ecf20Sopenharmony_ci } 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci fw_offset = __le16_to_cpu(phy->fw_offset); 35508c2ecf20Sopenharmony_ci if (fw_offset < sizeof(*phy)) { 35518c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "fw_offset too small\n"); 35528c2ecf20Sopenharmony_ci goto out; 35538c2ecf20Sopenharmony_ci } 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci length = __le32_to_cpu(phy->blk_hdr.length); 35568c2ecf20Sopenharmony_ci if (length < fw_offset) { 35578c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid fw_offset\n"); 35588c2ecf20Sopenharmony_ci goto out; 35598c2ecf20Sopenharmony_ci } 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci length -= __le16_to_cpu(phy->fw_offset); 35628c2ecf20Sopenharmony_ci if (!length || (length & 1)) { 35638c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid block length\n"); 35648c2ecf20Sopenharmony_ci goto out; 35658c2ecf20Sopenharmony_ci } 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->fw_reg) != fw_reg) { 35688c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid register to load firmware\n"); 35698c2ecf20Sopenharmony_ci goto out; 35708c2ecf20Sopenharmony_ci } 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->ba_reg) != ba_reg) { 35738c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid base address register\n"); 35748c2ecf20Sopenharmony_ci goto out; 35758c2ecf20Sopenharmony_ci } 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) { 35788c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 35798c2ecf20Sopenharmony_ci "invalid patch mode enabled register\n"); 35808c2ecf20Sopenharmony_ci goto out; 35818c2ecf20Sopenharmony_ci } 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->mode_reg) != mode_reg) { 35848c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 35858c2ecf20Sopenharmony_ci "invalid register to switch the mode\n"); 35868c2ecf20Sopenharmony_ci goto out; 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->bp_start) != bp_start) { 35908c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 35918c2ecf20Sopenharmony_ci "invalid start register of break point\n"); 35928c2ecf20Sopenharmony_ci goto out; 35938c2ecf20Sopenharmony_ci } 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci if (__le16_to_cpu(phy->bp_num) > 4) { 35968c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid break point number\n"); 35978c2ecf20Sopenharmony_ci goto out; 35988c2ecf20Sopenharmony_ci } 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci rc = true; 36018c2ecf20Sopenharmony_ciout: 36028c2ecf20Sopenharmony_ci return rc; 36038c2ecf20Sopenharmony_ci} 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_cistatic bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) 36068c2ecf20Sopenharmony_ci{ 36078c2ecf20Sopenharmony_ci u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; 36088c2ecf20Sopenharmony_ci bool rc = false; 36098c2ecf20Sopenharmony_ci u32 length, type; 36108c2ecf20Sopenharmony_ci int i, max_bp; 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci type = __le32_to_cpu(mac->blk_hdr.type); 36138c2ecf20Sopenharmony_ci if (type == RTL_FW_PLA) { 36148c2ecf20Sopenharmony_ci switch (tp->version) { 36158c2ecf20Sopenharmony_ci case RTL_VER_01: 36168c2ecf20Sopenharmony_ci case RTL_VER_02: 36178c2ecf20Sopenharmony_ci case RTL_VER_07: 36188c2ecf20Sopenharmony_ci fw_reg = 0xf800; 36198c2ecf20Sopenharmony_ci bp_ba_addr = PLA_BP_BA; 36208c2ecf20Sopenharmony_ci bp_en_addr = 0; 36218c2ecf20Sopenharmony_ci bp_start = PLA_BP_0; 36228c2ecf20Sopenharmony_ci max_bp = 8; 36238c2ecf20Sopenharmony_ci break; 36248c2ecf20Sopenharmony_ci case RTL_VER_03: 36258c2ecf20Sopenharmony_ci case RTL_VER_04: 36268c2ecf20Sopenharmony_ci case RTL_VER_05: 36278c2ecf20Sopenharmony_ci case RTL_VER_06: 36288c2ecf20Sopenharmony_ci case RTL_VER_08: 36298c2ecf20Sopenharmony_ci case RTL_VER_09: 36308c2ecf20Sopenharmony_ci fw_reg = 0xf800; 36318c2ecf20Sopenharmony_ci bp_ba_addr = PLA_BP_BA; 36328c2ecf20Sopenharmony_ci bp_en_addr = PLA_BP_EN; 36338c2ecf20Sopenharmony_ci bp_start = PLA_BP_0; 36348c2ecf20Sopenharmony_ci max_bp = 8; 36358c2ecf20Sopenharmony_ci break; 36368c2ecf20Sopenharmony_ci default: 36378c2ecf20Sopenharmony_ci goto out; 36388c2ecf20Sopenharmony_ci } 36398c2ecf20Sopenharmony_ci } else if (type == RTL_FW_USB) { 36408c2ecf20Sopenharmony_ci switch (tp->version) { 36418c2ecf20Sopenharmony_ci case RTL_VER_03: 36428c2ecf20Sopenharmony_ci case RTL_VER_04: 36438c2ecf20Sopenharmony_ci case RTL_VER_05: 36448c2ecf20Sopenharmony_ci case RTL_VER_06: 36458c2ecf20Sopenharmony_ci fw_reg = 0xf800; 36468c2ecf20Sopenharmony_ci bp_ba_addr = USB_BP_BA; 36478c2ecf20Sopenharmony_ci bp_en_addr = USB_BP_EN; 36488c2ecf20Sopenharmony_ci bp_start = USB_BP_0; 36498c2ecf20Sopenharmony_ci max_bp = 8; 36508c2ecf20Sopenharmony_ci break; 36518c2ecf20Sopenharmony_ci case RTL_VER_08: 36528c2ecf20Sopenharmony_ci case RTL_VER_09: 36538c2ecf20Sopenharmony_ci fw_reg = 0xe600; 36548c2ecf20Sopenharmony_ci bp_ba_addr = USB_BP_BA; 36558c2ecf20Sopenharmony_ci bp_en_addr = USB_BP2_EN; 36568c2ecf20Sopenharmony_ci bp_start = USB_BP_0; 36578c2ecf20Sopenharmony_ci max_bp = 16; 36588c2ecf20Sopenharmony_ci break; 36598c2ecf20Sopenharmony_ci case RTL_VER_01: 36608c2ecf20Sopenharmony_ci case RTL_VER_02: 36618c2ecf20Sopenharmony_ci case RTL_VER_07: 36628c2ecf20Sopenharmony_ci default: 36638c2ecf20Sopenharmony_ci goto out; 36648c2ecf20Sopenharmony_ci } 36658c2ecf20Sopenharmony_ci } else { 36668c2ecf20Sopenharmony_ci goto out; 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci fw_offset = __le16_to_cpu(mac->fw_offset); 36708c2ecf20Sopenharmony_ci if (fw_offset < sizeof(*mac)) { 36718c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "fw_offset too small\n"); 36728c2ecf20Sopenharmony_ci goto out; 36738c2ecf20Sopenharmony_ci } 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci length = __le32_to_cpu(mac->blk_hdr.length); 36768c2ecf20Sopenharmony_ci if (length < fw_offset) { 36778c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid fw_offset\n"); 36788c2ecf20Sopenharmony_ci goto out; 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci length -= fw_offset; 36828c2ecf20Sopenharmony_ci if (length < 4 || (length & 3)) { 36838c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid block length\n"); 36848c2ecf20Sopenharmony_ci goto out; 36858c2ecf20Sopenharmony_ci } 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci if (__le16_to_cpu(mac->fw_reg) != fw_reg) { 36888c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid register to load firmware\n"); 36898c2ecf20Sopenharmony_ci goto out; 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) { 36938c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid base address register\n"); 36948c2ecf20Sopenharmony_ci goto out; 36958c2ecf20Sopenharmony_ci } 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) { 36988c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid enabled mask register\n"); 36998c2ecf20Sopenharmony_ci goto out; 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (__le16_to_cpu(mac->bp_start) != bp_start) { 37038c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 37048c2ecf20Sopenharmony_ci "invalid start register of break point\n"); 37058c2ecf20Sopenharmony_ci goto out; 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci if (__le16_to_cpu(mac->bp_num) > max_bp) { 37098c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "invalid break point number\n"); 37108c2ecf20Sopenharmony_ci goto out; 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) { 37148c2ecf20Sopenharmony_ci if (mac->bp[i]) { 37158c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); 37168c2ecf20Sopenharmony_ci goto out; 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci rc = true; 37218c2ecf20Sopenharmony_ciout: 37228c2ecf20Sopenharmony_ci return rc; 37238c2ecf20Sopenharmony_ci} 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci/* Verify the checksum for the firmware file. It is calculated from the version 37268c2ecf20Sopenharmony_ci * field to the end of the file. Compare the result with the checksum field to 37278c2ecf20Sopenharmony_ci * make sure the file is correct. 37288c2ecf20Sopenharmony_ci */ 37298c2ecf20Sopenharmony_cistatic long rtl8152_fw_verify_checksum(struct r8152 *tp, 37308c2ecf20Sopenharmony_ci struct fw_header *fw_hdr, size_t size) 37318c2ecf20Sopenharmony_ci{ 37328c2ecf20Sopenharmony_ci unsigned char checksum[sizeof(fw_hdr->checksum)]; 37338c2ecf20Sopenharmony_ci struct crypto_shash *alg; 37348c2ecf20Sopenharmony_ci struct shash_desc *sdesc; 37358c2ecf20Sopenharmony_ci size_t len; 37368c2ecf20Sopenharmony_ci long rc; 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci alg = crypto_alloc_shash("sha256", 0, 0); 37398c2ecf20Sopenharmony_ci if (IS_ERR(alg)) { 37408c2ecf20Sopenharmony_ci rc = PTR_ERR(alg); 37418c2ecf20Sopenharmony_ci goto out; 37428c2ecf20Sopenharmony_ci } 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci if (crypto_shash_digestsize(alg) != sizeof(fw_hdr->checksum)) { 37458c2ecf20Sopenharmony_ci rc = -EFAULT; 37468c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "digestsize incorrect (%u)\n", 37478c2ecf20Sopenharmony_ci crypto_shash_digestsize(alg)); 37488c2ecf20Sopenharmony_ci goto free_shash; 37498c2ecf20Sopenharmony_ci } 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci len = sizeof(*sdesc) + crypto_shash_descsize(alg); 37528c2ecf20Sopenharmony_ci sdesc = kmalloc(len, GFP_KERNEL); 37538c2ecf20Sopenharmony_ci if (!sdesc) { 37548c2ecf20Sopenharmony_ci rc = -ENOMEM; 37558c2ecf20Sopenharmony_ci goto free_shash; 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci sdesc->tfm = alg; 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci len = size - sizeof(fw_hdr->checksum); 37608c2ecf20Sopenharmony_ci rc = crypto_shash_digest(sdesc, fw_hdr->version, len, checksum); 37618c2ecf20Sopenharmony_ci kfree(sdesc); 37628c2ecf20Sopenharmony_ci if (rc) 37638c2ecf20Sopenharmony_ci goto free_shash; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci if (memcmp(fw_hdr->checksum, checksum, sizeof(fw_hdr->checksum))) { 37668c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "checksum fail\n"); 37678c2ecf20Sopenharmony_ci rc = -EFAULT; 37688c2ecf20Sopenharmony_ci } 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_cifree_shash: 37718c2ecf20Sopenharmony_ci crypto_free_shash(alg); 37728c2ecf20Sopenharmony_ciout: 37738c2ecf20Sopenharmony_ci return rc; 37748c2ecf20Sopenharmony_ci} 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_cistatic long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci const struct firmware *fw = rtl_fw->fw; 37798c2ecf20Sopenharmony_ci struct fw_header *fw_hdr = (struct fw_header *)fw->data; 37808c2ecf20Sopenharmony_ci struct fw_mac *pla = NULL, *usb = NULL; 37818c2ecf20Sopenharmony_ci struct fw_phy_patch_key *start = NULL; 37828c2ecf20Sopenharmony_ci struct fw_phy_nc *phy_nc = NULL; 37838c2ecf20Sopenharmony_ci struct fw_block *stop = NULL; 37848c2ecf20Sopenharmony_ci long ret = -EFAULT; 37858c2ecf20Sopenharmony_ci int i; 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci if (fw->size < sizeof(*fw_hdr)) { 37888c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "file too small\n"); 37898c2ecf20Sopenharmony_ci goto fail; 37908c2ecf20Sopenharmony_ci } 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci ret = rtl8152_fw_verify_checksum(tp, fw_hdr, fw->size); 37938c2ecf20Sopenharmony_ci if (ret) 37948c2ecf20Sopenharmony_ci goto fail; 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci ret = -EFAULT; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci for (i = sizeof(*fw_hdr); i < fw->size;) { 37998c2ecf20Sopenharmony_ci struct fw_block *block = (struct fw_block *)&fw->data[i]; 38008c2ecf20Sopenharmony_ci u32 type; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci if ((i + sizeof(*block)) > fw->size) 38038c2ecf20Sopenharmony_ci goto fail; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci type = __le32_to_cpu(block->type); 38068c2ecf20Sopenharmony_ci switch (type) { 38078c2ecf20Sopenharmony_ci case RTL_FW_END: 38088c2ecf20Sopenharmony_ci if (__le32_to_cpu(block->length) != sizeof(*block)) 38098c2ecf20Sopenharmony_ci goto fail; 38108c2ecf20Sopenharmony_ci goto fw_end; 38118c2ecf20Sopenharmony_ci case RTL_FW_PLA: 38128c2ecf20Sopenharmony_ci if (pla) { 38138c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38148c2ecf20Sopenharmony_ci "multiple PLA firmware encountered"); 38158c2ecf20Sopenharmony_ci goto fail; 38168c2ecf20Sopenharmony_ci } 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci pla = (struct fw_mac *)block; 38198c2ecf20Sopenharmony_ci if (!rtl8152_is_fw_mac_ok(tp, pla)) { 38208c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38218c2ecf20Sopenharmony_ci "check PLA firmware failed\n"); 38228c2ecf20Sopenharmony_ci goto fail; 38238c2ecf20Sopenharmony_ci } 38248c2ecf20Sopenharmony_ci break; 38258c2ecf20Sopenharmony_ci case RTL_FW_USB: 38268c2ecf20Sopenharmony_ci if (usb) { 38278c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38288c2ecf20Sopenharmony_ci "multiple USB firmware encountered"); 38298c2ecf20Sopenharmony_ci goto fail; 38308c2ecf20Sopenharmony_ci } 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci usb = (struct fw_mac *)block; 38338c2ecf20Sopenharmony_ci if (!rtl8152_is_fw_mac_ok(tp, usb)) { 38348c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38358c2ecf20Sopenharmony_ci "check USB firmware failed\n"); 38368c2ecf20Sopenharmony_ci goto fail; 38378c2ecf20Sopenharmony_ci } 38388c2ecf20Sopenharmony_ci break; 38398c2ecf20Sopenharmony_ci case RTL_FW_PHY_START: 38408c2ecf20Sopenharmony_ci if (start || phy_nc || stop) { 38418c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38428c2ecf20Sopenharmony_ci "check PHY_START fail\n"); 38438c2ecf20Sopenharmony_ci goto fail; 38448c2ecf20Sopenharmony_ci } 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci if (__le32_to_cpu(block->length) != sizeof(*start)) { 38478c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38488c2ecf20Sopenharmony_ci "Invalid length for PHY_START\n"); 38498c2ecf20Sopenharmony_ci goto fail; 38508c2ecf20Sopenharmony_ci } 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci start = (struct fw_phy_patch_key *)block; 38538c2ecf20Sopenharmony_ci break; 38548c2ecf20Sopenharmony_ci case RTL_FW_PHY_STOP: 38558c2ecf20Sopenharmony_ci if (stop || !start) { 38568c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38578c2ecf20Sopenharmony_ci "Check PHY_STOP fail\n"); 38588c2ecf20Sopenharmony_ci goto fail; 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci if (__le32_to_cpu(block->length) != sizeof(*block)) { 38628c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38638c2ecf20Sopenharmony_ci "Invalid length for PHY_STOP\n"); 38648c2ecf20Sopenharmony_ci goto fail; 38658c2ecf20Sopenharmony_ci } 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci stop = block; 38688c2ecf20Sopenharmony_ci break; 38698c2ecf20Sopenharmony_ci case RTL_FW_PHY_NC: 38708c2ecf20Sopenharmony_ci if (!start || stop) { 38718c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38728c2ecf20Sopenharmony_ci "check PHY_NC fail\n"); 38738c2ecf20Sopenharmony_ci goto fail; 38748c2ecf20Sopenharmony_ci } 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci if (phy_nc) { 38778c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38788c2ecf20Sopenharmony_ci "multiple PHY NC encountered\n"); 38798c2ecf20Sopenharmony_ci goto fail; 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci phy_nc = (struct fw_phy_nc *)block; 38838c2ecf20Sopenharmony_ci if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) { 38848c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, 38858c2ecf20Sopenharmony_ci "check PHY NC firmware failed\n"); 38868c2ecf20Sopenharmony_ci goto fail; 38878c2ecf20Sopenharmony_ci } 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci break; 38908c2ecf20Sopenharmony_ci default: 38918c2ecf20Sopenharmony_ci dev_warn(&tp->intf->dev, "Unknown type %u is found\n", 38928c2ecf20Sopenharmony_ci type); 38938c2ecf20Sopenharmony_ci break; 38948c2ecf20Sopenharmony_ci } 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci /* next block */ 38978c2ecf20Sopenharmony_ci i += ALIGN(__le32_to_cpu(block->length), 8); 38988c2ecf20Sopenharmony_ci } 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_cifw_end: 39018c2ecf20Sopenharmony_ci if ((phy_nc || start) && !stop) { 39028c2ecf20Sopenharmony_ci dev_err(&tp->intf->dev, "without PHY_STOP\n"); 39038c2ecf20Sopenharmony_ci goto fail; 39048c2ecf20Sopenharmony_ci } 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci return 0; 39078c2ecf20Sopenharmony_cifail: 39088c2ecf20Sopenharmony_ci return ret; 39098c2ecf20Sopenharmony_ci} 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_cistatic void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) 39128c2ecf20Sopenharmony_ci{ 39138c2ecf20Sopenharmony_ci u16 mode_reg, bp_index; 39148c2ecf20Sopenharmony_ci u32 length, i, num; 39158c2ecf20Sopenharmony_ci __le16 *data; 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci mode_reg = __le16_to_cpu(phy->mode_reg); 39188c2ecf20Sopenharmony_ci sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre)); 39198c2ecf20Sopenharmony_ci sram_write(tp, __le16_to_cpu(phy->ba_reg), 39208c2ecf20Sopenharmony_ci __le16_to_cpu(phy->ba_data)); 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci length = __le32_to_cpu(phy->blk_hdr.length); 39238c2ecf20Sopenharmony_ci length -= __le16_to_cpu(phy->fw_offset); 39248c2ecf20Sopenharmony_ci num = length / 2; 39258c2ecf20Sopenharmony_ci data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset)); 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg)); 39288c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) 39298c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i])); 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci sram_write(tp, __le16_to_cpu(phy->patch_en_addr), 39328c2ecf20Sopenharmony_ci __le16_to_cpu(phy->patch_en_value)); 39338c2ecf20Sopenharmony_ci 39348c2ecf20Sopenharmony_ci bp_index = __le16_to_cpu(phy->bp_start); 39358c2ecf20Sopenharmony_ci num = __le16_to_cpu(phy->bp_num); 39368c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 39378c2ecf20Sopenharmony_ci sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i])); 39388c2ecf20Sopenharmony_ci bp_index += 2; 39398c2ecf20Sopenharmony_ci } 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post)); 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info); 39448c2ecf20Sopenharmony_ci} 39458c2ecf20Sopenharmony_ci 39468c2ecf20Sopenharmony_cistatic void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) 39478c2ecf20Sopenharmony_ci{ 39488c2ecf20Sopenharmony_ci u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; 39498c2ecf20Sopenharmony_ci u32 length; 39508c2ecf20Sopenharmony_ci u8 *data; 39518c2ecf20Sopenharmony_ci int i; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci switch (__le32_to_cpu(mac->blk_hdr.type)) { 39548c2ecf20Sopenharmony_ci case RTL_FW_PLA: 39558c2ecf20Sopenharmony_ci type = MCU_TYPE_PLA; 39568c2ecf20Sopenharmony_ci break; 39578c2ecf20Sopenharmony_ci case RTL_FW_USB: 39588c2ecf20Sopenharmony_ci type = MCU_TYPE_USB; 39598c2ecf20Sopenharmony_ci break; 39608c2ecf20Sopenharmony_ci default: 39618c2ecf20Sopenharmony_ci return; 39628c2ecf20Sopenharmony_ci } 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci rtl_clear_bp(tp, type); 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci /* Enable backup/restore of MACDBG. This is required after clearing PLA 39678c2ecf20Sopenharmony_ci * break points and before applying the PLA firmware. 39688c2ecf20Sopenharmony_ci */ 39698c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_04 && type == MCU_TYPE_PLA && 39708c2ecf20Sopenharmony_ci !(ocp_read_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST) & DEBUG_OE)) { 39718c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_PRE, DEBUG_LTSSM); 39728c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); 39738c2ecf20Sopenharmony_ci } 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci length = __le32_to_cpu(mac->blk_hdr.length); 39768c2ecf20Sopenharmony_ci length -= __le16_to_cpu(mac->fw_offset); 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci data = (u8 *)mac; 39798c2ecf20Sopenharmony_ci data += __le16_to_cpu(mac->fw_offset); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data, 39828c2ecf20Sopenharmony_ci type); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr), 39858c2ecf20Sopenharmony_ci __le16_to_cpu(mac->bp_ba_value)); 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci bp_index = __le16_to_cpu(mac->bp_start); 39888c2ecf20Sopenharmony_ci bp_num = __le16_to_cpu(mac->bp_num); 39898c2ecf20Sopenharmony_ci for (i = 0; i < bp_num; i++) { 39908c2ecf20Sopenharmony_ci ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i])); 39918c2ecf20Sopenharmony_ci bp_index += 2; 39928c2ecf20Sopenharmony_ci } 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci bp_en_addr = __le16_to_cpu(mac->bp_en_addr); 39958c2ecf20Sopenharmony_ci if (bp_en_addr) 39968c2ecf20Sopenharmony_ci ocp_write_word(tp, type, bp_en_addr, 39978c2ecf20Sopenharmony_ci __le16_to_cpu(mac->bp_en_value)); 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_ci fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg); 40008c2ecf20Sopenharmony_ci if (fw_ver_reg) 40018c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, 40028c2ecf20Sopenharmony_ci mac->fw_ver_data); 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info); 40058c2ecf20Sopenharmony_ci} 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_cistatic void rtl8152_apply_firmware(struct r8152 *tp) 40088c2ecf20Sopenharmony_ci{ 40098c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw = &tp->rtl_fw; 40108c2ecf20Sopenharmony_ci const struct firmware *fw; 40118c2ecf20Sopenharmony_ci struct fw_header *fw_hdr; 40128c2ecf20Sopenharmony_ci struct fw_phy_patch_key *key; 40138c2ecf20Sopenharmony_ci u16 key_addr = 0; 40148c2ecf20Sopenharmony_ci int i; 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(rtl_fw->fw)) 40178c2ecf20Sopenharmony_ci return; 40188c2ecf20Sopenharmony_ci 40198c2ecf20Sopenharmony_ci fw = rtl_fw->fw; 40208c2ecf20Sopenharmony_ci fw_hdr = (struct fw_header *)fw->data; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci if (rtl_fw->pre_fw) 40238c2ecf20Sopenharmony_ci rtl_fw->pre_fw(tp); 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci for (i = offsetof(struct fw_header, blocks); i < fw->size;) { 40268c2ecf20Sopenharmony_ci struct fw_block *block = (struct fw_block *)&fw->data[i]; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci switch (__le32_to_cpu(block->type)) { 40298c2ecf20Sopenharmony_ci case RTL_FW_END: 40308c2ecf20Sopenharmony_ci goto post_fw; 40318c2ecf20Sopenharmony_ci case RTL_FW_PLA: 40328c2ecf20Sopenharmony_ci case RTL_FW_USB: 40338c2ecf20Sopenharmony_ci rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); 40348c2ecf20Sopenharmony_ci break; 40358c2ecf20Sopenharmony_ci case RTL_FW_PHY_START: 40368c2ecf20Sopenharmony_ci key = (struct fw_phy_patch_key *)block; 40378c2ecf20Sopenharmony_ci key_addr = __le16_to_cpu(key->key_reg); 40388c2ecf20Sopenharmony_ci r8153_pre_ram_code(tp, key_addr, 40398c2ecf20Sopenharmony_ci __le16_to_cpu(key->key_data)); 40408c2ecf20Sopenharmony_ci break; 40418c2ecf20Sopenharmony_ci case RTL_FW_PHY_STOP: 40428c2ecf20Sopenharmony_ci WARN_ON(!key_addr); 40438c2ecf20Sopenharmony_ci r8153_post_ram_code(tp, key_addr); 40448c2ecf20Sopenharmony_ci break; 40458c2ecf20Sopenharmony_ci case RTL_FW_PHY_NC: 40468c2ecf20Sopenharmony_ci rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block); 40478c2ecf20Sopenharmony_ci break; 40488c2ecf20Sopenharmony_ci default: 40498c2ecf20Sopenharmony_ci break; 40508c2ecf20Sopenharmony_ci } 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci i += ALIGN(__le32_to_cpu(block->length), 8); 40538c2ecf20Sopenharmony_ci } 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_cipost_fw: 40568c2ecf20Sopenharmony_ci if (rtl_fw->post_fw) 40578c2ecf20Sopenharmony_ci rtl_fw->post_fw(tp); 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE); 40608c2ecf20Sopenharmony_ci dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version); 40618c2ecf20Sopenharmony_ci} 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_cistatic void rtl8152_release_firmware(struct r8152 *tp) 40648c2ecf20Sopenharmony_ci{ 40658c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw = &tp->rtl_fw; 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(rtl_fw->fw)) { 40688c2ecf20Sopenharmony_ci release_firmware(rtl_fw->fw); 40698c2ecf20Sopenharmony_ci rtl_fw->fw = NULL; 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci} 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_cistatic int rtl8152_request_firmware(struct r8152 *tp) 40748c2ecf20Sopenharmony_ci{ 40758c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw = &tp->rtl_fw; 40768c2ecf20Sopenharmony_ci long rc; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci if (rtl_fw->fw || !rtl_fw->fw_name) { 40798c2ecf20Sopenharmony_ci dev_info(&tp->intf->dev, "skip request firmware\n"); 40808c2ecf20Sopenharmony_ci rc = 0; 40818c2ecf20Sopenharmony_ci goto result; 40828c2ecf20Sopenharmony_ci } 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, &tp->intf->dev); 40858c2ecf20Sopenharmony_ci if (rc < 0) 40868c2ecf20Sopenharmony_ci goto result; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci rc = rtl8152_check_firmware(tp, rtl_fw); 40898c2ecf20Sopenharmony_ci if (rc < 0) 40908c2ecf20Sopenharmony_ci release_firmware(rtl_fw->fw); 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ciresult: 40938c2ecf20Sopenharmony_ci if (rc) { 40948c2ecf20Sopenharmony_ci rtl_fw->fw = ERR_PTR(rc); 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci dev_warn(&tp->intf->dev, 40978c2ecf20Sopenharmony_ci "unable to load firmware patch %s (%ld)\n", 40988c2ecf20Sopenharmony_ci rtl_fw->fw_name, rc); 40998c2ecf20Sopenharmony_ci } 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_ci return rc; 41028c2ecf20Sopenharmony_ci} 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_cistatic void r8152_aldps_en(struct r8152 *tp, bool enable) 41058c2ecf20Sopenharmony_ci{ 41068c2ecf20Sopenharmony_ci if (enable) { 41078c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | 41088c2ecf20Sopenharmony_ci LINKENA | DIS_SDSAVE); 41098c2ecf20Sopenharmony_ci } else { 41108c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | 41118c2ecf20Sopenharmony_ci DIS_SDSAVE); 41128c2ecf20Sopenharmony_ci msleep(20); 41138c2ecf20Sopenharmony_ci } 41148c2ecf20Sopenharmony_ci} 41158c2ecf20Sopenharmony_ci 41168c2ecf20Sopenharmony_cistatic inline void r8152_mmd_indirect(struct r8152 *tp, u16 dev, u16 reg) 41178c2ecf20Sopenharmony_ci{ 41188c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | dev); 41198c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_DATA, reg); 41208c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | dev); 41218c2ecf20Sopenharmony_ci} 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_cistatic u16 r8152_mmd_read(struct r8152 *tp, u16 dev, u16 reg) 41248c2ecf20Sopenharmony_ci{ 41258c2ecf20Sopenharmony_ci u16 data; 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci r8152_mmd_indirect(tp, dev, reg); 41288c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_EEE_DATA); 41298c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_AR, 0x0000); 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci return data; 41328c2ecf20Sopenharmony_ci} 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_cistatic void r8152_mmd_write(struct r8152 *tp, u16 dev, u16 reg, u16 data) 41358c2ecf20Sopenharmony_ci{ 41368c2ecf20Sopenharmony_ci r8152_mmd_indirect(tp, dev, reg); 41378c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_DATA, data); 41388c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_AR, 0x0000); 41398c2ecf20Sopenharmony_ci} 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_cistatic void r8152_eee_en(struct r8152 *tp, bool enable) 41428c2ecf20Sopenharmony_ci{ 41438c2ecf20Sopenharmony_ci u16 config1, config2, config3; 41448c2ecf20Sopenharmony_ci u32 ocp_data; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); 41478c2ecf20Sopenharmony_ci config1 = ocp_reg_read(tp, OCP_EEE_CONFIG1) & ~sd_rise_time_mask; 41488c2ecf20Sopenharmony_ci config2 = ocp_reg_read(tp, OCP_EEE_CONFIG2); 41498c2ecf20Sopenharmony_ci config3 = ocp_reg_read(tp, OCP_EEE_CONFIG3) & ~fast_snr_mask; 41508c2ecf20Sopenharmony_ci 41518c2ecf20Sopenharmony_ci if (enable) { 41528c2ecf20Sopenharmony_ci ocp_data |= EEE_RX_EN | EEE_TX_EN; 41538c2ecf20Sopenharmony_ci config1 |= EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | RX_QUIET_EN; 41548c2ecf20Sopenharmony_ci config1 |= sd_rise_time(1); 41558c2ecf20Sopenharmony_ci config2 |= RG_DACQUIET_EN | RG_LDVQUIET_EN; 41568c2ecf20Sopenharmony_ci config3 |= fast_snr(42); 41578c2ecf20Sopenharmony_ci } else { 41588c2ecf20Sopenharmony_ci ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); 41598c2ecf20Sopenharmony_ci config1 &= ~(EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | 41608c2ecf20Sopenharmony_ci RX_QUIET_EN); 41618c2ecf20Sopenharmony_ci config1 |= sd_rise_time(7); 41628c2ecf20Sopenharmony_ci config2 &= ~(RG_DACQUIET_EN | RG_LDVQUIET_EN); 41638c2ecf20Sopenharmony_ci config3 |= fast_snr(511); 41648c2ecf20Sopenharmony_ci } 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); 41678c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_CONFIG1, config1); 41688c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_CONFIG2, config2); 41698c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_CONFIG3, config3); 41708c2ecf20Sopenharmony_ci} 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_cistatic void r8153_eee_en(struct r8152 *tp, bool enable) 41738c2ecf20Sopenharmony_ci{ 41748c2ecf20Sopenharmony_ci u32 ocp_data; 41758c2ecf20Sopenharmony_ci u16 config; 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); 41788c2ecf20Sopenharmony_ci config = ocp_reg_read(tp, OCP_EEE_CFG); 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci if (enable) { 41818c2ecf20Sopenharmony_ci ocp_data |= EEE_RX_EN | EEE_TX_EN; 41828c2ecf20Sopenharmony_ci config |= EEE10_EN; 41838c2ecf20Sopenharmony_ci } else { 41848c2ecf20Sopenharmony_ci ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); 41858c2ecf20Sopenharmony_ci config &= ~EEE10_EN; 41868c2ecf20Sopenharmony_ci } 41878c2ecf20Sopenharmony_ci 41888c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); 41898c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_CFG, config); 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci tp->ups_info.eee = enable; 41928c2ecf20Sopenharmony_ci} 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_cistatic void rtl_eee_enable(struct r8152 *tp, bool enable) 41958c2ecf20Sopenharmony_ci{ 41968c2ecf20Sopenharmony_ci switch (tp->version) { 41978c2ecf20Sopenharmony_ci case RTL_VER_01: 41988c2ecf20Sopenharmony_ci case RTL_VER_02: 41998c2ecf20Sopenharmony_ci case RTL_VER_07: 42008c2ecf20Sopenharmony_ci if (enable) { 42018c2ecf20Sopenharmony_ci r8152_eee_en(tp, true); 42028c2ecf20Sopenharmony_ci r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 42038c2ecf20Sopenharmony_ci tp->eee_adv); 42048c2ecf20Sopenharmony_ci } else { 42058c2ecf20Sopenharmony_ci r8152_eee_en(tp, false); 42068c2ecf20Sopenharmony_ci r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0); 42078c2ecf20Sopenharmony_ci } 42088c2ecf20Sopenharmony_ci break; 42098c2ecf20Sopenharmony_ci case RTL_VER_03: 42108c2ecf20Sopenharmony_ci case RTL_VER_04: 42118c2ecf20Sopenharmony_ci case RTL_VER_05: 42128c2ecf20Sopenharmony_ci case RTL_VER_06: 42138c2ecf20Sopenharmony_ci case RTL_VER_08: 42148c2ecf20Sopenharmony_ci case RTL_VER_09: 42158c2ecf20Sopenharmony_ci if (enable) { 42168c2ecf20Sopenharmony_ci r8153_eee_en(tp, true); 42178c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv); 42188c2ecf20Sopenharmony_ci } else { 42198c2ecf20Sopenharmony_ci r8153_eee_en(tp, false); 42208c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_ADV, 0); 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci break; 42238c2ecf20Sopenharmony_ci default: 42248c2ecf20Sopenharmony_ci break; 42258c2ecf20Sopenharmony_ci } 42268c2ecf20Sopenharmony_ci} 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_cistatic void r8152b_enable_fc(struct r8152 *tp) 42298c2ecf20Sopenharmony_ci{ 42308c2ecf20Sopenharmony_ci u16 anar; 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci anar = r8152_mdio_read(tp, MII_ADVERTISE); 42338c2ecf20Sopenharmony_ci anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 42348c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_ADVERTISE, anar); 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci tp->ups_info.flow_control = true; 42378c2ecf20Sopenharmony_ci} 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_cistatic void rtl8152_disable(struct r8152 *tp) 42408c2ecf20Sopenharmony_ci{ 42418c2ecf20Sopenharmony_ci r8152_aldps_en(tp, false); 42428c2ecf20Sopenharmony_ci rtl_disable(tp); 42438c2ecf20Sopenharmony_ci r8152_aldps_en(tp, true); 42448c2ecf20Sopenharmony_ci} 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_cistatic void r8152b_hw_phy_cfg(struct r8152 *tp) 42478c2ecf20Sopenharmony_ci{ 42488c2ecf20Sopenharmony_ci rtl8152_apply_firmware(tp); 42498c2ecf20Sopenharmony_ci rtl_eee_enable(tp, tp->eee_en); 42508c2ecf20Sopenharmony_ci r8152_aldps_en(tp, true); 42518c2ecf20Sopenharmony_ci r8152b_enable_fc(tp); 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci set_bit(PHY_RESET, &tp->flags); 42548c2ecf20Sopenharmony_ci} 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_cistatic void wait_oob_link_list_ready(struct r8152 *tp) 42578c2ecf20Sopenharmony_ci{ 42588c2ecf20Sopenharmony_ci u32 ocp_data; 42598c2ecf20Sopenharmony_ci int i; 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 42628c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 42638c2ecf20Sopenharmony_ci if (ocp_data & LINK_LIST_READY) 42648c2ecf20Sopenharmony_ci break; 42658c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 42668c2ecf20Sopenharmony_ci } 42678c2ecf20Sopenharmony_ci} 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_cistatic void r8152b_exit_oob(struct r8152 *tp) 42708c2ecf20Sopenharmony_ci{ 42718c2ecf20Sopenharmony_ci u32 ocp_data; 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 42748c2ecf20Sopenharmony_ci ocp_data &= ~RCR_ACPT_ALL; 42758c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 42768c2ecf20Sopenharmony_ci 42778c2ecf20Sopenharmony_ci rxdy_gated_en(tp, true); 42788c2ecf20Sopenharmony_ci r8153_teredo_off(tp); 42798c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); 42808c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 42838c2ecf20Sopenharmony_ci ocp_data &= ~NOW_IS_OOB; 42848c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 42878c2ecf20Sopenharmony_ci ocp_data &= ~MCU_BORW_EN; 42888c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 42938c2ecf20Sopenharmony_ci ocp_data |= RE_INIT_LL; 42948c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci rtl8152_nic_reset(tp); 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci /* rx share fifo credit full threshold */ 43018c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci if (tp->udev->speed == USB_SPEED_FULL || 43048c2ecf20Sopenharmony_ci tp->udev->speed == USB_SPEED_LOW) { 43058c2ecf20Sopenharmony_ci /* rx share fifo credit near full threshold */ 43068c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, 43078c2ecf20Sopenharmony_ci RXFIFO_THR2_FULL); 43088c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, 43098c2ecf20Sopenharmony_ci RXFIFO_THR3_FULL); 43108c2ecf20Sopenharmony_ci } else { 43118c2ecf20Sopenharmony_ci /* rx share fifo credit near full threshold */ 43128c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, 43138c2ecf20Sopenharmony_ci RXFIFO_THR2_HIGH); 43148c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, 43158c2ecf20Sopenharmony_ci RXFIFO_THR3_HIGH); 43168c2ecf20Sopenharmony_ci } 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci /* TX share fifo free credit full threshold */ 43198c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL); 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD); 43228c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH); 43238c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA, 43248c2ecf20Sopenharmony_ci TEST_MODE_DISABLE | TX_SIZE_ADJUST1); 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); 43318c2ecf20Sopenharmony_ci ocp_data |= TCR0_AUTO_FIFO; 43328c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); 43338c2ecf20Sopenharmony_ci} 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_cistatic void r8152b_enter_oob(struct r8152 *tp) 43368c2ecf20Sopenharmony_ci{ 43378c2ecf20Sopenharmony_ci u32 ocp_data; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 43408c2ecf20Sopenharmony_ci ocp_data &= ~NOW_IS_OOB; 43418c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB); 43448c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB); 43458c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci rtl_disable(tp); 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 43528c2ecf20Sopenharmony_ci ocp_data |= RE_INIT_LL; 43538c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 43548c2ecf20Sopenharmony_ci 43558c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, true); 43608c2ecf20Sopenharmony_ci 43618c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR); 43628c2ecf20Sopenharmony_ci ocp_data |= ALDPS_PROXY_MODE; 43638c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data); 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 43668c2ecf20Sopenharmony_ci ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; 43678c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci rxdy_gated_en(tp, false); 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 43728c2ecf20Sopenharmony_ci ocp_data |= RCR_APM | RCR_AM | RCR_AB; 43738c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 43748c2ecf20Sopenharmony_ci} 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_cistatic int r8153_pre_firmware_1(struct r8152 *tp) 43778c2ecf20Sopenharmony_ci{ 43788c2ecf20Sopenharmony_ci int i; 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci /* Wait till the WTD timer is ready. It would take at most 104 ms. */ 43818c2ecf20Sopenharmony_ci for (i = 0; i < 104; i++) { 43828c2ecf20Sopenharmony_ci u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_WDT1_CTRL); 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci if (!(ocp_data & WTD1_EN)) 43858c2ecf20Sopenharmony_ci break; 43868c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 43878c2ecf20Sopenharmony_ci } 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_ci return 0; 43908c2ecf20Sopenharmony_ci} 43918c2ecf20Sopenharmony_ci 43928c2ecf20Sopenharmony_cistatic int r8153_post_firmware_1(struct r8152 *tp) 43938c2ecf20Sopenharmony_ci{ 43948c2ecf20Sopenharmony_ci /* set USB_BP_4 to support USB_SPEED_SUPER only */ 43958c2ecf20Sopenharmony_ci if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) 43968c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_BP_4, BP4_SUPER_ONLY); 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci /* reset UPHY timer to 36 ms */ 43998c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci return 0; 44028c2ecf20Sopenharmony_ci} 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_cistatic int r8153_pre_firmware_2(struct r8152 *tp) 44058c2ecf20Sopenharmony_ci{ 44068c2ecf20Sopenharmony_ci u32 ocp_data; 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci r8153_pre_firmware_1(tp); 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); 44118c2ecf20Sopenharmony_ci ocp_data &= ~FW_FIX_SUSPEND; 44128c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci return 0; 44158c2ecf20Sopenharmony_ci} 44168c2ecf20Sopenharmony_ci 44178c2ecf20Sopenharmony_cistatic int r8153_post_firmware_2(struct r8152 *tp) 44188c2ecf20Sopenharmony_ci{ 44198c2ecf20Sopenharmony_ci u32 ocp_data; 44208c2ecf20Sopenharmony_ci 44218c2ecf20Sopenharmony_ci /* enable bp0 if support USB_SPEED_SUPER only */ 44228c2ecf20Sopenharmony_ci if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) { 44238c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); 44248c2ecf20Sopenharmony_ci ocp_data |= BIT(0); 44258c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); 44268c2ecf20Sopenharmony_ci } 44278c2ecf20Sopenharmony_ci 44288c2ecf20Sopenharmony_ci /* reset UPHY timer to 36 ms */ 44298c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci /* enable U3P3 check, set the counter to 4 */ 44328c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, U3P3_CHECK_EN | 4); 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); 44358c2ecf20Sopenharmony_ci ocp_data |= FW_FIX_SUSPEND; 44368c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); 44398c2ecf20Sopenharmony_ci ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; 44408c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_ci return 0; 44438c2ecf20Sopenharmony_ci} 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_cistatic int r8153_post_firmware_3(struct r8152 *tp) 44468c2ecf20Sopenharmony_ci{ 44478c2ecf20Sopenharmony_ci u32 ocp_data; 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); 44508c2ecf20Sopenharmony_ci ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; 44518c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); 44528c2ecf20Sopenharmony_ci 44538c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); 44548c2ecf20Sopenharmony_ci ocp_data |= FW_IP_RESET_EN; 44558c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); 44568c2ecf20Sopenharmony_ci 44578c2ecf20Sopenharmony_ci return 0; 44588c2ecf20Sopenharmony_ci} 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_cistatic int r8153b_pre_firmware_1(struct r8152 *tp) 44618c2ecf20Sopenharmony_ci{ 44628c2ecf20Sopenharmony_ci /* enable fc timer and set timer to 1 second. */ 44638c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER, 44648c2ecf20Sopenharmony_ci CTRL_TIMER_EN | (1000 / 8)); 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci return 0; 44678c2ecf20Sopenharmony_ci} 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_cistatic int r8153b_post_firmware_1(struct r8152 *tp) 44708c2ecf20Sopenharmony_ci{ 44718c2ecf20Sopenharmony_ci u32 ocp_data; 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci /* enable bp0 for RTL8153-BND */ 44748c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); 44758c2ecf20Sopenharmony_ci if (ocp_data & BND_MASK) { 44768c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); 44778c2ecf20Sopenharmony_ci ocp_data |= BIT(0); 44788c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); 44798c2ecf20Sopenharmony_ci } 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL); 44828c2ecf20Sopenharmony_ci ocp_data |= FLOW_CTRL_PATCH_OPT; 44838c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data); 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK); 44868c2ecf20Sopenharmony_ci ocp_data |= FC_PATCH_TASK; 44878c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); 44888c2ecf20Sopenharmony_ci 44898c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); 44908c2ecf20Sopenharmony_ci ocp_data |= FW_IP_RESET_EN; 44918c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); 44928c2ecf20Sopenharmony_ci 44938c2ecf20Sopenharmony_ci return 0; 44948c2ecf20Sopenharmony_ci} 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_cistatic void r8153_aldps_en(struct r8152 *tp, bool enable) 44978c2ecf20Sopenharmony_ci{ 44988c2ecf20Sopenharmony_ci u16 data; 44998c2ecf20Sopenharmony_ci 45008c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_POWER_CFG); 45018c2ecf20Sopenharmony_ci if (enable) { 45028c2ecf20Sopenharmony_ci data |= EN_ALDPS; 45038c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_POWER_CFG, data); 45048c2ecf20Sopenharmony_ci } else { 45058c2ecf20Sopenharmony_ci int i; 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci data &= ~EN_ALDPS; 45088c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_POWER_CFG, data); 45098c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) { 45108c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 45118c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_PLA, 0xe000) & 0x0100) 45128c2ecf20Sopenharmony_ci break; 45138c2ecf20Sopenharmony_ci } 45148c2ecf20Sopenharmony_ci } 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_ci tp->ups_info.aldps = enable; 45178c2ecf20Sopenharmony_ci} 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_cistatic void r8153_hw_phy_cfg(struct r8152 *tp) 45208c2ecf20Sopenharmony_ci{ 45218c2ecf20Sopenharmony_ci u32 ocp_data; 45228c2ecf20Sopenharmony_ci u16 data; 45238c2ecf20Sopenharmony_ci 45248c2ecf20Sopenharmony_ci /* disable ALDPS before updating the PHY parameters */ 45258c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci /* disable EEE before updating the PHY parameters */ 45288c2ecf20Sopenharmony_ci rtl_eee_enable(tp, false); 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci rtl8152_apply_firmware(tp); 45318c2ecf20Sopenharmony_ci 45328c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_03) { 45338c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_EEE_CFG); 45348c2ecf20Sopenharmony_ci data &= ~CTAP_SHORT_EN; 45358c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_EEE_CFG, data); 45368c2ecf20Sopenharmony_ci } 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_POWER_CFG); 45398c2ecf20Sopenharmony_ci data |= EEE_CLKDIV_EN; 45408c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_POWER_CFG, data); 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_DOWN_SPEED); 45438c2ecf20Sopenharmony_ci data |= EN_10M_BGOFF; 45448c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_DOWN_SPEED, data); 45458c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_POWER_CFG); 45468c2ecf20Sopenharmony_ci data |= EN_10M_PLLOFF; 45478c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_POWER_CFG, data); 45488c2ecf20Sopenharmony_ci sram_write(tp, SRAM_IMPEDANCE, 0x0b13); 45498c2ecf20Sopenharmony_ci 45508c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); 45518c2ecf20Sopenharmony_ci ocp_data |= PFM_PWM_SWITCH; 45528c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); 45538c2ecf20Sopenharmony_ci 45548c2ecf20Sopenharmony_ci /* Enable LPF corner auto tune */ 45558c2ecf20Sopenharmony_ci sram_write(tp, SRAM_LPF_CFG, 0xf70f); 45568c2ecf20Sopenharmony_ci 45578c2ecf20Sopenharmony_ci /* Adjust 10M Amplitude */ 45588c2ecf20Sopenharmony_ci sram_write(tp, SRAM_10M_AMP1, 0x00af); 45598c2ecf20Sopenharmony_ci sram_write(tp, SRAM_10M_AMP2, 0x0208); 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci if (tp->eee_en) 45628c2ecf20Sopenharmony_ci rtl_eee_enable(tp, true); 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 45658c2ecf20Sopenharmony_ci r8152b_enable_fc(tp); 45668c2ecf20Sopenharmony_ci 45678c2ecf20Sopenharmony_ci switch (tp->version) { 45688c2ecf20Sopenharmony_ci case RTL_VER_03: 45698c2ecf20Sopenharmony_ci case RTL_VER_04: 45708c2ecf20Sopenharmony_ci break; 45718c2ecf20Sopenharmony_ci case RTL_VER_05: 45728c2ecf20Sopenharmony_ci case RTL_VER_06: 45738c2ecf20Sopenharmony_ci default: 45748c2ecf20Sopenharmony_ci r8153_u2p3en(tp, true); 45758c2ecf20Sopenharmony_ci break; 45768c2ecf20Sopenharmony_ci } 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci set_bit(PHY_RESET, &tp->flags); 45798c2ecf20Sopenharmony_ci} 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_cistatic u32 r8152_efuse_read(struct r8152 *tp, u8 addr) 45828c2ecf20Sopenharmony_ci{ 45838c2ecf20Sopenharmony_ci u32 ocp_data; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr); 45868c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD); 45878c2ecf20Sopenharmony_ci ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9; /* data of bit16 */ 45888c2ecf20Sopenharmony_ci ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA); 45898c2ecf20Sopenharmony_ci 45908c2ecf20Sopenharmony_ci return ocp_data; 45918c2ecf20Sopenharmony_ci} 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_cistatic void r8153b_hw_phy_cfg(struct r8152 *tp) 45948c2ecf20Sopenharmony_ci{ 45958c2ecf20Sopenharmony_ci u32 ocp_data; 45968c2ecf20Sopenharmony_ci u16 data; 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci /* disable ALDPS before updating the PHY parameters */ 45998c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ci /* disable EEE before updating the PHY parameters */ 46028c2ecf20Sopenharmony_ci rtl_eee_enable(tp, false); 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci rtl8152_apply_firmware(tp); 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags)); 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci data = sram_read(tp, SRAM_GREEN_CFG); 46098c2ecf20Sopenharmony_ci data |= R_TUNE_EN; 46108c2ecf20Sopenharmony_ci sram_write(tp, SRAM_GREEN_CFG, data); 46118c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_NCTL_CFG); 46128c2ecf20Sopenharmony_ci data |= PGA_RETURN_EN; 46138c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_NCTL_CFG, data); 46148c2ecf20Sopenharmony_ci 46158c2ecf20Sopenharmony_ci /* ADC Bias Calibration: 46168c2ecf20Sopenharmony_ci * read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake 46178c2ecf20Sopenharmony_ci * bit (bit3) to rebuild the real 16-bit data. Write the data to the 46188c2ecf20Sopenharmony_ci * ADC ioffset. 46198c2ecf20Sopenharmony_ci */ 46208c2ecf20Sopenharmony_ci ocp_data = r8152_efuse_read(tp, 0x7d); 46218c2ecf20Sopenharmony_ci data = (u16)(((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7)); 46228c2ecf20Sopenharmony_ci if (data != 0xffff) 46238c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_ADC_IOFFSET, data); 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci /* ups mode tx-link-pulse timing adjustment: 46268c2ecf20Sopenharmony_ci * rg_saw_cnt = OCP reg 0xC426 Bit[13:0] 46278c2ecf20Sopenharmony_ci * swr_cnt_1ms_ini = 16000000 / rg_saw_cnt 46288c2ecf20Sopenharmony_ci */ 46298c2ecf20Sopenharmony_ci ocp_data = ocp_reg_read(tp, 0xc426); 46308c2ecf20Sopenharmony_ci ocp_data &= 0x3fff; 46318c2ecf20Sopenharmony_ci if (ocp_data) { 46328c2ecf20Sopenharmony_ci u32 swr_cnt_1ms_ini; 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK; 46358c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG); 46368c2ecf20Sopenharmony_ci ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini; 46378c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data); 46388c2ecf20Sopenharmony_ci } 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); 46418c2ecf20Sopenharmony_ci ocp_data |= PFM_PWM_SWITCH; 46428c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); 46438c2ecf20Sopenharmony_ci 46448c2ecf20Sopenharmony_ci /* Advnace EEE */ 46458c2ecf20Sopenharmony_ci if (!r8153_patch_request(tp, true)) { 46468c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_POWER_CFG); 46478c2ecf20Sopenharmony_ci data |= EEE_CLKDIV_EN; 46488c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_POWER_CFG, data); 46498c2ecf20Sopenharmony_ci tp->ups_info.eee_ckdiv = true; 46508c2ecf20Sopenharmony_ci 46518c2ecf20Sopenharmony_ci data = ocp_reg_read(tp, OCP_DOWN_SPEED); 46528c2ecf20Sopenharmony_ci data |= EN_EEE_CMODE | EN_EEE_1000 | EN_10M_CLKDIV; 46538c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_DOWN_SPEED, data); 46548c2ecf20Sopenharmony_ci tp->ups_info.eee_cmod_lv = true; 46558c2ecf20Sopenharmony_ci tp->ups_info._10m_ckdiv = true; 46568c2ecf20Sopenharmony_ci tp->ups_info.eee_plloff_giga = true; 46578c2ecf20Sopenharmony_ci 46588c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SYSCLK_CFG, 0); 46598c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_SYSCLK_CFG, clk_div_expo(5)); 46608c2ecf20Sopenharmony_ci tp->ups_info._250m_ckdiv = true; 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci r8153_patch_request(tp, false); 46638c2ecf20Sopenharmony_ci } 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_ci if (tp->eee_en) 46668c2ecf20Sopenharmony_ci rtl_eee_enable(tp, true); 46678c2ecf20Sopenharmony_ci 46688c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 46698c2ecf20Sopenharmony_ci r8152b_enable_fc(tp); 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci set_bit(PHY_RESET, &tp->flags); 46728c2ecf20Sopenharmony_ci} 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_cistatic void r8153_first_init(struct r8152 *tp) 46758c2ecf20Sopenharmony_ci{ 46768c2ecf20Sopenharmony_ci u32 ocp_data; 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci rxdy_gated_en(tp, true); 46798c2ecf20Sopenharmony_ci r8153_teredo_off(tp); 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 46828c2ecf20Sopenharmony_ci ocp_data &= ~RCR_ACPT_ALL; 46838c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci rtl8152_nic_reset(tp); 46868c2ecf20Sopenharmony_ci rtl_reset_bmu(tp); 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 46898c2ecf20Sopenharmony_ci ocp_data &= ~NOW_IS_OOB; 46908c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 46918c2ecf20Sopenharmony_ci 46928c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 46938c2ecf20Sopenharmony_ci ocp_data &= ~MCU_BORW_EN; 46948c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 46958c2ecf20Sopenharmony_ci 46968c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 46998c2ecf20Sopenharmony_ci ocp_data |= RE_INIT_LL; 47008c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 47018c2ecf20Sopenharmony_ci 47028c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 47038c2ecf20Sopenharmony_ci 47048c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; 47078c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); 47088c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); 47118c2ecf20Sopenharmony_ci ocp_data |= TCR0_AUTO_FIFO; 47128c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); 47138c2ecf20Sopenharmony_ci 47148c2ecf20Sopenharmony_ci rtl8152_nic_reset(tp); 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci /* rx share fifo credit full threshold */ 47178c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); 47188c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL); 47198c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL); 47208c2ecf20Sopenharmony_ci /* TX share fifo free credit full threshold */ 47218c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); 47228c2ecf20Sopenharmony_ci} 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_cistatic void r8153_enter_oob(struct r8152 *tp) 47258c2ecf20Sopenharmony_ci{ 47268c2ecf20Sopenharmony_ci u32 ocp_data; 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 47298c2ecf20Sopenharmony_ci ocp_data &= ~NOW_IS_OOB; 47308c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci rtl_disable(tp); 47338c2ecf20Sopenharmony_ci rtl_reset_bmu(tp); 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 47368c2ecf20Sopenharmony_ci 47378c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); 47388c2ecf20Sopenharmony_ci ocp_data |= RE_INIT_LL; 47398c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci wait_oob_link_list_ready(tp); 47428c2ecf20Sopenharmony_ci 47438c2ecf20Sopenharmony_ci ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; 47448c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci switch (tp->version) { 47478c2ecf20Sopenharmony_ci case RTL_VER_03: 47488c2ecf20Sopenharmony_ci case RTL_VER_04: 47498c2ecf20Sopenharmony_ci case RTL_VER_05: 47508c2ecf20Sopenharmony_ci case RTL_VER_06: 47518c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); 47528c2ecf20Sopenharmony_ci ocp_data &= ~TEREDO_WAKE_MASK; 47538c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); 47548c2ecf20Sopenharmony_ci break; 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci case RTL_VER_08: 47578c2ecf20Sopenharmony_ci case RTL_VER_09: 47588c2ecf20Sopenharmony_ci /* Clear teredo wake event. bit[15:8] is the teredo wakeup 47598c2ecf20Sopenharmony_ci * type. Set it to zero. bits[7:0] are the W1C bits about 47608c2ecf20Sopenharmony_ci * the events. Set them to all 1 to clear them. 47618c2ecf20Sopenharmony_ci */ 47628c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff); 47638c2ecf20Sopenharmony_ci break; 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci default: 47668c2ecf20Sopenharmony_ci break; 47678c2ecf20Sopenharmony_ci } 47688c2ecf20Sopenharmony_ci 47698c2ecf20Sopenharmony_ci rtl_rx_vlan_en(tp, true); 47708c2ecf20Sopenharmony_ci 47718c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR); 47728c2ecf20Sopenharmony_ci ocp_data |= ALDPS_PROXY_MODE; 47738c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data); 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); 47768c2ecf20Sopenharmony_ci ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; 47778c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); 47788c2ecf20Sopenharmony_ci 47798c2ecf20Sopenharmony_ci rxdy_gated_en(tp, false); 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 47828c2ecf20Sopenharmony_ci ocp_data |= RCR_APM | RCR_AM | RCR_AB; 47838c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 47848c2ecf20Sopenharmony_ci} 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_cistatic void rtl8153_disable(struct r8152 *tp) 47878c2ecf20Sopenharmony_ci{ 47888c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 47898c2ecf20Sopenharmony_ci rtl_disable(tp); 47908c2ecf20Sopenharmony_ci rtl_reset_bmu(tp); 47918c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 47928c2ecf20Sopenharmony_ci} 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_cistatic int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex, 47958c2ecf20Sopenharmony_ci u32 advertising) 47968c2ecf20Sopenharmony_ci{ 47978c2ecf20Sopenharmony_ci u16 bmcr; 47988c2ecf20Sopenharmony_ci int ret = 0; 47998c2ecf20Sopenharmony_ci 48008c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_DISABLE) { 48018c2ecf20Sopenharmony_ci if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL) 48028c2ecf20Sopenharmony_ci return -EINVAL; 48038c2ecf20Sopenharmony_ci 48048c2ecf20Sopenharmony_ci switch (speed) { 48058c2ecf20Sopenharmony_ci case SPEED_10: 48068c2ecf20Sopenharmony_ci bmcr = BMCR_SPEED10; 48078c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) { 48088c2ecf20Sopenharmony_ci bmcr |= BMCR_FULLDPLX; 48098c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = FORCE_10M_FULL; 48108c2ecf20Sopenharmony_ci } else { 48118c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = FORCE_10M_HALF; 48128c2ecf20Sopenharmony_ci } 48138c2ecf20Sopenharmony_ci break; 48148c2ecf20Sopenharmony_ci case SPEED_100: 48158c2ecf20Sopenharmony_ci bmcr = BMCR_SPEED100; 48168c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) { 48178c2ecf20Sopenharmony_ci bmcr |= BMCR_FULLDPLX; 48188c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = FORCE_100M_FULL; 48198c2ecf20Sopenharmony_ci } else { 48208c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = FORCE_100M_HALF; 48218c2ecf20Sopenharmony_ci } 48228c2ecf20Sopenharmony_ci break; 48238c2ecf20Sopenharmony_ci case SPEED_1000: 48248c2ecf20Sopenharmony_ci if (tp->mii.supports_gmii) { 48258c2ecf20Sopenharmony_ci bmcr = BMCR_SPEED1000 | BMCR_FULLDPLX; 48268c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_1000M_FULL; 48278c2ecf20Sopenharmony_ci break; 48288c2ecf20Sopenharmony_ci } 48298c2ecf20Sopenharmony_ci fallthrough; 48308c2ecf20Sopenharmony_ci default: 48318c2ecf20Sopenharmony_ci ret = -EINVAL; 48328c2ecf20Sopenharmony_ci goto out; 48338c2ecf20Sopenharmony_ci } 48348c2ecf20Sopenharmony_ci 48358c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) 48368c2ecf20Sopenharmony_ci tp->mii.full_duplex = 1; 48378c2ecf20Sopenharmony_ci else 48388c2ecf20Sopenharmony_ci tp->mii.full_duplex = 0; 48398c2ecf20Sopenharmony_ci 48408c2ecf20Sopenharmony_ci tp->mii.force_media = 1; 48418c2ecf20Sopenharmony_ci } else { 48428c2ecf20Sopenharmony_ci u16 anar, tmp1; 48438c2ecf20Sopenharmony_ci u32 support; 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci support = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL | 48468c2ecf20Sopenharmony_ci RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL; 48478c2ecf20Sopenharmony_ci 48488c2ecf20Sopenharmony_ci if (tp->mii.supports_gmii) 48498c2ecf20Sopenharmony_ci support |= RTL_ADVERTISED_1000_FULL; 48508c2ecf20Sopenharmony_ci 48518c2ecf20Sopenharmony_ci if (!(advertising & support)) 48528c2ecf20Sopenharmony_ci return -EINVAL; 48538c2ecf20Sopenharmony_ci 48548c2ecf20Sopenharmony_ci anar = r8152_mdio_read(tp, MII_ADVERTISE); 48558c2ecf20Sopenharmony_ci tmp1 = anar & ~(ADVERTISE_10HALF | ADVERTISE_10FULL | 48568c2ecf20Sopenharmony_ci ADVERTISE_100HALF | ADVERTISE_100FULL); 48578c2ecf20Sopenharmony_ci if (advertising & RTL_ADVERTISED_10_HALF) { 48588c2ecf20Sopenharmony_ci tmp1 |= ADVERTISE_10HALF; 48598c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_10M_HALF; 48608c2ecf20Sopenharmony_ci } 48618c2ecf20Sopenharmony_ci if (advertising & RTL_ADVERTISED_10_FULL) { 48628c2ecf20Sopenharmony_ci tmp1 |= ADVERTISE_10FULL; 48638c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_10M_FULL; 48648c2ecf20Sopenharmony_ci } 48658c2ecf20Sopenharmony_ci 48668c2ecf20Sopenharmony_ci if (advertising & RTL_ADVERTISED_100_HALF) { 48678c2ecf20Sopenharmony_ci tmp1 |= ADVERTISE_100HALF; 48688c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_100M_HALF; 48698c2ecf20Sopenharmony_ci } 48708c2ecf20Sopenharmony_ci if (advertising & RTL_ADVERTISED_100_FULL) { 48718c2ecf20Sopenharmony_ci tmp1 |= ADVERTISE_100FULL; 48728c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_100M_FULL; 48738c2ecf20Sopenharmony_ci } 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci if (anar != tmp1) { 48768c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_ADVERTISE, tmp1); 48778c2ecf20Sopenharmony_ci tp->mii.advertising = tmp1; 48788c2ecf20Sopenharmony_ci } 48798c2ecf20Sopenharmony_ci 48808c2ecf20Sopenharmony_ci if (tp->mii.supports_gmii) { 48818c2ecf20Sopenharmony_ci u16 gbcr; 48828c2ecf20Sopenharmony_ci 48838c2ecf20Sopenharmony_ci gbcr = r8152_mdio_read(tp, MII_CTRL1000); 48848c2ecf20Sopenharmony_ci tmp1 = gbcr & ~(ADVERTISE_1000FULL | 48858c2ecf20Sopenharmony_ci ADVERTISE_1000HALF); 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci if (advertising & RTL_ADVERTISED_1000_FULL) { 48888c2ecf20Sopenharmony_ci tmp1 |= ADVERTISE_1000FULL; 48898c2ecf20Sopenharmony_ci tp->ups_info.speed_duplex = NWAY_1000M_FULL; 48908c2ecf20Sopenharmony_ci } 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_ci if (gbcr != tmp1) 48938c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_CTRL1000, tmp1); 48948c2ecf20Sopenharmony_ci } 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci bmcr = BMCR_ANENABLE | BMCR_ANRESTART; 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci tp->mii.force_media = 0; 48998c2ecf20Sopenharmony_ci } 49008c2ecf20Sopenharmony_ci 49018c2ecf20Sopenharmony_ci if (test_and_clear_bit(PHY_RESET, &tp->flags)) 49028c2ecf20Sopenharmony_ci bmcr |= BMCR_RESET; 49038c2ecf20Sopenharmony_ci 49048c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_BMCR, bmcr); 49058c2ecf20Sopenharmony_ci 49068c2ecf20Sopenharmony_ci if (bmcr & BMCR_RESET) { 49078c2ecf20Sopenharmony_ci int i; 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci for (i = 0; i < 50; i++) { 49108c2ecf20Sopenharmony_ci msleep(20); 49118c2ecf20Sopenharmony_ci if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) 49128c2ecf20Sopenharmony_ci break; 49138c2ecf20Sopenharmony_ci } 49148c2ecf20Sopenharmony_ci } 49158c2ecf20Sopenharmony_ci 49168c2ecf20Sopenharmony_ciout: 49178c2ecf20Sopenharmony_ci return ret; 49188c2ecf20Sopenharmony_ci} 49198c2ecf20Sopenharmony_ci 49208c2ecf20Sopenharmony_cistatic void rtl8152_up(struct r8152 *tp) 49218c2ecf20Sopenharmony_ci{ 49228c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 49238c2ecf20Sopenharmony_ci return; 49248c2ecf20Sopenharmony_ci 49258c2ecf20Sopenharmony_ci r8152_aldps_en(tp, false); 49268c2ecf20Sopenharmony_ci r8152b_exit_oob(tp); 49278c2ecf20Sopenharmony_ci r8152_aldps_en(tp, true); 49288c2ecf20Sopenharmony_ci} 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_cistatic void rtl8152_down(struct r8152 *tp) 49318c2ecf20Sopenharmony_ci{ 49328c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) { 49338c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 49348c2ecf20Sopenharmony_ci return; 49358c2ecf20Sopenharmony_ci } 49368c2ecf20Sopenharmony_ci 49378c2ecf20Sopenharmony_ci r8152_power_cut_en(tp, false); 49388c2ecf20Sopenharmony_ci r8152_aldps_en(tp, false); 49398c2ecf20Sopenharmony_ci r8152b_enter_oob(tp); 49408c2ecf20Sopenharmony_ci r8152_aldps_en(tp, true); 49418c2ecf20Sopenharmony_ci} 49428c2ecf20Sopenharmony_ci 49438c2ecf20Sopenharmony_cistatic void rtl8153_up(struct r8152 *tp) 49448c2ecf20Sopenharmony_ci{ 49458c2ecf20Sopenharmony_ci u32 ocp_data; 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 49488c2ecf20Sopenharmony_ci return; 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_ci r8153_u1u2en(tp, false); 49518c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 49528c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 49538c2ecf20Sopenharmony_ci r8153_first_init(tp); 49548c2ecf20Sopenharmony_ci 49558c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6); 49568c2ecf20Sopenharmony_ci ocp_data |= LANWAKE_CLR_EN; 49578c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data); 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG); 49608c2ecf20Sopenharmony_ci ocp_data &= ~LANWAKE_PIN; 49618c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data); 49628c2ecf20Sopenharmony_ci 49638c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1); 49648c2ecf20Sopenharmony_ci ocp_data &= ~DELAY_PHY_PWR_CHG; 49658c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1, ocp_data); 49668c2ecf20Sopenharmony_ci 49678c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 49688c2ecf20Sopenharmony_ci 49698c2ecf20Sopenharmony_ci switch (tp->version) { 49708c2ecf20Sopenharmony_ci case RTL_VER_03: 49718c2ecf20Sopenharmony_ci case RTL_VER_04: 49728c2ecf20Sopenharmony_ci break; 49738c2ecf20Sopenharmony_ci case RTL_VER_05: 49748c2ecf20Sopenharmony_ci case RTL_VER_06: 49758c2ecf20Sopenharmony_ci default: 49768c2ecf20Sopenharmony_ci r8153_u2p3en(tp, true); 49778c2ecf20Sopenharmony_ci break; 49788c2ecf20Sopenharmony_ci } 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_ci r8153_u1u2en(tp, true); 49818c2ecf20Sopenharmony_ci} 49828c2ecf20Sopenharmony_ci 49838c2ecf20Sopenharmony_cistatic void rtl8153_down(struct r8152 *tp) 49848c2ecf20Sopenharmony_ci{ 49858c2ecf20Sopenharmony_ci u32 ocp_data; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) { 49888c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 49898c2ecf20Sopenharmony_ci return; 49908c2ecf20Sopenharmony_ci } 49918c2ecf20Sopenharmony_ci 49928c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6); 49938c2ecf20Sopenharmony_ci ocp_data &= ~LANWAKE_CLR_EN; 49948c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data); 49958c2ecf20Sopenharmony_ci 49968c2ecf20Sopenharmony_ci r8153_u1u2en(tp, false); 49978c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 49988c2ecf20Sopenharmony_ci r8153_power_cut_en(tp, false); 49998c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 50008c2ecf20Sopenharmony_ci r8153_enter_oob(tp); 50018c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 50028c2ecf20Sopenharmony_ci} 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_cistatic void rtl8153b_up(struct r8152 *tp) 50058c2ecf20Sopenharmony_ci{ 50068c2ecf20Sopenharmony_ci u32 ocp_data; 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 50098c2ecf20Sopenharmony_ci return; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, false); 50128c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 50138c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 50148c2ecf20Sopenharmony_ci 50158c2ecf20Sopenharmony_ci r8153_first_init(tp); 50168c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B); 50178c2ecf20Sopenharmony_ci 50188c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3); 50198c2ecf20Sopenharmony_ci ocp_data &= ~PLA_MCU_SPDWN_EN; 50208c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data); 50218c2ecf20Sopenharmony_ci 50228c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 50238c2ecf20Sopenharmony_ci 50248c2ecf20Sopenharmony_ci if (tp->udev->speed != USB_SPEED_HIGH) 50258c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, true); 50268c2ecf20Sopenharmony_ci} 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_cistatic void rtl8153b_down(struct r8152 *tp) 50298c2ecf20Sopenharmony_ci{ 50308c2ecf20Sopenharmony_ci u32 ocp_data; 50318c2ecf20Sopenharmony_ci 50328c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) { 50338c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 50348c2ecf20Sopenharmony_ci return; 50358c2ecf20Sopenharmony_ci } 50368c2ecf20Sopenharmony_ci 50378c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3); 50388c2ecf20Sopenharmony_ci ocp_data |= PLA_MCU_SPDWN_EN; 50398c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data); 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, false); 50428c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 50438c2ecf20Sopenharmony_ci r8153b_power_cut_en(tp, false); 50448c2ecf20Sopenharmony_ci r8153_aldps_en(tp, false); 50458c2ecf20Sopenharmony_ci r8153_enter_oob(tp); 50468c2ecf20Sopenharmony_ci r8153_aldps_en(tp, true); 50478c2ecf20Sopenharmony_ci} 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_cistatic bool rtl8152_in_nway(struct r8152 *tp) 50508c2ecf20Sopenharmony_ci{ 50518c2ecf20Sopenharmony_ci u16 nway_state; 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); 50548c2ecf20Sopenharmony_ci tp->ocp_base = 0x2000; 50558c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c); /* phy state */ 50568c2ecf20Sopenharmony_ci nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a); 50578c2ecf20Sopenharmony_ci 50588c2ecf20Sopenharmony_ci /* bit 15: TXDIS_STATE, bit 14: ABD_STATE */ 50598c2ecf20Sopenharmony_ci if (nway_state & 0xc000) 50608c2ecf20Sopenharmony_ci return false; 50618c2ecf20Sopenharmony_ci else 50628c2ecf20Sopenharmony_ci return true; 50638c2ecf20Sopenharmony_ci} 50648c2ecf20Sopenharmony_ci 50658c2ecf20Sopenharmony_cistatic bool rtl8153_in_nway(struct r8152 *tp) 50668c2ecf20Sopenharmony_ci{ 50678c2ecf20Sopenharmony_ci u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff; 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci if (phy_state == TXDIS_STATE || phy_state == ABD_STATE) 50708c2ecf20Sopenharmony_ci return false; 50718c2ecf20Sopenharmony_ci else 50728c2ecf20Sopenharmony_ci return true; 50738c2ecf20Sopenharmony_ci} 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_cistatic void set_carrier(struct r8152 *tp) 50768c2ecf20Sopenharmony_ci{ 50778c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 50788c2ecf20Sopenharmony_ci struct napi_struct *napi = &tp->napi; 50798c2ecf20Sopenharmony_ci u8 speed; 50808c2ecf20Sopenharmony_ci 50818c2ecf20Sopenharmony_ci speed = rtl8152_get_speed(tp); 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci if (speed & LINK_STATUS) { 50848c2ecf20Sopenharmony_ci if (!netif_carrier_ok(netdev)) { 50858c2ecf20Sopenharmony_ci tp->rtl_ops.enable(tp); 50868c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 50878c2ecf20Sopenharmony_ci napi_disable(napi); 50888c2ecf20Sopenharmony_ci netif_carrier_on(netdev); 50898c2ecf20Sopenharmony_ci rtl_start_rx(tp); 50908c2ecf20Sopenharmony_ci clear_bit(RTL8152_SET_RX_MODE, &tp->flags); 50918c2ecf20Sopenharmony_ci _rtl8152_set_rx_mode(netdev); 50928c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 50938c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 50948c2ecf20Sopenharmony_ci netif_info(tp, link, netdev, "carrier on\n"); 50958c2ecf20Sopenharmony_ci } else if (netif_queue_stopped(netdev) && 50968c2ecf20Sopenharmony_ci skb_queue_len(&tp->tx_queue) < tp->tx_qlen) { 50978c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 50988c2ecf20Sopenharmony_ci } 50998c2ecf20Sopenharmony_ci } else { 51008c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 51018c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 51028c2ecf20Sopenharmony_ci tasklet_disable(&tp->tx_tl); 51038c2ecf20Sopenharmony_ci napi_disable(napi); 51048c2ecf20Sopenharmony_ci tp->rtl_ops.disable(tp); 51058c2ecf20Sopenharmony_ci napi_enable(napi); 51068c2ecf20Sopenharmony_ci tasklet_enable(&tp->tx_tl); 51078c2ecf20Sopenharmony_ci netif_info(tp, link, netdev, "carrier off\n"); 51088c2ecf20Sopenharmony_ci } 51098c2ecf20Sopenharmony_ci } 51108c2ecf20Sopenharmony_ci} 51118c2ecf20Sopenharmony_ci 51128c2ecf20Sopenharmony_cistatic void rtl_work_func_t(struct work_struct *work) 51138c2ecf20Sopenharmony_ci{ 51148c2ecf20Sopenharmony_ci struct r8152 *tp = container_of(work, struct r8152, schedule.work); 51158c2ecf20Sopenharmony_ci 51168c2ecf20Sopenharmony_ci /* If the device is unplugged or !netif_running(), the workqueue 51178c2ecf20Sopenharmony_ci * doesn't need to wake the device, and could return directly. 51188c2ecf20Sopenharmony_ci */ 51198c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags) || !netif_running(tp->netdev)) 51208c2ecf20Sopenharmony_ci return; 51218c2ecf20Sopenharmony_ci 51228c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(tp->intf) < 0) 51238c2ecf20Sopenharmony_ci return; 51248c2ecf20Sopenharmony_ci 51258c2ecf20Sopenharmony_ci if (!test_bit(WORK_ENABLE, &tp->flags)) 51268c2ecf20Sopenharmony_ci goto out1; 51278c2ecf20Sopenharmony_ci 51288c2ecf20Sopenharmony_ci if (!mutex_trylock(&tp->control)) { 51298c2ecf20Sopenharmony_ci schedule_delayed_work(&tp->schedule, 0); 51308c2ecf20Sopenharmony_ci goto out1; 51318c2ecf20Sopenharmony_ci } 51328c2ecf20Sopenharmony_ci 51338c2ecf20Sopenharmony_ci if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags)) 51348c2ecf20Sopenharmony_ci set_carrier(tp); 51358c2ecf20Sopenharmony_ci 51368c2ecf20Sopenharmony_ci if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags)) 51378c2ecf20Sopenharmony_ci _rtl8152_set_rx_mode(tp->netdev); 51388c2ecf20Sopenharmony_ci 51398c2ecf20Sopenharmony_ci /* don't schedule tasket before linking */ 51408c2ecf20Sopenharmony_ci if (test_and_clear_bit(SCHEDULE_TASKLET, &tp->flags) && 51418c2ecf20Sopenharmony_ci netif_carrier_ok(tp->netdev)) 51428c2ecf20Sopenharmony_ci tasklet_schedule(&tp->tx_tl); 51438c2ecf20Sopenharmony_ci 51448c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 51458c2ecf20Sopenharmony_ci 51468c2ecf20Sopenharmony_ciout1: 51478c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 51488c2ecf20Sopenharmony_ci} 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_cistatic void rtl_hw_phy_work_func_t(struct work_struct *work) 51518c2ecf20Sopenharmony_ci{ 51528c2ecf20Sopenharmony_ci struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work); 51538c2ecf20Sopenharmony_ci 51548c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 51558c2ecf20Sopenharmony_ci return; 51568c2ecf20Sopenharmony_ci 51578c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(tp->intf) < 0) 51588c2ecf20Sopenharmony_ci return; 51598c2ecf20Sopenharmony_ci 51608c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_ci if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) { 51638c2ecf20Sopenharmony_ci tp->rtl_fw.retry = false; 51648c2ecf20Sopenharmony_ci tp->rtl_fw.fw = NULL; 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci /* Delay execution in case request_firmware() is not ready yet. 51678c2ecf20Sopenharmony_ci */ 51688c2ecf20Sopenharmony_ci queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10); 51698c2ecf20Sopenharmony_ci goto ignore_once; 51708c2ecf20Sopenharmony_ci } 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ci tp->rtl_ops.hw_phy_cfg(tp); 51738c2ecf20Sopenharmony_ci 51748c2ecf20Sopenharmony_ci rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex, 51758c2ecf20Sopenharmony_ci tp->advertising); 51768c2ecf20Sopenharmony_ci 51778c2ecf20Sopenharmony_ciignore_once: 51788c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 51818c2ecf20Sopenharmony_ci} 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 51848c2ecf20Sopenharmony_cistatic int rtl_notifier(struct notifier_block *nb, unsigned long action, 51858c2ecf20Sopenharmony_ci void *data) 51868c2ecf20Sopenharmony_ci{ 51878c2ecf20Sopenharmony_ci struct r8152 *tp = container_of(nb, struct r8152, pm_notifier); 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci switch (action) { 51908c2ecf20Sopenharmony_ci case PM_HIBERNATION_PREPARE: 51918c2ecf20Sopenharmony_ci case PM_SUSPEND_PREPARE: 51928c2ecf20Sopenharmony_ci usb_autopm_get_interface(tp->intf); 51938c2ecf20Sopenharmony_ci break; 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci case PM_POST_HIBERNATION: 51968c2ecf20Sopenharmony_ci case PM_POST_SUSPEND: 51978c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 51988c2ecf20Sopenharmony_ci break; 51998c2ecf20Sopenharmony_ci 52008c2ecf20Sopenharmony_ci case PM_POST_RESTORE: 52018c2ecf20Sopenharmony_ci case PM_RESTORE_PREPARE: 52028c2ecf20Sopenharmony_ci default: 52038c2ecf20Sopenharmony_ci break; 52048c2ecf20Sopenharmony_ci } 52058c2ecf20Sopenharmony_ci 52068c2ecf20Sopenharmony_ci return NOTIFY_DONE; 52078c2ecf20Sopenharmony_ci} 52088c2ecf20Sopenharmony_ci#endif 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_cistatic int rtl8152_open(struct net_device *netdev) 52118c2ecf20Sopenharmony_ci{ 52128c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 52138c2ecf20Sopenharmony_ci int res = 0; 52148c2ecf20Sopenharmony_ci 52158c2ecf20Sopenharmony_ci if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) { 52168c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->hw_phy_work); 52178c2ecf20Sopenharmony_ci rtl_hw_phy_work_func_t(&tp->hw_phy_work.work); 52188c2ecf20Sopenharmony_ci } 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_ci res = alloc_all_mem(tp); 52218c2ecf20Sopenharmony_ci if (res) 52228c2ecf20Sopenharmony_ci goto out; 52238c2ecf20Sopenharmony_ci 52248c2ecf20Sopenharmony_ci res = usb_autopm_get_interface(tp->intf); 52258c2ecf20Sopenharmony_ci if (res < 0) 52268c2ecf20Sopenharmony_ci goto out_free; 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 52298c2ecf20Sopenharmony_ci 52308c2ecf20Sopenharmony_ci tp->rtl_ops.up(tp); 52318c2ecf20Sopenharmony_ci 52328c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 52338c2ecf20Sopenharmony_ci netif_start_queue(netdev); 52348c2ecf20Sopenharmony_ci set_bit(WORK_ENABLE, &tp->flags); 52358c2ecf20Sopenharmony_ci 52368c2ecf20Sopenharmony_ci res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); 52378c2ecf20Sopenharmony_ci if (res) { 52388c2ecf20Sopenharmony_ci if (res == -ENODEV) 52398c2ecf20Sopenharmony_ci netif_device_detach(tp->netdev); 52408c2ecf20Sopenharmony_ci netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", 52418c2ecf20Sopenharmony_ci res); 52428c2ecf20Sopenharmony_ci goto out_unlock; 52438c2ecf20Sopenharmony_ci } 52448c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 52458c2ecf20Sopenharmony_ci tasklet_enable(&tp->tx_tl); 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 52488c2ecf20Sopenharmony_ci 52498c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 52508c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 52518c2ecf20Sopenharmony_ci tp->pm_notifier.notifier_call = rtl_notifier; 52528c2ecf20Sopenharmony_ci register_pm_notifier(&tp->pm_notifier); 52538c2ecf20Sopenharmony_ci#endif 52548c2ecf20Sopenharmony_ci return 0; 52558c2ecf20Sopenharmony_ci 52568c2ecf20Sopenharmony_ciout_unlock: 52578c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 52588c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 52598c2ecf20Sopenharmony_ciout_free: 52608c2ecf20Sopenharmony_ci free_all_mem(tp); 52618c2ecf20Sopenharmony_ciout: 52628c2ecf20Sopenharmony_ci return res; 52638c2ecf20Sopenharmony_ci} 52648c2ecf20Sopenharmony_ci 52658c2ecf20Sopenharmony_cistatic int rtl8152_close(struct net_device *netdev) 52668c2ecf20Sopenharmony_ci{ 52678c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 52688c2ecf20Sopenharmony_ci int res = 0; 52698c2ecf20Sopenharmony_ci 52708c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 52718c2ecf20Sopenharmony_ci unregister_pm_notifier(&tp->pm_notifier); 52728c2ecf20Sopenharmony_ci#endif 52738c2ecf20Sopenharmony_ci tasklet_disable(&tp->tx_tl); 52748c2ecf20Sopenharmony_ci clear_bit(WORK_ENABLE, &tp->flags); 52758c2ecf20Sopenharmony_ci usb_kill_urb(tp->intr_urb); 52768c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->schedule); 52778c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 52788c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 52798c2ecf20Sopenharmony_ci 52808c2ecf20Sopenharmony_ci res = usb_autopm_get_interface(tp->intf); 52818c2ecf20Sopenharmony_ci if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { 52828c2ecf20Sopenharmony_ci rtl_drop_queued_tx(tp); 52838c2ecf20Sopenharmony_ci rtl_stop_rx(tp); 52848c2ecf20Sopenharmony_ci } else { 52858c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 52868c2ecf20Sopenharmony_ci 52878c2ecf20Sopenharmony_ci tp->rtl_ops.down(tp); 52888c2ecf20Sopenharmony_ci 52898c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 52908c2ecf20Sopenharmony_ci } 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_ci if (!res) 52938c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 52948c2ecf20Sopenharmony_ci 52958c2ecf20Sopenharmony_ci free_all_mem(tp); 52968c2ecf20Sopenharmony_ci 52978c2ecf20Sopenharmony_ci return res; 52988c2ecf20Sopenharmony_ci} 52998c2ecf20Sopenharmony_ci 53008c2ecf20Sopenharmony_cistatic void rtl_tally_reset(struct r8152 *tp) 53018c2ecf20Sopenharmony_ci{ 53028c2ecf20Sopenharmony_ci u32 ocp_data; 53038c2ecf20Sopenharmony_ci 53048c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); 53058c2ecf20Sopenharmony_ci ocp_data |= TALLY_RESET; 53068c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); 53078c2ecf20Sopenharmony_ci} 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_cistatic void r8152b_init(struct r8152 *tp) 53108c2ecf20Sopenharmony_ci{ 53118c2ecf20Sopenharmony_ci u32 ocp_data; 53128c2ecf20Sopenharmony_ci u16 data; 53138c2ecf20Sopenharmony_ci 53148c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 53158c2ecf20Sopenharmony_ci return; 53168c2ecf20Sopenharmony_ci 53178c2ecf20Sopenharmony_ci data = r8152_mdio_read(tp, MII_BMCR); 53188c2ecf20Sopenharmony_ci if (data & BMCR_PDOWN) { 53198c2ecf20Sopenharmony_ci data &= ~BMCR_PDOWN; 53208c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_BMCR, data); 53218c2ecf20Sopenharmony_ci } 53228c2ecf20Sopenharmony_ci 53238c2ecf20Sopenharmony_ci r8152_aldps_en(tp, false); 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_01) { 53268c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); 53278c2ecf20Sopenharmony_ci ocp_data &= ~LED_MODE_MASK; 53288c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); 53298c2ecf20Sopenharmony_ci } 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci r8152_power_cut_en(tp, false); 53328c2ecf20Sopenharmony_ci 53338c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); 53348c2ecf20Sopenharmony_ci ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; 53358c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); 53368c2ecf20Sopenharmony_ci ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL); 53378c2ecf20Sopenharmony_ci ocp_data &= ~MCU_CLK_RATIO_MASK; 53388c2ecf20Sopenharmony_ci ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN; 53398c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data); 53408c2ecf20Sopenharmony_ci ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK | 53418c2ecf20Sopenharmony_ci SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK; 53428c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data); 53438c2ecf20Sopenharmony_ci 53448c2ecf20Sopenharmony_ci rtl_tally_reset(tp); 53458c2ecf20Sopenharmony_ci 53468c2ecf20Sopenharmony_ci /* enable rx aggregation */ 53478c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); 53488c2ecf20Sopenharmony_ci ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); 53498c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); 53508c2ecf20Sopenharmony_ci} 53518c2ecf20Sopenharmony_ci 53528c2ecf20Sopenharmony_cistatic void r8153_init(struct r8152 *tp) 53538c2ecf20Sopenharmony_ci{ 53548c2ecf20Sopenharmony_ci u32 ocp_data; 53558c2ecf20Sopenharmony_ci u16 data; 53568c2ecf20Sopenharmony_ci int i; 53578c2ecf20Sopenharmony_ci 53588c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 53598c2ecf20Sopenharmony_ci return; 53608c2ecf20Sopenharmony_ci 53618c2ecf20Sopenharmony_ci r8153_u1u2en(tp, false); 53628c2ecf20Sopenharmony_ci 53638c2ecf20Sopenharmony_ci for (i = 0; i < 500; i++) { 53648c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & 53658c2ecf20Sopenharmony_ci AUTOLOAD_DONE) 53668c2ecf20Sopenharmony_ci break; 53678c2ecf20Sopenharmony_ci 53688c2ecf20Sopenharmony_ci msleep(20); 53698c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 53708c2ecf20Sopenharmony_ci break; 53718c2ecf20Sopenharmony_ci } 53728c2ecf20Sopenharmony_ci 53738c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, 0); 53748c2ecf20Sopenharmony_ci 53758c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || 53768c2ecf20Sopenharmony_ci tp->version == RTL_VER_05) 53778c2ecf20Sopenharmony_ci ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci data = r8152_mdio_read(tp, MII_BMCR); 53808c2ecf20Sopenharmony_ci if (data & BMCR_PDOWN) { 53818c2ecf20Sopenharmony_ci data &= ~BMCR_PDOWN; 53828c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_BMCR, data); 53838c2ecf20Sopenharmony_ci } 53848c2ecf20Sopenharmony_ci 53858c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, PHY_STAT_LAN_ON); 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 53888c2ecf20Sopenharmony_ci 53898c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_04) { 53908c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2); 53918c2ecf20Sopenharmony_ci ocp_data &= ~pwd_dn_scale_mask; 53928c2ecf20Sopenharmony_ci ocp_data |= pwd_dn_scale(96); 53938c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data); 53948c2ecf20Sopenharmony_ci 53958c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); 53968c2ecf20Sopenharmony_ci ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; 53978c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); 53988c2ecf20Sopenharmony_ci } else if (tp->version == RTL_VER_05) { 53998c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0); 54008c2ecf20Sopenharmony_ci ocp_data &= ~ECM_ALDPS; 54018c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data); 54028c2ecf20Sopenharmony_ci 54038c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); 54048c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) 54058c2ecf20Sopenharmony_ci ocp_data &= ~DYNAMIC_BURST; 54068c2ecf20Sopenharmony_ci else 54078c2ecf20Sopenharmony_ci ocp_data |= DYNAMIC_BURST; 54088c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); 54098c2ecf20Sopenharmony_ci } else if (tp->version == RTL_VER_06) { 54108c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); 54118c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) 54128c2ecf20Sopenharmony_ci ocp_data &= ~DYNAMIC_BURST; 54138c2ecf20Sopenharmony_ci else 54148c2ecf20Sopenharmony_ci ocp_data |= DYNAMIC_BURST; 54158c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); 54168c2ecf20Sopenharmony_ci 54178c2ecf20Sopenharmony_ci r8153_queue_wake(tp, false); 54188c2ecf20Sopenharmony_ci 54198c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS); 54208c2ecf20Sopenharmony_ci if (rtl8152_get_speed(tp) & LINK_STATUS) 54218c2ecf20Sopenharmony_ci ocp_data |= CUR_LINK_OK; 54228c2ecf20Sopenharmony_ci else 54238c2ecf20Sopenharmony_ci ocp_data &= ~CUR_LINK_OK; 54248c2ecf20Sopenharmony_ci ocp_data |= POLL_LINK_CHG; 54258c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data); 54268c2ecf20Sopenharmony_ci } 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2); 54298c2ecf20Sopenharmony_ci ocp_data |= EP4_FULL_FC; 54308c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data); 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); 54338c2ecf20Sopenharmony_ci ocp_data &= ~TIMER11_EN; 54348c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); 54378c2ecf20Sopenharmony_ci ocp_data &= ~LED_MODE_MASK; 54388c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); 54398c2ecf20Sopenharmony_ci 54408c2ecf20Sopenharmony_ci ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM; 54418c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_04 && tp->udev->speed < USB_SPEED_SUPER) 54428c2ecf20Sopenharmony_ci ocp_data |= LPM_TIMER_500MS; 54438c2ecf20Sopenharmony_ci else 54448c2ecf20Sopenharmony_ci ocp_data |= LPM_TIMER_500US; 54458c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); 54468c2ecf20Sopenharmony_ci 54478c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); 54488c2ecf20Sopenharmony_ci ocp_data &= ~SEN_VAL_MASK; 54498c2ecf20Sopenharmony_ci ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; 54508c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); 54518c2ecf20Sopenharmony_ci 54528c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001); 54538c2ecf20Sopenharmony_ci 54548c2ecf20Sopenharmony_ci /* MAC clock speed down */ 54558c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); 54568c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0); 54578c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0); 54588c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0); 54598c2ecf20Sopenharmony_ci 54608c2ecf20Sopenharmony_ci r8153_power_cut_en(tp, false); 54618c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, false); 54628c2ecf20Sopenharmony_ci r8153_u1u2en(tp, true); 54638c2ecf20Sopenharmony_ci usb_enable_lpm(tp->udev); 54648c2ecf20Sopenharmony_ci 54658c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6); 54668c2ecf20Sopenharmony_ci ocp_data |= LANWAKE_CLR_EN; 54678c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data); 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG); 54708c2ecf20Sopenharmony_ci ocp_data &= ~LANWAKE_PIN; 54718c2ecf20Sopenharmony_ci ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data); 54728c2ecf20Sopenharmony_ci 54738c2ecf20Sopenharmony_ci /* rx aggregation */ 54748c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); 54758c2ecf20Sopenharmony_ci ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); 54768c2ecf20Sopenharmony_ci if (test_bit(DELL_TB_RX_AGG_BUG, &tp->flags)) 54778c2ecf20Sopenharmony_ci ocp_data |= RX_AGG_DISABLE; 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci rtl_tally_reset(tp); 54828c2ecf20Sopenharmony_ci 54838c2ecf20Sopenharmony_ci switch (tp->udev->speed) { 54848c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 54858c2ecf20Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 54868c2ecf20Sopenharmony_ci tp->coalesce = COALESCE_SUPER; 54878c2ecf20Sopenharmony_ci break; 54888c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 54898c2ecf20Sopenharmony_ci tp->coalesce = COALESCE_HIGH; 54908c2ecf20Sopenharmony_ci break; 54918c2ecf20Sopenharmony_ci default: 54928c2ecf20Sopenharmony_ci tp->coalesce = COALESCE_SLOW; 54938c2ecf20Sopenharmony_ci break; 54948c2ecf20Sopenharmony_ci } 54958c2ecf20Sopenharmony_ci} 54968c2ecf20Sopenharmony_ci 54978c2ecf20Sopenharmony_cistatic void r8153b_init(struct r8152 *tp) 54988c2ecf20Sopenharmony_ci{ 54998c2ecf20Sopenharmony_ci u32 ocp_data; 55008c2ecf20Sopenharmony_ci u16 data; 55018c2ecf20Sopenharmony_ci int i; 55028c2ecf20Sopenharmony_ci 55038c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 55048c2ecf20Sopenharmony_ci return; 55058c2ecf20Sopenharmony_ci 55068c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, false); 55078c2ecf20Sopenharmony_ci 55088c2ecf20Sopenharmony_ci for (i = 0; i < 500; i++) { 55098c2ecf20Sopenharmony_ci if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & 55108c2ecf20Sopenharmony_ci AUTOLOAD_DONE) 55118c2ecf20Sopenharmony_ci break; 55128c2ecf20Sopenharmony_ci 55138c2ecf20Sopenharmony_ci msleep(20); 55148c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 55158c2ecf20Sopenharmony_ci break; 55168c2ecf20Sopenharmony_ci } 55178c2ecf20Sopenharmony_ci 55188c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, 0); 55198c2ecf20Sopenharmony_ci 55208c2ecf20Sopenharmony_ci data = r8152_mdio_read(tp, MII_BMCR); 55218c2ecf20Sopenharmony_ci if (data & BMCR_PDOWN) { 55228c2ecf20Sopenharmony_ci data &= ~BMCR_PDOWN; 55238c2ecf20Sopenharmony_ci r8152_mdio_write(tp, MII_BMCR, data); 55248c2ecf20Sopenharmony_ci } 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_ci data = r8153_phy_status(tp, PHY_STAT_LAN_ON); 55278c2ecf20Sopenharmony_ci 55288c2ecf20Sopenharmony_ci r8153_u2p3en(tp, false); 55298c2ecf20Sopenharmony_ci 55308c2ecf20Sopenharmony_ci /* MSC timer = 0xfff * 8ms = 32760 ms */ 55318c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff); 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_ci /* U1/U2/L1 idle timer. 500 us */ 55348c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500); 55358c2ecf20Sopenharmony_ci 55368c2ecf20Sopenharmony_ci r8153b_power_cut_en(tp, false); 55378c2ecf20Sopenharmony_ci r8153b_ups_en(tp, false); 55388c2ecf20Sopenharmony_ci r8153_queue_wake(tp, false); 55398c2ecf20Sopenharmony_ci rtl_runtime_suspend_enable(tp, false); 55408c2ecf20Sopenharmony_ci 55418c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS); 55428c2ecf20Sopenharmony_ci if (rtl8152_get_speed(tp) & LINK_STATUS) 55438c2ecf20Sopenharmony_ci ocp_data |= CUR_LINK_OK; 55448c2ecf20Sopenharmony_ci else 55458c2ecf20Sopenharmony_ci ocp_data &= ~CUR_LINK_OK; 55468c2ecf20Sopenharmony_ci ocp_data |= POLL_LINK_CHG; 55478c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data); 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_ci if (tp->udev->speed != USB_SPEED_HIGH) 55508c2ecf20Sopenharmony_ci r8153b_u1u2en(tp, true); 55518c2ecf20Sopenharmony_ci usb_enable_lpm(tp->udev); 55528c2ecf20Sopenharmony_ci 55538c2ecf20Sopenharmony_ci /* MAC clock speed down */ 55548c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2); 55558c2ecf20Sopenharmony_ci ocp_data |= MAC_CLK_SPDWN_EN; 55568c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data); 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3); 55598c2ecf20Sopenharmony_ci ocp_data &= ~PLA_MCU_SPDWN_EN; 55608c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data); 55618c2ecf20Sopenharmony_ci 55628c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_09) { 55638c2ecf20Sopenharmony_ci /* Disable Test IO for 32QFN */ 55648c2ecf20Sopenharmony_ci if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) { 55658c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); 55668c2ecf20Sopenharmony_ci ocp_data |= TEST_IO_OFF; 55678c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); 55688c2ecf20Sopenharmony_ci } 55698c2ecf20Sopenharmony_ci } 55708c2ecf20Sopenharmony_ci 55718c2ecf20Sopenharmony_ci set_bit(GREEN_ETHERNET, &tp->flags); 55728c2ecf20Sopenharmony_ci 55738c2ecf20Sopenharmony_ci /* rx aggregation */ 55748c2ecf20Sopenharmony_ci ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); 55758c2ecf20Sopenharmony_ci ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); 55768c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); 55778c2ecf20Sopenharmony_ci 55788c2ecf20Sopenharmony_ci rtl_tally_reset(tp); 55798c2ecf20Sopenharmony_ci 55808c2ecf20Sopenharmony_ci tp->coalesce = 15000; /* 15 us */ 55818c2ecf20Sopenharmony_ci} 55828c2ecf20Sopenharmony_ci 55838c2ecf20Sopenharmony_cistatic int rtl8152_pre_reset(struct usb_interface *intf) 55848c2ecf20Sopenharmony_ci{ 55858c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 55868c2ecf20Sopenharmony_ci struct net_device *netdev; 55878c2ecf20Sopenharmony_ci 55888c2ecf20Sopenharmony_ci if (!tp) 55898c2ecf20Sopenharmony_ci return 0; 55908c2ecf20Sopenharmony_ci 55918c2ecf20Sopenharmony_ci netdev = tp->netdev; 55928c2ecf20Sopenharmony_ci if (!netif_running(netdev)) 55938c2ecf20Sopenharmony_ci return 0; 55948c2ecf20Sopenharmony_ci 55958c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 55968c2ecf20Sopenharmony_ci tasklet_disable(&tp->tx_tl); 55978c2ecf20Sopenharmony_ci clear_bit(WORK_ENABLE, &tp->flags); 55988c2ecf20Sopenharmony_ci usb_kill_urb(tp->intr_urb); 55998c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->schedule); 56008c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 56018c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 56028c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 56038c2ecf20Sopenharmony_ci tp->rtl_ops.disable(tp); 56048c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 56058c2ecf20Sopenharmony_ci } 56068c2ecf20Sopenharmony_ci 56078c2ecf20Sopenharmony_ci return 0; 56088c2ecf20Sopenharmony_ci} 56098c2ecf20Sopenharmony_ci 56108c2ecf20Sopenharmony_cistatic int rtl8152_post_reset(struct usb_interface *intf) 56118c2ecf20Sopenharmony_ci{ 56128c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 56138c2ecf20Sopenharmony_ci struct net_device *netdev; 56148c2ecf20Sopenharmony_ci struct sockaddr sa; 56158c2ecf20Sopenharmony_ci 56168c2ecf20Sopenharmony_ci if (!tp) 56178c2ecf20Sopenharmony_ci return 0; 56188c2ecf20Sopenharmony_ci 56198c2ecf20Sopenharmony_ci /* reset the MAC adddress in case of policy change */ 56208c2ecf20Sopenharmony_ci if (determine_ethernet_addr(tp, &sa) >= 0) { 56218c2ecf20Sopenharmony_ci rtnl_lock(); 56228c2ecf20Sopenharmony_ci dev_set_mac_address (tp->netdev, &sa, NULL); 56238c2ecf20Sopenharmony_ci rtnl_unlock(); 56248c2ecf20Sopenharmony_ci } 56258c2ecf20Sopenharmony_ci 56268c2ecf20Sopenharmony_ci netdev = tp->netdev; 56278c2ecf20Sopenharmony_ci if (!netif_running(netdev)) 56288c2ecf20Sopenharmony_ci return 0; 56298c2ecf20Sopenharmony_ci 56308c2ecf20Sopenharmony_ci set_bit(WORK_ENABLE, &tp->flags); 56318c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 56328c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 56338c2ecf20Sopenharmony_ci tp->rtl_ops.enable(tp); 56348c2ecf20Sopenharmony_ci rtl_start_rx(tp); 56358c2ecf20Sopenharmony_ci _rtl8152_set_rx_mode(netdev); 56368c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 56378c2ecf20Sopenharmony_ci } 56388c2ecf20Sopenharmony_ci 56398c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 56408c2ecf20Sopenharmony_ci tasklet_enable(&tp->tx_tl); 56418c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 56428c2ecf20Sopenharmony_ci usb_submit_urb(tp->intr_urb, GFP_KERNEL); 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci if (!list_empty(&tp->rx_done)) 56458c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 56468c2ecf20Sopenharmony_ci 56478c2ecf20Sopenharmony_ci return 0; 56488c2ecf20Sopenharmony_ci} 56498c2ecf20Sopenharmony_ci 56508c2ecf20Sopenharmony_cistatic bool delay_autosuspend(struct r8152 *tp) 56518c2ecf20Sopenharmony_ci{ 56528c2ecf20Sopenharmony_ci bool sw_linking = !!netif_carrier_ok(tp->netdev); 56538c2ecf20Sopenharmony_ci bool hw_linking = !!(rtl8152_get_speed(tp) & LINK_STATUS); 56548c2ecf20Sopenharmony_ci 56558c2ecf20Sopenharmony_ci /* This means a linking change occurs and the driver doesn't detect it, 56568c2ecf20Sopenharmony_ci * yet. If the driver has disabled tx/rx and hw is linking on, the 56578c2ecf20Sopenharmony_ci * device wouldn't wake up by receiving any packet. 56588c2ecf20Sopenharmony_ci */ 56598c2ecf20Sopenharmony_ci if (work_busy(&tp->schedule.work) || sw_linking != hw_linking) 56608c2ecf20Sopenharmony_ci return true; 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci /* If the linking down is occurred by nway, the device may miss the 56638c2ecf20Sopenharmony_ci * linking change event. And it wouldn't wake when linking on. 56648c2ecf20Sopenharmony_ci */ 56658c2ecf20Sopenharmony_ci if (!sw_linking && tp->rtl_ops.in_nway(tp)) 56668c2ecf20Sopenharmony_ci return true; 56678c2ecf20Sopenharmony_ci else if (!skb_queue_empty(&tp->tx_queue)) 56688c2ecf20Sopenharmony_ci return true; 56698c2ecf20Sopenharmony_ci else 56708c2ecf20Sopenharmony_ci return false; 56718c2ecf20Sopenharmony_ci} 56728c2ecf20Sopenharmony_ci 56738c2ecf20Sopenharmony_cistatic int rtl8152_runtime_resume(struct r8152 *tp) 56748c2ecf20Sopenharmony_ci{ 56758c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 56768c2ecf20Sopenharmony_ci 56778c2ecf20Sopenharmony_ci if (netif_running(netdev) && netdev->flags & IFF_UP) { 56788c2ecf20Sopenharmony_ci struct napi_struct *napi = &tp->napi; 56798c2ecf20Sopenharmony_ci 56808c2ecf20Sopenharmony_ci tp->rtl_ops.autosuspend_en(tp, false); 56818c2ecf20Sopenharmony_ci napi_disable(napi); 56828c2ecf20Sopenharmony_ci set_bit(WORK_ENABLE, &tp->flags); 56838c2ecf20Sopenharmony_ci 56848c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 56858c2ecf20Sopenharmony_ci if (rtl8152_get_speed(tp) & LINK_STATUS) { 56868c2ecf20Sopenharmony_ci rtl_start_rx(tp); 56878c2ecf20Sopenharmony_ci } else { 56888c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 56898c2ecf20Sopenharmony_ci tp->rtl_ops.disable(tp); 56908c2ecf20Sopenharmony_ci netif_info(tp, link, netdev, "linking down\n"); 56918c2ecf20Sopenharmony_ci } 56928c2ecf20Sopenharmony_ci } 56938c2ecf20Sopenharmony_ci 56948c2ecf20Sopenharmony_ci napi_enable(napi); 56958c2ecf20Sopenharmony_ci clear_bit(SELECTIVE_SUSPEND, &tp->flags); 56968c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 56978c2ecf20Sopenharmony_ci 56988c2ecf20Sopenharmony_ci if (!list_empty(&tp->rx_done)) 56998c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 57008c2ecf20Sopenharmony_ci 57018c2ecf20Sopenharmony_ci usb_submit_urb(tp->intr_urb, GFP_NOIO); 57028c2ecf20Sopenharmony_ci } else { 57038c2ecf20Sopenharmony_ci if (netdev->flags & IFF_UP) 57048c2ecf20Sopenharmony_ci tp->rtl_ops.autosuspend_en(tp, false); 57058c2ecf20Sopenharmony_ci 57068c2ecf20Sopenharmony_ci clear_bit(SELECTIVE_SUSPEND, &tp->flags); 57078c2ecf20Sopenharmony_ci } 57088c2ecf20Sopenharmony_ci 57098c2ecf20Sopenharmony_ci return 0; 57108c2ecf20Sopenharmony_ci} 57118c2ecf20Sopenharmony_ci 57128c2ecf20Sopenharmony_cistatic int rtl8152_system_resume(struct r8152 *tp) 57138c2ecf20Sopenharmony_ci{ 57148c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 57158c2ecf20Sopenharmony_ci 57168c2ecf20Sopenharmony_ci netif_device_attach(netdev); 57178c2ecf20Sopenharmony_ci 57188c2ecf20Sopenharmony_ci if (netif_running(netdev) && (netdev->flags & IFF_UP)) { 57198c2ecf20Sopenharmony_ci tp->rtl_ops.up(tp); 57208c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 57218c2ecf20Sopenharmony_ci set_bit(WORK_ENABLE, &tp->flags); 57228c2ecf20Sopenharmony_ci usb_submit_urb(tp->intr_urb, GFP_NOIO); 57238c2ecf20Sopenharmony_ci } 57248c2ecf20Sopenharmony_ci 57258c2ecf20Sopenharmony_ci return 0; 57268c2ecf20Sopenharmony_ci} 57278c2ecf20Sopenharmony_ci 57288c2ecf20Sopenharmony_cistatic int rtl8152_runtime_suspend(struct r8152 *tp) 57298c2ecf20Sopenharmony_ci{ 57308c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 57318c2ecf20Sopenharmony_ci int ret = 0; 57328c2ecf20Sopenharmony_ci 57338c2ecf20Sopenharmony_ci set_bit(SELECTIVE_SUSPEND, &tp->flags); 57348c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 57358c2ecf20Sopenharmony_ci 57368c2ecf20Sopenharmony_ci if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { 57378c2ecf20Sopenharmony_ci u32 rcr = 0; 57388c2ecf20Sopenharmony_ci 57398c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 57408c2ecf20Sopenharmony_ci u32 ocp_data; 57418c2ecf20Sopenharmony_ci 57428c2ecf20Sopenharmony_ci rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); 57438c2ecf20Sopenharmony_ci ocp_data = rcr & ~RCR_ACPT_ALL; 57448c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 57458c2ecf20Sopenharmony_ci rxdy_gated_en(tp, true); 57468c2ecf20Sopenharmony_ci ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 57478c2ecf20Sopenharmony_ci PLA_OOB_CTRL); 57488c2ecf20Sopenharmony_ci if (!(ocp_data & RXFIFO_EMPTY)) { 57498c2ecf20Sopenharmony_ci rxdy_gated_en(tp, false); 57508c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); 57518c2ecf20Sopenharmony_ci clear_bit(SELECTIVE_SUSPEND, &tp->flags); 57528c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 57538c2ecf20Sopenharmony_ci ret = -EBUSY; 57548c2ecf20Sopenharmony_ci goto out1; 57558c2ecf20Sopenharmony_ci } 57568c2ecf20Sopenharmony_ci } 57578c2ecf20Sopenharmony_ci 57588c2ecf20Sopenharmony_ci clear_bit(WORK_ENABLE, &tp->flags); 57598c2ecf20Sopenharmony_ci usb_kill_urb(tp->intr_urb); 57608c2ecf20Sopenharmony_ci 57618c2ecf20Sopenharmony_ci tp->rtl_ops.autosuspend_en(tp, true); 57628c2ecf20Sopenharmony_ci 57638c2ecf20Sopenharmony_ci if (netif_carrier_ok(netdev)) { 57648c2ecf20Sopenharmony_ci struct napi_struct *napi = &tp->napi; 57658c2ecf20Sopenharmony_ci 57668c2ecf20Sopenharmony_ci napi_disable(napi); 57678c2ecf20Sopenharmony_ci rtl_stop_rx(tp); 57688c2ecf20Sopenharmony_ci rxdy_gated_en(tp, false); 57698c2ecf20Sopenharmony_ci ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); 57708c2ecf20Sopenharmony_ci napi_enable(napi); 57718c2ecf20Sopenharmony_ci } 57728c2ecf20Sopenharmony_ci 57738c2ecf20Sopenharmony_ci if (delay_autosuspend(tp)) { 57748c2ecf20Sopenharmony_ci rtl8152_runtime_resume(tp); 57758c2ecf20Sopenharmony_ci ret = -EBUSY; 57768c2ecf20Sopenharmony_ci } 57778c2ecf20Sopenharmony_ci } 57788c2ecf20Sopenharmony_ci 57798c2ecf20Sopenharmony_ciout1: 57808c2ecf20Sopenharmony_ci return ret; 57818c2ecf20Sopenharmony_ci} 57828c2ecf20Sopenharmony_ci 57838c2ecf20Sopenharmony_cistatic int rtl8152_system_suspend(struct r8152 *tp) 57848c2ecf20Sopenharmony_ci{ 57858c2ecf20Sopenharmony_ci struct net_device *netdev = tp->netdev; 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci netif_device_detach(netdev); 57888c2ecf20Sopenharmony_ci 57898c2ecf20Sopenharmony_ci if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { 57908c2ecf20Sopenharmony_ci struct napi_struct *napi = &tp->napi; 57918c2ecf20Sopenharmony_ci 57928c2ecf20Sopenharmony_ci clear_bit(WORK_ENABLE, &tp->flags); 57938c2ecf20Sopenharmony_ci usb_kill_urb(tp->intr_urb); 57948c2ecf20Sopenharmony_ci tasklet_disable(&tp->tx_tl); 57958c2ecf20Sopenharmony_ci napi_disable(napi); 57968c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->schedule); 57978c2ecf20Sopenharmony_ci tp->rtl_ops.down(tp); 57988c2ecf20Sopenharmony_ci napi_enable(napi); 57998c2ecf20Sopenharmony_ci tasklet_enable(&tp->tx_tl); 58008c2ecf20Sopenharmony_ci } 58018c2ecf20Sopenharmony_ci 58028c2ecf20Sopenharmony_ci return 0; 58038c2ecf20Sopenharmony_ci} 58048c2ecf20Sopenharmony_ci 58058c2ecf20Sopenharmony_cistatic int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) 58068c2ecf20Sopenharmony_ci{ 58078c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 58088c2ecf20Sopenharmony_ci int ret; 58098c2ecf20Sopenharmony_ci 58108c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 58118c2ecf20Sopenharmony_ci 58128c2ecf20Sopenharmony_ci if (PMSG_IS_AUTO(message)) 58138c2ecf20Sopenharmony_ci ret = rtl8152_runtime_suspend(tp); 58148c2ecf20Sopenharmony_ci else 58158c2ecf20Sopenharmony_ci ret = rtl8152_system_suspend(tp); 58168c2ecf20Sopenharmony_ci 58178c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci return ret; 58208c2ecf20Sopenharmony_ci} 58218c2ecf20Sopenharmony_ci 58228c2ecf20Sopenharmony_cistatic int rtl8152_resume(struct usb_interface *intf) 58238c2ecf20Sopenharmony_ci{ 58248c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 58258c2ecf20Sopenharmony_ci int ret; 58268c2ecf20Sopenharmony_ci 58278c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 58288c2ecf20Sopenharmony_ci 58298c2ecf20Sopenharmony_ci if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) 58308c2ecf20Sopenharmony_ci ret = rtl8152_runtime_resume(tp); 58318c2ecf20Sopenharmony_ci else 58328c2ecf20Sopenharmony_ci ret = rtl8152_system_resume(tp); 58338c2ecf20Sopenharmony_ci 58348c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 58358c2ecf20Sopenharmony_ci 58368c2ecf20Sopenharmony_ci return ret; 58378c2ecf20Sopenharmony_ci} 58388c2ecf20Sopenharmony_ci 58398c2ecf20Sopenharmony_cistatic int rtl8152_reset_resume(struct usb_interface *intf) 58408c2ecf20Sopenharmony_ci{ 58418c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_ci clear_bit(SELECTIVE_SUSPEND, &tp->flags); 58448c2ecf20Sopenharmony_ci tp->rtl_ops.init(tp); 58458c2ecf20Sopenharmony_ci queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); 58468c2ecf20Sopenharmony_ci set_ethernet_addr(tp); 58478c2ecf20Sopenharmony_ci return rtl8152_resume(intf); 58488c2ecf20Sopenharmony_ci} 58498c2ecf20Sopenharmony_ci 58508c2ecf20Sopenharmony_cistatic void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 58518c2ecf20Sopenharmony_ci{ 58528c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 58538c2ecf20Sopenharmony_ci 58548c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(tp->intf) < 0) 58558c2ecf20Sopenharmony_ci return; 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci if (!rtl_can_wakeup(tp)) { 58588c2ecf20Sopenharmony_ci wol->supported = 0; 58598c2ecf20Sopenharmony_ci wol->wolopts = 0; 58608c2ecf20Sopenharmony_ci } else { 58618c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 58628c2ecf20Sopenharmony_ci wol->supported = WAKE_ANY; 58638c2ecf20Sopenharmony_ci wol->wolopts = __rtl_get_wol(tp); 58648c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 58658c2ecf20Sopenharmony_ci } 58668c2ecf20Sopenharmony_ci 58678c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 58688c2ecf20Sopenharmony_ci} 58698c2ecf20Sopenharmony_ci 58708c2ecf20Sopenharmony_cistatic int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 58718c2ecf20Sopenharmony_ci{ 58728c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 58738c2ecf20Sopenharmony_ci int ret; 58748c2ecf20Sopenharmony_ci 58758c2ecf20Sopenharmony_ci if (!rtl_can_wakeup(tp)) 58768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 58778c2ecf20Sopenharmony_ci 58788c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_ANY) 58798c2ecf20Sopenharmony_ci return -EINVAL; 58808c2ecf20Sopenharmony_ci 58818c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 58828c2ecf20Sopenharmony_ci if (ret < 0) 58838c2ecf20Sopenharmony_ci goto out_set_wol; 58848c2ecf20Sopenharmony_ci 58858c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 58868c2ecf20Sopenharmony_ci 58878c2ecf20Sopenharmony_ci __rtl_set_wol(tp, wol->wolopts); 58888c2ecf20Sopenharmony_ci tp->saved_wolopts = wol->wolopts & WAKE_ANY; 58898c2ecf20Sopenharmony_ci 58908c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 58918c2ecf20Sopenharmony_ci 58928c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 58938c2ecf20Sopenharmony_ci 58948c2ecf20Sopenharmony_ciout_set_wol: 58958c2ecf20Sopenharmony_ci return ret; 58968c2ecf20Sopenharmony_ci} 58978c2ecf20Sopenharmony_ci 58988c2ecf20Sopenharmony_cistatic u32 rtl8152_get_msglevel(struct net_device *dev) 58998c2ecf20Sopenharmony_ci{ 59008c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 59018c2ecf20Sopenharmony_ci 59028c2ecf20Sopenharmony_ci return tp->msg_enable; 59038c2ecf20Sopenharmony_ci} 59048c2ecf20Sopenharmony_ci 59058c2ecf20Sopenharmony_cistatic void rtl8152_set_msglevel(struct net_device *dev, u32 value) 59068c2ecf20Sopenharmony_ci{ 59078c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 59088c2ecf20Sopenharmony_ci 59098c2ecf20Sopenharmony_ci tp->msg_enable = value; 59108c2ecf20Sopenharmony_ci} 59118c2ecf20Sopenharmony_ci 59128c2ecf20Sopenharmony_cistatic void rtl8152_get_drvinfo(struct net_device *netdev, 59138c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 59148c2ecf20Sopenharmony_ci{ 59158c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 59168c2ecf20Sopenharmony_ci 59178c2ecf20Sopenharmony_ci strlcpy(info->driver, MODULENAME, sizeof(info->driver)); 59188c2ecf20Sopenharmony_ci strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); 59198c2ecf20Sopenharmony_ci usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info)); 59208c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(tp->rtl_fw.fw)) 59218c2ecf20Sopenharmony_ci strlcpy(info->fw_version, tp->rtl_fw.version, 59228c2ecf20Sopenharmony_ci sizeof(info->fw_version)); 59238c2ecf20Sopenharmony_ci} 59248c2ecf20Sopenharmony_ci 59258c2ecf20Sopenharmony_cistatic 59268c2ecf20Sopenharmony_ciint rtl8152_get_link_ksettings(struct net_device *netdev, 59278c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 59288c2ecf20Sopenharmony_ci{ 59298c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 59308c2ecf20Sopenharmony_ci int ret; 59318c2ecf20Sopenharmony_ci 59328c2ecf20Sopenharmony_ci if (!tp->mii.mdio_read) 59338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 59348c2ecf20Sopenharmony_ci 59358c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 59368c2ecf20Sopenharmony_ci if (ret < 0) 59378c2ecf20Sopenharmony_ci goto out; 59388c2ecf20Sopenharmony_ci 59398c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 59408c2ecf20Sopenharmony_ci 59418c2ecf20Sopenharmony_ci mii_ethtool_get_link_ksettings(&tp->mii, cmd); 59428c2ecf20Sopenharmony_ci 59438c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 59448c2ecf20Sopenharmony_ci 59458c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 59468c2ecf20Sopenharmony_ci 59478c2ecf20Sopenharmony_ciout: 59488c2ecf20Sopenharmony_ci return ret; 59498c2ecf20Sopenharmony_ci} 59508c2ecf20Sopenharmony_ci 59518c2ecf20Sopenharmony_cistatic int rtl8152_set_link_ksettings(struct net_device *dev, 59528c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 59538c2ecf20Sopenharmony_ci{ 59548c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 59558c2ecf20Sopenharmony_ci u32 advertising = 0; 59568c2ecf20Sopenharmony_ci int ret; 59578c2ecf20Sopenharmony_ci 59588c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 59598c2ecf20Sopenharmony_ci if (ret < 0) 59608c2ecf20Sopenharmony_ci goto out; 59618c2ecf20Sopenharmony_ci 59628c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, 59638c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59648c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_10_HALF; 59658c2ecf20Sopenharmony_ci 59668c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, 59678c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59688c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_10_FULL; 59698c2ecf20Sopenharmony_ci 59708c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, 59718c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59728c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_100_HALF; 59738c2ecf20Sopenharmony_ci 59748c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, 59758c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59768c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_100_FULL; 59778c2ecf20Sopenharmony_ci 59788c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 59798c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59808c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_1000_HALF; 59818c2ecf20Sopenharmony_ci 59828c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 59838c2ecf20Sopenharmony_ci cmd->link_modes.advertising)) 59848c2ecf20Sopenharmony_ci advertising |= RTL_ADVERTISED_1000_FULL; 59858c2ecf20Sopenharmony_ci 59868c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 59878c2ecf20Sopenharmony_ci 59888c2ecf20Sopenharmony_ci ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed, 59898c2ecf20Sopenharmony_ci cmd->base.duplex, advertising); 59908c2ecf20Sopenharmony_ci if (!ret) { 59918c2ecf20Sopenharmony_ci tp->autoneg = cmd->base.autoneg; 59928c2ecf20Sopenharmony_ci tp->speed = cmd->base.speed; 59938c2ecf20Sopenharmony_ci tp->duplex = cmd->base.duplex; 59948c2ecf20Sopenharmony_ci tp->advertising = advertising; 59958c2ecf20Sopenharmony_ci } 59968c2ecf20Sopenharmony_ci 59978c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 60008c2ecf20Sopenharmony_ci 60018c2ecf20Sopenharmony_ciout: 60028c2ecf20Sopenharmony_ci return ret; 60038c2ecf20Sopenharmony_ci} 60048c2ecf20Sopenharmony_ci 60058c2ecf20Sopenharmony_cistatic const char rtl8152_gstrings[][ETH_GSTRING_LEN] = { 60068c2ecf20Sopenharmony_ci "tx_packets", 60078c2ecf20Sopenharmony_ci "rx_packets", 60088c2ecf20Sopenharmony_ci "tx_errors", 60098c2ecf20Sopenharmony_ci "rx_errors", 60108c2ecf20Sopenharmony_ci "rx_missed", 60118c2ecf20Sopenharmony_ci "align_errors", 60128c2ecf20Sopenharmony_ci "tx_single_collisions", 60138c2ecf20Sopenharmony_ci "tx_multi_collisions", 60148c2ecf20Sopenharmony_ci "rx_unicast", 60158c2ecf20Sopenharmony_ci "rx_broadcast", 60168c2ecf20Sopenharmony_ci "rx_multicast", 60178c2ecf20Sopenharmony_ci "tx_aborted", 60188c2ecf20Sopenharmony_ci "tx_underrun", 60198c2ecf20Sopenharmony_ci}; 60208c2ecf20Sopenharmony_ci 60218c2ecf20Sopenharmony_cistatic int rtl8152_get_sset_count(struct net_device *dev, int sset) 60228c2ecf20Sopenharmony_ci{ 60238c2ecf20Sopenharmony_ci switch (sset) { 60248c2ecf20Sopenharmony_ci case ETH_SS_STATS: 60258c2ecf20Sopenharmony_ci return ARRAY_SIZE(rtl8152_gstrings); 60268c2ecf20Sopenharmony_ci default: 60278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 60288c2ecf20Sopenharmony_ci } 60298c2ecf20Sopenharmony_ci} 60308c2ecf20Sopenharmony_ci 60318c2ecf20Sopenharmony_cistatic void rtl8152_get_ethtool_stats(struct net_device *dev, 60328c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 60338c2ecf20Sopenharmony_ci{ 60348c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 60358c2ecf20Sopenharmony_ci struct tally_counter tally; 60368c2ecf20Sopenharmony_ci 60378c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(tp->intf) < 0) 60388c2ecf20Sopenharmony_ci return; 60398c2ecf20Sopenharmony_ci 60408c2ecf20Sopenharmony_ci generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); 60418c2ecf20Sopenharmony_ci 60428c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 60438c2ecf20Sopenharmony_ci 60448c2ecf20Sopenharmony_ci data[0] = le64_to_cpu(tally.tx_packets); 60458c2ecf20Sopenharmony_ci data[1] = le64_to_cpu(tally.rx_packets); 60468c2ecf20Sopenharmony_ci data[2] = le64_to_cpu(tally.tx_errors); 60478c2ecf20Sopenharmony_ci data[3] = le32_to_cpu(tally.rx_errors); 60488c2ecf20Sopenharmony_ci data[4] = le16_to_cpu(tally.rx_missed); 60498c2ecf20Sopenharmony_ci data[5] = le16_to_cpu(tally.align_errors); 60508c2ecf20Sopenharmony_ci data[6] = le32_to_cpu(tally.tx_one_collision); 60518c2ecf20Sopenharmony_ci data[7] = le32_to_cpu(tally.tx_multi_collision); 60528c2ecf20Sopenharmony_ci data[8] = le64_to_cpu(tally.rx_unicast); 60538c2ecf20Sopenharmony_ci data[9] = le64_to_cpu(tally.rx_broadcast); 60548c2ecf20Sopenharmony_ci data[10] = le32_to_cpu(tally.rx_multicast); 60558c2ecf20Sopenharmony_ci data[11] = le16_to_cpu(tally.tx_aborted); 60568c2ecf20Sopenharmony_ci data[12] = le16_to_cpu(tally.tx_underrun); 60578c2ecf20Sopenharmony_ci} 60588c2ecf20Sopenharmony_ci 60598c2ecf20Sopenharmony_cistatic void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) 60608c2ecf20Sopenharmony_ci{ 60618c2ecf20Sopenharmony_ci switch (stringset) { 60628c2ecf20Sopenharmony_ci case ETH_SS_STATS: 60638c2ecf20Sopenharmony_ci memcpy(data, rtl8152_gstrings, sizeof(rtl8152_gstrings)); 60648c2ecf20Sopenharmony_ci break; 60658c2ecf20Sopenharmony_ci } 60668c2ecf20Sopenharmony_ci} 60678c2ecf20Sopenharmony_ci 60688c2ecf20Sopenharmony_cistatic int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) 60698c2ecf20Sopenharmony_ci{ 60708c2ecf20Sopenharmony_ci u32 lp, adv, supported = 0; 60718c2ecf20Sopenharmony_ci u16 val; 60728c2ecf20Sopenharmony_ci 60738c2ecf20Sopenharmony_ci val = r8152_mmd_read(tp, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); 60748c2ecf20Sopenharmony_ci supported = mmd_eee_cap_to_ethtool_sup_t(val); 60758c2ecf20Sopenharmony_ci 60768c2ecf20Sopenharmony_ci val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV); 60778c2ecf20Sopenharmony_ci adv = mmd_eee_adv_to_ethtool_adv_t(val); 60788c2ecf20Sopenharmony_ci 60798c2ecf20Sopenharmony_ci val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); 60808c2ecf20Sopenharmony_ci lp = mmd_eee_adv_to_ethtool_adv_t(val); 60818c2ecf20Sopenharmony_ci 60828c2ecf20Sopenharmony_ci eee->eee_enabled = tp->eee_en; 60838c2ecf20Sopenharmony_ci eee->eee_active = !!(supported & adv & lp); 60848c2ecf20Sopenharmony_ci eee->supported = supported; 60858c2ecf20Sopenharmony_ci eee->advertised = tp->eee_adv; 60868c2ecf20Sopenharmony_ci eee->lp_advertised = lp; 60878c2ecf20Sopenharmony_ci 60888c2ecf20Sopenharmony_ci return 0; 60898c2ecf20Sopenharmony_ci} 60908c2ecf20Sopenharmony_ci 60918c2ecf20Sopenharmony_cistatic int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) 60928c2ecf20Sopenharmony_ci{ 60938c2ecf20Sopenharmony_ci u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); 60948c2ecf20Sopenharmony_ci 60958c2ecf20Sopenharmony_ci tp->eee_en = eee->eee_enabled; 60968c2ecf20Sopenharmony_ci tp->eee_adv = val; 60978c2ecf20Sopenharmony_ci 60988c2ecf20Sopenharmony_ci rtl_eee_enable(tp, tp->eee_en); 60998c2ecf20Sopenharmony_ci 61008c2ecf20Sopenharmony_ci return 0; 61018c2ecf20Sopenharmony_ci} 61028c2ecf20Sopenharmony_ci 61038c2ecf20Sopenharmony_cistatic int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) 61048c2ecf20Sopenharmony_ci{ 61058c2ecf20Sopenharmony_ci u32 lp, adv, supported = 0; 61068c2ecf20Sopenharmony_ci u16 val; 61078c2ecf20Sopenharmony_ci 61088c2ecf20Sopenharmony_ci val = ocp_reg_read(tp, OCP_EEE_ABLE); 61098c2ecf20Sopenharmony_ci supported = mmd_eee_cap_to_ethtool_sup_t(val); 61108c2ecf20Sopenharmony_ci 61118c2ecf20Sopenharmony_ci val = ocp_reg_read(tp, OCP_EEE_ADV); 61128c2ecf20Sopenharmony_ci adv = mmd_eee_adv_to_ethtool_adv_t(val); 61138c2ecf20Sopenharmony_ci 61148c2ecf20Sopenharmony_ci val = ocp_reg_read(tp, OCP_EEE_LPABLE); 61158c2ecf20Sopenharmony_ci lp = mmd_eee_adv_to_ethtool_adv_t(val); 61168c2ecf20Sopenharmony_ci 61178c2ecf20Sopenharmony_ci eee->eee_enabled = tp->eee_en; 61188c2ecf20Sopenharmony_ci eee->eee_active = !!(supported & adv & lp); 61198c2ecf20Sopenharmony_ci eee->supported = supported; 61208c2ecf20Sopenharmony_ci eee->advertised = tp->eee_adv; 61218c2ecf20Sopenharmony_ci eee->lp_advertised = lp; 61228c2ecf20Sopenharmony_ci 61238c2ecf20Sopenharmony_ci return 0; 61248c2ecf20Sopenharmony_ci} 61258c2ecf20Sopenharmony_ci 61268c2ecf20Sopenharmony_cistatic int 61278c2ecf20Sopenharmony_cirtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) 61288c2ecf20Sopenharmony_ci{ 61298c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(net); 61308c2ecf20Sopenharmony_ci int ret; 61318c2ecf20Sopenharmony_ci 61328c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 61338c2ecf20Sopenharmony_ci if (ret < 0) 61348c2ecf20Sopenharmony_ci goto out; 61358c2ecf20Sopenharmony_ci 61368c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 61378c2ecf20Sopenharmony_ci 61388c2ecf20Sopenharmony_ci ret = tp->rtl_ops.eee_get(tp, edata); 61398c2ecf20Sopenharmony_ci 61408c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 61418c2ecf20Sopenharmony_ci 61428c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 61438c2ecf20Sopenharmony_ci 61448c2ecf20Sopenharmony_ciout: 61458c2ecf20Sopenharmony_ci return ret; 61468c2ecf20Sopenharmony_ci} 61478c2ecf20Sopenharmony_ci 61488c2ecf20Sopenharmony_cistatic int 61498c2ecf20Sopenharmony_cirtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) 61508c2ecf20Sopenharmony_ci{ 61518c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(net); 61528c2ecf20Sopenharmony_ci int ret; 61538c2ecf20Sopenharmony_ci 61548c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 61558c2ecf20Sopenharmony_ci if (ret < 0) 61568c2ecf20Sopenharmony_ci goto out; 61578c2ecf20Sopenharmony_ci 61588c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 61598c2ecf20Sopenharmony_ci 61608c2ecf20Sopenharmony_ci ret = tp->rtl_ops.eee_set(tp, edata); 61618c2ecf20Sopenharmony_ci if (!ret) 61628c2ecf20Sopenharmony_ci ret = mii_nway_restart(&tp->mii); 61638c2ecf20Sopenharmony_ci 61648c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 61658c2ecf20Sopenharmony_ci 61668c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 61678c2ecf20Sopenharmony_ci 61688c2ecf20Sopenharmony_ciout: 61698c2ecf20Sopenharmony_ci return ret; 61708c2ecf20Sopenharmony_ci} 61718c2ecf20Sopenharmony_ci 61728c2ecf20Sopenharmony_cistatic int rtl8152_nway_reset(struct net_device *dev) 61738c2ecf20Sopenharmony_ci{ 61748c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 61758c2ecf20Sopenharmony_ci int ret; 61768c2ecf20Sopenharmony_ci 61778c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 61788c2ecf20Sopenharmony_ci if (ret < 0) 61798c2ecf20Sopenharmony_ci goto out; 61808c2ecf20Sopenharmony_ci 61818c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 61828c2ecf20Sopenharmony_ci 61838c2ecf20Sopenharmony_ci ret = mii_nway_restart(&tp->mii); 61848c2ecf20Sopenharmony_ci 61858c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 61868c2ecf20Sopenharmony_ci 61878c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 61888c2ecf20Sopenharmony_ci 61898c2ecf20Sopenharmony_ciout: 61908c2ecf20Sopenharmony_ci return ret; 61918c2ecf20Sopenharmony_ci} 61928c2ecf20Sopenharmony_ci 61938c2ecf20Sopenharmony_cistatic int rtl8152_get_coalesce(struct net_device *netdev, 61948c2ecf20Sopenharmony_ci struct ethtool_coalesce *coalesce) 61958c2ecf20Sopenharmony_ci{ 61968c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 61978c2ecf20Sopenharmony_ci 61988c2ecf20Sopenharmony_ci switch (tp->version) { 61998c2ecf20Sopenharmony_ci case RTL_VER_01: 62008c2ecf20Sopenharmony_ci case RTL_VER_02: 62018c2ecf20Sopenharmony_ci case RTL_VER_07: 62028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 62038c2ecf20Sopenharmony_ci default: 62048c2ecf20Sopenharmony_ci break; 62058c2ecf20Sopenharmony_ci } 62068c2ecf20Sopenharmony_ci 62078c2ecf20Sopenharmony_ci coalesce->rx_coalesce_usecs = tp->coalesce; 62088c2ecf20Sopenharmony_ci 62098c2ecf20Sopenharmony_ci return 0; 62108c2ecf20Sopenharmony_ci} 62118c2ecf20Sopenharmony_ci 62128c2ecf20Sopenharmony_cistatic int rtl8152_set_coalesce(struct net_device *netdev, 62138c2ecf20Sopenharmony_ci struct ethtool_coalesce *coalesce) 62148c2ecf20Sopenharmony_ci{ 62158c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 62168c2ecf20Sopenharmony_ci int ret; 62178c2ecf20Sopenharmony_ci 62188c2ecf20Sopenharmony_ci switch (tp->version) { 62198c2ecf20Sopenharmony_ci case RTL_VER_01: 62208c2ecf20Sopenharmony_ci case RTL_VER_02: 62218c2ecf20Sopenharmony_ci case RTL_VER_07: 62228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 62238c2ecf20Sopenharmony_ci default: 62248c2ecf20Sopenharmony_ci break; 62258c2ecf20Sopenharmony_ci } 62268c2ecf20Sopenharmony_ci 62278c2ecf20Sopenharmony_ci if (coalesce->rx_coalesce_usecs > COALESCE_SLOW) 62288c2ecf20Sopenharmony_ci return -EINVAL; 62298c2ecf20Sopenharmony_ci 62308c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 62318c2ecf20Sopenharmony_ci if (ret < 0) 62328c2ecf20Sopenharmony_ci return ret; 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 62358c2ecf20Sopenharmony_ci 62368c2ecf20Sopenharmony_ci if (tp->coalesce != coalesce->rx_coalesce_usecs) { 62378c2ecf20Sopenharmony_ci tp->coalesce = coalesce->rx_coalesce_usecs; 62388c2ecf20Sopenharmony_ci 62398c2ecf20Sopenharmony_ci if (netif_running(netdev) && netif_carrier_ok(netdev)) { 62408c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 62418c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 62428c2ecf20Sopenharmony_ci tp->rtl_ops.disable(tp); 62438c2ecf20Sopenharmony_ci tp->rtl_ops.enable(tp); 62448c2ecf20Sopenharmony_ci rtl_start_rx(tp); 62458c2ecf20Sopenharmony_ci clear_bit(RTL8152_SET_RX_MODE, &tp->flags); 62468c2ecf20Sopenharmony_ci _rtl8152_set_rx_mode(netdev); 62478c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 62488c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 62498c2ecf20Sopenharmony_ci } 62508c2ecf20Sopenharmony_ci } 62518c2ecf20Sopenharmony_ci 62528c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 62538c2ecf20Sopenharmony_ci 62548c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 62558c2ecf20Sopenharmony_ci 62568c2ecf20Sopenharmony_ci return ret; 62578c2ecf20Sopenharmony_ci} 62588c2ecf20Sopenharmony_ci 62598c2ecf20Sopenharmony_cistatic int rtl8152_get_tunable(struct net_device *netdev, 62608c2ecf20Sopenharmony_ci const struct ethtool_tunable *tunable, void *d) 62618c2ecf20Sopenharmony_ci{ 62628c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 62638c2ecf20Sopenharmony_ci 62648c2ecf20Sopenharmony_ci switch (tunable->id) { 62658c2ecf20Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 62668c2ecf20Sopenharmony_ci *(u32 *)d = tp->rx_copybreak; 62678c2ecf20Sopenharmony_ci break; 62688c2ecf20Sopenharmony_ci default: 62698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 62708c2ecf20Sopenharmony_ci } 62718c2ecf20Sopenharmony_ci 62728c2ecf20Sopenharmony_ci return 0; 62738c2ecf20Sopenharmony_ci} 62748c2ecf20Sopenharmony_ci 62758c2ecf20Sopenharmony_cistatic int rtl8152_set_tunable(struct net_device *netdev, 62768c2ecf20Sopenharmony_ci const struct ethtool_tunable *tunable, 62778c2ecf20Sopenharmony_ci const void *d) 62788c2ecf20Sopenharmony_ci{ 62798c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 62808c2ecf20Sopenharmony_ci u32 val; 62818c2ecf20Sopenharmony_ci 62828c2ecf20Sopenharmony_ci switch (tunable->id) { 62838c2ecf20Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 62848c2ecf20Sopenharmony_ci val = *(u32 *)d; 62858c2ecf20Sopenharmony_ci if (val < ETH_ZLEN) { 62868c2ecf20Sopenharmony_ci netif_err(tp, rx_err, netdev, 62878c2ecf20Sopenharmony_ci "Invalid rx copy break value\n"); 62888c2ecf20Sopenharmony_ci return -EINVAL; 62898c2ecf20Sopenharmony_ci } 62908c2ecf20Sopenharmony_ci 62918c2ecf20Sopenharmony_ci if (tp->rx_copybreak != val) { 62928c2ecf20Sopenharmony_ci if (netdev->flags & IFF_UP) { 62938c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 62948c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 62958c2ecf20Sopenharmony_ci tp->rx_copybreak = val; 62968c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 62978c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 62988c2ecf20Sopenharmony_ci } else { 62998c2ecf20Sopenharmony_ci tp->rx_copybreak = val; 63008c2ecf20Sopenharmony_ci } 63018c2ecf20Sopenharmony_ci } 63028c2ecf20Sopenharmony_ci break; 63038c2ecf20Sopenharmony_ci default: 63048c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 63058c2ecf20Sopenharmony_ci } 63068c2ecf20Sopenharmony_ci 63078c2ecf20Sopenharmony_ci return 0; 63088c2ecf20Sopenharmony_ci} 63098c2ecf20Sopenharmony_ci 63108c2ecf20Sopenharmony_cistatic void rtl8152_get_ringparam(struct net_device *netdev, 63118c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 63128c2ecf20Sopenharmony_ci{ 63138c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 63148c2ecf20Sopenharmony_ci 63158c2ecf20Sopenharmony_ci ring->rx_max_pending = RTL8152_RX_MAX_PENDING; 63168c2ecf20Sopenharmony_ci ring->rx_pending = tp->rx_pending; 63178c2ecf20Sopenharmony_ci} 63188c2ecf20Sopenharmony_ci 63198c2ecf20Sopenharmony_cistatic int rtl8152_set_ringparam(struct net_device *netdev, 63208c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 63218c2ecf20Sopenharmony_ci{ 63228c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 63238c2ecf20Sopenharmony_ci 63248c2ecf20Sopenharmony_ci if (ring->rx_pending < (RTL8152_MAX_RX * 2)) 63258c2ecf20Sopenharmony_ci return -EINVAL; 63268c2ecf20Sopenharmony_ci 63278c2ecf20Sopenharmony_ci if (tp->rx_pending != ring->rx_pending) { 63288c2ecf20Sopenharmony_ci if (netdev->flags & IFF_UP) { 63298c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 63308c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 63318c2ecf20Sopenharmony_ci tp->rx_pending = ring->rx_pending; 63328c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 63338c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 63348c2ecf20Sopenharmony_ci } else { 63358c2ecf20Sopenharmony_ci tp->rx_pending = ring->rx_pending; 63368c2ecf20Sopenharmony_ci } 63378c2ecf20Sopenharmony_ci } 63388c2ecf20Sopenharmony_ci 63398c2ecf20Sopenharmony_ci return 0; 63408c2ecf20Sopenharmony_ci} 63418c2ecf20Sopenharmony_ci 63428c2ecf20Sopenharmony_cistatic const struct ethtool_ops ops = { 63438c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 63448c2ecf20Sopenharmony_ci .get_drvinfo = rtl8152_get_drvinfo, 63458c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 63468c2ecf20Sopenharmony_ci .nway_reset = rtl8152_nway_reset, 63478c2ecf20Sopenharmony_ci .get_msglevel = rtl8152_get_msglevel, 63488c2ecf20Sopenharmony_ci .set_msglevel = rtl8152_set_msglevel, 63498c2ecf20Sopenharmony_ci .get_wol = rtl8152_get_wol, 63508c2ecf20Sopenharmony_ci .set_wol = rtl8152_set_wol, 63518c2ecf20Sopenharmony_ci .get_strings = rtl8152_get_strings, 63528c2ecf20Sopenharmony_ci .get_sset_count = rtl8152_get_sset_count, 63538c2ecf20Sopenharmony_ci .get_ethtool_stats = rtl8152_get_ethtool_stats, 63548c2ecf20Sopenharmony_ci .get_coalesce = rtl8152_get_coalesce, 63558c2ecf20Sopenharmony_ci .set_coalesce = rtl8152_set_coalesce, 63568c2ecf20Sopenharmony_ci .get_eee = rtl_ethtool_get_eee, 63578c2ecf20Sopenharmony_ci .set_eee = rtl_ethtool_set_eee, 63588c2ecf20Sopenharmony_ci .get_link_ksettings = rtl8152_get_link_ksettings, 63598c2ecf20Sopenharmony_ci .set_link_ksettings = rtl8152_set_link_ksettings, 63608c2ecf20Sopenharmony_ci .get_tunable = rtl8152_get_tunable, 63618c2ecf20Sopenharmony_ci .set_tunable = rtl8152_set_tunable, 63628c2ecf20Sopenharmony_ci .get_ringparam = rtl8152_get_ringparam, 63638c2ecf20Sopenharmony_ci .set_ringparam = rtl8152_set_ringparam, 63648c2ecf20Sopenharmony_ci}; 63658c2ecf20Sopenharmony_ci 63668c2ecf20Sopenharmony_cistatic int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 63678c2ecf20Sopenharmony_ci{ 63688c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(netdev); 63698c2ecf20Sopenharmony_ci struct mii_ioctl_data *data = if_mii(rq); 63708c2ecf20Sopenharmony_ci int res; 63718c2ecf20Sopenharmony_ci 63728c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 63738c2ecf20Sopenharmony_ci return -ENODEV; 63748c2ecf20Sopenharmony_ci 63758c2ecf20Sopenharmony_ci res = usb_autopm_get_interface(tp->intf); 63768c2ecf20Sopenharmony_ci if (res < 0) 63778c2ecf20Sopenharmony_ci goto out; 63788c2ecf20Sopenharmony_ci 63798c2ecf20Sopenharmony_ci switch (cmd) { 63808c2ecf20Sopenharmony_ci case SIOCGMIIPHY: 63818c2ecf20Sopenharmony_ci data->phy_id = R8152_PHY_ID; /* Internal PHY */ 63828c2ecf20Sopenharmony_ci break; 63838c2ecf20Sopenharmony_ci 63848c2ecf20Sopenharmony_ci case SIOCGMIIREG: 63858c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 63868c2ecf20Sopenharmony_ci data->val_out = r8152_mdio_read(tp, data->reg_num); 63878c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 63888c2ecf20Sopenharmony_ci break; 63898c2ecf20Sopenharmony_ci 63908c2ecf20Sopenharmony_ci case SIOCSMIIREG: 63918c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 63928c2ecf20Sopenharmony_ci res = -EPERM; 63938c2ecf20Sopenharmony_ci break; 63948c2ecf20Sopenharmony_ci } 63958c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 63968c2ecf20Sopenharmony_ci r8152_mdio_write(tp, data->reg_num, data->val_in); 63978c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 63988c2ecf20Sopenharmony_ci break; 63998c2ecf20Sopenharmony_ci 64008c2ecf20Sopenharmony_ci default: 64018c2ecf20Sopenharmony_ci res = -EOPNOTSUPP; 64028c2ecf20Sopenharmony_ci } 64038c2ecf20Sopenharmony_ci 64048c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 64058c2ecf20Sopenharmony_ci 64068c2ecf20Sopenharmony_ciout: 64078c2ecf20Sopenharmony_ci return res; 64088c2ecf20Sopenharmony_ci} 64098c2ecf20Sopenharmony_ci 64108c2ecf20Sopenharmony_cistatic int rtl8152_change_mtu(struct net_device *dev, int new_mtu) 64118c2ecf20Sopenharmony_ci{ 64128c2ecf20Sopenharmony_ci struct r8152 *tp = netdev_priv(dev); 64138c2ecf20Sopenharmony_ci int ret; 64148c2ecf20Sopenharmony_ci 64158c2ecf20Sopenharmony_ci switch (tp->version) { 64168c2ecf20Sopenharmony_ci case RTL_VER_01: 64178c2ecf20Sopenharmony_ci case RTL_VER_02: 64188c2ecf20Sopenharmony_ci case RTL_VER_07: 64198c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 64208c2ecf20Sopenharmony_ci return 0; 64218c2ecf20Sopenharmony_ci default: 64228c2ecf20Sopenharmony_ci break; 64238c2ecf20Sopenharmony_ci } 64248c2ecf20Sopenharmony_ci 64258c2ecf20Sopenharmony_ci ret = usb_autopm_get_interface(tp->intf); 64268c2ecf20Sopenharmony_ci if (ret < 0) 64278c2ecf20Sopenharmony_ci return ret; 64288c2ecf20Sopenharmony_ci 64298c2ecf20Sopenharmony_ci mutex_lock(&tp->control); 64308c2ecf20Sopenharmony_ci 64318c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 64328c2ecf20Sopenharmony_ci 64338c2ecf20Sopenharmony_ci if (netif_running(dev)) { 64348c2ecf20Sopenharmony_ci u32 rms = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; 64358c2ecf20Sopenharmony_ci 64368c2ecf20Sopenharmony_ci ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rms); 64378c2ecf20Sopenharmony_ci 64388c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) 64398c2ecf20Sopenharmony_ci r8153_set_rx_early_size(tp); 64408c2ecf20Sopenharmony_ci } 64418c2ecf20Sopenharmony_ci 64428c2ecf20Sopenharmony_ci mutex_unlock(&tp->control); 64438c2ecf20Sopenharmony_ci 64448c2ecf20Sopenharmony_ci usb_autopm_put_interface(tp->intf); 64458c2ecf20Sopenharmony_ci 64468c2ecf20Sopenharmony_ci return ret; 64478c2ecf20Sopenharmony_ci} 64488c2ecf20Sopenharmony_ci 64498c2ecf20Sopenharmony_cistatic const struct net_device_ops rtl8152_netdev_ops = { 64508c2ecf20Sopenharmony_ci .ndo_open = rtl8152_open, 64518c2ecf20Sopenharmony_ci .ndo_stop = rtl8152_close, 64528c2ecf20Sopenharmony_ci .ndo_do_ioctl = rtl8152_ioctl, 64538c2ecf20Sopenharmony_ci .ndo_start_xmit = rtl8152_start_xmit, 64548c2ecf20Sopenharmony_ci .ndo_tx_timeout = rtl8152_tx_timeout, 64558c2ecf20Sopenharmony_ci .ndo_set_features = rtl8152_set_features, 64568c2ecf20Sopenharmony_ci .ndo_set_rx_mode = rtl8152_set_rx_mode, 64578c2ecf20Sopenharmony_ci .ndo_set_mac_address = rtl8152_set_mac_address, 64588c2ecf20Sopenharmony_ci .ndo_change_mtu = rtl8152_change_mtu, 64598c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 64608c2ecf20Sopenharmony_ci .ndo_features_check = rtl8152_features_check, 64618c2ecf20Sopenharmony_ci}; 64628c2ecf20Sopenharmony_ci 64638c2ecf20Sopenharmony_cistatic void rtl8152_unload(struct r8152 *tp) 64648c2ecf20Sopenharmony_ci{ 64658c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 64668c2ecf20Sopenharmony_ci return; 64678c2ecf20Sopenharmony_ci 64688c2ecf20Sopenharmony_ci if (tp->version != RTL_VER_01) 64698c2ecf20Sopenharmony_ci r8152_power_cut_en(tp, true); 64708c2ecf20Sopenharmony_ci} 64718c2ecf20Sopenharmony_ci 64728c2ecf20Sopenharmony_cistatic void rtl8153_unload(struct r8152 *tp) 64738c2ecf20Sopenharmony_ci{ 64748c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 64758c2ecf20Sopenharmony_ci return; 64768c2ecf20Sopenharmony_ci 64778c2ecf20Sopenharmony_ci r8153_power_cut_en(tp, false); 64788c2ecf20Sopenharmony_ci} 64798c2ecf20Sopenharmony_ci 64808c2ecf20Sopenharmony_cistatic void rtl8153b_unload(struct r8152 *tp) 64818c2ecf20Sopenharmony_ci{ 64828c2ecf20Sopenharmony_ci if (test_bit(RTL8152_UNPLUG, &tp->flags)) 64838c2ecf20Sopenharmony_ci return; 64848c2ecf20Sopenharmony_ci 64858c2ecf20Sopenharmony_ci r8153b_power_cut_en(tp, false); 64868c2ecf20Sopenharmony_ci} 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_cistatic int rtl_ops_init(struct r8152 *tp) 64898c2ecf20Sopenharmony_ci{ 64908c2ecf20Sopenharmony_ci struct rtl_ops *ops = &tp->rtl_ops; 64918c2ecf20Sopenharmony_ci int ret = 0; 64928c2ecf20Sopenharmony_ci 64938c2ecf20Sopenharmony_ci switch (tp->version) { 64948c2ecf20Sopenharmony_ci case RTL_VER_01: 64958c2ecf20Sopenharmony_ci case RTL_VER_02: 64968c2ecf20Sopenharmony_ci case RTL_VER_07: 64978c2ecf20Sopenharmony_ci ops->init = r8152b_init; 64988c2ecf20Sopenharmony_ci ops->enable = rtl8152_enable; 64998c2ecf20Sopenharmony_ci ops->disable = rtl8152_disable; 65008c2ecf20Sopenharmony_ci ops->up = rtl8152_up; 65018c2ecf20Sopenharmony_ci ops->down = rtl8152_down; 65028c2ecf20Sopenharmony_ci ops->unload = rtl8152_unload; 65038c2ecf20Sopenharmony_ci ops->eee_get = r8152_get_eee; 65048c2ecf20Sopenharmony_ci ops->eee_set = r8152_set_eee; 65058c2ecf20Sopenharmony_ci ops->in_nway = rtl8152_in_nway; 65068c2ecf20Sopenharmony_ci ops->hw_phy_cfg = r8152b_hw_phy_cfg; 65078c2ecf20Sopenharmony_ci ops->autosuspend_en = rtl_runtime_suspend_enable; 65088c2ecf20Sopenharmony_ci tp->rx_buf_sz = 16 * 1024; 65098c2ecf20Sopenharmony_ci tp->eee_en = true; 65108c2ecf20Sopenharmony_ci tp->eee_adv = MDIO_EEE_100TX; 65118c2ecf20Sopenharmony_ci break; 65128c2ecf20Sopenharmony_ci 65138c2ecf20Sopenharmony_ci case RTL_VER_03: 65148c2ecf20Sopenharmony_ci case RTL_VER_04: 65158c2ecf20Sopenharmony_ci case RTL_VER_05: 65168c2ecf20Sopenharmony_ci case RTL_VER_06: 65178c2ecf20Sopenharmony_ci ops->init = r8153_init; 65188c2ecf20Sopenharmony_ci ops->enable = rtl8153_enable; 65198c2ecf20Sopenharmony_ci ops->disable = rtl8153_disable; 65208c2ecf20Sopenharmony_ci ops->up = rtl8153_up; 65218c2ecf20Sopenharmony_ci ops->down = rtl8153_down; 65228c2ecf20Sopenharmony_ci ops->unload = rtl8153_unload; 65238c2ecf20Sopenharmony_ci ops->eee_get = r8153_get_eee; 65248c2ecf20Sopenharmony_ci ops->eee_set = r8152_set_eee; 65258c2ecf20Sopenharmony_ci ops->in_nway = rtl8153_in_nway; 65268c2ecf20Sopenharmony_ci ops->hw_phy_cfg = r8153_hw_phy_cfg; 65278c2ecf20Sopenharmony_ci ops->autosuspend_en = rtl8153_runtime_enable; 65288c2ecf20Sopenharmony_ci if (tp->udev->speed < USB_SPEED_SUPER) 65298c2ecf20Sopenharmony_ci tp->rx_buf_sz = 16 * 1024; 65308c2ecf20Sopenharmony_ci else 65318c2ecf20Sopenharmony_ci tp->rx_buf_sz = 32 * 1024; 65328c2ecf20Sopenharmony_ci tp->eee_en = true; 65338c2ecf20Sopenharmony_ci tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX; 65348c2ecf20Sopenharmony_ci break; 65358c2ecf20Sopenharmony_ci 65368c2ecf20Sopenharmony_ci case RTL_VER_08: 65378c2ecf20Sopenharmony_ci case RTL_VER_09: 65388c2ecf20Sopenharmony_ci ops->init = r8153b_init; 65398c2ecf20Sopenharmony_ci ops->enable = rtl8153_enable; 65408c2ecf20Sopenharmony_ci ops->disable = rtl8153_disable; 65418c2ecf20Sopenharmony_ci ops->up = rtl8153b_up; 65428c2ecf20Sopenharmony_ci ops->down = rtl8153b_down; 65438c2ecf20Sopenharmony_ci ops->unload = rtl8153b_unload; 65448c2ecf20Sopenharmony_ci ops->eee_get = r8153_get_eee; 65458c2ecf20Sopenharmony_ci ops->eee_set = r8152_set_eee; 65468c2ecf20Sopenharmony_ci ops->in_nway = rtl8153_in_nway; 65478c2ecf20Sopenharmony_ci ops->hw_phy_cfg = r8153b_hw_phy_cfg; 65488c2ecf20Sopenharmony_ci ops->autosuspend_en = rtl8153b_runtime_enable; 65498c2ecf20Sopenharmony_ci tp->rx_buf_sz = 32 * 1024; 65508c2ecf20Sopenharmony_ci tp->eee_en = true; 65518c2ecf20Sopenharmony_ci tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX; 65528c2ecf20Sopenharmony_ci break; 65538c2ecf20Sopenharmony_ci 65548c2ecf20Sopenharmony_ci default: 65558c2ecf20Sopenharmony_ci ret = -ENODEV; 65568c2ecf20Sopenharmony_ci netif_err(tp, probe, tp->netdev, "Unknown Device\n"); 65578c2ecf20Sopenharmony_ci break; 65588c2ecf20Sopenharmony_ci } 65598c2ecf20Sopenharmony_ci 65608c2ecf20Sopenharmony_ci return ret; 65618c2ecf20Sopenharmony_ci} 65628c2ecf20Sopenharmony_ci 65638c2ecf20Sopenharmony_ci#define FIRMWARE_8153A_2 "rtl_nic/rtl8153a-2.fw" 65648c2ecf20Sopenharmony_ci#define FIRMWARE_8153A_3 "rtl_nic/rtl8153a-3.fw" 65658c2ecf20Sopenharmony_ci#define FIRMWARE_8153A_4 "rtl_nic/rtl8153a-4.fw" 65668c2ecf20Sopenharmony_ci#define FIRMWARE_8153B_2 "rtl_nic/rtl8153b-2.fw" 65678c2ecf20Sopenharmony_ci 65688c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_2); 65698c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_3); 65708c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153A_4); 65718c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8153B_2); 65728c2ecf20Sopenharmony_ci 65738c2ecf20Sopenharmony_cistatic int rtl_fw_init(struct r8152 *tp) 65748c2ecf20Sopenharmony_ci{ 65758c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw = &tp->rtl_fw; 65768c2ecf20Sopenharmony_ci 65778c2ecf20Sopenharmony_ci switch (tp->version) { 65788c2ecf20Sopenharmony_ci case RTL_VER_04: 65798c2ecf20Sopenharmony_ci rtl_fw->fw_name = FIRMWARE_8153A_2; 65808c2ecf20Sopenharmony_ci rtl_fw->pre_fw = r8153_pre_firmware_1; 65818c2ecf20Sopenharmony_ci rtl_fw->post_fw = r8153_post_firmware_1; 65828c2ecf20Sopenharmony_ci break; 65838c2ecf20Sopenharmony_ci case RTL_VER_05: 65848c2ecf20Sopenharmony_ci rtl_fw->fw_name = FIRMWARE_8153A_3; 65858c2ecf20Sopenharmony_ci rtl_fw->pre_fw = r8153_pre_firmware_2; 65868c2ecf20Sopenharmony_ci rtl_fw->post_fw = r8153_post_firmware_2; 65878c2ecf20Sopenharmony_ci break; 65888c2ecf20Sopenharmony_ci case RTL_VER_06: 65898c2ecf20Sopenharmony_ci rtl_fw->fw_name = FIRMWARE_8153A_4; 65908c2ecf20Sopenharmony_ci rtl_fw->post_fw = r8153_post_firmware_3; 65918c2ecf20Sopenharmony_ci break; 65928c2ecf20Sopenharmony_ci case RTL_VER_09: 65938c2ecf20Sopenharmony_ci rtl_fw->fw_name = FIRMWARE_8153B_2; 65948c2ecf20Sopenharmony_ci rtl_fw->pre_fw = r8153b_pre_firmware_1; 65958c2ecf20Sopenharmony_ci rtl_fw->post_fw = r8153b_post_firmware_1; 65968c2ecf20Sopenharmony_ci break; 65978c2ecf20Sopenharmony_ci default: 65988c2ecf20Sopenharmony_ci break; 65998c2ecf20Sopenharmony_ci } 66008c2ecf20Sopenharmony_ci 66018c2ecf20Sopenharmony_ci return 0; 66028c2ecf20Sopenharmony_ci} 66038c2ecf20Sopenharmony_ci 66048c2ecf20Sopenharmony_cistatic u8 rtl_get_version(struct usb_interface *intf) 66058c2ecf20Sopenharmony_ci{ 66068c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 66078c2ecf20Sopenharmony_ci u32 ocp_data = 0; 66088c2ecf20Sopenharmony_ci __le32 *tmp; 66098c2ecf20Sopenharmony_ci u8 version; 66108c2ecf20Sopenharmony_ci int ret; 66118c2ecf20Sopenharmony_ci 66128c2ecf20Sopenharmony_ci tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 66138c2ecf20Sopenharmony_ci if (!tmp) 66148c2ecf20Sopenharmony_ci return 0; 66158c2ecf20Sopenharmony_ci 66168c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 66178c2ecf20Sopenharmony_ci RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, 66188c2ecf20Sopenharmony_ci PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), 66198c2ecf20Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 66208c2ecf20Sopenharmony_ci if (ret > 0) 66218c2ecf20Sopenharmony_ci ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK; 66228c2ecf20Sopenharmony_ci 66238c2ecf20Sopenharmony_ci kfree(tmp); 66248c2ecf20Sopenharmony_ci 66258c2ecf20Sopenharmony_ci switch (ocp_data) { 66268c2ecf20Sopenharmony_ci case 0x4c00: 66278c2ecf20Sopenharmony_ci version = RTL_VER_01; 66288c2ecf20Sopenharmony_ci break; 66298c2ecf20Sopenharmony_ci case 0x4c10: 66308c2ecf20Sopenharmony_ci version = RTL_VER_02; 66318c2ecf20Sopenharmony_ci break; 66328c2ecf20Sopenharmony_ci case 0x5c00: 66338c2ecf20Sopenharmony_ci version = RTL_VER_03; 66348c2ecf20Sopenharmony_ci break; 66358c2ecf20Sopenharmony_ci case 0x5c10: 66368c2ecf20Sopenharmony_ci version = RTL_VER_04; 66378c2ecf20Sopenharmony_ci break; 66388c2ecf20Sopenharmony_ci case 0x5c20: 66398c2ecf20Sopenharmony_ci version = RTL_VER_05; 66408c2ecf20Sopenharmony_ci break; 66418c2ecf20Sopenharmony_ci case 0x5c30: 66428c2ecf20Sopenharmony_ci version = RTL_VER_06; 66438c2ecf20Sopenharmony_ci break; 66448c2ecf20Sopenharmony_ci case 0x4800: 66458c2ecf20Sopenharmony_ci version = RTL_VER_07; 66468c2ecf20Sopenharmony_ci break; 66478c2ecf20Sopenharmony_ci case 0x6000: 66488c2ecf20Sopenharmony_ci version = RTL_VER_08; 66498c2ecf20Sopenharmony_ci break; 66508c2ecf20Sopenharmony_ci case 0x6010: 66518c2ecf20Sopenharmony_ci version = RTL_VER_09; 66528c2ecf20Sopenharmony_ci break; 66538c2ecf20Sopenharmony_ci default: 66548c2ecf20Sopenharmony_ci version = RTL_VER_UNKNOWN; 66558c2ecf20Sopenharmony_ci dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data); 66568c2ecf20Sopenharmony_ci break; 66578c2ecf20Sopenharmony_ci } 66588c2ecf20Sopenharmony_ci 66598c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "Detected version 0x%04x\n", version); 66608c2ecf20Sopenharmony_ci 66618c2ecf20Sopenharmony_ci return version; 66628c2ecf20Sopenharmony_ci} 66638c2ecf20Sopenharmony_ci 66648c2ecf20Sopenharmony_cistatic int rtl8152_probe(struct usb_interface *intf, 66658c2ecf20Sopenharmony_ci const struct usb_device_id *id) 66668c2ecf20Sopenharmony_ci{ 66678c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 66688c2ecf20Sopenharmony_ci u8 version = rtl_get_version(intf); 66698c2ecf20Sopenharmony_ci struct r8152 *tp; 66708c2ecf20Sopenharmony_ci struct net_device *netdev; 66718c2ecf20Sopenharmony_ci int ret; 66728c2ecf20Sopenharmony_ci 66738c2ecf20Sopenharmony_ci if (version == RTL_VER_UNKNOWN) 66748c2ecf20Sopenharmony_ci return -ENODEV; 66758c2ecf20Sopenharmony_ci 66768c2ecf20Sopenharmony_ci if (udev->actconfig->desc.bConfigurationValue != 1) { 66778c2ecf20Sopenharmony_ci usb_driver_set_configuration(udev, 1); 66788c2ecf20Sopenharmony_ci return -ENODEV; 66798c2ecf20Sopenharmony_ci } 66808c2ecf20Sopenharmony_ci 66818c2ecf20Sopenharmony_ci if (intf->cur_altsetting->desc.bNumEndpoints < 3) 66828c2ecf20Sopenharmony_ci return -ENODEV; 66838c2ecf20Sopenharmony_ci 66848c2ecf20Sopenharmony_ci usb_reset_device(udev); 66858c2ecf20Sopenharmony_ci netdev = alloc_etherdev(sizeof(struct r8152)); 66868c2ecf20Sopenharmony_ci if (!netdev) { 66878c2ecf20Sopenharmony_ci dev_err(&intf->dev, "Out of memory\n"); 66888c2ecf20Sopenharmony_ci return -ENOMEM; 66898c2ecf20Sopenharmony_ci } 66908c2ecf20Sopenharmony_ci 66918c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &intf->dev); 66928c2ecf20Sopenharmony_ci tp = netdev_priv(netdev); 66938c2ecf20Sopenharmony_ci tp->msg_enable = 0x7FFF; 66948c2ecf20Sopenharmony_ci 66958c2ecf20Sopenharmony_ci tp->udev = udev; 66968c2ecf20Sopenharmony_ci tp->netdev = netdev; 66978c2ecf20Sopenharmony_ci tp->intf = intf; 66988c2ecf20Sopenharmony_ci tp->version = version; 66998c2ecf20Sopenharmony_ci 67008c2ecf20Sopenharmony_ci switch (version) { 67018c2ecf20Sopenharmony_ci case RTL_VER_01: 67028c2ecf20Sopenharmony_ci case RTL_VER_02: 67038c2ecf20Sopenharmony_ci case RTL_VER_07: 67048c2ecf20Sopenharmony_ci tp->mii.supports_gmii = 0; 67058c2ecf20Sopenharmony_ci break; 67068c2ecf20Sopenharmony_ci default: 67078c2ecf20Sopenharmony_ci tp->mii.supports_gmii = 1; 67088c2ecf20Sopenharmony_ci break; 67098c2ecf20Sopenharmony_ci } 67108c2ecf20Sopenharmony_ci 67118c2ecf20Sopenharmony_ci ret = rtl_ops_init(tp); 67128c2ecf20Sopenharmony_ci if (ret) 67138c2ecf20Sopenharmony_ci goto out; 67148c2ecf20Sopenharmony_ci 67158c2ecf20Sopenharmony_ci rtl_fw_init(tp); 67168c2ecf20Sopenharmony_ci 67178c2ecf20Sopenharmony_ci mutex_init(&tp->control); 67188c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); 67198c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t); 67208c2ecf20Sopenharmony_ci tasklet_init(&tp->tx_tl, bottom_half, (unsigned long)tp); 67218c2ecf20Sopenharmony_ci tasklet_disable(&tp->tx_tl); 67228c2ecf20Sopenharmony_ci 67238c2ecf20Sopenharmony_ci netdev->netdev_ops = &rtl8152_netdev_ops; 67248c2ecf20Sopenharmony_ci netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; 67258c2ecf20Sopenharmony_ci 67268c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | 67278c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | 67288c2ecf20Sopenharmony_ci NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX | 67298c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX; 67308c2ecf20Sopenharmony_ci netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | 67318c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_FRAGLIST | 67328c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | 67338c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; 67348c2ecf20Sopenharmony_ci netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | 67358c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | 67368c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM | NETIF_F_TSO6; 67378c2ecf20Sopenharmony_ci 67388c2ecf20Sopenharmony_ci if (tp->version == RTL_VER_01) { 67398c2ecf20Sopenharmony_ci netdev->features &= ~NETIF_F_RXCSUM; 67408c2ecf20Sopenharmony_ci netdev->hw_features &= ~NETIF_F_RXCSUM; 67418c2ecf20Sopenharmony_ci } 67428c2ecf20Sopenharmony_ci 67438c2ecf20Sopenharmony_ci if (le16_to_cpu(udev->descriptor.idVendor) == VENDOR_ID_LENOVO) { 67448c2ecf20Sopenharmony_ci switch (le16_to_cpu(udev->descriptor.idProduct)) { 67458c2ecf20Sopenharmony_ci case DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2: 67468c2ecf20Sopenharmony_ci case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2: 67478c2ecf20Sopenharmony_ci set_bit(LENOVO_MACPASSTHRU, &tp->flags); 67488c2ecf20Sopenharmony_ci } 67498c2ecf20Sopenharmony_ci } 67508c2ecf20Sopenharmony_ci 67518c2ecf20Sopenharmony_ci if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial && 67528c2ecf20Sopenharmony_ci (!strcmp(udev->serial, "000001000000") || 67538c2ecf20Sopenharmony_ci !strcmp(udev->serial, "000002000000"))) { 67548c2ecf20Sopenharmony_ci dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation"); 67558c2ecf20Sopenharmony_ci set_bit(DELL_TB_RX_AGG_BUG, &tp->flags); 67568c2ecf20Sopenharmony_ci } 67578c2ecf20Sopenharmony_ci 67588c2ecf20Sopenharmony_ci netdev->ethtool_ops = &ops; 67598c2ecf20Sopenharmony_ci netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); 67608c2ecf20Sopenharmony_ci 67618c2ecf20Sopenharmony_ci /* MTU range: 68 - 1500 or 9194 */ 67628c2ecf20Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 67638c2ecf20Sopenharmony_ci switch (tp->version) { 67648c2ecf20Sopenharmony_ci case RTL_VER_01: 67658c2ecf20Sopenharmony_ci case RTL_VER_02: 67668c2ecf20Sopenharmony_ci netdev->max_mtu = ETH_DATA_LEN; 67678c2ecf20Sopenharmony_ci break; 67688c2ecf20Sopenharmony_ci default: 67698c2ecf20Sopenharmony_ci netdev->max_mtu = RTL8153_MAX_MTU; 67708c2ecf20Sopenharmony_ci break; 67718c2ecf20Sopenharmony_ci } 67728c2ecf20Sopenharmony_ci 67738c2ecf20Sopenharmony_ci tp->mii.dev = netdev; 67748c2ecf20Sopenharmony_ci tp->mii.mdio_read = read_mii_word; 67758c2ecf20Sopenharmony_ci tp->mii.mdio_write = write_mii_word; 67768c2ecf20Sopenharmony_ci tp->mii.phy_id_mask = 0x3f; 67778c2ecf20Sopenharmony_ci tp->mii.reg_num_mask = 0x1f; 67788c2ecf20Sopenharmony_ci tp->mii.phy_id = R8152_PHY_ID; 67798c2ecf20Sopenharmony_ci 67808c2ecf20Sopenharmony_ci tp->autoneg = AUTONEG_ENABLE; 67818c2ecf20Sopenharmony_ci tp->speed = SPEED_100; 67828c2ecf20Sopenharmony_ci tp->advertising = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL | 67838c2ecf20Sopenharmony_ci RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL; 67848c2ecf20Sopenharmony_ci if (tp->mii.supports_gmii) { 67858c2ecf20Sopenharmony_ci tp->speed = SPEED_1000; 67868c2ecf20Sopenharmony_ci tp->advertising |= RTL_ADVERTISED_1000_FULL; 67878c2ecf20Sopenharmony_ci } 67888c2ecf20Sopenharmony_ci tp->duplex = DUPLEX_FULL; 67898c2ecf20Sopenharmony_ci 67908c2ecf20Sopenharmony_ci tp->rx_copybreak = RTL8152_RXFG_HEADSZ; 67918c2ecf20Sopenharmony_ci tp->rx_pending = 10 * RTL8152_MAX_RX; 67928c2ecf20Sopenharmony_ci 67938c2ecf20Sopenharmony_ci intf->needs_remote_wakeup = 1; 67948c2ecf20Sopenharmony_ci 67958c2ecf20Sopenharmony_ci if (!rtl_can_wakeup(tp)) 67968c2ecf20Sopenharmony_ci __rtl_set_wol(tp, 0); 67978c2ecf20Sopenharmony_ci else 67988c2ecf20Sopenharmony_ci tp->saved_wolopts = __rtl_get_wol(tp); 67998c2ecf20Sopenharmony_ci 68008c2ecf20Sopenharmony_ci tp->rtl_ops.init(tp); 68018c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_USB_RTL8152) 68028c2ecf20Sopenharmony_ci /* Retry in case request_firmware() is not ready yet. */ 68038c2ecf20Sopenharmony_ci tp->rtl_fw.retry = true; 68048c2ecf20Sopenharmony_ci#endif 68058c2ecf20Sopenharmony_ci queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); 68068c2ecf20Sopenharmony_ci set_ethernet_addr(tp); 68078c2ecf20Sopenharmony_ci 68088c2ecf20Sopenharmony_ci usb_set_intfdata(intf, tp); 68098c2ecf20Sopenharmony_ci netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT); 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci ret = register_netdev(netdev); 68128c2ecf20Sopenharmony_ci if (ret != 0) { 68138c2ecf20Sopenharmony_ci netif_err(tp, probe, netdev, "couldn't register the device\n"); 68148c2ecf20Sopenharmony_ci goto out1; 68158c2ecf20Sopenharmony_ci } 68168c2ecf20Sopenharmony_ci 68178c2ecf20Sopenharmony_ci if (tp->saved_wolopts) 68188c2ecf20Sopenharmony_ci device_set_wakeup_enable(&udev->dev, true); 68198c2ecf20Sopenharmony_ci else 68208c2ecf20Sopenharmony_ci device_set_wakeup_enable(&udev->dev, false); 68218c2ecf20Sopenharmony_ci 68228c2ecf20Sopenharmony_ci netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); 68238c2ecf20Sopenharmony_ci 68248c2ecf20Sopenharmony_ci return 0; 68258c2ecf20Sopenharmony_ci 68268c2ecf20Sopenharmony_ciout1: 68278c2ecf20Sopenharmony_ci tasklet_kill(&tp->tx_tl); 68288c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->hw_phy_work); 68298c2ecf20Sopenharmony_ci if (tp->rtl_ops.unload) 68308c2ecf20Sopenharmony_ci tp->rtl_ops.unload(tp); 68318c2ecf20Sopenharmony_ci rtl8152_release_firmware(tp); 68328c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 68338c2ecf20Sopenharmony_ciout: 68348c2ecf20Sopenharmony_ci free_netdev(netdev); 68358c2ecf20Sopenharmony_ci return ret; 68368c2ecf20Sopenharmony_ci} 68378c2ecf20Sopenharmony_ci 68388c2ecf20Sopenharmony_cistatic void rtl8152_disconnect(struct usb_interface *intf) 68398c2ecf20Sopenharmony_ci{ 68408c2ecf20Sopenharmony_ci struct r8152 *tp = usb_get_intfdata(intf); 68418c2ecf20Sopenharmony_ci 68428c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 68438c2ecf20Sopenharmony_ci if (tp) { 68448c2ecf20Sopenharmony_ci rtl_set_unplug(tp); 68458c2ecf20Sopenharmony_ci 68468c2ecf20Sopenharmony_ci unregister_netdev(tp->netdev); 68478c2ecf20Sopenharmony_ci tasklet_kill(&tp->tx_tl); 68488c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tp->hw_phy_work); 68498c2ecf20Sopenharmony_ci tp->rtl_ops.unload(tp); 68508c2ecf20Sopenharmony_ci rtl8152_release_firmware(tp); 68518c2ecf20Sopenharmony_ci free_netdev(tp->netdev); 68528c2ecf20Sopenharmony_ci } 68538c2ecf20Sopenharmony_ci} 68548c2ecf20Sopenharmony_ci 68558c2ecf20Sopenharmony_ci#define REALTEK_USB_DEVICE(vend, prod) \ 68568c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 68578c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_INT_CLASS, \ 68588c2ecf20Sopenharmony_ci .idVendor = (vend), \ 68598c2ecf20Sopenharmony_ci .idProduct = (prod), \ 68608c2ecf20Sopenharmony_ci .bInterfaceClass = USB_CLASS_VENDOR_SPEC \ 68618c2ecf20Sopenharmony_ci}, \ 68628c2ecf20Sopenharmony_ci{ \ 68638c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | \ 68648c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_DEVICE, \ 68658c2ecf20Sopenharmony_ci .idVendor = (vend), \ 68668c2ecf20Sopenharmony_ci .idProduct = (prod), \ 68678c2ecf20Sopenharmony_ci .bInterfaceClass = USB_CLASS_COMM, \ 68688c2ecf20Sopenharmony_ci .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ 68698c2ecf20Sopenharmony_ci .bInterfaceProtocol = USB_CDC_PROTO_NONE 68708c2ecf20Sopenharmony_ci 68718c2ecf20Sopenharmony_ci/* table of devices that work with this driver */ 68728c2ecf20Sopenharmony_cistatic const struct usb_device_id rtl8152_table[] = { 68738c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050)}, 68748c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, 68758c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, 68768c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, 68778c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)}, 68788c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927)}, 68798c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, 68808c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, 68818c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3054)}, 68828c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, 68838c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3069)}, 68848c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3082)}, 68858c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, 68868c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c)}, 68878c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)}, 68888c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x721e)}, 68898c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0xa387)}, 68908c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)}, 68918c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)}, 68928c2ecf20Sopenharmony_ci {REALTEK_USB_DEVICE(VENDOR_ID_TPLINK, 0x0601)}, 68938c2ecf20Sopenharmony_ci {} 68948c2ecf20Sopenharmony_ci}; 68958c2ecf20Sopenharmony_ci 68968c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, rtl8152_table); 68978c2ecf20Sopenharmony_ci 68988c2ecf20Sopenharmony_cistatic struct usb_driver rtl8152_driver = { 68998c2ecf20Sopenharmony_ci .name = MODULENAME, 69008c2ecf20Sopenharmony_ci .id_table = rtl8152_table, 69018c2ecf20Sopenharmony_ci .probe = rtl8152_probe, 69028c2ecf20Sopenharmony_ci .disconnect = rtl8152_disconnect, 69038c2ecf20Sopenharmony_ci .suspend = rtl8152_suspend, 69048c2ecf20Sopenharmony_ci .resume = rtl8152_resume, 69058c2ecf20Sopenharmony_ci .reset_resume = rtl8152_reset_resume, 69068c2ecf20Sopenharmony_ci .pre_reset = rtl8152_pre_reset, 69078c2ecf20Sopenharmony_ci .post_reset = rtl8152_post_reset, 69088c2ecf20Sopenharmony_ci .supports_autosuspend = 1, 69098c2ecf20Sopenharmony_ci .disable_hub_initiated_lpm = 1, 69108c2ecf20Sopenharmony_ci}; 69118c2ecf20Sopenharmony_ci 69128c2ecf20Sopenharmony_cimodule_usb_driver(rtl8152_driver); 69138c2ecf20Sopenharmony_ci 69148c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 69158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 69168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 69178c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 6918