diff options
author | David S. Miller | 2014-09-28 23:24:32 +0200 |
---|---|---|
committer | David S. Miller | 2014-09-28 23:24:32 +0200 |
commit | a8404ce5ae7a6054322afb5aa77cefe3ad54475e (patch) | |
tree | d068ba8cc4ee9a19fa8c278b3215cc21b13dce97 | |
parent | Merge branch 'defxx-next' (diff) | |
parent | r8152: support ethtool eee (diff) | |
download | kernel-qcow2-linux-a8404ce5ae7a6054322afb5aa77cefe3ad54475e.tar.gz kernel-qcow2-linux-a8404ce5ae7a6054322afb5aa77cefe3ad54475e.tar.xz kernel-qcow2-linux-a8404ce5ae7a6054322afb5aa77cefe3ad54475e.zip |
Merge branch 'r8152'
Hayes Wang says:
====================
r8152: support setting eee by ethtool
Modify some definitions about EEE, and add the support of setting
the EEE through ethtool.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/r8152.c | 246 |
1 files changed, 209 insertions, 37 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3d5c39a1e46f..a4d4c4a1354f 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -22,6 +22,8 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <net/ip6_checksum.h> +#include <uapi/linux/mdio.h> +#include <linux/mdio.h> /* Version Information */ #define DRIVER_VERSION "v1.06.0 (2014/03/03)" @@ -129,7 +131,9 @@ #define OCP_SRAM_ADDR 0xa436 #define OCP_SRAM_DATA 0xa438 #define OCP_DOWN_SPEED 0xa442 -#define OCP_EEE_CFG2 0xa5d0 +#define OCP_EEE_ABLE 0xa5c4 +#define OCP_EEE_ADV 0xa5d0 +#define OCP_EEE_LPABLE 0xa5d2 #define OCP_ADC_CFG 0xbc06 /* SRAM Register */ @@ -361,7 +365,8 @@ #define EEE_NWAY_EN 0x1000 #define TX_QUIET_EN 0x0200 #define RX_QUIET_EN 0x0100 -#define SDRISETIME 0x0010 /* bit 4 ~ 6 */ +#define sd_rise_time_mask 0x0070 +#define sd_rise_time(x) (min(x, 7) << 4) /* bit 4 ~ 6 */ #define RG_RXLPI_MSK_HFDUP 0x0008 #define SDFALLTIME 0x0007 /* bit 0 ~ 2 */ @@ -373,7 +378,8 @@ #define RG_EEEPRG_EN 0x0010 /* OCP_EEE_CONFIG3 */ -#define FST_SNR_EYE_R 0x1500 /* bit 7 ~ 15 */ +#define fast_snr_mask 0xff80 +#define fast_snr(x) (min(x, 0x1ff) << 7) /* bit 7 ~ 15 */ #define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */ #define MSK_PH 0x0006 /* bit 0 ~ 3 */ @@ -382,11 +388,6 @@ #define FUN_ADDR 0x0000 #define FUN_DATA 0x4000 /* bit[4:0] device addr */ -#define DEVICE_ADDR 0x0007 - -/* OCP_EEE_DATA */ -#define EEE_ADDR 0x003C -#define EEE_DATA 0x0002 /* OCP_EEE_CFG */ #define CTAP_SHORT_EN 0x0040 @@ -395,10 +396,6 @@ /* OCP_DOWN_SPEED */ #define EN_10M_BGOFF 0x0080 -/* OCP_EEE_CFG2 */ -#define MY1000_EEE 0x0004 -#define MY100_EEE 0x0002 - /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 @@ -577,6 +574,8 @@ struct r8152 { void (*up)(struct r8152 *); void (*down)(struct r8152 *); void (*unload)(struct r8152 *); + int (*eee_get)(struct r8152 *, struct ethtool_eee *); + int (*eee_set)(struct r8152 *, struct ethtool_eee *); } rtl_ops; int intr_interval; @@ -2957,43 +2956,92 @@ static int rtl8152_close(struct net_device *netdev) return res; } -static void r8152b_enable_eee(struct r8152 *tp) +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) { + 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; u32 ocp_data; ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data |= EEE_RX_EN | EEE_TX_EN; + 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); + } + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); - ocp_reg_write(tp, OCP_EEE_CONFIG1, RG_TXLPI_MSK_HFDUP | RG_MATCLR_EN | - EEE_10_CAP | EEE_NWAY_EN | - TX_QUIET_EN | RX_QUIET_EN | - SDRISETIME | RG_RXLPI_MSK_HFDUP | - SDFALLTIME); - ocp_reg_write(tp, OCP_EEE_CONFIG2, RG_LPIHYS_NUM | RG_DACQUIET_EN | - RG_LDVQUIET_EN | RG_CKRSEL | - RG_EEEPRG_EN); - ocp_reg_write(tp, OCP_EEE_CONFIG3, FST_SNR_EYE_R | RG_LFS_SEL | MSK_PH); - ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | DEVICE_ADDR); - ocp_reg_write(tp, OCP_EEE_DATA, EEE_ADDR); - ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | DEVICE_ADDR); - ocp_reg_write(tp, OCP_EEE_DATA, EEE_DATA); - ocp_reg_write(tp, OCP_EEE_AR, 0x0000); + ocp_reg_write(tp, OCP_EEE_CONFIG1, config1); + ocp_reg_write(tp, OCP_EEE_CONFIG2, config2); + ocp_reg_write(tp, OCP_EEE_CONFIG3, config3); } -static void r8153_enable_eee(struct r8152 *tp) +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) { u32 ocp_data; - u16 data; + u16 config; ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data |= EEE_RX_EN | EEE_TX_EN; + 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; + } + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); - data = ocp_reg_read(tp, OCP_EEE_CFG); - data |= EEE10_EN; - ocp_reg_write(tp, OCP_EEE_CFG, data); - data = ocp_reg_read(tp, OCP_EEE_CFG2); - data |= MY1000_EEE | MY100_EEE; - ocp_reg_write(tp, OCP_EEE_CFG2, data); + 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); } static void r8152b_enable_fc(struct r8152 *tp) @@ -3322,6 +3370,122 @@ static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } +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); + + usb_autopm_put_interface(tp->intf); + +out: + return ret; +} + static struct ethtool_ops ops = { .get_drvinfo = rtl8152_get_drvinfo, .get_settings = rtl8152_get_settings, @@ -3334,6 +3498,8 @@ static struct ethtool_ops ops = { .get_strings = rtl8152_get_strings, .get_sset_count = rtl8152_get_sset_count, .get_ethtool_stats = rtl8152_get_ethtool_stats, + .get_eee = rtl_ethtool_get_eee, + .set_eee = rtl_ethtool_set_eee, }; static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -3475,6 +3641,8 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->up = rtl8152_up; ops->down = rtl8152_down; ops->unload = rtl8152_unload; + ops->eee_get = r8152_get_eee; + ops->eee_set = r8152_set_eee; ret = 0; break; case PRODUCT_ID_RTL8153: @@ -3484,6 +3652,8 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->up = rtl8153_up; ops->down = rtl8153_down; ops->unload = rtl8153_unload; + ops->eee_get = r8153_get_eee; + ops->eee_set = r8153_set_eee; ret = 0; break; default: @@ -3500,6 +3670,8 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->up = rtl8153_up; ops->down = rtl8153_down; ops->unload = rtl8153_unload; + ops->eee_get = r8153_get_eee; + ops->eee_set = r8153_set_eee; ret = 0; break; default: |