2013-05-02 20:01:25 +04:00
/*
2014-01-15 06:42:16 +04:00
* Copyright ( c ) 2014 Realtek Semiconductor Corp . All rights reserved .
2013-05-02 20:01:25 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
*/
# include <linux/signal.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/mii.h>
# include <linux/ethtool.h>
# include <linux/usb.h>
# include <linux/crc32.h>
# include <linux/if_vlan.h>
# include <linux/uaccess.h>
2013-08-14 16:54:38 +04:00
# include <linux/list.h>
2013-08-14 16:54:39 +04:00
# include <linux/ip.h>
# include <linux/ipv6.h>
2014-03-07 07:04:40 +04:00
# include <net/ip6_checksum.h>
2014-09-25 16:54:00 +04:00
# include <uapi/linux/mdio.h>
# include <linux/mdio.h>
2013-05-02 20:01:25 +04:00
/* Version Information */
2014-10-01 09:25:10 +04:00
# define DRIVER_VERSION "v1.06.1 (2014 / 10 / 01)"
2013-05-02 20:01:25 +04:00
# define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
2014-01-15 06:42:14 +04:00
# define DRIVER_DESC "Realtek RTL8152 / RTL8153 Based USB Ethernet Adapters"
2013-05-02 20:01:25 +04:00
# define MODULENAME "r8152"
# define R8152_PHY_ID 32
# define PLA_IDR 0xc000
# define PLA_RCR 0xc010
# define PLA_RMS 0xc016
# define PLA_RXFIFO_CTRL0 0xc0a0
# define PLA_RXFIFO_CTRL1 0xc0a4
# define PLA_RXFIFO_CTRL2 0xc0a8
# define PLA_FMC 0xc0b4
# define PLA_CFG_WOL 0xc0b6
2014-01-02 07:25:10 +04:00
# define PLA_TEREDO_CFG 0xc0bc
2013-05-02 20:01:25 +04:00
# define PLA_MAR 0xcd00
2014-01-02 07:25:10 +04:00
# define PLA_BACKUP 0xd000
2013-05-02 20:01:25 +04:00
# define PAL_BDC_CR 0xd1a0
2014-01-02 07:25:10 +04:00
# define PLA_TEREDO_TIMER 0xd2cc
# define PLA_REALWOW_TIMER 0xd2e8
2013-05-02 20:01:25 +04:00
# define PLA_LEDSEL 0xdd90
# define PLA_LED_FEATURE 0xdd92
# define PLA_PHYAR 0xde00
2014-01-02 07:25:10 +04:00
# define PLA_BOOT_CTRL 0xe004
2013-05-02 20:01:25 +04:00
# define PLA_GPHY_INTR_IMR 0xe022
# define PLA_EEE_CR 0xe040
# define PLA_EEEP_CR 0xe080
# define PLA_MAC_PWR_CTRL 0xe0c0
2014-01-02 07:25:10 +04:00
# define PLA_MAC_PWR_CTRL2 0xe0ca
# define PLA_MAC_PWR_CTRL3 0xe0cc
# define PLA_MAC_PWR_CTRL4 0xe0ce
# define PLA_WDT6_CTRL 0xe428
2013-05-02 20:01:25 +04:00
# define PLA_TCR0 0xe610
# define PLA_TCR1 0xe612
2014-07-10 06:58:54 +04:00
# define PLA_MTPS 0xe615
2013-05-02 20:01:25 +04:00
# define PLA_TXFIFO_CTRL 0xe618
2014-03-11 12:24:19 +04:00
# define PLA_RSTTALLY 0xe800
2013-05-02 20:01:25 +04:00
# define PLA_CR 0xe813
# define PLA_CRWECR 0xe81c
2014-02-18 17:49:06 +04:00
# define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */
# define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */
2013-05-02 20:01:25 +04:00
# define PLA_CONFIG5 0xe822
# define PLA_PHY_PWR 0xe84c
# define PLA_OOB_CTRL 0xe84f
# define PLA_CPCR 0xe854
# define PLA_MISC_0 0xe858
# define PLA_MISC_1 0xe85a
# define PLA_OCP_GPHY_BASE 0xe86c
2014-03-11 12:24:19 +04:00
# define PLA_TALLYCNT 0xe890
2013-05-02 20:01:25 +04:00
# define PLA_SFF_STS_7 0xe8de
# define PLA_PHYSTATUS 0xe908
# define PLA_BP_BA 0xfc26
# define PLA_BP_0 0xfc28
# define PLA_BP_1 0xfc2a
# define PLA_BP_2 0xfc2c
# define PLA_BP_3 0xfc2e
# define PLA_BP_4 0xfc30
# define PLA_BP_5 0xfc32
# define PLA_BP_6 0xfc34
# define PLA_BP_7 0xfc36
2014-01-02 07:25:10 +04:00
# define PLA_BP_EN 0xfc38
2013-05-02 20:01:25 +04:00
2014-01-02 07:25:10 +04:00
# define USB_U2P3_CTRL 0xb460
2013-05-02 20:01:25 +04:00
# define USB_DEV_STAT 0xb808
# define USB_USB_CTRL 0xd406
# define USB_PHY_CTRL 0xd408
# define USB_TX_AGG 0xd40a
# define USB_RX_BUF_TH 0xd40c
# define USB_USB_TIMER 0xd428
2014-01-02 07:25:10 +04:00
# define USB_RX_EARLY_AGG 0xd42c
2013-05-02 20:01:25 +04:00
# define USB_PM_CTRL_STATUS 0xd432
# define USB_TX_DMA 0xd434
2014-01-02 07:25:10 +04:00
# define USB_TOLERANCE 0xd490
# define USB_LPM_CTRL 0xd41a
2013-05-02 20:01:25 +04:00
# define USB_UPS_CTRL 0xd800
2014-01-02 07:25:10 +04:00
# define USB_MISC_0 0xd81a
# define USB_POWER_CUT 0xd80a
# define USB_AFE_CTRL2 0xd824
# define USB_WDT11_CTRL 0xe43c
2013-05-02 20:01:25 +04:00
# define USB_BP_BA 0xfc26
# define USB_BP_0 0xfc28
# define USB_BP_1 0xfc2a
# define USB_BP_2 0xfc2c
# define USB_BP_3 0xfc2e
# define USB_BP_4 0xfc30
# define USB_BP_5 0xfc32
# define USB_BP_6 0xfc34
# define USB_BP_7 0xfc36
2014-01-02 07:25:10 +04:00
# define USB_BP_EN 0xfc38
2013-05-02 20:01:25 +04:00
/* OCP Registers */
# define OCP_ALDPS_CONFIG 0x2010
# define OCP_EEE_CONFIG1 0x2080
# define OCP_EEE_CONFIG2 0x2092
# define OCP_EEE_CONFIG3 0x2094
2014-01-02 07:22:40 +04:00
# define OCP_BASE_MII 0xa400
2013-05-02 20:01:25 +04:00
# define OCP_EEE_AR 0xa41a
# define OCP_EEE_DATA 0xa41c
2014-01-02 07:25:10 +04:00
# define OCP_PHY_STATUS 0xa420
# define OCP_POWER_CFG 0xa430
# define OCP_EEE_CFG 0xa432
# define OCP_SRAM_ADDR 0xa436
# define OCP_SRAM_DATA 0xa438
# define OCP_DOWN_SPEED 0xa442
2014-09-25 16:54:02 +04:00
# define OCP_EEE_ABLE 0xa5c4
2014-09-25 16:54:00 +04:00
# define OCP_EEE_ADV 0xa5d0
2014-09-25 16:54:02 +04:00
# define OCP_EEE_LPABLE 0xa5d2
2014-01-02 07:25:10 +04:00
# define OCP_ADC_CFG 0xbc06
/* SRAM Register */
# define SRAM_LPF_CFG 0x8012
# define SRAM_10M_AMP1 0x8080
# define SRAM_10M_AMP2 0x8082
# define SRAM_IMPEDANCE 0x8084
2013-05-02 20:01:25 +04:00
/* PLA_RCR */
# define RCR_AAP 0x00000001
# define RCR_APM 0x00000002
# define RCR_AM 0x00000004
# define RCR_AB 0x00000008
# define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
/* PLA_RXFIFO_CTRL0 */
# define RXFIFO_THR1_NORMAL 0x00080002
# define RXFIFO_THR1_OOB 0x01800003
/* PLA_RXFIFO_CTRL1 */
# define RXFIFO_THR2_FULL 0x00000060
# define RXFIFO_THR2_HIGH 0x00000038
# define RXFIFO_THR2_OOB 0x0000004a
2014-01-02 07:25:10 +04:00
# define RXFIFO_THR2_NORMAL 0x00a0
2013-05-02 20:01:25 +04:00
/* PLA_RXFIFO_CTRL2 */
# define RXFIFO_THR3_FULL 0x00000078
# define RXFIFO_THR3_HIGH 0x00000048
# define RXFIFO_THR3_OOB 0x0000005a
2014-01-02 07:25:10 +04:00
# define RXFIFO_THR3_NORMAL 0x0110
2013-05-02 20:01:25 +04:00
/* PLA_TXFIFO_CTRL */
# define TXFIFO_THR_NORMAL 0x00400008
2014-01-02 07:25:10 +04:00
# define TXFIFO_THR_NORMAL2 0x01000008
2013-05-02 20:01:25 +04:00
/* PLA_FMC */
# define FMC_FCR_MCU_EN 0x0001
/* PLA_EEEP_CR */
# define EEEP_CR_EEEP_TX 0x0002
2014-01-02 07:25:10 +04:00
/* PLA_WDT6_CTRL */
# define WDT6_SET_MODE 0x0010
2013-05-02 20:01:25 +04:00
/* PLA_TCR0 */
# define TCR0_TX_EMPTY 0x0800
# define TCR0_AUTO_FIFO 0x0080
/* PLA_TCR1 */
# define VERSION_MASK 0x7cf0
2014-07-10 06:58:54 +04:00
/* PLA_MTPS */
# define MTPS_JUMBO (12 * 1024 / 64)
# define MTPS_DEFAULT (6 * 1024 / 64)
2014-03-11 12:24:19 +04:00
/* PLA_RSTTALLY */
# define TALLY_RESET 0x0001
2013-05-02 20:01:25 +04:00
/* PLA_CR */
# define CR_RST 0x10
# define CR_RE 0x08
# define CR_TE 0x04
/* PLA_CRWECR */
# define CRWECR_NORAML 0x00
# define CRWECR_CONFIG 0xc0
/* PLA_OOB_CTRL */
# define NOW_IS_OOB 0x80
# define TXFIFO_EMPTY 0x20
# define RXFIFO_EMPTY 0x10
# define LINK_LIST_READY 0x02
# define DIS_MCU_CLROOB 0x01
# define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY)
/* PLA_MISC_1 */
# define RXDY_GATED_EN 0x0008
/* PLA_SFF_STS_7 */
# define RE_INIT_LL 0x8000
# define MCU_BORW_EN 0x4000
/* PLA_CPCR */
# define CPCR_RX_VLAN 0x0040
/* PLA_CFG_WOL */
# define MAGIC_EN 0x0001
2014-01-02 07:25:10 +04:00
/* PLA_TEREDO_CFG */
# define TEREDO_SEL 0x8000
# define TEREDO_WAKE_MASK 0x7f00
# define TEREDO_RS_EVENT_MASK 0x00fe
# define OOB_TEREDO_EN 0x0001
2013-05-02 20:01:25 +04:00
/* PAL_BDC_CR */
# define ALDPS_PROXY_MODE 0x0001
2014-02-18 17:49:06 +04:00
/* PLA_CONFIG34 */
# define LINK_ON_WAKE_EN 0x0010
# define LINK_OFF_WAKE_EN 0x0008
2013-05-02 20:01:25 +04:00
/* PLA_CONFIG5 */
2014-02-18 17:49:06 +04:00
# define BWF_EN 0x0040
# define MWF_EN 0x0020
# define UWF_EN 0x0010
2013-05-02 20:01:25 +04:00
# define LAN_WAKE_EN 0x0002
/* PLA_LED_FEATURE */
# define LED_MODE_MASK 0x0700
/* PLA_PHY_PWR */
# define TX_10M_IDLE_EN 0x0080
# define PFM_PWM_SWITCH 0x0040
/* PLA_MAC_PWR_CTRL */
# define D3_CLK_GATED_EN 0x00004000
# define MCU_CLK_RATIO 0x07010f07
# define MCU_CLK_RATIO_MASK 0x0f0f0f0f
2014-01-02 07:25:10 +04:00
# define ALDPS_SPDWN_RATIO 0x0f87
/* PLA_MAC_PWR_CTRL2 */
# define EEE_SPDWN_RATIO 0x8007
/* PLA_MAC_PWR_CTRL3 */
# define PKT_AVAIL_SPDWN_EN 0x0100
# define SUSPEND_SPDWN_EN 0x0004
# define U1U2_SPDWN_EN 0x0002
# define L1_SPDWN_EN 0x0001
/* PLA_MAC_PWR_CTRL4 */
# define PWRSAVE_SPDWN_EN 0x1000
# define RXDV_SPDWN_EN 0x0800
# define TX10MIDLE_EN 0x0100
# define TP100_SPDWN_EN 0x0020
# define TP500_SPDWN_EN 0x0010
# define TP1000_SPDWN_EN 0x0008
# define EEE_SPDWN_EN 0x0001
2013-05-02 20:01:25 +04:00
/* PLA_GPHY_INTR_IMR */
# define GPHY_STS_MSK 0x0001
# define SPEED_DOWN_MSK 0x0002
# define SPDWN_RXDV_MSK 0x0004
# define SPDWN_LINKCHG_MSK 0x0008
/* PLA_PHYAR */
# define PHYAR_FLAG 0x80000000
/* PLA_EEE_CR */
# define EEE_RX_EN 0x0001
# define EEE_TX_EN 0x0002
2014-01-02 07:25:10 +04:00
/* PLA_BOOT_CTRL */
# define AUTOLOAD_DONE 0x0002
2013-05-02 20:01:25 +04:00
/* USB_DEV_STAT */
# define STAT_SPEED_MASK 0x0006
# define STAT_SPEED_HIGH 0x0000
2014-07-24 12:37:43 +04:00
# define STAT_SPEED_FULL 0x0002
2013-05-02 20:01:25 +04:00
/* USB_TX_AGG */
# define TX_AGG_MAX_THRESHOLD 0x03
/* USB_RX_BUF_TH */
2014-01-02 07:25:10 +04:00
# define RX_THR_SUPPER 0x0c350180
2014-01-02 07:22:41 +04:00
# define RX_THR_HIGH 0x7a120180
2014-01-02 07:25:10 +04:00
# define RX_THR_SLOW 0xffff0180
2013-05-02 20:01:25 +04:00
/* USB_TX_DMA */
# define TEST_MODE_DISABLE 0x00000001
# define TX_SIZE_ADJUST1 0x00000100
/* USB_UPS_CTRL */
# define POWER_CUT 0x0100
/* USB_PM_CTRL_STATUS */
2014-01-02 07:22:41 +04:00
# define RESUME_INDICATE 0x0001
2013-05-02 20:01:25 +04:00
/* USB_USB_CTRL */
# define RX_AGG_DISABLE 0x0010
2014-01-02 07:25:10 +04:00
/* USB_U2P3_CTRL */
# define U2P3_ENABLE 0x0001
/* USB_POWER_CUT */
# define PWR_EN 0x0001
# define PHASE2_EN 0x0008
/* USB_MISC_0 */
# define PCUT_STATUS 0x0001
/* USB_RX_EARLY_AGG */
# define EARLY_AGG_SUPPER 0x0e832981
# define EARLY_AGG_HIGH 0x0e837a12
# define EARLY_AGG_SLOW 0x0e83ffff
/* USB_WDT11_CTRL */
# define TIMER11_EN 0x0001
/* USB_LPM_CTRL */
# define LPM_TIMER_MASK 0x0c
# define LPM_TIMER_500MS 0x04 /* 500 ms */
# define LPM_TIMER_500US 0x0c /* 500 us */
/* USB_AFE_CTRL2 */
# define SEN_VAL_MASK 0xf800
# define SEN_VAL_NORMAL 0xa000
# define SEL_RXIDLE 0x0100
2013-05-02 20:01:25 +04:00
/* OCP_ALDPS_CONFIG */
# define ENPWRSAVE 0x8000
# define ENPDNPS 0x0200
# define LINKENA 0x0100
# define DIS_SDSAVE 0x0010
2014-01-02 07:25:10 +04:00
/* OCP_PHY_STATUS */
# define PHY_STAT_MASK 0x0007
# define PHY_STAT_LAN_ON 3
# define PHY_STAT_PWRDN 5
/* OCP_POWER_CFG */
# define EEE_CLKDIV_EN 0x8000
# define EN_ALDPS 0x0004
# define EN_10M_PLLOFF 0x0001
2013-05-02 20:01:25 +04:00
/* OCP_EEE_CONFIG1 */
# define RG_TXLPI_MSK_HFDUP 0x8000
# define RG_MATCLR_EN 0x4000
# define EEE_10_CAP 0x2000
# define EEE_NWAY_EN 0x1000
# define TX_QUIET_EN 0x0200
# define RX_QUIET_EN 0x0100
2014-09-25 16:54:01 +04:00
# define sd_rise_time_mask 0x0070
2014-09-25 16:54:00 +04:00
# define sd_rise_time(x) (min(x, 7) << 4) /* bit 4 ~ 6 */
2013-05-02 20:01:25 +04:00
# define RG_RXLPI_MSK_HFDUP 0x0008
# define SDFALLTIME 0x0007 /* bit 0 ~ 2 */
/* OCP_EEE_CONFIG2 */
# define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */
# define RG_DACQUIET_EN 0x0400
# define RG_LDVQUIET_EN 0x0200
# define RG_CKRSEL 0x0020
# define RG_EEEPRG_EN 0x0010
/* OCP_EEE_CONFIG3 */
2014-09-25 16:54:01 +04:00
# define fast_snr_mask 0xff80
2014-09-25 16:54:00 +04:00
# define fast_snr(x) (min(x, 0x1ff) << 7) /* bit 7 ~ 15 */
2013-05-02 20:01:25 +04:00
# define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */
# define MSK_PH 0x0006 /* bit 0 ~ 3 */
/* OCP_EEE_AR */
/* bit[15:14] function */
# define FUN_ADDR 0x0000
# define FUN_DATA 0x4000
/* bit[4:0] device addr */
2014-01-02 07:25:10 +04:00
/* OCP_EEE_CFG */
# define CTAP_SHORT_EN 0x0040
# define EEE10_EN 0x0010
/* OCP_DOWN_SPEED */
# define EN_10M_BGOFF 0x0080
/* OCP_ADC_CFG */
# define CKADSEL_L 0x0100
# define ADC_EN 0x0080
# define EN_EMI_L 0x0040
/* SRAM_LPF_CFG */
# define LPF_AUTO_TUNE 0x8000
/* SRAM_10M_AMP1 */
# define GDAC_IB_UPALL 0x0008
/* SRAM_10M_AMP2 */
# define AMP_DN 0x0200
/* SRAM_IMPEDANCE */
# define RX_DRIVING_MASK 0x6000
2013-05-02 20:01:25 +04:00
enum rtl_register_content {
2014-01-02 07:25:10 +04:00
_1000bps = 0x10 ,
2013-05-02 20:01:25 +04:00
_100bps = 0x08 ,
_10bps = 0x04 ,
LINK_STATUS = 0x02 ,
FULL_DUP = 0x01 ,
} ;
2014-08-28 06:24:18 +04:00
# define RTL8152_MAX_TX 4
2013-08-14 16:54:38 +04:00
# define RTL8152_MAX_RX 10
2013-08-14 16:54:40 +04:00
# define INTBUFSIZE 2
2014-01-02 07:22:41 +04:00
# define CRC_SIZE 4
# define TX_ALIGN 4
# define RX_ALIGN 8
2013-08-14 16:54:40 +04:00
# define INTR_LINK 0x0004
2013-08-14 16:54:38 +04:00
2013-05-02 20:01:25 +04:00
# define RTL8152_REQT_READ 0xc0
# define RTL8152_REQT_WRITE 0x40
# define RTL8152_REQ_GET_REGS 0x05
# define RTL8152_REQ_SET_REGS 0x05
# define BYTE_EN_DWORD 0xff
# define BYTE_EN_WORD 0x33
# define BYTE_EN_BYTE 0x11
# define BYTE_EN_SIX_BYTES 0x3f
# define BYTE_EN_START_MASK 0x0f
# define BYTE_EN_END_MASK 0xf0
2014-07-10 06:58:54 +04:00
# define RTL8153_MAX_PACKET 9216 /* 9K */
# define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN)
2013-05-02 20:01:25 +04:00
# define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN)
2014-07-10 06:58:54 +04:00
# define RTL8153_RMS RTL8153_MAX_PACKET
2014-07-03 07:55:48 +04:00
# define RTL8152_TX_TIMEOUT (5 * HZ)
2013-05-02 20:01:25 +04:00
/* rtl8152 flags */
enum rtl8152_flags {
RTL8152_UNPLUG = 0 ,
RTL8152_SET_RX_MODE ,
2013-08-14 16:54:40 +04:00
WORK_ENABLE ,
RTL8152_LINK_CHG ,
2014-02-18 17:49:07 +04:00
SELECTIVE_SUSPEND ,
2014-02-18 17:49:04 +04:00
PHY_RESET ,
2014-03-07 07:04:36 +04:00
SCHEDULE_TASKLET ,
2013-05-02 20:01:25 +04:00
} ;
/* Define these values to match your device */
# define VENDOR_ID_REALTEK 0x0bda
# define PRODUCT_ID_RTL8152 0x8152
2014-01-02 07:25:10 +04:00
# define PRODUCT_ID_RTL8153 0x8153
# define VENDOR_ID_SAMSUNG 0x04e8
# define PRODUCT_ID_SAMSUNG 0xa101
2013-05-02 20:01:25 +04:00
# define MCU_TYPE_PLA 0x0100
# define MCU_TYPE_USB 0x0000
2014-01-15 06:42:16 +04:00
# define REALTEK_USB_DEVICE(vend, prod) \
USB_DEVICE_INTERFACE_CLASS ( vend , prod , USB_CLASS_VENDOR_SPEC )
2014-03-11 12:24:19 +04:00
struct tally_counter {
__le64 tx_packets ;
__le64 rx_packets ;
__le64 tx_errors ;
__le32 rx_errors ;
__le16 rx_missed ;
__le16 align_errors ;
__le32 tx_one_collision ;
__le32 tx_multi_collision ;
__le64 rx_unicast ;
__le64 rx_broadcast ;
__le32 rx_multicast ;
__le16 tx_aborted ;
__le16 tx_underun ;
} ;
2013-05-02 20:01:25 +04:00
struct rx_desc {
2013-11-20 13:30:57 +04:00
__le32 opts1 ;
2013-05-02 20:01:25 +04:00
# define RX_LEN_MASK 0x7fff
2014-03-07 07:04:38 +04:00
2013-11-20 13:30:57 +04:00
__le32 opts2 ;
2014-03-07 07:04:38 +04:00
# define RD_UDP_CS (1 << 23)
# define RD_TCP_CS (1 << 22)
2014-03-07 07:04:40 +04:00
# define RD_IPV6_CS (1 << 20)
2014-03-07 07:04:38 +04:00
# define RD_IPV4_CS (1 << 19)
2013-11-20 13:30:57 +04:00
__le32 opts3 ;
2014-03-07 07:04:38 +04:00
# define IPF (1 << 23) /* IP checksum fail */
# define UDPF (1 << 22) /* UDP checksum fail */
# define TCPF (1 << 21) /* TCP checksum fail */
2014-09-12 06:43:11 +04:00
# define RX_VLAN_TAG (1 << 16)
2014-03-07 07:04:38 +04:00
2013-11-20 13:30:57 +04:00
__le32 opts4 ;
__le32 opts5 ;
__le32 opts6 ;
2013-05-02 20:01:25 +04:00
} ;
struct tx_desc {
2013-11-20 13:30:57 +04:00
__le32 opts1 ;
2013-05-02 20:01:25 +04:00
# define TX_FS (1 << 31) /* First segment of a packet */
# define TX_LS (1 << 30) /* Final segment of a packet */
2014-03-07 07:04:39 +04:00
# define GTSENDV4 (1 << 28)
2014-03-07 07:04:40 +04:00
# define GTSENDV6 (1 << 27)
2014-03-07 07:04:39 +04:00
# define GTTCPHO_SHIFT 18
2014-03-07 07:04:40 +04:00
# define GTTCPHO_MAX 0x7fU
2014-03-07 07:04:39 +04:00
# define TX_LEN_MAX 0x3ffffU
2013-08-14 16:54:39 +04:00
2013-11-20 13:30:57 +04:00
__le32 opts2 ;
2013-08-14 16:54:39 +04:00
# define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */
# define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */
# define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */
# define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */
2014-03-07 07:04:39 +04:00
# define MSS_SHIFT 17
# define MSS_MAX 0x7ffU
# define TCPHO_SHIFT 17
2014-03-07 07:04:40 +04:00
# define TCPHO_MAX 0x7ffU
2014-09-12 06:43:11 +04:00
# define TX_VLAN_TAG (1 << 16)
2013-05-02 20:01:25 +04:00
} ;
2013-08-16 12:09:33 +04:00
struct r8152 ;
2013-08-14 16:54:38 +04:00
struct rx_agg {
struct list_head list ;
struct urb * urb ;
2013-08-16 12:09:33 +04:00
struct r8152 * context ;
2013-08-14 16:54:38 +04:00
void * buffer ;
void * head ;
} ;
struct tx_agg {
struct list_head list ;
struct urb * urb ;
2013-08-16 12:09:33 +04:00
struct r8152 * context ;
2013-08-14 16:54:38 +04:00
void * buffer ;
void * head ;
u32 skb_num ;
u32 skb_len ;
} ;
2013-05-02 20:01:25 +04:00
struct r8152 {
unsigned long flags ;
struct usb_device * udev ;
struct tasklet_struct tl ;
2013-08-14 16:54:40 +04:00
struct usb_interface * intf ;
2013-05-02 20:01:25 +04:00
struct net_device * netdev ;
2013-08-14 16:54:40 +04:00
struct urb * intr_urb ;
2013-08-14 16:54:38 +04:00
struct tx_agg tx_info [ RTL8152_MAX_TX ] ;
struct rx_agg rx_info [ RTL8152_MAX_RX ] ;
struct list_head rx_done , tx_free ;
struct sk_buff_head tx_queue ;
spinlock_t rx_lock , tx_lock ;
2013-05-02 20:01:25 +04:00
struct delayed_work schedule ;
struct mii_if_info mii ;
2014-01-02 07:22:42 +04:00
struct rtl_ops {
void ( * init ) ( struct r8152 * ) ;
int ( * enable ) ( struct r8152 * ) ;
void ( * disable ) ( struct r8152 * ) ;
2014-02-18 17:49:05 +04:00
void ( * up ) ( struct r8152 * ) ;
2014-01-02 07:22:42 +04:00
void ( * down ) ( struct r8152 * ) ;
void ( * unload ) ( struct r8152 * ) ;
2014-09-25 16:54:02 +04:00
int ( * eee_get ) ( struct r8152 * , struct ethtool_eee * ) ;
int ( * eee_set ) ( struct r8152 * , struct ethtool_eee * ) ;
2014-01-02 07:22:42 +04:00
} rtl_ops ;
2013-08-14 16:54:40 +04:00
int intr_interval ;
2014-02-18 17:49:06 +04:00
u32 saved_wolopts ;
2013-05-02 20:01:25 +04:00
u32 msg_enable ;
2013-11-20 13:30:56 +04:00
u32 tx_qlen ;
2013-05-02 20:01:25 +04:00
u16 ocp_base ;
2013-08-14 16:54:40 +04:00
u8 * intr_buff ;
2013-05-02 20:01:25 +04:00
u8 version ;
u8 speed ;
} ;
enum rtl_version {
RTL_VER_UNKNOWN = 0 ,
RTL_VER_01 ,
2014-01-02 07:25:10 +04:00
RTL_VER_02 ,
RTL_VER_03 ,
RTL_VER_04 ,
RTL_VER_05 ,
RTL_VER_MAX
2013-05-02 20:01:25 +04:00
} ;
2014-03-07 07:04:39 +04:00
enum tx_csum_stat {
TX_CSUM_SUCCESS = 0 ,
TX_CSUM_TSO ,
TX_CSUM_NONE
} ;
2013-05-02 20:01:25 +04:00
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
* The RTL chips use a 64 element hash table based on the Ethernet CRC .
*/
static const int multicast_filter_limit = 32 ;
2014-09-02 06:27:52 +04:00
static unsigned int agg_buf_sz = 16384 ;
2013-05-02 20:01:25 +04:00
2014-09-02 06:27:52 +04:00
# define RTL_LIMITED_TSO_SIZE (agg_buf_sz - sizeof(struct tx_desc) - \
2014-03-07 07:04:39 +04:00
VLAN_ETH_HLEN - VLAN_HLEN )
2013-05-02 20:01:25 +04:00
static
int get_registers ( struct r8152 * tp , u16 value , u16 index , u16 size , void * data )
{
2013-07-31 13:21:25 +04:00
int ret ;
void * tmp ;
tmp = kmalloc ( size , GFP_KERNEL ) ;
if ( ! tmp )
return - ENOMEM ;
ret = usb_control_msg ( tp - > udev , usb_rcvctrlpipe ( tp - > udev , 0 ) ,
2014-08-25 11:53:00 +04:00
RTL8152_REQ_GET_REGS , RTL8152_REQT_READ ,
value , index , tmp , size , 500 ) ;
2013-07-31 13:21:25 +04:00
memcpy ( data , tmp , size ) ;
kfree ( tmp ) ;
return ret ;
2013-05-02 20:01:25 +04:00
}
static
int set_registers ( struct r8152 * tp , u16 value , u16 index , u16 size , void * data )
{
2013-07-31 13:21:25 +04:00
int ret ;
void * tmp ;
2014-05-26 19:21:23 +04:00
tmp = kmemdup ( data , size , GFP_KERNEL ) ;
2013-07-31 13:21:25 +04:00
if ( ! tmp )
return - ENOMEM ;
ret = usb_control_msg ( tp - > udev , usb_sndctrlpipe ( tp - > udev , 0 ) ,
2014-08-25 11:53:00 +04:00
RTL8152_REQ_SET_REGS , RTL8152_REQT_WRITE ,
value , index , tmp , size , 500 ) ;
2013-07-31 13:21:25 +04:00
kfree ( tmp ) ;
2014-03-06 11:07:16 +04:00
2013-07-31 13:21:25 +04:00
return ret ;
2013-05-02 20:01:25 +04:00
}
static int generic_ocp_read ( struct r8152 * tp , u16 index , u16 size ,
2014-08-25 11:53:00 +04:00
void * data , u16 type )
2013-05-02 20:01:25 +04:00
{
2014-01-06 13:08:41 +04:00
u16 limit = 64 ;
int ret = 0 ;
2013-05-02 20:01:25 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
/* both size and indix must be 4 bytes align */
if ( ( size & 3 ) | | ! size | | ( index & 3 ) | | ! data )
return - EPERM ;
if ( ( u32 ) index + ( u32 ) size > 0xffff )
return - EPERM ;
while ( size ) {
if ( size > limit ) {
ret = get_registers ( tp , index , type , limit , data ) ;
if ( ret < 0 )
break ;
index + = limit ;
data + = limit ;
size - = limit ;
} else {
ret = get_registers ( tp , index , type , size , data ) ;
if ( ret < 0 )
break ;
index + = size ;
data + = size ;
size = 0 ;
break ;
}
}
return ret ;
}
static int generic_ocp_write ( struct r8152 * tp , u16 index , u16 byteen ,
2014-08-25 11:53:00 +04:00
u16 size , void * data , u16 type )
2013-05-02 20:01:25 +04:00
{
2014-01-06 13:08:41 +04:00
int ret ;
u16 byteen_start , byteen_end , byen ;
u16 limit = 512 ;
2013-05-02 20:01:25 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
/* both size and indix must be 4 bytes align */
if ( ( size & 3 ) | | ! size | | ( index & 3 ) | | ! data )
return - EPERM ;
if ( ( u32 ) index + ( u32 ) size > 0xffff )
return - EPERM ;
byteen_start = byteen & BYTE_EN_START_MASK ;
byteen_end = byteen & BYTE_EN_END_MASK ;
byen = byteen_start | ( byteen_start < < 4 ) ;
ret = set_registers ( tp , index , type | byen , 4 , data ) ;
if ( ret < 0 )
goto error1 ;
index + = 4 ;
data + = 4 ;
size - = 4 ;
if ( size ) {
size - = 4 ;
while ( size ) {
if ( size > limit ) {
ret = set_registers ( tp , index ,
2014-08-25 11:53:00 +04:00
type | BYTE_EN_DWORD ,
limit , data ) ;
2013-05-02 20:01:25 +04:00
if ( ret < 0 )
goto error1 ;
index + = limit ;
data + = limit ;
size - = limit ;
} else {
ret = set_registers ( tp , index ,
2014-08-25 11:53:00 +04:00
type | BYTE_EN_DWORD ,
size , data ) ;
2013-05-02 20:01:25 +04:00
if ( ret < 0 )
goto error1 ;
index + = size ;
data + = size ;
size = 0 ;
break ;
}
}
byen = byteen_end | ( byteen_end > > 4 ) ;
ret = set_registers ( tp , index , type | byen , 4 , data ) ;
if ( ret < 0 )
goto error1 ;
}
error1 :
return ret ;
}
static inline
int pla_ocp_read ( struct r8152 * tp , u16 index , u16 size , void * data )
{
return generic_ocp_read ( tp , index , size , data , MCU_TYPE_PLA ) ;
}
static inline
int pla_ocp_write ( struct r8152 * tp , u16 index , u16 byteen , u16 size , void * data )
{
return generic_ocp_write ( tp , index , byteen , size , data , MCU_TYPE_PLA ) ;
}
static inline
int usb_ocp_read ( struct r8152 * tp , u16 index , u16 size , void * data )
{
return generic_ocp_read ( tp , index , size , data , MCU_TYPE_USB ) ;
}
static inline
int usb_ocp_write ( struct r8152 * tp , u16 index , u16 byteen , u16 size , void * data )
{
return generic_ocp_write ( tp , index , byteen , size , data , MCU_TYPE_USB ) ;
}
static u32 ocp_read_dword ( struct r8152 * tp , u16 type , u16 index )
{
2013-07-31 13:21:26 +04:00
__le32 data ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
generic_ocp_read ( tp , index , sizeof ( data ) , & data , type ) ;
2013-05-02 20:01:25 +04:00
return __le32_to_cpu ( data ) ;
}
static void ocp_write_dword ( struct r8152 * tp , u16 type , u16 index , u32 data )
{
2013-07-31 13:21:26 +04:00
__le32 tmp = __cpu_to_le32 ( data ) ;
generic_ocp_write ( tp , index , BYTE_EN_DWORD , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
}
static u16 ocp_read_word ( struct r8152 * tp , u16 type , u16 index )
{
u32 data ;
2013-07-31 13:21:26 +04:00
__le32 tmp ;
2013-05-02 20:01:25 +04:00
u8 shift = index & 2 ;
index & = ~ 3 ;
2013-07-31 13:21:26 +04:00
generic_ocp_read ( tp , index , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
data = __le32_to_cpu ( tmp ) ;
2013-05-02 20:01:25 +04:00
data > > = ( shift * 8 ) ;
data & = 0xffff ;
return ( u16 ) data ;
}
static void ocp_write_word ( struct r8152 * tp , u16 type , u16 index , u32 data )
{
2013-07-31 13:21:26 +04:00
u32 mask = 0xffff ;
__le32 tmp ;
2013-05-02 20:01:25 +04:00
u16 byen = BYTE_EN_WORD ;
u8 shift = index & 2 ;
data & = mask ;
if ( index & 2 ) {
byen < < = shift ;
mask < < = ( shift * 8 ) ;
data < < = ( shift * 8 ) ;
index & = ~ 3 ;
}
2013-07-31 13:21:26 +04:00
generic_ocp_read ( tp , index , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
data | = __le32_to_cpu ( tmp ) & ~ mask ;
tmp = __cpu_to_le32 ( data ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
generic_ocp_write ( tp , index , byen , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
}
static u8 ocp_read_byte ( struct r8152 * tp , u16 type , u16 index )
{
u32 data ;
2013-07-31 13:21:26 +04:00
__le32 tmp ;
2013-05-02 20:01:25 +04:00
u8 shift = index & 3 ;
index & = ~ 3 ;
2013-07-31 13:21:26 +04:00
generic_ocp_read ( tp , index , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
data = __le32_to_cpu ( tmp ) ;
2013-05-02 20:01:25 +04:00
data > > = ( shift * 8 ) ;
data & = 0xff ;
return ( u8 ) data ;
}
static void ocp_write_byte ( struct r8152 * tp , u16 type , u16 index , u32 data )
{
2013-07-31 13:21:26 +04:00
u32 mask = 0xff ;
__le32 tmp ;
2013-05-02 20:01:25 +04:00
u16 byen = BYTE_EN_BYTE ;
u8 shift = index & 3 ;
data & = mask ;
if ( index & 3 ) {
byen < < = shift ;
mask < < = ( shift * 8 ) ;
data < < = ( shift * 8 ) ;
index & = ~ 3 ;
}
2013-07-31 13:21:26 +04:00
generic_ocp_read ( tp , index , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
data | = __le32_to_cpu ( tmp ) & ~ mask ;
tmp = __cpu_to_le32 ( data ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:26 +04:00
generic_ocp_write ( tp , index , byen , sizeof ( tmp ) , & tmp , type ) ;
2013-05-02 20:01:25 +04:00
}
2014-01-02 07:22:40 +04:00
static u16 ocp_reg_read ( struct r8152 * tp , u16 addr )
2014-01-02 07:22:39 +04:00
{
u16 ocp_base , ocp_index ;
ocp_base = addr & 0xf000 ;
if ( ocp_base ! = tp - > ocp_base ) {
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_OCP_GPHY_BASE , ocp_base ) ;
tp - > ocp_base = ocp_base ;
}
ocp_index = ( addr & 0x0fff ) | 0xb000 ;
2014-01-02 07:22:40 +04:00
return ocp_read_word ( tp , MCU_TYPE_PLA , ocp_index ) ;
2014-01-02 07:22:39 +04:00
}
2014-01-02 07:22:40 +04:00
static void ocp_reg_write ( struct r8152 * tp , u16 addr , u16 data )
2013-05-02 20:01:25 +04:00
{
2014-01-02 07:22:40 +04:00
u16 ocp_base , ocp_index ;
2013-05-02 20:01:25 +04:00
2014-01-02 07:22:40 +04:00
ocp_base = addr & 0xf000 ;
if ( ocp_base ! = tp - > ocp_base ) {
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_OCP_GPHY_BASE , ocp_base ) ;
tp - > ocp_base = ocp_base ;
2013-05-02 20:01:25 +04:00
}
2014-01-02 07:22:40 +04:00
ocp_index = ( addr & 0x0fff ) | 0xb000 ;
ocp_write_word ( tp , MCU_TYPE_PLA , ocp_index , data ) ;
2013-05-02 20:01:25 +04:00
}
2014-01-02 07:22:40 +04:00
static inline void r8152_mdio_write ( struct r8152 * tp , u32 reg_addr , u32 value )
2013-05-02 20:01:25 +04:00
{
2014-01-02 07:22:40 +04:00
ocp_reg_write ( tp , OCP_BASE_MII + reg_addr * 2 , value ) ;
}
2013-05-02 20:01:25 +04:00
2014-01-02 07:22:40 +04:00
static inline int r8152_mdio_read ( struct r8152 * tp , u32 reg_addr )
{
return ocp_reg_read ( tp , OCP_BASE_MII + reg_addr * 2 ) ;
2013-05-02 20:01:25 +04:00
}
2014-01-02 07:25:10 +04:00
static void sram_write ( struct r8152 * tp , u16 addr , u16 data )
{
ocp_reg_write ( tp , OCP_SRAM_ADDR , addr ) ;
ocp_reg_write ( tp , OCP_SRAM_DATA , data ) ;
}
static u16 sram_read ( struct r8152 * tp , u16 addr )
{
ocp_reg_write ( tp , OCP_SRAM_ADDR , addr ) ;
return ocp_reg_read ( tp , OCP_SRAM_DATA ) ;
}
2013-05-02 20:01:25 +04:00
static int read_mii_word ( struct net_device * netdev , int phy_id , int reg )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2014-02-18 17:49:07 +04:00
int ret ;
2013-05-02 20:01:25 +04:00
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
2013-05-02 20:01:25 +04:00
if ( phy_id ! = R8152_PHY_ID )
return - EINVAL ;
2014-02-18 17:49:07 +04:00
ret = usb_autopm_get_interface ( tp - > intf ) ;
if ( ret < 0 )
goto out ;
ret = r8152_mdio_read ( tp , reg ) ;
usb_autopm_put_interface ( tp - > intf ) ;
out :
return ret ;
2013-05-02 20:01:25 +04:00
}
static
void write_mii_word ( struct net_device * netdev , int phy_id , int reg , int val )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2013-05-02 20:01:25 +04:00
if ( phy_id ! = R8152_PHY_ID )
return ;
2014-02-18 17:49:07 +04:00
if ( usb_autopm_get_interface ( tp - > intf ) < 0 )
return ;
2013-05-02 20:01:25 +04:00
r8152_mdio_write ( tp , reg , val ) ;
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
2013-05-02 20:01:25 +04:00
}
2014-08-25 11:53:00 +04:00
static int
r8152_submit_rx ( struct r8152 * tp , struct rx_agg * agg , gfp_t mem_flags ) ;
2013-08-14 16:54:38 +04:00
2014-09-04 12:15:41 +04:00
static int rtl8152_set_mac_address ( struct net_device * netdev , void * p )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
struct sockaddr * addr = p ;
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
memcpy ( netdev - > dev_addr , addr - > sa_data , netdev - > addr_len ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_CONFIG ) ;
pla_ocp_write ( tp , PLA_IDR , BYTE_EN_SIX_BYTES , 8 , addr - > sa_data ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_NORAML ) ;
return 0 ;
}
2014-09-04 12:15:42 +04:00
static int set_ethernet_addr ( struct r8152 * tp )
2013-05-02 20:01:25 +04:00
{
struct net_device * dev = tp - > netdev ;
2014-09-04 12:15:42 +04:00
struct sockaddr sa ;
2014-02-18 17:49:01 +04:00
int ret ;
2013-05-02 20:01:25 +04:00
2014-02-18 17:49:01 +04:00
if ( tp - > version = = RTL_VER_01 )
2014-09-04 12:15:42 +04:00
ret = pla_ocp_read ( tp , PLA_IDR , 8 , sa . sa_data ) ;
2014-02-18 17:49:01 +04:00
else
2014-09-04 12:15:42 +04:00
ret = pla_ocp_read ( tp , PLA_BACKUP , 8 , sa . sa_data ) ;
2014-02-18 17:49:01 +04:00
if ( ret < 0 ) {
2014-09-04 12:15:42 +04:00
netif_err ( tp , probe , dev , " Get ether addr fail \n " ) ;
} else if ( ! is_valid_ether_addr ( sa . sa_data ) ) {
netif_err ( tp , probe , dev , " Invalid ether addr %pM \n " ,
sa . sa_data ) ;
eth_hw_addr_random ( dev ) ;
ether_addr_copy ( sa . sa_data , dev - > dev_addr ) ;
ret = rtl8152_set_mac_address ( dev , & sa ) ;
netif_info ( tp , probe , dev , " Random ether addr %pM \n " ,
sa . sa_data ) ;
2014-02-18 17:49:01 +04:00
} else {
2014-09-04 12:15:42 +04:00
if ( tp - > version = = RTL_VER_01 )
ether_addr_copy ( dev - > dev_addr , sa . sa_data ) ;
else
ret = rtl8152_set_mac_address ( dev , & sa ) ;
2013-05-02 20:01:25 +04:00
}
2014-09-04 12:15:42 +04:00
return ret ;
2013-05-02 20:01:25 +04:00
}
static void read_bulk_callback ( struct urb * urb )
{
struct net_device * netdev ;
int status = urb - > status ;
2013-08-14 16:54:38 +04:00
struct rx_agg * agg ;
struct r8152 * tp ;
2013-05-02 20:01:25 +04:00
int result ;
2013-08-14 16:54:38 +04:00
agg = urb - > context ;
if ( ! agg )
return ;
tp = agg - > context ;
2013-05-02 20:01:25 +04:00
if ( ! tp )
return ;
2013-08-14 16:54:38 +04:00
2013-05-02 20:01:25 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2013-08-14 16:54:38 +04:00
if ( ! test_bit ( WORK_ENABLE , & tp - > flags ) )
return ;
2013-05-02 20:01:25 +04:00
netdev = tp - > netdev ;
2013-08-16 12:09:38 +04:00
/* When link down, the driver would cancel all bulks. */
/* This avoid the re-submitting bulk */
2013-08-14 16:54:38 +04:00
if ( ! netif_carrier_ok ( netdev ) )
2013-05-02 20:01:25 +04:00
return ;
2014-02-18 17:49:07 +04:00
usb_mark_last_busy ( tp - > udev ) ;
2013-05-02 20:01:25 +04:00
switch ( status ) {
case 0 :
2013-08-14 16:54:38 +04:00
if ( urb - > actual_length < ETH_ZLEN )
break ;
2014-03-07 07:04:34 +04:00
spin_lock ( & tp - > rx_lock ) ;
2013-08-14 16:54:38 +04:00
list_add_tail ( & agg - > list , & tp - > rx_done ) ;
2014-03-07 07:04:34 +04:00
spin_unlock ( & tp - > rx_lock ) ;
2013-08-14 16:54:38 +04:00
tasklet_schedule ( & tp - > tl ) ;
return ;
2013-05-02 20:01:25 +04:00
case - ESHUTDOWN :
set_bit ( RTL8152_UNPLUG , & tp - > flags ) ;
netif_device_detach ( tp - > netdev ) ;
2013-08-14 16:54:38 +04:00
return ;
2013-05-02 20:01:25 +04:00
case - ENOENT :
return ; /* the urb is in unlink state */
case - ETIME :
2014-01-07 07:18:22 +04:00
if ( net_ratelimit ( ) )
netdev_warn ( netdev , " maybe reset is needed? \n " ) ;
2013-08-14 16:54:38 +04:00
break ;
2013-05-02 20:01:25 +04:00
default :
2014-01-07 07:18:22 +04:00
if ( net_ratelimit ( ) )
netdev_warn ( netdev , " Rx status %d \n " , status ) ;
2013-08-14 16:54:38 +04:00
break ;
2013-05-02 20:01:25 +04:00
}
2013-08-14 16:54:38 +04:00
result = r8152_submit_rx ( tp , agg , GFP_ATOMIC ) ;
2013-05-02 20:01:25 +04:00
if ( result = = - ENODEV ) {
netif_device_detach ( tp - > netdev ) ;
} else if ( result ) {
2014-03-07 07:04:34 +04:00
spin_lock ( & tp - > rx_lock ) ;
2013-08-14 16:54:38 +04:00
list_add_tail ( & agg - > list , & tp - > rx_done ) ;
2014-03-07 07:04:34 +04:00
spin_unlock ( & tp - > rx_lock ) ;
2013-08-14 16:54:38 +04:00
tasklet_schedule ( & tp - > tl ) ;
2013-05-02 20:01:25 +04:00
}
}
2013-08-14 16:54:38 +04:00
static void write_bulk_callback ( struct urb * urb )
2013-05-02 20:01:25 +04:00
{
2013-08-14 16:54:38 +04:00
struct net_device_stats * stats ;
2014-03-06 11:07:17 +04:00
struct net_device * netdev ;
2013-08-14 16:54:38 +04:00
struct tx_agg * agg ;
2013-05-02 20:01:25 +04:00
struct r8152 * tp ;
2013-08-14 16:54:38 +04:00
int status = urb - > status ;
2013-05-02 20:01:25 +04:00
2013-08-14 16:54:38 +04:00
agg = urb - > context ;
if ( ! agg )
2013-05-02 20:01:25 +04:00
return ;
2013-08-14 16:54:38 +04:00
tp = agg - > context ;
if ( ! tp )
return ;
2014-03-06 11:07:17 +04:00
netdev = tp - > netdev ;
2014-03-06 11:07:18 +04:00
stats = & netdev - > stats ;
2013-08-14 16:54:38 +04:00
if ( status ) {
2014-01-07 07:18:22 +04:00
if ( net_ratelimit ( ) )
2014-03-06 11:07:17 +04:00
netdev_warn ( netdev , " Tx status %d \n " , status ) ;
2013-08-14 16:54:38 +04:00
stats - > tx_errors + = agg - > skb_num ;
2013-05-02 20:01:25 +04:00
} else {
2013-08-14 16:54:38 +04:00
stats - > tx_packets + = agg - > skb_num ;
stats - > tx_bytes + = agg - > skb_len ;
2013-05-02 20:01:25 +04:00
}
2014-03-07 07:04:34 +04:00
spin_lock ( & tp - > tx_lock ) ;
2013-08-14 16:54:38 +04:00
list_add_tail ( & agg - > list , & tp - > tx_free ) ;
2014-03-07 07:04:34 +04:00
spin_unlock ( & tp - > tx_lock ) ;
2013-08-14 16:54:38 +04:00
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface_async ( tp - > intf ) ;
2014-03-06 11:07:17 +04:00
if ( ! netif_carrier_ok ( netdev ) )
2013-08-14 16:54:38 +04:00
return ;
if ( ! test_bit ( WORK_ENABLE , & tp - > flags ) )
return ;
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
if ( ! skb_queue_empty ( & tp - > tx_queue ) )
2014-03-07 07:04:36 +04:00
tasklet_schedule ( & tp - > tl ) ;
2013-05-02 20:01:25 +04:00
}
2013-08-14 16:54:40 +04:00
static void intr_callback ( struct urb * urb )
{
struct r8152 * tp ;
2013-11-20 13:30:57 +04:00
__le16 * d ;
2013-08-14 16:54:40 +04:00
int status = urb - > status ;
int res ;
tp = urb - > context ;
if ( ! tp )
return ;
if ( ! test_bit ( WORK_ENABLE , & tp - > flags ) )
return ;
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
switch ( status ) {
case 0 : /* success */
break ;
case - ECONNRESET : /* unlink */
case - ESHUTDOWN :
netif_device_detach ( tp - > netdev ) ;
case - ENOENT :
return ;
case - EOVERFLOW :
netif_info ( tp , intr , tp - > netdev , " intr status -EOVERFLOW \n " ) ;
goto resubmit ;
/* -EPIPE: should clear the halt */
default :
netif_info ( tp , intr , tp - > netdev , " intr status %d \n " , status ) ;
goto resubmit ;
}
d = urb - > transfer_buffer ;
if ( INTR_LINK & __le16_to_cpu ( d [ 0 ] ) ) {
if ( ! ( tp - > speed & LINK_STATUS ) ) {
set_bit ( RTL8152_LINK_CHG , & tp - > flags ) ;
schedule_delayed_work ( & tp - > schedule , 0 ) ;
}
} else {
if ( tp - > speed & LINK_STATUS ) {
set_bit ( RTL8152_LINK_CHG , & tp - > flags ) ;
schedule_delayed_work ( & tp - > schedule , 0 ) ;
}
}
resubmit :
res = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( res = = - ENODEV )
netif_device_detach ( tp - > netdev ) ;
else if ( res )
netif_err ( tp , intr , tp - > netdev ,
2014-01-07 07:18:22 +04:00
" can't resubmit intr, status %d \n " , res ) ;
2013-08-14 16:54:40 +04:00
}
2013-08-14 16:54:38 +04:00
static inline void * rx_agg_align ( void * data )
{
2014-01-02 07:22:41 +04:00
return ( void * ) ALIGN ( ( uintptr_t ) data , RX_ALIGN ) ;
2013-08-14 16:54:38 +04:00
}
static inline void * tx_agg_align ( void * data )
{
2014-01-02 07:22:41 +04:00
return ( void * ) ALIGN ( ( uintptr_t ) data , TX_ALIGN ) ;
2013-08-14 16:54:38 +04:00
}
static void free_all_mem ( struct r8152 * tp )
{
int i ;
for ( i = 0 ; i < RTL8152_MAX_RX ; i + + ) {
2014-01-15 06:42:15 +04:00
usb_free_urb ( tp - > rx_info [ i ] . urb ) ;
tp - > rx_info [ i ] . urb = NULL ;
2013-08-14 16:54:38 +04:00
2014-01-15 06:42:15 +04:00
kfree ( tp - > rx_info [ i ] . buffer ) ;
tp - > rx_info [ i ] . buffer = NULL ;
tp - > rx_info [ i ] . head = NULL ;
2013-08-14 16:54:38 +04:00
}
for ( i = 0 ; i < RTL8152_MAX_TX ; i + + ) {
2014-01-15 06:42:15 +04:00
usb_free_urb ( tp - > tx_info [ i ] . urb ) ;
tp - > tx_info [ i ] . urb = NULL ;
2013-08-14 16:54:38 +04:00
2014-01-15 06:42:15 +04:00
kfree ( tp - > tx_info [ i ] . buffer ) ;
tp - > tx_info [ i ] . buffer = NULL ;
tp - > tx_info [ i ] . head = NULL ;
2013-08-14 16:54:38 +04:00
}
2013-08-14 16:54:40 +04:00
2014-01-15 06:42:15 +04:00
usb_free_urb ( tp - > intr_urb ) ;
tp - > intr_urb = NULL ;
2013-08-14 16:54:40 +04:00
2014-01-15 06:42:15 +04:00
kfree ( tp - > intr_buff ) ;
tp - > intr_buff = NULL ;
2013-08-14 16:54:38 +04:00
}
static int alloc_all_mem ( struct r8152 * tp )
{
struct net_device * netdev = tp - > netdev ;
2013-08-14 16:54:40 +04:00
struct usb_interface * intf = tp - > intf ;
struct usb_host_interface * alt = intf - > cur_altsetting ;
struct usb_host_endpoint * ep_intr = alt - > endpoint + 2 ;
2013-08-14 16:54:38 +04:00
struct urb * urb ;
int node , i ;
u8 * buf ;
node = netdev - > dev . parent ? dev_to_node ( netdev - > dev . parent ) : - 1 ;
spin_lock_init ( & tp - > rx_lock ) ;
spin_lock_init ( & tp - > tx_lock ) ;
INIT_LIST_HEAD ( & tp - > rx_done ) ;
INIT_LIST_HEAD ( & tp - > tx_free ) ;
skb_queue_head_init ( & tp - > tx_queue ) ;
for ( i = 0 ; i < RTL8152_MAX_RX ; i + + ) {
2014-09-02 06:27:52 +04:00
buf = kmalloc_node ( agg_buf_sz , GFP_KERNEL , node ) ;
2013-08-14 16:54:38 +04:00
if ( ! buf )
goto err1 ;
if ( buf ! = rx_agg_align ( buf ) ) {
kfree ( buf ) ;
2014-09-02 06:27:52 +04:00
buf = kmalloc_node ( agg_buf_sz + RX_ALIGN , GFP_KERNEL ,
2014-01-02 07:22:41 +04:00
node ) ;
2013-08-14 16:54:38 +04:00
if ( ! buf )
goto err1 ;
}
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! urb ) {
kfree ( buf ) ;
goto err1 ;
}
INIT_LIST_HEAD ( & tp - > rx_info [ i ] . list ) ;
tp - > rx_info [ i ] . context = tp ;
tp - > rx_info [ i ] . urb = urb ;
tp - > rx_info [ i ] . buffer = buf ;
tp - > rx_info [ i ] . head = rx_agg_align ( buf ) ;
}
for ( i = 0 ; i < RTL8152_MAX_TX ; i + + ) {
2014-09-02 06:27:52 +04:00
buf = kmalloc_node ( agg_buf_sz , GFP_KERNEL , node ) ;
2013-08-14 16:54:38 +04:00
if ( ! buf )
goto err1 ;
if ( buf ! = tx_agg_align ( buf ) ) {
kfree ( buf ) ;
2014-09-02 06:27:52 +04:00
buf = kmalloc_node ( agg_buf_sz + TX_ALIGN , GFP_KERNEL ,
2014-01-02 07:22:41 +04:00
node ) ;
2013-08-14 16:54:38 +04:00
if ( ! buf )
goto err1 ;
}
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! urb ) {
kfree ( buf ) ;
goto err1 ;
}
INIT_LIST_HEAD ( & tp - > tx_info [ i ] . list ) ;
tp - > tx_info [ i ] . context = tp ;
tp - > tx_info [ i ] . urb = urb ;
tp - > tx_info [ i ] . buffer = buf ;
tp - > tx_info [ i ] . head = tx_agg_align ( buf ) ;
list_add_tail ( & tp - > tx_info [ i ] . list , & tp - > tx_free ) ;
}
2013-08-14 16:54:40 +04:00
tp - > intr_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! tp - > intr_urb )
goto err1 ;
tp - > intr_buff = kmalloc ( INTBUFSIZE , GFP_KERNEL ) ;
if ( ! tp - > intr_buff )
goto err1 ;
tp - > intr_interval = ( int ) ep_intr - > desc . bInterval ;
usb_fill_int_urb ( tp - > intr_urb , tp - > udev , usb_rcvintpipe ( tp - > udev , 3 ) ,
2014-08-25 11:53:00 +04:00
tp - > intr_buff , INTBUFSIZE , intr_callback ,
tp , tp - > intr_interval ) ;
2013-08-14 16:54:40 +04:00
2013-08-14 16:54:38 +04:00
return 0 ;
err1 :
free_all_mem ( tp ) ;
return - ENOMEM ;
}
2013-08-16 12:09:35 +04:00
static struct tx_agg * r8152_get_tx_agg ( struct r8152 * tp )
{
struct tx_agg * agg = NULL ;
unsigned long flags ;
2014-03-07 07:04:35 +04:00
if ( list_empty ( & tp - > tx_free ) )
return NULL ;
2013-08-16 12:09:35 +04:00
spin_lock_irqsave ( & tp - > tx_lock , flags ) ;
if ( ! list_empty ( & tp - > tx_free ) ) {
struct list_head * cursor ;
cursor = tp - > tx_free . next ;
list_del_init ( cursor ) ;
agg = list_entry ( cursor , struct tx_agg , list ) ;
}
spin_unlock_irqrestore ( & tp - > tx_lock , flags ) ;
return agg ;
}
2014-03-07 07:04:39 +04:00
static inline __be16 get_protocol ( struct sk_buff * skb )
2013-08-14 16:54:39 +04:00
{
2014-03-07 07:04:39 +04:00
__be16 protocol ;
2013-08-14 16:54:39 +04:00
2014-03-07 07:04:39 +04:00
if ( skb - > protocol = = htons ( ETH_P_8021Q ) )
protocol = vlan_eth_hdr ( skb ) - > h_vlan_encapsulated_proto ;
else
protocol = skb - > protocol ;
2013-08-14 16:54:39 +04:00
2014-03-07 07:04:39 +04:00
return protocol ;
}
2013-08-14 16:54:39 +04:00
2014-08-25 11:53:00 +04:00
/* r8152_csum_workaround()
2014-03-07 07:04:40 +04:00
* The hw limites the value the transport offset . When the offset is out of the
* range , calculate the checksum by sw .
*/
static void r8152_csum_workaround ( struct r8152 * tp , struct sk_buff * skb ,
struct sk_buff_head * list )
{
if ( skb_shinfo ( skb ) - > gso_size ) {
netdev_features_t features = tp - > netdev - > features ;
struct sk_buff_head seg_list ;
struct sk_buff * segs , * nskb ;
2014-07-11 12:48:27 +04:00
features & = ~ ( NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6 ) ;
2014-03-07 07:04:40 +04:00
segs = skb_gso_segment ( skb , features ) ;
if ( IS_ERR ( segs ) | | ! segs )
goto drop ;
__skb_queue_head_init ( & seg_list ) ;
do {
nskb = segs ;
segs = segs - > next ;
nskb - > next = NULL ;
__skb_queue_tail ( & seg_list , nskb ) ;
} while ( segs ) ;
skb_queue_splice ( & seg_list , list ) ;
dev_kfree_skb ( skb ) ;
} else if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
if ( skb_checksum_help ( skb ) < 0 )
goto drop ;
__skb_queue_head ( list , skb ) ;
} else {
struct net_device_stats * stats ;
drop :
stats = & tp - > netdev - > stats ;
stats - > tx_dropped + + ;
dev_kfree_skb ( skb ) ;
}
}
2014-08-25 11:53:00 +04:00
/* msdn_giant_send_check()
2014-03-07 07:04:40 +04:00
* According to the document of microsoft , the TCP Pseudo Header excludes the
* packet length for IPv6 TCP large packets .
*/
static int msdn_giant_send_check ( struct sk_buff * skb )
{
const struct ipv6hdr * ipv6h ;
struct tcphdr * th ;
2014-03-11 06:20:32 +04:00
int ret ;
ret = skb_cow_head ( skb , 0 ) ;
if ( ret )
return ret ;
2014-03-07 07:04:40 +04:00
ipv6h = ipv6_hdr ( skb ) ;
th = tcp_hdr ( skb ) ;
th - > check = 0 ;
th - > check = ~ tcp_v6_check ( 0 , & ipv6h - > saddr , & ipv6h - > daddr , 0 ) ;
2014-03-11 06:20:32 +04:00
return ret ;
2014-03-07 07:04:40 +04:00
}
2014-09-12 06:43:11 +04:00
static inline void rtl_tx_vlan_tag ( struct tx_desc * desc , struct sk_buff * skb )
{
if ( vlan_tx_tag_present ( skb ) ) {
u32 opts2 ;
opts2 = TX_VLAN_TAG | swab16 ( vlan_tx_tag_get ( skb ) ) ;
desc - > opts2 | = cpu_to_le32 ( opts2 ) ;
}
}
static inline void rtl_rx_vlan_tag ( struct rx_desc * desc , struct sk_buff * skb )
{
u32 opts2 = le32_to_cpu ( desc - > opts2 ) ;
if ( opts2 & RX_VLAN_TAG )
__vlan_hwaccel_put_tag ( skb , htons ( ETH_P_8021Q ) ,
swab16 ( opts2 & 0xffff ) ) ;
}
2014-03-07 07:04:39 +04:00
static int r8152_tx_csum ( struct r8152 * tp , struct tx_desc * desc ,
struct sk_buff * skb , u32 len , u32 transport_offset )
{
u32 mss = skb_shinfo ( skb ) - > gso_size ;
u32 opts1 , opts2 = 0 ;
int ret = TX_CSUM_SUCCESS ;
WARN_ON_ONCE ( len > TX_LEN_MAX ) ;
opts1 = len | TX_FS | TX_LS ;
if ( mss ) {
2014-03-07 07:04:40 +04:00
if ( transport_offset > GTTCPHO_MAX ) {
netif_warn ( tp , tx_err , tp - > netdev ,
" Invalid transport offset 0x%x for TSO \n " ,
transport_offset ) ;
ret = TX_CSUM_TSO ;
goto unavailable ;
}
2014-03-07 07:04:39 +04:00
switch ( get_protocol ( skb ) ) {
case htons ( ETH_P_IP ) :
opts1 | = GTSENDV4 ;
break ;
2014-03-07 07:04:40 +04:00
case htons ( ETH_P_IPV6 ) :
2014-03-11 06:20:32 +04:00
if ( msdn_giant_send_check ( skb ) ) {
ret = TX_CSUM_TSO ;
goto unavailable ;
}
2014-03-07 07:04:40 +04:00
opts1 | = GTSENDV6 ;
break ;
2014-03-07 07:04:39 +04:00
default :
WARN_ON_ONCE ( 1 ) ;
break ;
}
opts1 | = transport_offset < < GTTCPHO_SHIFT ;
opts2 | = min ( mss , MSS_MAX ) < < MSS_SHIFT ;
} else if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
u8 ip_protocol ;
2013-08-14 16:54:39 +04:00
2014-03-07 07:04:40 +04:00
if ( transport_offset > TCPHO_MAX ) {
netif_warn ( tp , tx_err , tp - > netdev ,
" Invalid transport offset 0x%x \n " ,
transport_offset ) ;
ret = TX_CSUM_NONE ;
goto unavailable ;
}
2014-03-07 07:04:39 +04:00
switch ( get_protocol ( skb ) ) {
2013-08-14 16:54:39 +04:00
case htons ( ETH_P_IP ) :
opts2 | = IPV4_CS ;
ip_protocol = ip_hdr ( skb ) - > protocol ;
break ;
case htons ( ETH_P_IPV6 ) :
opts2 | = IPV6_CS ;
ip_protocol = ipv6_hdr ( skb ) - > nexthdr ;
break ;
default :
ip_protocol = IPPROTO_RAW ;
break ;
}
2014-03-07 07:04:39 +04:00
if ( ip_protocol = = IPPROTO_TCP )
2013-08-14 16:54:39 +04:00
opts2 | = TCP_CS ;
2014-03-07 07:04:39 +04:00
else if ( ip_protocol = = IPPROTO_UDP )
2013-08-14 16:54:39 +04:00
opts2 | = UDP_CS ;
2014-03-07 07:04:39 +04:00
else
2013-08-14 16:54:39 +04:00
WARN_ON_ONCE ( 1 ) ;
2014-03-07 07:04:39 +04:00
opts2 | = transport_offset < < TCPHO_SHIFT ;
2013-08-14 16:54:39 +04:00
}
2014-03-07 07:04:39 +04:00
desc - > opts2 = cpu_to_le32 ( opts2 ) ;
desc - > opts1 = cpu_to_le32 ( opts1 ) ;
2014-03-07 07:04:40 +04:00
unavailable :
2014-03-07 07:04:39 +04:00
return ret ;
2013-08-14 16:54:39 +04:00
}
2013-08-16 12:09:37 +04:00
static int r8152_tx_agg_fill ( struct r8152 * tp , struct tx_agg * agg )
{
2014-02-18 17:49:02 +04:00
struct sk_buff_head skb_head , * tx_queue = & tp - > tx_queue ;
2014-02-18 17:49:07 +04:00
int remain , ret ;
2013-08-16 12:09:37 +04:00
u8 * tx_data ;
2014-02-18 17:49:02 +04:00
__skb_queue_head_init ( & skb_head ) ;
2014-03-07 07:04:36 +04:00
spin_lock ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
skb_queue_splice_init ( tx_queue , & skb_head ) ;
2014-03-07 07:04:36 +04:00
spin_unlock ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
2013-08-16 12:09:37 +04:00
tx_data = agg - > head ;
2014-08-25 11:53:00 +04:00
agg - > skb_num = 0 ;
agg - > skb_len = 0 ;
2014-09-02 06:27:52 +04:00
remain = agg_buf_sz ;
2013-08-16 12:09:37 +04:00
2013-11-20 13:30:54 +04:00
while ( remain > = ETH_ZLEN + sizeof ( struct tx_desc ) ) {
2013-08-16 12:09:37 +04:00
struct tx_desc * tx_desc ;
struct sk_buff * skb ;
unsigned int len ;
2014-03-07 07:04:39 +04:00
u32 offset ;
2013-08-16 12:09:37 +04:00
2014-02-18 17:49:02 +04:00
skb = __skb_dequeue ( & skb_head ) ;
2013-08-16 12:09:37 +04:00
if ( ! skb )
break ;
2014-03-07 07:04:39 +04:00
len = skb - > len + sizeof ( * tx_desc ) ;
if ( len > remain ) {
2014-02-18 17:49:02 +04:00
__skb_queue_head ( & skb_head , skb ) ;
2013-08-16 12:09:37 +04:00
break ;
}
2013-11-20 13:30:54 +04:00
tx_data = tx_agg_align ( tx_data ) ;
2013-08-16 12:09:37 +04:00
tx_desc = ( struct tx_desc * ) tx_data ;
2014-03-07 07:04:39 +04:00
offset = ( u32 ) skb_transport_offset ( skb ) ;
2014-03-07 07:04:40 +04:00
if ( r8152_tx_csum ( tp , tx_desc , skb , skb - > len , offset ) ) {
r8152_csum_workaround ( tp , skb , & skb_head ) ;
continue ;
}
2014-03-07 07:04:39 +04:00
2014-09-12 06:43:11 +04:00
rtl_tx_vlan_tag ( tx_desc , skb ) ;
2013-08-16 12:09:37 +04:00
tx_data + = sizeof ( * tx_desc ) ;
2014-03-07 07:04:39 +04:00
len = skb - > len ;
if ( skb_copy_bits ( skb , 0 , tx_data , len ) < 0 ) {
struct net_device_stats * stats = & tp - > netdev - > stats ;
stats - > tx_dropped + + ;
dev_kfree_skb_any ( skb ) ;
tx_data - = sizeof ( * tx_desc ) ;
continue ;
}
tx_data + = len ;
2013-08-16 12:09:37 +04:00
agg - > skb_len + = len ;
2014-03-07 07:04:39 +04:00
agg - > skb_num + + ;
2013-08-16 12:09:37 +04:00
dev_kfree_skb_any ( skb ) ;
2014-09-02 06:27:52 +04:00
remain = agg_buf_sz - ( int ) ( tx_agg_align ( tx_data ) - agg - > head ) ;
2013-08-16 12:09:37 +04:00
}
2014-02-18 17:49:02 +04:00
if ( ! skb_queue_empty ( & skb_head ) ) {
2014-03-07 07:04:36 +04:00
spin_lock ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
skb_queue_splice ( & skb_head , tx_queue ) ;
2014-03-07 07:04:36 +04:00
spin_unlock ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
}
2014-03-07 07:04:36 +04:00
netif_tx_lock ( tp - > netdev ) ;
2013-11-20 13:30:56 +04:00
if ( netif_queue_stopped ( tp - > netdev ) & &
skb_queue_len ( & tp - > tx_queue ) < tp - > tx_qlen )
netif_wake_queue ( tp - > netdev ) ;
2014-03-07 07:04:36 +04:00
netif_tx_unlock ( tp - > netdev ) ;
2014-02-18 17:49:07 +04:00
2014-03-07 07:04:36 +04:00
ret = usb_autopm_get_interface_async ( tp - > intf ) ;
2014-02-18 17:49:07 +04:00
if ( ret < 0 )
goto out_tx_fill ;
2013-11-20 13:30:56 +04:00
2013-08-16 12:09:37 +04:00
usb_fill_bulk_urb ( agg - > urb , tp - > udev , usb_sndbulkpipe ( tp - > udev , 2 ) ,
agg - > head , ( int ) ( tx_data - ( u8 * ) agg - > head ) ,
( usb_complete_t ) write_bulk_callback , agg ) ;
2014-03-07 07:04:36 +04:00
ret = usb_submit_urb ( agg - > urb , GFP_ATOMIC ) ;
2014-02-18 17:49:07 +04:00
if ( ret < 0 )
2014-03-07 07:04:36 +04:00
usb_autopm_put_interface_async ( tp - > intf ) ;
2014-02-18 17:49:07 +04:00
out_tx_fill :
return ret ;
2013-08-16 12:09:37 +04:00
}
2014-03-07 07:04:38 +04:00
static u8 r8152_rx_csum ( struct r8152 * tp , struct rx_desc * rx_desc )
{
u8 checksum = CHECKSUM_NONE ;
u32 opts2 , opts3 ;
if ( tp - > version = = RTL_VER_01 )
goto return_result ;
opts2 = le32_to_cpu ( rx_desc - > opts2 ) ;
opts3 = le32_to_cpu ( rx_desc - > opts3 ) ;
if ( opts2 & RD_IPV4_CS ) {
if ( opts3 & IPF )
checksum = CHECKSUM_NONE ;
else if ( ( opts2 & RD_UDP_CS ) & & ( opts3 & UDPF ) )
checksum = CHECKSUM_NONE ;
else if ( ( opts2 & RD_TCP_CS ) & & ( opts3 & TCPF ) )
checksum = CHECKSUM_NONE ;
else
checksum = CHECKSUM_UNNECESSARY ;
2014-03-07 07:04:40 +04:00
} else if ( RD_IPV6_CS ) {
if ( ( opts2 & RD_UDP_CS ) & & ! ( opts3 & UDPF ) )
checksum = CHECKSUM_UNNECESSARY ;
else if ( ( opts2 & RD_TCP_CS ) & & ! ( opts3 & TCPF ) )
checksum = CHECKSUM_UNNECESSARY ;
2014-03-07 07:04:38 +04:00
}
return_result :
return checksum ;
}
2013-08-14 16:54:38 +04:00
static void rx_bottom ( struct r8152 * tp )
{
2013-08-16 12:09:34 +04:00
unsigned long flags ;
2014-02-18 17:49:02 +04:00
struct list_head * cursor , * next , rx_queue ;
2013-08-14 16:54:38 +04:00
2014-02-18 17:49:02 +04:00
if ( list_empty ( & tp - > rx_done ) )
return ;
INIT_LIST_HEAD ( & rx_queue ) ;
2013-08-16 12:09:34 +04:00
spin_lock_irqsave ( & tp - > rx_lock , flags ) ;
2014-02-18 17:49:02 +04:00
list_splice_init ( & tp - > rx_done , & rx_queue ) ;
spin_unlock_irqrestore ( & tp - > rx_lock , flags ) ;
list_for_each_safe ( cursor , next , & rx_queue ) {
2013-08-16 12:09:36 +04:00
struct rx_desc * rx_desc ;
struct rx_agg * agg ;
int len_used = 0 ;
struct urb * urb ;
u8 * rx_data ;
int ret ;
2013-08-14 16:54:38 +04:00
list_del_init ( cursor ) ;
agg = list_entry ( cursor , struct rx_agg , list ) ;
urb = agg - > urb ;
2013-08-16 12:09:35 +04:00
if ( urb - > actual_length < ETH_ZLEN )
goto submit ;
2013-08-14 16:54:38 +04:00
rx_desc = agg - > head ;
rx_data = agg - > head ;
2013-11-20 13:30:54 +04:00
len_used + = sizeof ( struct rx_desc ) ;
2013-08-14 16:54:38 +04:00
2013-11-20 13:30:54 +04:00
while ( urb - > actual_length > len_used ) {
2013-08-16 12:09:36 +04:00
struct net_device * netdev = tp - > netdev ;
2014-03-06 11:07:18 +04:00
struct net_device_stats * stats = & netdev - > stats ;
2013-11-20 13:30:54 +04:00
unsigned int pkt_len ;
2013-08-16 12:09:36 +04:00
struct sk_buff * skb ;
2013-11-20 13:30:54 +04:00
pkt_len = le32_to_cpu ( rx_desc - > opts1 ) & RX_LEN_MASK ;
2013-08-14 16:54:38 +04:00
if ( pkt_len < ETH_ZLEN )
break ;
2013-11-20 13:30:54 +04:00
len_used + = pkt_len ;
if ( urb - > actual_length < len_used )
break ;
2014-01-02 07:22:41 +04:00
pkt_len - = CRC_SIZE ;
2013-08-14 16:54:38 +04:00
rx_data + = sizeof ( struct rx_desc ) ;
skb = netdev_alloc_skb_ip_align ( netdev , pkt_len ) ;
if ( ! skb ) {
stats - > rx_dropped + + ;
2014-03-07 07:04:37 +04:00
goto find_next_rx ;
2013-08-14 16:54:38 +04:00
}
2014-03-07 07:04:38 +04:00
skb - > ip_summed = r8152_rx_csum ( tp , rx_desc ) ;
2013-08-14 16:54:38 +04:00
memcpy ( skb - > data , rx_data , pkt_len ) ;
skb_put ( skb , pkt_len ) ;
skb - > protocol = eth_type_trans ( skb , netdev ) ;
2014-09-12 06:43:11 +04:00
rtl_rx_vlan_tag ( rx_desc , skb ) ;
2014-02-18 17:49:09 +04:00
netif_receive_skb ( skb ) ;
2013-08-14 16:54:38 +04:00
stats - > rx_packets + + ;
stats - > rx_bytes + = pkt_len ;
2014-03-07 07:04:37 +04:00
find_next_rx :
2014-01-02 07:22:41 +04:00
rx_data = rx_agg_align ( rx_data + pkt_len + CRC_SIZE ) ;
2013-08-14 16:54:38 +04:00
rx_desc = ( struct rx_desc * ) rx_data ;
len_used = ( int ) ( rx_data - ( u8 * ) agg - > head ) ;
2013-11-20 13:30:54 +04:00
len_used + = sizeof ( struct rx_desc ) ;
2013-08-14 16:54:38 +04:00
}
2013-08-16 12:09:35 +04:00
submit :
2013-08-14 16:54:38 +04:00
ret = r8152_submit_rx ( tp , agg , GFP_ATOMIC ) ;
if ( ret & & ret ! = - ENODEV ) {
2014-02-18 17:49:02 +04:00
spin_lock_irqsave ( & tp - > rx_lock , flags ) ;
list_add_tail ( & agg - > list , & tp - > rx_done ) ;
spin_unlock_irqrestore ( & tp - > rx_lock , flags ) ;
2013-08-14 16:54:38 +04:00
tasklet_schedule ( & tp - > tl ) ;
}
}
}
static void tx_bottom ( struct r8152 * tp )
{
int res ;
2013-08-16 12:09:37 +04:00
do {
struct tx_agg * agg ;
2013-08-14 16:54:38 +04:00
2013-08-16 12:09:37 +04:00
if ( skb_queue_empty ( & tp - > tx_queue ) )
2013-08-14 16:54:38 +04:00
break ;
2013-08-16 12:09:37 +04:00
agg = r8152_get_tx_agg ( tp ) ;
if ( ! agg )
2013-08-14 16:54:38 +04:00
break ;
2013-08-16 12:09:37 +04:00
res = r8152_tx_agg_fill ( tp , agg ) ;
if ( res ) {
2014-03-06 11:07:18 +04:00
struct net_device * netdev = tp - > netdev ;
2013-08-14 16:54:38 +04:00
2013-08-16 12:09:37 +04:00
if ( res = = - ENODEV ) {
netif_device_detach ( netdev ) ;
} else {
2014-03-06 11:07:18 +04:00
struct net_device_stats * stats = & netdev - > stats ;
unsigned long flags ;
2013-08-16 12:09:37 +04:00
netif_warn ( tp , tx_err , netdev ,
" failed tx_urb %d \n " , res ) ;
stats - > tx_dropped + = agg - > skb_num ;
2014-03-06 11:07:16 +04:00
2013-08-16 12:09:37 +04:00
spin_lock_irqsave ( & tp - > tx_lock , flags ) ;
list_add_tail ( & agg - > list , & tp - > tx_free ) ;
spin_unlock_irqrestore ( & tp - > tx_lock , flags ) ;
}
2013-08-14 16:54:38 +04:00
}
2013-08-16 12:09:37 +04:00
} while ( res = = 0 ) ;
2013-08-14 16:54:38 +04:00
}
static void bottom_half ( unsigned long data )
2013-05-02 20:01:25 +04:00
{
struct r8152 * tp ;
2013-08-14 16:54:38 +04:00
tp = ( struct r8152 * ) data ;
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
if ( ! test_bit ( WORK_ENABLE , & tp - > flags ) )
2013-05-02 20:01:25 +04:00
return ;
2013-08-14 16:54:38 +04:00
2013-08-16 12:09:38 +04:00
/* When link down, the driver would cancel all bulks. */
/* This avoid the re-submitting bulk */
2013-08-14 16:54:38 +04:00
if ( ! netif_carrier_ok ( tp - > netdev ) )
2013-05-02 20:01:25 +04:00
return ;
2013-08-14 16:54:38 +04:00
rx_bottom ( tp ) ;
2014-03-07 07:04:36 +04:00
tx_bottom ( tp ) ;
2013-08-14 16:54:38 +04:00
}
static
int r8152_submit_rx ( struct r8152 * tp , struct rx_agg * agg , gfp_t mem_flags )
{
usb_fill_bulk_urb ( agg - > urb , tp - > udev , usb_rcvbulkpipe ( tp - > udev , 1 ) ,
2014-09-02 06:27:52 +04:00
agg - > head , agg_buf_sz ,
2014-08-25 11:53:00 +04:00
( usb_complete_t ) read_bulk_callback , agg ) ;
2013-08-14 16:54:38 +04:00
return usb_submit_urb ( agg - > urb , mem_flags ) ;
2013-05-02 20:01:25 +04:00
}
2014-02-18 17:48:59 +04:00
static void rtl_drop_queued_tx ( struct r8152 * tp )
{
struct net_device_stats * stats = & tp - > netdev - > stats ;
2014-02-18 17:49:02 +04:00
struct sk_buff_head skb_head , * tx_queue = & tp - > tx_queue ;
2014-02-18 17:48:59 +04:00
struct sk_buff * skb ;
2014-02-18 17:49:02 +04:00
if ( skb_queue_empty ( tx_queue ) )
return ;
__skb_queue_head_init ( & skb_head ) ;
2014-03-07 07:04:34 +04:00
spin_lock_bh ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
skb_queue_splice_init ( tx_queue , & skb_head ) ;
2014-03-07 07:04:34 +04:00
spin_unlock_bh ( & tx_queue - > lock ) ;
2014-02-18 17:49:02 +04:00
while ( ( skb = __skb_dequeue ( & skb_head ) ) ) {
2014-02-18 17:48:59 +04:00
dev_kfree_skb ( skb ) ;
stats - > tx_dropped + + ;
}
}
2013-05-02 20:01:25 +04:00
static void rtl8152_tx_timeout ( struct net_device * netdev )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2013-08-14 16:54:38 +04:00
int i ;
2014-01-07 07:18:22 +04:00
netif_warn ( tp , tx_err , netdev , " Tx timeout \n " ) ;
2013-08-14 16:54:38 +04:00
for ( i = 0 ; i < RTL8152_MAX_TX ; i + + )
usb_unlink_urb ( tp - > tx_info [ i ] . urb ) ;
2013-05-02 20:01:25 +04:00
}
static void rtl8152_set_rx_mode ( struct net_device * netdev )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2013-08-14 16:54:40 +04:00
if ( tp - > speed & LINK_STATUS ) {
2013-05-02 20:01:25 +04:00
set_bit ( RTL8152_SET_RX_MODE , & tp - > flags ) ;
2013-08-14 16:54:40 +04:00
schedule_delayed_work ( & tp - > schedule , 0 ) ;
}
2013-05-02 20:01:25 +04:00
}
static void _rtl8152_set_rx_mode ( struct net_device * netdev )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2013-07-31 13:21:25 +04:00
u32 mc_filter [ 2 ] ; /* Multicast hash filter */
__le32 tmp [ 2 ] ;
2013-05-02 20:01:25 +04:00
u32 ocp_data ;
clear_bit ( RTL8152_SET_RX_MODE , & tp - > flags ) ;
netif_stop_queue ( netdev ) ;
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data & = ~ RCR_ACPT_ALL ;
ocp_data | = RCR_AB | RCR_APM ;
if ( netdev - > flags & IFF_PROMISC ) {
/* Unconditionally log net taps. */
netif_notice ( tp , link , netdev , " Promiscuous mode enabled \n " ) ;
ocp_data | = RCR_AM | RCR_AAP ;
2014-08-25 11:53:00 +04:00
mc_filter [ 1 ] = 0xffffffff ;
mc_filter [ 0 ] = 0xffffffff ;
2013-05-02 20:01:25 +04:00
} else if ( ( netdev_mc_count ( netdev ) > multicast_filter_limit ) | |
( netdev - > flags & IFF_ALLMULTI ) ) {
/* Too many to filter perfectly -- accept all multicasts. */
ocp_data | = RCR_AM ;
2014-08-25 11:53:00 +04:00
mc_filter [ 1 ] = 0xffffffff ;
mc_filter [ 0 ] = 0xffffffff ;
2013-05-02 20:01:25 +04:00
} else {
struct netdev_hw_addr * ha ;
2014-08-25 11:53:00 +04:00
mc_filter [ 1 ] = 0 ;
mc_filter [ 0 ] = 0 ;
2013-05-02 20:01:25 +04:00
netdev_for_each_mc_addr ( ha , netdev ) {
int bit_nr = ether_crc ( ETH_ALEN , ha - > addr ) > > 26 ;
2014-08-25 11:53:00 +04:00
2013-05-02 20:01:25 +04:00
mc_filter [ bit_nr > > 5 ] | = 1 < < ( bit_nr & 31 ) ;
ocp_data | = RCR_AM ;
}
}
2013-07-31 13:21:25 +04:00
tmp [ 0 ] = __cpu_to_le32 ( swab32 ( mc_filter [ 1 ] ) ) ;
tmp [ 1 ] = __cpu_to_le32 ( swab32 ( mc_filter [ 0 ] ) ) ;
2013-05-02 20:01:25 +04:00
2013-07-31 13:21:25 +04:00
pla_ocp_write ( tp , PLA_MAR , BYTE_EN_DWORD , sizeof ( tmp ) , tmp ) ;
2013-05-02 20:01:25 +04:00
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
netif_wake_queue ( netdev ) ;
}
static netdev_tx_t rtl8152_start_xmit ( struct sk_buff * skb ,
2014-08-25 11:53:00 +04:00
struct net_device * netdev )
2013-05-02 20:01:25 +04:00
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2013-08-14 16:54:38 +04:00
skb_tx_timestamp ( skb ) ;
2013-05-02 20:01:25 +04:00
2013-11-20 13:30:55 +04:00
skb_queue_tail ( & tp - > tx_queue , skb ) ;
2013-08-14 16:54:38 +04:00
2014-03-07 07:04:36 +04:00
if ( ! list_empty ( & tp - > tx_free ) ) {
if ( test_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ) {
set_bit ( SCHEDULE_TASKLET , & tp - > flags ) ;
schedule_delayed_work ( & tp - > schedule , 0 ) ;
} else {
usb_mark_last_busy ( tp - > udev ) ;
tasklet_schedule ( & tp - > tl ) ;
}
2014-08-25 11:53:00 +04:00
} else if ( skb_queue_len ( & tp - > tx_queue ) > tp - > tx_qlen ) {
2013-11-20 13:30:56 +04:00
netif_stop_queue ( netdev ) ;
2014-08-25 11:53:00 +04:00
}
2013-11-20 13:30:56 +04:00
2013-05-02 20:01:25 +04:00
return NETDEV_TX_OK ;
}
static void r8152b_reset_packet_filter ( struct r8152 * tp )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_FMC ) ;
ocp_data & = ~ FMC_FCR_MCU_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_FMC , ocp_data ) ;
ocp_data | = FMC_FCR_MCU_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_FMC , ocp_data ) ;
}
static void rtl8152_nic_reset ( struct r8152 * tp )
{
int i ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CR , CR_RST ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
if ( ! ( ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_CR ) & CR_RST ) )
break ;
2014-08-25 11:53:00 +04:00
usleep_range ( 100 , 400 ) ;
2013-05-02 20:01:25 +04:00
}
}
2013-11-20 13:30:56 +04:00
static void set_tx_qlen ( struct r8152 * tp )
{
struct net_device * netdev = tp - > netdev ;
2014-09-02 06:27:52 +04:00
tp - > tx_qlen = agg_buf_sz / ( netdev - > mtu + VLAN_ETH_HLEN + VLAN_HLEN +
sizeof ( struct tx_desc ) ) ;
2013-11-20 13:30:56 +04:00
}
2013-05-02 20:01:25 +04:00
static inline u8 rtl8152_get_speed ( struct r8152 * tp )
{
return ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_PHYSTATUS ) ;
}
2014-01-02 07:22:43 +04:00
static void rtl_set_eee_plus ( struct r8152 * tp )
2013-05-02 20:01:25 +04:00
{
2013-08-14 16:54:38 +04:00
u32 ocp_data ;
2013-05-02 20:01:25 +04:00
u8 speed ;
speed = rtl8152_get_speed ( tp ) ;
2013-08-14 16:54:38 +04:00
if ( speed & _10bps ) {
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEEP_CR ) ;
2013-08-14 16:54:38 +04:00
ocp_data | = EEEP_CR_EEEP_TX ;
2013-05-02 20:01:25 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_EEEP_CR , ocp_data ) ;
} else {
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEEP_CR ) ;
2013-08-14 16:54:38 +04:00
ocp_data & = ~ EEEP_CR_EEEP_TX ;
2013-05-02 20:01:25 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_EEEP_CR , ocp_data ) ;
}
2014-01-02 07:22:43 +04:00
}
2014-02-18 17:48:59 +04:00
static void rxdy_gated_en ( struct r8152 * tp , bool enable )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_MISC_1 ) ;
if ( enable )
ocp_data | = RXDY_GATED_EN ;
else
ocp_data & = ~ RXDY_GATED_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_MISC_1 , ocp_data ) ;
}
2014-09-23 12:31:47 +04:00
static int rtl_start_rx ( struct r8152 * tp )
{
int i , ret = 0 ;
INIT_LIST_HEAD ( & tp - > rx_done ) ;
for ( i = 0 ; i < RTL8152_MAX_RX ; i + + ) {
INIT_LIST_HEAD ( & tp - > rx_info [ i ] . list ) ;
ret = r8152_submit_rx ( tp , & tp - > rx_info [ i ] , GFP_KERNEL ) ;
if ( ret )
break ;
}
return ret ;
}
static int rtl_stop_rx ( struct r8152 * tp )
{
int i ;
for ( i = 0 ; i < RTL8152_MAX_RX ; i + + )
usb_kill_urb ( tp - > rx_info [ i ] . urb ) ;
return 0 ;
}
2014-01-02 07:22:43 +04:00
static int rtl_enable ( struct r8152 * tp )
{
u32 ocp_data ;
2013-05-02 20:01:25 +04:00
r8152b_reset_packet_filter ( tp ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_CR ) ;
ocp_data | = CR_RE | CR_TE ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CR , ocp_data ) ;
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , false ) ;
2013-05-02 20:01:25 +04:00
2014-09-23 12:31:47 +04:00
return rtl_start_rx ( tp ) ;
2013-05-02 20:01:25 +04:00
}
2014-01-02 07:22:43 +04:00
static int rtl8152_enable ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
2014-01-02 07:22:43 +04:00
set_tx_qlen ( tp ) ;
rtl_set_eee_plus ( tp ) ;
return rtl_enable ( tp ) ;
}
2014-01-02 07:25:10 +04:00
static void r8153_set_rx_agg ( struct r8152 * tp )
{
u8 speed ;
speed = rtl8152_get_speed ( tp ) ;
if ( speed & _1000bps ) {
if ( tp - > udev - > speed = = USB_SPEED_SUPER ) {
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_BUF_TH ,
RX_THR_SUPPER ) ;
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_EARLY_AGG ,
EARLY_AGG_SUPPER ) ;
} else {
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_BUF_TH ,
RX_THR_HIGH ) ;
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_EARLY_AGG ,
EARLY_AGG_HIGH ) ;
}
} else {
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_BUF_TH , RX_THR_SLOW ) ;
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_EARLY_AGG ,
EARLY_AGG_SLOW ) ;
}
}
static int rtl8153_enable ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
2014-01-02 07:25:10 +04:00
set_tx_qlen ( tp ) ;
rtl_set_eee_plus ( tp ) ;
r8153_set_rx_agg ( tp ) ;
return rtl_enable ( tp ) ;
}
2014-09-19 11:17:18 +04:00
static void rtl_disable ( struct r8152 * tp )
2013-05-02 20:01:25 +04:00
{
2013-08-14 16:54:38 +04:00
u32 ocp_data ;
int i ;
2013-05-02 20:01:25 +04:00
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) ) {
rtl_drop_queued_tx ( tp ) ;
return ;
}
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data & = ~ RCR_ACPT_ALL ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
2014-02-18 17:48:59 +04:00
rtl_drop_queued_tx ( tp ) ;
2013-08-14 16:54:38 +04:00
for ( i = 0 ; i < RTL8152_MAX_TX ; i + + )
usb_kill_urb ( tp - > tx_info [ i ] . urb ) ;
2013-05-02 20:01:25 +04:00
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , true ) ;
2013-05-02 20:01:25 +04:00
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ( ocp_data & FIFO_EMPTY ) = = FIFO_EMPTY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
for ( i = 0 ; i < 1000 ; i + + ) {
if ( ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TCR0 ) & TCR0_TX_EMPTY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
2014-09-23 12:31:47 +04:00
rtl_stop_rx ( tp ) ;
2013-05-02 20:01:25 +04:00
rtl8152_nic_reset ( tp ) ;
}
2014-02-18 17:48:59 +04:00
static void r8152_power_cut_en ( struct r8152 * tp , bool enable )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_UPS_CTRL ) ;
if ( enable )
ocp_data | = POWER_CUT ;
else
ocp_data & = ~ POWER_CUT ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_UPS_CTRL , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_PM_CTRL_STATUS ) ;
ocp_data & = ~ RESUME_INDICATE ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_PM_CTRL_STATUS , ocp_data ) ;
}
2014-09-12 06:43:11 +04:00
static void rtl_rx_vlan_en ( struct r8152 * tp , bool enable )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CPCR ) ;
if ( enable )
ocp_data | = CPCR_RX_VLAN ;
else
ocp_data & = ~ CPCR_RX_VLAN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_CPCR , ocp_data ) ;
}
static int rtl8152_set_features ( struct net_device * dev ,
netdev_features_t features )
{
netdev_features_t changed = features ^ dev - > features ;
struct r8152 * tp = netdev_priv ( dev ) ;
if ( changed & NETIF_F_HW_VLAN_CTAG_RX ) {
if ( features & NETIF_F_HW_VLAN_CTAG_RX )
rtl_rx_vlan_en ( tp , true ) ;
else
rtl_rx_vlan_en ( tp , false ) ;
}
return 0 ;
}
2014-02-18 17:49:06 +04:00
# define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
static u32 __rtl_get_wol ( struct r8152 * tp )
{
u32 ocp_data ;
u32 wolopts = 0 ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_CONFIG5 ) ;
if ( ! ( ocp_data & LAN_WAKE_EN ) )
return 0 ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CONFIG34 ) ;
if ( ocp_data & LINK_ON_WAKE_EN )
wolopts | = WAKE_PHY ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CONFIG5 ) ;
if ( ocp_data & UWF_EN )
wolopts | = WAKE_UCAST ;
if ( ocp_data & BWF_EN )
wolopts | = WAKE_BCAST ;
if ( ocp_data & MWF_EN )
wolopts | = WAKE_MCAST ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CFG_WOL ) ;
if ( ocp_data & MAGIC_EN )
wolopts | = WAKE_MAGIC ;
return wolopts ;
}
static void __rtl_set_wol ( struct r8152 * tp , u32 wolopts )
{
u32 ocp_data ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_CONFIG ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CONFIG34 ) ;
ocp_data & = ~ LINK_ON_WAKE_EN ;
if ( wolopts & WAKE_PHY )
ocp_data | = LINK_ON_WAKE_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_CONFIG34 , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CONFIG5 ) ;
ocp_data & = ~ ( UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN ) ;
if ( wolopts & WAKE_UCAST )
ocp_data | = UWF_EN ;
if ( wolopts & WAKE_BCAST )
ocp_data | = BWF_EN ;
if ( wolopts & WAKE_MCAST )
ocp_data | = MWF_EN ;
if ( wolopts & WAKE_ANY )
ocp_data | = LAN_WAKE_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_CONFIG5 , ocp_data ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_NORAML ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CFG_WOL ) ;
ocp_data & = ~ MAGIC_EN ;
if ( wolopts & WAKE_MAGIC )
ocp_data | = MAGIC_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_CFG_WOL , ocp_data ) ;
if ( wolopts & WAKE_ANY )
device_set_wakeup_enable ( & tp - > udev - > dev , true ) ;
else
device_set_wakeup_enable ( & tp - > udev - > dev , false ) ;
}
2014-02-18 17:49:07 +04:00
static void rtl_runtime_suspend_enable ( struct r8152 * tp , bool enable )
{
if ( enable ) {
u32 ocp_data ;
__rtl_set_wol ( tp , WAKE_ANY ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_CONFIG ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_CONFIG34 ) ;
ocp_data | = LINK_OFF_WAKE_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_CONFIG34 , ocp_data ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_NORAML ) ;
} else {
__rtl_set_wol ( tp , tp - > saved_wolopts ) ;
}
}
2014-02-18 17:49:04 +04:00
static void rtl_phy_reset ( struct r8152 * tp )
{
u16 data ;
int i ;
clear_bit ( PHY_RESET , & tp - > flags ) ;
data = r8152_mdio_read ( tp , MII_BMCR ) ;
/* don't reset again before the previous one complete */
if ( data & BMCR_RESET )
return ;
data | = BMCR_RESET ;
r8152_mdio_write ( tp , MII_BMCR , data ) ;
for ( i = 0 ; i < 50 ; i + + ) {
msleep ( 20 ) ;
if ( ( r8152_mdio_read ( tp , MII_BMCR ) & BMCR_RESET ) = = 0 )
break ;
}
}
2014-02-18 17:48:58 +04:00
static void r8153_teredo_off ( struct r8152 * tp )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TEREDO_CFG ) ;
ocp_data & = ~ ( TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_TEREDO_CFG , ocp_data ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_WDT6_CTRL , WDT6_SET_MODE ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_REALWOW_TIMER , 0 ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_TEREDO_TIMER , 0 ) ;
}
static void r8152b_disable_aldps ( struct r8152 * tp )
{
ocp_reg_write ( tp , OCP_ALDPS_CONFIG , ENPDNPS | LINKENA | DIS_SDSAVE ) ;
msleep ( 20 ) ;
}
static inline void r8152b_enable_aldps ( struct r8152 * tp )
{
ocp_reg_write ( tp , OCP_ALDPS_CONFIG , ENPWRSAVE | ENPDNPS |
LINKENA | DIS_SDSAVE ) ;
}
2014-09-19 11:17:18 +04:00
static void rtl8152_disable ( struct r8152 * tp )
{
r8152b_disable_aldps ( tp ) ;
rtl_disable ( tp ) ;
r8152b_enable_aldps ( tp ) ;
}
2014-02-18 17:48:58 +04:00
static void r8152b_hw_phy_cfg ( struct r8152 * tp )
{
2014-02-18 17:49:03 +04:00
u16 data ;
data = r8152_mdio_read ( tp , MII_BMCR ) ;
if ( data & BMCR_PDOWN ) {
data & = ~ BMCR_PDOWN ;
r8152_mdio_write ( tp , MII_BMCR , data ) ;
}
2014-02-18 17:49:04 +04:00
set_bit ( PHY_RESET , & tp - > flags ) ;
2014-02-18 17:48:58 +04:00
}
2013-05-02 20:01:25 +04:00
static void r8152b_exit_oob ( struct r8152 * tp )
{
2014-03-06 11:07:16 +04:00
u32 ocp_data ;
int i ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data & = ~ RCR_ACPT_ALL ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , true ) ;
2014-02-18 17:49:08 +04:00
r8153_teredo_off ( tp ) ;
2014-02-18 17:49:05 +04:00
r8152b_hw_phy_cfg ( tp ) ;
2013-05-02 20:01:25 +04:00
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CRWECR , CRWECR_NORAML ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_CR , 0x00 ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data & = ~ NOW_IS_OOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data & = ~ MCU_BORW_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data | = RE_INIT_LL ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
rtl8152_nic_reset ( tp ) ;
/* rx share fifo credit full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL0 , RXFIFO_THR1_NORMAL ) ;
2014-07-24 12:37:43 +04:00
if ( tp - > udev - > speed = = USB_SPEED_FULL | |
tp - > udev - > speed = = USB_SPEED_LOW ) {
2013-05-02 20:01:25 +04:00
/* rx share fifo credit near full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL1 ,
RXFIFO_THR2_FULL ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL2 ,
RXFIFO_THR3_FULL ) ;
} else {
/* rx share fifo credit near full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL1 ,
RXFIFO_THR2_HIGH ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL2 ,
RXFIFO_THR3_HIGH ) ;
}
/* TX share fifo free credit full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_TXFIFO_CTRL , TXFIFO_THR_NORMAL ) ;
ocp_write_byte ( tp , MCU_TYPE_USB , USB_TX_AGG , TX_AGG_MAX_THRESHOLD ) ;
2014-01-02 07:22:41 +04:00
ocp_write_dword ( tp , MCU_TYPE_USB , USB_RX_BUF_TH , RX_THR_HIGH ) ;
2013-05-02 20:01:25 +04:00
ocp_write_dword ( tp , MCU_TYPE_USB , USB_TX_DMA ,
TEST_MODE_DISABLE | TX_SIZE_ADJUST1 ) ;
2014-09-12 06:43:11 +04:00
rtl_rx_vlan_en ( tp , tp - > netdev - > features & NETIF_F_HW_VLAN_CTAG_RX ) ;
2013-05-02 20:01:25 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RMS , RTL8152_RMS ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TCR0 ) ;
ocp_data | = TCR0_AUTO_FIFO ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_TCR0 , ocp_data ) ;
}
static void r8152b_enter_oob ( struct r8152 * tp )
{
2014-01-06 13:08:41 +04:00
u32 ocp_data ;
int i ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data & = ~ NOW_IS_OOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL0 , RXFIFO_THR1_OOB ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL1 , RXFIFO_THR2_OOB ) ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL2 , RXFIFO_THR3_OOB ) ;
2014-09-19 11:17:18 +04:00
rtl_disable ( tp ) ;
2013-05-02 20:01:25 +04:00
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data | = RE_INIT_LL ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2013-05-02 20:01:25 +04:00
}
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RMS , RTL8152_RMS ) ;
2014-09-12 06:43:11 +04:00
rtl_rx_vlan_en ( tp , true ) ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PAL_BDC_CR ) ;
ocp_data | = ALDPS_PROXY_MODE ;
ocp_write_word ( tp , MCU_TYPE_PLA , PAL_BDC_CR , ocp_data ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data | = NOW_IS_OOB | DIS_MCU_CLROOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , false ) ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data | = RCR_APM | RCR_AM | RCR_AB ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
}
2014-01-02 07:25:10 +04:00
static void r8153_hw_phy_cfg ( struct r8152 * tp )
{
u32 ocp_data ;
u16 data ;
ocp_reg_write ( tp , OCP_ADC_CFG , CKADSEL_L | ADC_EN | EN_EMI_L ) ;
2014-02-18 17:49:03 +04:00
data = r8152_mdio_read ( tp , MII_BMCR ) ;
if ( data & BMCR_PDOWN ) {
data & = ~ BMCR_PDOWN ;
r8152_mdio_write ( tp , MII_BMCR , data ) ;
}
2014-01-02 07:25:10 +04:00
if ( tp - > version = = RTL_VER_03 ) {
data = ocp_reg_read ( tp , OCP_EEE_CFG ) ;
data & = ~ CTAP_SHORT_EN ;
ocp_reg_write ( tp , OCP_EEE_CFG , data ) ;
}
data = ocp_reg_read ( tp , OCP_POWER_CFG ) ;
data | = EEE_CLKDIV_EN ;
ocp_reg_write ( tp , OCP_POWER_CFG , data ) ;
data = ocp_reg_read ( tp , OCP_DOWN_SPEED ) ;
data | = EN_10M_BGOFF ;
ocp_reg_write ( tp , OCP_DOWN_SPEED , data ) ;
data = ocp_reg_read ( tp , OCP_POWER_CFG ) ;
data | = EN_10M_PLLOFF ;
ocp_reg_write ( tp , OCP_POWER_CFG , data ) ;
data = sram_read ( tp , SRAM_IMPEDANCE ) ;
data & = ~ RX_DRIVING_MASK ;
sram_write ( tp , SRAM_IMPEDANCE , data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_PHY_PWR ) ;
ocp_data | = PFM_PWM_SWITCH ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_PHY_PWR , ocp_data ) ;
data = sram_read ( tp , SRAM_LPF_CFG ) ;
data | = LPF_AUTO_TUNE ;
sram_write ( tp , SRAM_LPF_CFG , data ) ;
data = sram_read ( tp , SRAM_10M_AMP1 ) ;
data | = GDAC_IB_UPALL ;
sram_write ( tp , SRAM_10M_AMP1 , data ) ;
data = sram_read ( tp , SRAM_10M_AMP2 ) ;
data | = AMP_DN ;
sram_write ( tp , SRAM_10M_AMP2 , data ) ;
2014-02-18 17:49:04 +04:00
set_bit ( PHY_RESET , & tp - > flags ) ;
2014-01-02 07:25:10 +04:00
}
2014-02-18 17:49:00 +04:00
static void r8153_u1u2en ( struct r8152 * tp , bool enable )
2014-01-02 07:25:10 +04:00
{
u8 u1u2 [ 8 ] ;
if ( enable )
memset ( u1u2 , 0xff , sizeof ( u1u2 ) ) ;
else
memset ( u1u2 , 0x00 , sizeof ( u1u2 ) ) ;
usb_ocp_write ( tp , USB_TOLERANCE , BYTE_EN_SIX_BYTES , sizeof ( u1u2 ) , u1u2 ) ;
}
2014-02-18 17:49:00 +04:00
static void r8153_u2p3en ( struct r8152 * tp , bool enable )
2014-01-02 07:25:10 +04:00
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_U2P3_CTRL ) ;
if ( enable )
ocp_data | = U2P3_ENABLE ;
else
ocp_data & = ~ U2P3_ENABLE ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_U2P3_CTRL , ocp_data ) ;
}
2014-02-18 17:49:00 +04:00
static void r8153_power_cut_en ( struct r8152 * tp , bool enable )
2014-01-02 07:25:10 +04:00
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_POWER_CUT ) ;
if ( enable )
ocp_data | = PWR_EN | PHASE2_EN ;
else
ocp_data & = ~ ( PWR_EN | PHASE2_EN ) ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_POWER_CUT , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_MISC_0 ) ;
ocp_data & = ~ PCUT_STATUS ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_MISC_0 , ocp_data ) ;
}
static void r8153_first_init ( struct r8152 * tp )
{
u32 ocp_data ;
int i ;
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , true ) ;
2014-01-02 07:25:10 +04:00
r8153_teredo_off ( tp ) ;
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data & = ~ RCR_ACPT_ALL ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
r8153_hw_phy_cfg ( tp ) ;
rtl8152_nic_reset ( tp ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data & = ~ NOW_IS_OOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data & = ~ MCU_BORW_EN ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-01-02 07:25:10 +04:00
}
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data | = RE_INIT_LL ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-01-02 07:25:10 +04:00
}
2014-09-12 06:43:11 +04:00
rtl_rx_vlan_en ( tp , tp - > netdev - > features & NETIF_F_HW_VLAN_CTAG_RX ) ;
2014-01-02 07:25:10 +04:00
2014-07-10 06:58:54 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RMS , RTL8153_RMS ) ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_MTPS , MTPS_JUMBO ) ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TCR0 ) ;
ocp_data | = TCR0_AUTO_FIFO ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_TCR0 , ocp_data ) ;
rtl8152_nic_reset ( tp ) ;
/* rx share fifo credit full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL0 , RXFIFO_THR1_NORMAL ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL1 , RXFIFO_THR2_NORMAL ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RXFIFO_CTRL2 , RXFIFO_THR3_NORMAL ) ;
/* TX share fifo free credit full threshold */
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_TXFIFO_CTRL , TXFIFO_THR_NORMAL2 ) ;
2014-01-15 06:42:15 +04:00
/* rx aggregation */
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_USB_CTRL ) ;
ocp_data & = ~ RX_AGG_DISABLE ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_USB_CTRL , ocp_data ) ;
}
static void r8153_enter_oob ( struct r8152 * tp )
{
u32 ocp_data ;
int i ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data & = ~ NOW_IS_OOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
2014-09-19 11:17:18 +04:00
rtl_disable ( tp ) ;
2014-01-02 07:25:10 +04:00
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-01-02 07:25:10 +04:00
}
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 ) ;
ocp_data | = RE_INIT_LL ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_SFF_STS_7 , ocp_data ) ;
for ( i = 0 ; i < 1000 ; i + + ) {
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
if ( ocp_data & LINK_LIST_READY )
break ;
2014-09-09 07:40:28 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-01-02 07:25:10 +04:00
}
2014-07-10 06:58:54 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RMS , RTL8153_RMS ) ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TEREDO_CFG ) ;
ocp_data & = ~ TEREDO_WAKE_MASK ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_TEREDO_CFG , ocp_data ) ;
2014-09-12 06:43:11 +04:00
rtl_rx_vlan_en ( tp , true ) ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PAL_BDC_CR ) ;
ocp_data | = ALDPS_PROXY_MODE ;
ocp_write_word ( tp , MCU_TYPE_PLA , PAL_BDC_CR , ocp_data ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL ) ;
ocp_data | = NOW_IS_OOB | DIS_MCU_CLROOB ;
ocp_write_byte ( tp , MCU_TYPE_PLA , PLA_OOB_CTRL , ocp_data ) ;
2014-02-18 17:48:59 +04:00
rxdy_gated_en ( tp , false ) ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_RCR ) ;
ocp_data | = RCR_APM | RCR_AM | RCR_AB ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_RCR , ocp_data ) ;
}
static void r8153_disable_aldps ( struct r8152 * tp )
{
u16 data ;
data = ocp_reg_read ( tp , OCP_POWER_CFG ) ;
data & = ~ EN_ALDPS ;
ocp_reg_write ( tp , OCP_POWER_CFG , data ) ;
msleep ( 20 ) ;
}
static void r8153_enable_aldps ( struct r8152 * tp )
{
u16 data ;
data = ocp_reg_read ( tp , OCP_POWER_CFG ) ;
data | = EN_ALDPS ;
ocp_reg_write ( tp , OCP_POWER_CFG , data ) ;
}
2014-09-19 11:17:18 +04:00
static void rtl8153_disable ( struct r8152 * tp )
{
r8153_disable_aldps ( tp ) ;
rtl_disable ( tp ) ;
r8153_enable_aldps ( tp ) ;
}
2013-05-02 20:01:25 +04:00
static int rtl8152_set_speed ( struct r8152 * tp , u8 autoneg , u16 speed , u8 duplex )
{
2014-01-02 07:25:10 +04:00
u16 bmcr , anar , gbcr ;
2013-05-02 20:01:25 +04:00
int ret = 0 ;
cancel_delayed_work_sync ( & tp - > schedule ) ;
anar = r8152_mdio_read ( tp , MII_ADVERTISE ) ;
anar & = ~ ( ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL ) ;
2014-01-02 07:25:10 +04:00
if ( tp - > mii . supports_gmii ) {
gbcr = r8152_mdio_read ( tp , MII_CTRL1000 ) ;
gbcr & = ~ ( ADVERTISE_1000FULL | ADVERTISE_1000HALF ) ;
} else {
gbcr = 0 ;
}
2013-05-02 20:01:25 +04:00
if ( autoneg = = AUTONEG_DISABLE ) {
if ( speed = = SPEED_10 ) {
bmcr = 0 ;
anar | = ADVERTISE_10HALF | ADVERTISE_10FULL ;
} else if ( speed = = SPEED_100 ) {
bmcr = BMCR_SPEED100 ;
anar | = ADVERTISE_100HALF | ADVERTISE_100FULL ;
2014-01-02 07:25:10 +04:00
} else if ( speed = = SPEED_1000 & & tp - > mii . supports_gmii ) {
bmcr = BMCR_SPEED1000 ;
gbcr | = ADVERTISE_1000FULL | ADVERTISE_1000HALF ;
2013-05-02 20:01:25 +04:00
} else {
ret = - EINVAL ;
goto out ;
}
if ( duplex = = DUPLEX_FULL )
bmcr | = BMCR_FULLDPLX ;
} else {
if ( speed = = SPEED_10 ) {
if ( duplex = = DUPLEX_FULL )
anar | = ADVERTISE_10HALF | ADVERTISE_10FULL ;
else
anar | = ADVERTISE_10HALF ;
} else if ( speed = = SPEED_100 ) {
if ( duplex = = DUPLEX_FULL ) {
anar | = ADVERTISE_10HALF | ADVERTISE_10FULL ;
anar | = ADVERTISE_100HALF | ADVERTISE_100FULL ;
} else {
anar | = ADVERTISE_10HALF ;
anar | = ADVERTISE_100HALF ;
}
2014-01-02 07:25:10 +04:00
} else if ( speed = = SPEED_1000 & & tp - > mii . supports_gmii ) {
if ( duplex = = DUPLEX_FULL ) {
anar | = ADVERTISE_10HALF | ADVERTISE_10FULL ;
anar | = ADVERTISE_100HALF | ADVERTISE_100FULL ;
gbcr | = ADVERTISE_1000FULL | ADVERTISE_1000HALF ;
} else {
anar | = ADVERTISE_10HALF ;
anar | = ADVERTISE_100HALF ;
gbcr | = ADVERTISE_1000HALF ;
}
2013-05-02 20:01:25 +04:00
} else {
ret = - EINVAL ;
goto out ;
}
bmcr = BMCR_ANENABLE | BMCR_ANRESTART ;
}
2014-02-18 17:49:04 +04:00
if ( test_bit ( PHY_RESET , & tp - > flags ) )
bmcr | = BMCR_RESET ;
2014-01-02 07:25:10 +04:00
if ( tp - > mii . supports_gmii )
r8152_mdio_write ( tp , MII_CTRL1000 , gbcr ) ;
2013-05-02 20:01:25 +04:00
r8152_mdio_write ( tp , MII_ADVERTISE , anar ) ;
r8152_mdio_write ( tp , MII_BMCR , bmcr ) ;
2014-02-18 17:49:04 +04:00
if ( test_bit ( PHY_RESET , & tp - > flags ) ) {
int i ;
clear_bit ( PHY_RESET , & tp - > flags ) ;
for ( i = 0 ; i < 50 ; i + + ) {
msleep ( 20 ) ;
if ( ( r8152_mdio_read ( tp , MII_BMCR ) & BMCR_RESET ) = = 0 )
break ;
}
}
2013-05-02 20:01:25 +04:00
out :
return ret ;
}
2014-09-19 11:17:18 +04:00
static void rtl8152_up ( struct r8152 * tp )
{
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
r8152b_disable_aldps ( tp ) ;
r8152b_exit_oob ( tp ) ;
r8152b_enable_aldps ( tp ) ;
}
2013-05-02 20:01:25 +04:00
static void rtl8152_down ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) ) {
rtl_drop_queued_tx ( tp ) ;
return ;
}
2014-02-18 17:48:59 +04:00
r8152_power_cut_en ( tp , false ) ;
2013-05-02 20:01:25 +04:00
r8152b_disable_aldps ( tp ) ;
r8152b_enter_oob ( tp ) ;
r8152b_enable_aldps ( tp ) ;
}
2014-09-19 11:17:18 +04:00
static void rtl8153_up ( struct r8152 * tp )
{
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
r8153_disable_aldps ( tp ) ;
r8153_first_init ( tp ) ;
r8153_enable_aldps ( tp ) ;
}
2014-01-02 07:25:10 +04:00
static void rtl8153_down ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) ) {
rtl_drop_queued_tx ( tp ) ;
return ;
}
2014-02-18 17:49:00 +04:00
r8153_u1u2en ( tp , false ) ;
r8153_power_cut_en ( tp , false ) ;
2014-01-02 07:25:10 +04:00
r8153_disable_aldps ( tp ) ;
r8153_enter_oob ( tp ) ;
r8153_enable_aldps ( tp ) ;
}
2013-05-02 20:01:25 +04:00
static void set_carrier ( struct r8152 * tp )
{
struct net_device * netdev = tp - > netdev ;
u8 speed ;
2013-08-14 16:54:40 +04:00
clear_bit ( RTL8152_LINK_CHG , & tp - > flags ) ;
2013-05-02 20:01:25 +04:00
speed = rtl8152_get_speed ( tp ) ;
if ( speed & LINK_STATUS ) {
if ( ! ( tp - > speed & LINK_STATUS ) ) {
2014-01-02 07:22:42 +04:00
tp - > rtl_ops . enable ( tp ) ;
2013-05-02 20:01:25 +04:00
set_bit ( RTL8152_SET_RX_MODE , & tp - > flags ) ;
netif_carrier_on ( netdev ) ;
}
} else {
if ( tp - > speed & LINK_STATUS ) {
netif_carrier_off ( netdev ) ;
2013-08-14 16:54:38 +04:00
tasklet_disable ( & tp - > tl ) ;
2014-01-02 07:22:42 +04:00
tp - > rtl_ops . disable ( tp ) ;
2013-08-14 16:54:38 +04:00
tasklet_enable ( & tp - > tl ) ;
2013-05-02 20:01:25 +04:00
}
}
tp - > speed = speed ;
}
static void rtl_work_func_t ( struct work_struct * work )
{
struct r8152 * tp = container_of ( work , struct r8152 , schedule . work ) ;
2014-02-18 17:49:07 +04:00
if ( usb_autopm_get_interface ( tp - > intf ) < 0 )
return ;
2013-05-02 20:01:25 +04:00
if ( ! test_bit ( WORK_ENABLE , & tp - > flags ) )
goto out1 ;
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
goto out1 ;
2013-08-14 16:54:40 +04:00
if ( test_bit ( RTL8152_LINK_CHG , & tp - > flags ) )
set_carrier ( tp ) ;
2013-05-02 20:01:25 +04:00
if ( test_bit ( RTL8152_SET_RX_MODE , & tp - > flags ) )
_rtl8152_set_rx_mode ( tp - > netdev ) ;
2014-03-07 07:04:36 +04:00
if ( test_bit ( SCHEDULE_TASKLET , & tp - > flags ) & &
( tp - > speed & LINK_STATUS ) ) {
clear_bit ( SCHEDULE_TASKLET , & tp - > flags ) ;
tasklet_schedule ( & tp - > tl ) ;
}
2014-02-18 17:49:04 +04:00
if ( test_bit ( PHY_RESET , & tp - > flags ) )
rtl_phy_reset ( tp ) ;
2013-05-02 20:01:25 +04:00
out1 :
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
2013-05-02 20:01:25 +04:00
}
static int rtl8152_open ( struct net_device * netdev )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
int res = 0 ;
2014-02-18 17:49:05 +04:00
res = alloc_all_mem ( tp ) ;
if ( res )
goto out ;
2014-02-18 17:49:07 +04:00
res = usb_autopm_get_interface ( tp - > intf ) ;
if ( res < 0 ) {
free_all_mem ( tp ) ;
goto out ;
}
/* The WORK_ENABLE may be set when autoresume occurs */
if ( test_bit ( WORK_ENABLE , & tp - > flags ) ) {
clear_bit ( WORK_ENABLE , & tp - > flags ) ;
usb_kill_urb ( tp - > intr_urb ) ;
cancel_delayed_work_sync ( & tp - > schedule ) ;
if ( tp - > speed & LINK_STATUS )
tp - > rtl_ops . disable ( tp ) ;
}
2014-02-18 17:49:05 +04:00
tp - > rtl_ops . up ( tp ) ;
2014-02-06 07:55:48 +04:00
rtl8152_set_speed ( tp , AUTONEG_ENABLE ,
tp - > mii . supports_gmii ? SPEED_1000 : SPEED_100 ,
DUPLEX_FULL ) ;
tp - > speed = 0 ;
netif_carrier_off ( netdev ) ;
netif_start_queue ( netdev ) ;
set_bit ( WORK_ENABLE , & tp - > flags ) ;
2014-03-06 11:07:16 +04:00
2013-08-14 16:54:40 +04:00
res = usb_submit_urb ( tp - > intr_urb , GFP_KERNEL ) ;
if ( res ) {
if ( res = = - ENODEV )
netif_device_detach ( tp - > netdev ) ;
2014-01-07 07:18:22 +04:00
netif_warn ( tp , ifup , netdev , " intr_urb submit failed: %d \n " ,
res ) ;
2014-02-18 17:49:05 +04:00
free_all_mem ( tp ) ;
2013-05-02 20:01:25 +04:00
}
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
2013-05-02 20:01:25 +04:00
2014-02-18 17:49:05 +04:00
out :
2013-05-02 20:01:25 +04:00
return res ;
}
static int rtl8152_close ( struct net_device * netdev )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
int res = 0 ;
clear_bit ( WORK_ENABLE , & tp - > flags ) ;
2014-02-06 07:55:48 +04:00
usb_kill_urb ( tp - > intr_urb ) ;
2013-05-02 20:01:25 +04:00
cancel_delayed_work_sync ( & tp - > schedule ) ;
netif_stop_queue ( netdev ) ;
2014-02-18 17:49:07 +04:00
res = usb_autopm_get_interface ( tp - > intf ) ;
if ( res < 0 ) {
rtl_drop_queued_tx ( tp ) ;
} else {
2014-08-25 11:53:00 +04:00
/* The autosuspend may have been enabled and wouldn't
2014-02-18 17:49:07 +04:00
* be disable when autoresume occurs , because the
* netif_running ( ) would be false .
*/
if ( test_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ) {
rtl_runtime_suspend_enable ( tp , false ) ;
clear_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ;
}
tasklet_disable ( & tp - > tl ) ;
tp - > rtl_ops . down ( tp ) ;
tasklet_enable ( & tp - > tl ) ;
usb_autopm_put_interface ( tp - > intf ) ;
}
2013-05-02 20:01:25 +04:00
2014-02-18 17:49:05 +04:00
free_all_mem ( tp ) ;
2013-05-02 20:01:25 +04:00
return res ;
}
2014-09-25 16:54:01 +04:00
static inline void r8152_mmd_indirect ( struct r8152 * tp , u16 dev , u16 reg )
{
ocp_reg_write ( tp , OCP_EEE_AR , FUN_ADDR | dev ) ;
ocp_reg_write ( tp , OCP_EEE_DATA , reg ) ;
ocp_reg_write ( tp , OCP_EEE_AR , FUN_DATA | dev ) ;
}
static u16 r8152_mmd_read ( struct r8152 * tp , u16 dev , u16 reg )
{
u16 data ;
r8152_mmd_indirect ( tp , dev , reg ) ;
data = ocp_reg_read ( tp , OCP_EEE_DATA ) ;
ocp_reg_write ( tp , OCP_EEE_AR , 0x0000 ) ;
return data ;
}
static void r8152_mmd_write ( struct r8152 * tp , u16 dev , u16 reg , u16 data )
2013-05-02 20:01:25 +04:00
{
2014-09-25 16:54:01 +04:00
r8152_mmd_indirect ( tp , dev , reg ) ;
ocp_reg_write ( tp , OCP_EEE_DATA , data ) ;
ocp_reg_write ( tp , OCP_EEE_AR , 0x0000 ) ;
}
static void r8152_eee_en ( struct r8152 * tp , bool enable )
{
u16 config1 , config2 , config3 ;
2014-01-06 13:08:41 +04:00
u32 ocp_data ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR ) ;
2014-09-25 16:54:01 +04:00
config1 = ocp_reg_read ( tp , OCP_EEE_CONFIG1 ) & ~ sd_rise_time_mask ;
config2 = ocp_reg_read ( tp , OCP_EEE_CONFIG2 ) ;
config3 = ocp_reg_read ( tp , OCP_EEE_CONFIG3 ) & ~ fast_snr_mask ;
if ( enable ) {
ocp_data | = EEE_RX_EN | EEE_TX_EN ;
config1 | = EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | RX_QUIET_EN ;
config1 | = sd_rise_time ( 1 ) ;
config2 | = RG_DACQUIET_EN | RG_LDVQUIET_EN ;
config3 | = fast_snr ( 42 ) ;
} else {
ocp_data & = ~ ( EEE_RX_EN | EEE_TX_EN ) ;
config1 & = ~ ( EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN |
RX_QUIET_EN ) ;
config1 | = sd_rise_time ( 7 ) ;
config2 & = ~ ( RG_DACQUIET_EN | RG_LDVQUIET_EN ) ;
config3 | = fast_snr ( 511 ) ;
}
2013-05-02 20:01:25 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR , ocp_data ) ;
2014-09-25 16:54:01 +04:00
ocp_reg_write ( tp , OCP_EEE_CONFIG1 , config1 ) ;
ocp_reg_write ( tp , OCP_EEE_CONFIG2 , config2 ) ;
ocp_reg_write ( tp , OCP_EEE_CONFIG3 , config3 ) ;
2013-05-02 20:01:25 +04:00
}
2014-09-25 16:54:01 +04:00
static void r8152b_enable_eee ( struct r8152 * tp )
{
r8152_eee_en ( tp , true ) ;
r8152_mmd_write ( tp , MDIO_MMD_AN , MDIO_AN_EEE_ADV , MDIO_EEE_100TX ) ;
}
static void r8153_eee_en ( struct r8152 * tp , bool enable )
2014-01-02 07:25:10 +04:00
{
u32 ocp_data ;
2014-09-25 16:54:01 +04:00
u16 config ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR ) ;
2014-09-25 16:54:01 +04:00
config = ocp_reg_read ( tp , OCP_EEE_CFG ) ;
if ( enable ) {
ocp_data | = EEE_RX_EN | EEE_TX_EN ;
config | = EEE10_EN ;
} else {
ocp_data & = ~ ( EEE_RX_EN | EEE_TX_EN ) ;
config & = ~ EEE10_EN ;
}
2014-01-02 07:25:10 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR , ocp_data ) ;
2014-09-25 16:54:01 +04:00
ocp_reg_write ( tp , OCP_EEE_CFG , config ) ;
}
static void r8153_enable_eee ( struct r8152 * tp )
{
r8153_eee_en ( tp , true ) ;
ocp_reg_write ( tp , OCP_EEE_ADV , MDIO_EEE_1000T | MDIO_EEE_100TX ) ;
2014-01-02 07:25:10 +04:00
}
2013-05-02 20:01:25 +04:00
static void r8152b_enable_fc ( struct r8152 * tp )
{
u16 anar ;
anar = r8152_mdio_read ( tp , MII_ADVERTISE ) ;
anar | = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM ;
r8152_mdio_write ( tp , MII_ADVERTISE , anar ) ;
}
2014-03-11 12:24:19 +04:00
static void rtl_tally_reset ( struct r8152 * tp )
{
u32 ocp_data ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_RSTTALLY ) ;
ocp_data | = TALLY_RESET ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_RSTTALLY , ocp_data ) ;
}
2013-05-02 20:01:25 +04:00
static void r8152b_init ( struct r8152 * tp )
{
2013-08-14 16:54:38 +04:00
u32 ocp_data ;
2013-05-02 20:01:25 +04:00
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2014-09-19 11:17:18 +04:00
r8152b_disable_aldps ( tp ) ;
2013-05-02 20:01:25 +04:00
if ( tp - > version = = RTL_VER_01 ) {
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_LED_FEATURE ) ;
ocp_data & = ~ LED_MODE_MASK ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_LED_FEATURE , ocp_data ) ;
}
2014-02-18 17:48:59 +04:00
r8152_power_cut_en ( tp , false ) ;
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_PHY_PWR ) ;
ocp_data | = TX_10M_IDLE_EN | PFM_PWM_SWITCH ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_PHY_PWR , ocp_data ) ;
ocp_data = ocp_read_dword ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL ) ;
ocp_data & = ~ MCU_CLK_RATIO_MASK ;
ocp_data | = MCU_CLK_RATIO | D3_CLK_GATED_EN ;
ocp_write_dword ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL , ocp_data ) ;
ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_GPHY_INTR_IMR , ocp_data ) ;
r8152b_enable_eee ( tp ) ;
r8152b_enable_aldps ( tp ) ;
r8152b_enable_fc ( tp ) ;
2014-03-11 12:24:19 +04:00
rtl_tally_reset ( tp ) ;
2013-05-02 20:01:25 +04:00
2013-08-14 16:54:38 +04:00
/* enable rx aggregation */
2013-05-02 20:01:25 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_USB_CTRL ) ;
2013-08-14 16:54:38 +04:00
ocp_data & = ~ RX_AGG_DISABLE ;
2013-05-02 20:01:25 +04:00
ocp_write_word ( tp , MCU_TYPE_USB , USB_USB_CTRL , ocp_data ) ;
}
2014-01-02 07:25:10 +04:00
static void r8153_init ( struct r8152 * tp )
{
u32 ocp_data ;
int i ;
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2014-09-19 11:17:18 +04:00
r8153_disable_aldps ( tp ) ;
2014-02-18 17:49:00 +04:00
r8153_u1u2en ( tp , false ) ;
2014-01-02 07:25:10 +04:00
for ( i = 0 ; i < 500 ; i + + ) {
if ( ocp_read_word ( tp , MCU_TYPE_PLA , PLA_BOOT_CTRL ) &
AUTOLOAD_DONE )
break ;
msleep ( 20 ) ;
}
for ( i = 0 ; i < 500 ; i + + ) {
ocp_data = ocp_reg_read ( tp , OCP_PHY_STATUS ) & PHY_STAT_MASK ;
if ( ocp_data = = PHY_STAT_LAN_ON | | ocp_data = = PHY_STAT_PWRDN )
break ;
msleep ( 20 ) ;
}
2014-02-18 17:49:00 +04:00
r8153_u2p3en ( tp , false ) ;
2014-01-02 07:25:10 +04:00
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_WDT11_CTRL ) ;
ocp_data & = ~ TIMER11_EN ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_WDT11_CTRL , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_LED_FEATURE ) ;
ocp_data & = ~ LED_MODE_MASK ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_LED_FEATURE , ocp_data ) ;
ocp_data = ocp_read_byte ( tp , MCU_TYPE_USB , USB_LPM_CTRL ) ;
ocp_data & = ~ LPM_TIMER_MASK ;
if ( tp - > udev - > speed = = USB_SPEED_SUPER )
ocp_data | = LPM_TIMER_500US ;
else
ocp_data | = LPM_TIMER_500MS ;
ocp_write_byte ( tp , MCU_TYPE_USB , USB_LPM_CTRL , ocp_data ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_USB , USB_AFE_CTRL2 ) ;
ocp_data & = ~ SEN_VAL_MASK ;
ocp_data | = SEN_VAL_NORMAL | SEL_RXIDLE ;
ocp_write_word ( tp , MCU_TYPE_USB , USB_AFE_CTRL2 , ocp_data ) ;
2014-02-18 17:49:00 +04:00
r8153_power_cut_en ( tp , false ) ;
r8153_u1u2en ( tp , true ) ;
2014-01-02 07:25:10 +04:00
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL , ALDPS_SPDWN_RATIO ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL2 , EEE_SPDWN_RATIO ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL3 ,
PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN |
U1U2_SPDWN_EN | L1_SPDWN_EN ) ;
ocp_write_word ( tp , MCU_TYPE_PLA , PLA_MAC_PWR_CTRL4 ,
PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN |
TP100_SPDWN_EN | TP500_SPDWN_EN | TP1000_SPDWN_EN |
EEE_SPDWN_EN ) ;
r8153_enable_eee ( tp ) ;
r8153_enable_aldps ( tp ) ;
r8152b_enable_fc ( tp ) ;
2014-03-11 12:24:19 +04:00
rtl_tally_reset ( tp ) ;
2014-01-02 07:25:10 +04:00
}
2013-05-02 20:01:25 +04:00
static int rtl8152_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct r8152 * tp = usb_get_intfdata ( intf ) ;
2014-02-18 17:49:07 +04:00
if ( PMSG_IS_AUTO ( message ) )
set_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ;
else
netif_device_detach ( tp - > netdev ) ;
2013-05-02 20:01:25 +04:00
if ( netif_running ( tp - > netdev ) ) {
clear_bit ( WORK_ENABLE , & tp - > flags ) ;
2013-08-14 16:54:40 +04:00
usb_kill_urb ( tp - > intr_urb ) ;
2013-05-02 20:01:25 +04:00
cancel_delayed_work_sync ( & tp - > schedule ) ;
2014-09-23 12:31:47 +04:00
tasklet_disable ( & tp - > tl ) ;
2014-02-18 17:49:07 +04:00
if ( test_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ) {
2014-09-23 12:31:47 +04:00
rtl_stop_rx ( tp ) ;
2014-02-18 17:49:07 +04:00
rtl_runtime_suspend_enable ( tp , true ) ;
} else {
tp - > rtl_ops . down ( tp ) ;
}
2014-09-23 12:31:47 +04:00
tasklet_enable ( & tp - > tl ) ;
2013-05-02 20:01:25 +04:00
}
return 0 ;
}
static int rtl8152_resume ( struct usb_interface * intf )
{
struct r8152 * tp = usb_get_intfdata ( intf ) ;
2014-02-18 17:49:07 +04:00
if ( ! test_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ) {
tp - > rtl_ops . init ( tp ) ;
netif_device_attach ( tp - > netdev ) ;
}
2013-05-02 20:01:25 +04:00
if ( netif_running ( tp - > netdev ) ) {
2014-02-18 17:49:07 +04:00
if ( test_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ) {
rtl_runtime_suspend_enable ( tp , false ) ;
clear_bit ( SELECTIVE_SUSPEND , & tp - > flags ) ;
2014-09-23 12:31:47 +04:00
set_bit ( WORK_ENABLE , & tp - > flags ) ;
2014-02-18 17:49:07 +04:00
if ( tp - > speed & LINK_STATUS )
2014-09-23 12:31:47 +04:00
rtl_start_rx ( tp ) ;
2014-02-18 17:49:07 +04:00
} else {
tp - > rtl_ops . up ( tp ) ;
rtl8152_set_speed ( tp , AUTONEG_ENABLE ,
2014-08-25 11:53:00 +04:00
tp - > mii . supports_gmii ?
SPEED_1000 : SPEED_100 ,
DUPLEX_FULL ) ;
2014-09-23 12:31:47 +04:00
tp - > speed = 0 ;
netif_carrier_off ( tp - > netdev ) ;
set_bit ( WORK_ENABLE , & tp - > flags ) ;
2014-02-18 17:49:07 +04:00
}
2013-08-14 16:54:40 +04:00
usb_submit_urb ( tp - > intr_urb , GFP_KERNEL ) ;
2013-05-02 20:01:25 +04:00
}
return 0 ;
}
2014-02-18 17:49:06 +04:00
static void rtl8152_get_wol ( struct net_device * dev , struct ethtool_wolinfo * wol )
{
struct r8152 * tp = netdev_priv ( dev ) ;
2014-02-18 17:49:07 +04:00
if ( usb_autopm_get_interface ( tp - > intf ) < 0 )
return ;
2014-02-18 17:49:06 +04:00
wol - > supported = WAKE_ANY ;
wol - > wolopts = __rtl_get_wol ( tp ) ;
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
2014-02-18 17:49:06 +04:00
}
static int rtl8152_set_wol ( struct net_device * dev , struct ethtool_wolinfo * wol )
{
struct r8152 * tp = netdev_priv ( dev ) ;
2014-02-18 17:49:07 +04:00
int ret ;
ret = usb_autopm_get_interface ( tp - > intf ) ;
if ( ret < 0 )
goto out_set_wol ;
2014-02-18 17:49:06 +04:00
__rtl_set_wol ( tp , wol - > wolopts ) ;
tp - > saved_wolopts = wol - > wolopts & WAKE_ANY ;
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
out_set_wol :
return ret ;
2014-02-18 17:49:06 +04:00
}
2014-02-18 17:49:11 +04:00
static u32 rtl8152_get_msglevel ( struct net_device * dev )
{
struct r8152 * tp = netdev_priv ( dev ) ;
return tp - > msg_enable ;
}
static void rtl8152_set_msglevel ( struct net_device * dev , u32 value )
{
struct r8152 * tp = netdev_priv ( dev ) ;
tp - > msg_enable = value ;
}
2013-05-02 20:01:25 +04:00
static void rtl8152_get_drvinfo ( struct net_device * netdev ,
struct ethtool_drvinfo * info )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
2014-08-26 06:08:23 +04:00
strlcpy ( info - > driver , MODULENAME , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , DRIVER_VERSION , sizeof ( info - > version ) ) ;
2013-05-02 20:01:25 +04:00
usb_make_path ( tp - > udev , info - > bus_info , sizeof ( info - > bus_info ) ) ;
}
static
int rtl8152_get_settings ( struct net_device * netdev , struct ethtool_cmd * cmd )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
if ( ! tp - > mii . mdio_read )
return - EOPNOTSUPP ;
return mii_ethtool_gset ( & tp - > mii , cmd ) ;
}
static int rtl8152_set_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
{
struct r8152 * tp = netdev_priv ( dev ) ;
2014-02-18 17:49:07 +04:00
int ret ;
ret = usb_autopm_get_interface ( tp - > intf ) ;
if ( ret < 0 )
goto out ;
2013-05-02 20:01:25 +04:00
2014-02-18 17:49:07 +04:00
ret = rtl8152_set_speed ( tp , cmd - > autoneg , cmd - > speed , cmd - > duplex ) ;
usb_autopm_put_interface ( tp - > intf ) ;
out :
return ret ;
2013-05-02 20:01:25 +04:00
}
2014-03-11 12:24:19 +04:00
static const char rtl8152_gstrings [ ] [ ETH_GSTRING_LEN ] = {
" tx_packets " ,
" rx_packets " ,
" tx_errors " ,
" rx_errors " ,
" rx_missed " ,
" align_errors " ,
" tx_single_collisions " ,
" tx_multi_collisions " ,
" rx_unicast " ,
" rx_broadcast " ,
" rx_multicast " ,
" tx_aborted " ,
" tx_underrun " ,
} ;
static int rtl8152_get_sset_count ( struct net_device * dev , int sset )
{
switch ( sset ) {
case ETH_SS_STATS :
return ARRAY_SIZE ( rtl8152_gstrings ) ;
default :
return - EOPNOTSUPP ;
}
}
static void rtl8152_get_ethtool_stats ( struct net_device * dev ,
struct ethtool_stats * stats , u64 * data )
{
struct r8152 * tp = netdev_priv ( dev ) ;
struct tally_counter tally ;
2014-07-08 10:49:28 +04:00
if ( usb_autopm_get_interface ( tp - > intf ) < 0 )
return ;
2014-03-11 12:24:19 +04:00
generic_ocp_read ( tp , PLA_TALLYCNT , sizeof ( tally ) , & tally , MCU_TYPE_PLA ) ;
2014-07-08 10:49:28 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
2014-03-11 12:24:19 +04:00
data [ 0 ] = le64_to_cpu ( tally . tx_packets ) ;
data [ 1 ] = le64_to_cpu ( tally . rx_packets ) ;
data [ 2 ] = le64_to_cpu ( tally . tx_errors ) ;
data [ 3 ] = le32_to_cpu ( tally . rx_errors ) ;
data [ 4 ] = le16_to_cpu ( tally . rx_missed ) ;
data [ 5 ] = le16_to_cpu ( tally . align_errors ) ;
data [ 6 ] = le32_to_cpu ( tally . tx_one_collision ) ;
data [ 7 ] = le32_to_cpu ( tally . tx_multi_collision ) ;
data [ 8 ] = le64_to_cpu ( tally . rx_unicast ) ;
data [ 9 ] = le64_to_cpu ( tally . rx_broadcast ) ;
data [ 10 ] = le32_to_cpu ( tally . rx_multicast ) ;
data [ 11 ] = le16_to_cpu ( tally . tx_aborted ) ;
data [ 12 ] = le16_to_cpu ( tally . tx_underun ) ;
}
static void rtl8152_get_strings ( struct net_device * dev , u32 stringset , u8 * data )
{
switch ( stringset ) {
case ETH_SS_STATS :
memcpy ( data , * rtl8152_gstrings , sizeof ( rtl8152_gstrings ) ) ;
break ;
}
}
2014-09-25 16:54:02 +04:00
static int r8152_get_eee ( struct r8152 * tp , struct ethtool_eee * eee )
{
u32 ocp_data , lp , adv , supported = 0 ;
u16 val ;
val = r8152_mmd_read ( tp , MDIO_MMD_PCS , MDIO_PCS_EEE_ABLE ) ;
supported = mmd_eee_cap_to_ethtool_sup_t ( val ) ;
val = r8152_mmd_read ( tp , MDIO_MMD_AN , MDIO_AN_EEE_ADV ) ;
adv = mmd_eee_adv_to_ethtool_adv_t ( val ) ;
val = r8152_mmd_read ( tp , MDIO_MMD_AN , MDIO_AN_EEE_LPABLE ) ;
lp = mmd_eee_adv_to_ethtool_adv_t ( val ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR ) ;
ocp_data & = EEE_RX_EN | EEE_TX_EN ;
eee - > eee_enabled = ! ! ocp_data ;
eee - > eee_active = ! ! ( supported & adv & lp ) ;
eee - > supported = supported ;
eee - > advertised = adv ;
eee - > lp_advertised = lp ;
return 0 ;
}
static int r8152_set_eee ( struct r8152 * tp , struct ethtool_eee * eee )
{
u16 val = ethtool_adv_to_mmd_eee_adv_t ( eee - > advertised ) ;
r8152_eee_en ( tp , eee - > eee_enabled ) ;
if ( ! eee - > eee_enabled )
val = 0 ;
r8152_mmd_write ( tp , MDIO_MMD_AN , MDIO_AN_EEE_ADV , val ) ;
return 0 ;
}
static int r8153_get_eee ( struct r8152 * tp , struct ethtool_eee * eee )
{
u32 ocp_data , lp , adv , supported = 0 ;
u16 val ;
val = ocp_reg_read ( tp , OCP_EEE_ABLE ) ;
supported = mmd_eee_cap_to_ethtool_sup_t ( val ) ;
val = ocp_reg_read ( tp , OCP_EEE_ADV ) ;
adv = mmd_eee_adv_to_ethtool_adv_t ( val ) ;
val = ocp_reg_read ( tp , OCP_EEE_LPABLE ) ;
lp = mmd_eee_adv_to_ethtool_adv_t ( val ) ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_EEE_CR ) ;
ocp_data & = EEE_RX_EN | EEE_TX_EN ;
eee - > eee_enabled = ! ! ocp_data ;
eee - > eee_active = ! ! ( supported & adv & lp ) ;
eee - > supported = supported ;
eee - > advertised = adv ;
eee - > lp_advertised = lp ;
return 0 ;
}
static int r8153_set_eee ( struct r8152 * tp , struct ethtool_eee * eee )
{
u16 val = ethtool_adv_to_mmd_eee_adv_t ( eee - > advertised ) ;
r8153_eee_en ( tp , eee - > eee_enabled ) ;
if ( ! eee - > eee_enabled )
val = 0 ;
ocp_reg_write ( tp , OCP_EEE_ADV , val ) ;
return 0 ;
}
static int
rtl_ethtool_get_eee ( struct net_device * net , struct ethtool_eee * edata )
{
struct r8152 * tp = netdev_priv ( net ) ;
int ret ;
ret = usb_autopm_get_interface ( tp - > intf ) ;
if ( ret < 0 )
goto out ;
ret = tp - > rtl_ops . eee_get ( tp , edata ) ;
usb_autopm_put_interface ( tp - > intf ) ;
out :
return ret ;
}
static int
rtl_ethtool_set_eee ( struct net_device * net , struct ethtool_eee * edata )
{
struct r8152 * tp = netdev_priv ( net ) ;
int ret ;
ret = usb_autopm_get_interface ( tp - > intf ) ;
if ( ret < 0 )
goto out ;
ret = tp - > rtl_ops . eee_set ( tp , edata ) ;
2014-10-06 06:36:04 +04:00
if ( ! ret )
ret = mii_nway_restart ( & tp - > mii ) ;
2014-09-25 16:54:02 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
out :
return ret ;
}
2013-05-02 20:01:25 +04:00
static struct ethtool_ops ops = {
. get_drvinfo = rtl8152_get_drvinfo ,
. get_settings = rtl8152_get_settings ,
. set_settings = rtl8152_set_settings ,
. get_link = ethtool_op_get_link ,
2014-02-18 17:49:11 +04:00
. get_msglevel = rtl8152_get_msglevel ,
. set_msglevel = rtl8152_set_msglevel ,
2014-02-18 17:49:06 +04:00
. get_wol = rtl8152_get_wol ,
. set_wol = rtl8152_set_wol ,
2014-03-11 12:24:19 +04:00
. get_strings = rtl8152_get_strings ,
. get_sset_count = rtl8152_get_sset_count ,
. get_ethtool_stats = rtl8152_get_ethtool_stats ,
2014-09-25 16:54:02 +04:00
. get_eee = rtl_ethtool_get_eee ,
. set_eee = rtl_ethtool_set_eee ,
2013-05-02 20:01:25 +04:00
} ;
static int rtl8152_ioctl ( struct net_device * netdev , struct ifreq * rq , int cmd )
{
struct r8152 * tp = netdev_priv ( netdev ) ;
struct mii_ioctl_data * data = if_mii ( rq ) ;
2014-02-18 17:49:07 +04:00
int res ;
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return - ENODEV ;
2014-02-18 17:49:07 +04:00
res = usb_autopm_get_interface ( tp - > intf ) ;
if ( res < 0 )
goto out ;
2013-05-02 20:01:25 +04:00
switch ( cmd ) {
case SIOCGMIIPHY :
data - > phy_id = R8152_PHY_ID ; /* Internal PHY */
break ;
case SIOCGMIIREG :
data - > val_out = r8152_mdio_read ( tp , data - > reg_num ) ;
break ;
case SIOCSMIIREG :
if ( ! capable ( CAP_NET_ADMIN ) ) {
res = - EPERM ;
break ;
}
r8152_mdio_write ( tp , data - > reg_num , data - > val_in ) ;
break ;
default :
res = - EOPNOTSUPP ;
}
2014-02-18 17:49:07 +04:00
usb_autopm_put_interface ( tp - > intf ) ;
out :
2013-05-02 20:01:25 +04:00
return res ;
}
2014-07-10 06:58:54 +04:00
static int rtl8152_change_mtu ( struct net_device * dev , int new_mtu )
{
struct r8152 * tp = netdev_priv ( dev ) ;
switch ( tp - > version ) {
case RTL_VER_01 :
case RTL_VER_02 :
return eth_change_mtu ( dev , new_mtu ) ;
default :
break ;
}
if ( new_mtu < 68 | | new_mtu > RTL8153_MAX_MTU )
return - EINVAL ;
dev - > mtu = new_mtu ;
return 0 ;
}
2013-05-02 20:01:25 +04:00
static const struct net_device_ops rtl8152_netdev_ops = {
. ndo_open = rtl8152_open ,
. ndo_stop = rtl8152_close ,
. ndo_do_ioctl = rtl8152_ioctl ,
. ndo_start_xmit = rtl8152_start_xmit ,
. ndo_tx_timeout = rtl8152_tx_timeout ,
2014-09-12 06:43:11 +04:00
. ndo_set_features = rtl8152_set_features ,
2013-05-02 20:01:25 +04:00
. ndo_set_rx_mode = rtl8152_set_rx_mode ,
. ndo_set_mac_address = rtl8152_set_mac_address ,
2014-07-10 06:58:54 +04:00
. ndo_change_mtu = rtl8152_change_mtu ,
2013-05-02 20:01:25 +04:00
. ndo_validate_addr = eth_validate_addr ,
} ;
static void r8152b_get_version ( struct r8152 * tp )
{
u32 ocp_data ;
u16 version ;
ocp_data = ocp_read_word ( tp , MCU_TYPE_PLA , PLA_TCR1 ) ;
version = ( u16 ) ( ocp_data & VERSION_MASK ) ;
switch ( version ) {
case 0x4c00 :
tp - > version = RTL_VER_01 ;
break ;
case 0x4c10 :
tp - > version = RTL_VER_02 ;
break ;
2014-01-02 07:25:10 +04:00
case 0x5c00 :
tp - > version = RTL_VER_03 ;
tp - > mii . supports_gmii = 1 ;
break ;
case 0x5c10 :
tp - > version = RTL_VER_04 ;
tp - > mii . supports_gmii = 1 ;
break ;
case 0x5c20 :
tp - > version = RTL_VER_05 ;
tp - > mii . supports_gmii = 1 ;
break ;
2013-05-02 20:01:25 +04:00
default :
netif_info ( tp , probe , tp - > netdev ,
" Unknown version 0x%04x \n " , version ) ;
break ;
}
}
2014-01-02 07:22:39 +04:00
static void rtl8152_unload ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2014-02-18 17:48:59 +04:00
if ( tp - > version ! = RTL_VER_01 )
r8152_power_cut_en ( tp , true ) ;
2014-01-02 07:22:39 +04:00
}
2014-01-02 07:25:10 +04:00
static void rtl8153_unload ( struct r8152 * tp )
{
2014-04-11 13:54:31 +04:00
if ( test_bit ( RTL8152_UNPLUG , & tp - > flags ) )
return ;
2014-10-01 09:25:11 +04:00
r8153_power_cut_en ( tp , false ) ;
2014-01-02 07:25:10 +04:00
}
2014-01-06 13:08:43 +04:00
static int rtl_ops_init ( struct r8152 * tp , const struct usb_device_id * id )
2014-01-02 07:22:42 +04:00
{
struct rtl_ops * ops = & tp - > rtl_ops ;
2014-01-06 13:08:43 +04:00
int ret = - ENODEV ;
2014-01-02 07:22:42 +04:00
switch ( id - > idVendor ) {
case VENDOR_ID_REALTEK :
switch ( id - > idProduct ) {
case PRODUCT_ID_RTL8152 :
ops - > init = r8152b_init ;
ops - > enable = rtl8152_enable ;
ops - > disable = rtl8152_disable ;
2014-09-19 11:17:18 +04:00
ops - > up = rtl8152_up ;
2014-01-02 07:22:42 +04:00
ops - > down = rtl8152_down ;
ops - > unload = rtl8152_unload ;
2014-09-25 16:54:02 +04:00
ops - > eee_get = r8152_get_eee ;
ops - > eee_set = r8152_set_eee ;
2014-01-06 13:08:43 +04:00
ret = 0 ;
2014-01-02 07:22:42 +04:00
break ;
2014-01-02 07:25:10 +04:00
case PRODUCT_ID_RTL8153 :
ops - > init = r8153_init ;
ops - > enable = rtl8153_enable ;
2014-09-19 11:17:18 +04:00
ops - > disable = rtl8153_disable ;
ops - > up = rtl8153_up ;
2014-01-02 07:25:10 +04:00
ops - > down = rtl8153_down ;
ops - > unload = rtl8153_unload ;
2014-09-25 16:54:02 +04:00
ops - > eee_get = r8153_get_eee ;
ops - > eee_set = r8153_set_eee ;
2014-01-06 13:08:43 +04:00
ret = 0 ;
2014-01-02 07:25:10 +04:00
break ;
default :
break ;
}
break ;
case VENDOR_ID_SAMSUNG :
switch ( id - > idProduct ) {
case PRODUCT_ID_SAMSUNG :
ops - > init = r8153_init ;
ops - > enable = rtl8153_enable ;
2014-09-19 11:17:18 +04:00
ops - > disable = rtl8153_disable ;
ops - > up = rtl8153_up ;
2014-01-02 07:25:10 +04:00
ops - > down = rtl8153_down ;
ops - > unload = rtl8153_unload ;
2014-09-25 16:54:02 +04:00
ops - > eee_get = r8153_get_eee ;
ops - > eee_set = r8153_set_eee ;
2014-01-06 13:08:43 +04:00
ret = 0 ;
2014-01-02 07:25:10 +04:00
break ;
2014-01-02 07:22:42 +04:00
default :
break ;
}
break ;
default :
break ;
}
2014-01-06 13:08:43 +04:00
if ( ret )
netif_err ( tp , probe , tp - > netdev , " Unknown Device \n " ) ;
2014-01-02 07:22:42 +04:00
return ret ;
}
2013-05-02 20:01:25 +04:00
static int rtl8152_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct r8152 * tp ;
struct net_device * netdev ;
2013-08-14 16:54:38 +04:00
int ret ;
2013-05-02 20:01:25 +04:00
2014-03-04 16:47:48 +04:00
if ( udev - > actconfig - > desc . bConfigurationValue ! = 1 ) {
usb_driver_set_configuration ( udev , 1 ) ;
return - ENODEV ;
}
usb_reset_device ( udev ) ;
2013-05-02 20:01:25 +04:00
netdev = alloc_etherdev ( sizeof ( struct r8152 ) ) ;
if ( ! netdev ) {
2014-01-07 07:18:22 +04:00
dev_err ( & intf - > dev , " Out of memory \n " ) ;
2013-05-02 20:01:25 +04:00
return - ENOMEM ;
}
2013-08-14 16:54:38 +04:00
SET_NETDEV_DEV ( netdev , & intf - > dev ) ;
2013-05-02 20:01:25 +04:00
tp = netdev_priv ( netdev ) ;
tp - > msg_enable = 0x7FFF ;
2014-01-06 13:08:42 +04:00
tp - > udev = udev ;
tp - > netdev = netdev ;
tp - > intf = intf ;
2014-01-06 13:08:43 +04:00
ret = rtl_ops_init ( tp , id ) ;
if ( ret )
goto out ;
2014-01-02 07:22:42 +04:00
2013-08-14 16:54:38 +04:00
tasklet_init ( & tp - > tl , bottom_half , ( unsigned long ) tp ) ;
2013-05-02 20:01:25 +04:00
INIT_DELAYED_WORK ( & tp - > schedule , rtl_work_func_t ) ;
netdev - > netdev_ops = & rtl8152_netdev_ops ;
netdev - > watchdog_timeo = RTL8152_TX_TIMEOUT ;
2013-08-14 16:54:39 +04:00
2014-03-07 07:04:39 +04:00
netdev - > features | = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
2014-03-07 07:04:40 +04:00
NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM |
2014-09-12 06:43:11 +04:00
NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX ;
2014-03-07 07:04:39 +04:00
netdev - > hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
2014-03-07 07:04:40 +04:00
NETIF_F_TSO | NETIF_F_FRAGLIST |
2014-09-12 06:43:11 +04:00
NETIF_F_IPV6_CSUM | NETIF_F_TSO6 |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX ;
netdev - > vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
NETIF_F_IPV6_CSUM | NETIF_F_TSO6 ;
2014-03-06 11:07:16 +04:00
2014-05-11 04:12:32 +04:00
netdev - > ethtool_ops = & ops ;
2014-03-07 07:04:39 +04:00
netif_set_gso_max_size ( netdev , RTL_LIMITED_TSO_SIZE ) ;
2013-05-02 20:01:25 +04:00
tp - > mii . dev = netdev ;
tp - > mii . mdio_read = read_mii_word ;
tp - > mii . mdio_write = write_mii_word ;
tp - > mii . phy_id_mask = 0x3f ;
tp - > mii . reg_num_mask = 0x1f ;
tp - > mii . phy_id = R8152_PHY_ID ;
tp - > mii . supports_gmii = 0 ;
2014-02-18 17:49:07 +04:00
intf - > needs_remote_wakeup = 1 ;
2013-05-02 20:01:25 +04:00
r8152b_get_version ( tp ) ;
2014-01-02 07:22:42 +04:00
tp - > rtl_ops . init ( tp ) ;
2013-05-02 20:01:25 +04:00
set_ethernet_addr ( tp ) ;
usb_set_intfdata ( intf , tp ) ;
2013-08-14 16:54:38 +04:00
ret = register_netdev ( netdev ) ;
if ( ret ! = 0 ) {
2014-01-07 07:18:22 +04:00
netif_err ( tp , probe , netdev , " couldn't register the device \n " ) ;
2013-08-14 16:54:38 +04:00
goto out1 ;
2013-05-02 20:01:25 +04:00
}
2014-02-18 17:49:06 +04:00
tp - > saved_wolopts = __rtl_get_wol ( tp ) ;
if ( tp - > saved_wolopts )
device_set_wakeup_enable ( & udev - > dev , true ) ;
else
device_set_wakeup_enable ( & udev - > dev , false ) ;
2014-01-07 07:18:22 +04:00
netif_info ( tp , probe , netdev , " %s \n " , DRIVER_VERSION ) ;
2013-05-02 20:01:25 +04:00
return 0 ;
out1 :
2013-08-14 16:54:38 +04:00
usb_set_intfdata ( intf , NULL ) ;
2013-05-02 20:01:25 +04:00
out :
free_netdev ( netdev ) ;
2013-08-14 16:54:38 +04:00
return ret ;
2013-05-02 20:01:25 +04:00
}
static void rtl8152_disconnect ( struct usb_interface * intf )
{
struct r8152 * tp = usb_get_intfdata ( intf ) ;
usb_set_intfdata ( intf , NULL ) ;
if ( tp ) {
2014-09-30 12:48:01 +04:00
struct usb_device * udev = tp - > udev ;
if ( udev - > state = = USB_STATE_NOTATTACHED )
set_bit ( RTL8152_UNPLUG , & tp - > flags ) ;
2013-05-02 20:01:25 +04:00
tasklet_kill ( & tp - > tl ) ;
unregister_netdev ( tp - > netdev ) ;
2014-01-02 07:22:42 +04:00
tp - > rtl_ops . unload ( tp ) ;
2013-05-02 20:01:25 +04:00
free_netdev ( tp - > netdev ) ;
}
}
/* table of devices that work with this driver */
static struct usb_device_id rtl8152_table [ ] = {
2014-03-04 16:47:48 +04:00
{ USB_DEVICE ( VENDOR_ID_REALTEK , PRODUCT_ID_RTL8152 ) } ,
{ USB_DEVICE ( VENDOR_ID_REALTEK , PRODUCT_ID_RTL8153 ) } ,
{ USB_DEVICE ( VENDOR_ID_SAMSUNG , PRODUCT_ID_SAMSUNG ) } ,
2013-05-02 20:01:25 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( usb , rtl8152_table ) ;
static struct usb_driver rtl8152_driver = {
. name = MODULENAME ,
2013-08-14 16:54:38 +04:00
. id_table = rtl8152_table ,
2013-05-02 20:01:25 +04:00
. probe = rtl8152_probe ,
. disconnect = rtl8152_disconnect ,
. suspend = rtl8152_suspend ,
2013-08-14 16:54:38 +04:00
. resume = rtl8152_resume ,
. reset_resume = rtl8152_resume ,
2014-02-18 17:49:07 +04:00
. supports_autosuspend = 1 ,
2014-02-18 17:49:10 +04:00
. disable_hub_initiated_lpm = 1 ,
2013-05-02 20:01:25 +04:00
} ;
2013-05-16 21:48:08 +04:00
module_usb_driver ( rtl8152_driver ) ;
2013-05-02 20:01:25 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;