From 4349968ad29a9023005e31eca5d971143d127ba8 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:48:58 +0800 Subject: [PATCH 01/14] r8152: move some functions Move the following functions which is for the further coding. - rtl_clear_bp - r8153_clear_bp - r8153_teredo_off - r8152b_disable_aldps - r8152b_enable_aldps - r8152b_hw_phy_cfg Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 106 ++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index d89dbe395ad29..f042a85b84e97 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1721,6 +1721,59 @@ static void rtl8152_disable(struct r8152 *tp) rtl8152_nic_reset(tp); } +static void rtl_clear_bp(struct r8152 *tp) +{ + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); + mdelay(3); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); +} + +static void r8153_clear_bp(struct r8152 *tp) +{ + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); + ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); + rtl_clear_bp(tp); +} + +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); +} + +static void r8152b_hw_phy_cfg(struct r8152 *tp) +{ + r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); + r8152b_disable_aldps(tp); +} + static void r8152b_exit_oob(struct r8152 *tp) { u32 ocp_data; @@ -1865,18 +1918,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } -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); -} - static void r8153_hw_phy_cfg(struct r8152 *tp) { u32 ocp_data; @@ -1961,19 +2002,6 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable) ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); } -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 r8153_first_init(struct r8152 *tp) { u32 ocp_data; @@ -2308,28 +2336,6 @@ static int rtl8152_close(struct net_device *netdev) return res; } -static void rtl_clear_bp(struct r8152 *tp) -{ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); - mdelay(3); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} - -static void r8153_clear_bp(struct r8152 *tp) -{ - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); - rtl_clear_bp(tp); -} - static void r8152b_enable_eee(struct r8152 *tp) { u32 ocp_data; @@ -2378,12 +2384,6 @@ static void r8152b_enable_fc(struct r8152 *tp) r8152_mdio_write(tp, MII_ADVERTISE, anar); } -static void r8152b_hw_phy_cfg(struct r8152 *tp) -{ - r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); - r8152b_disable_aldps(tp); -} - static void r8152b_init(struct r8152 *tp) { u32 ocp_data; From 00a5e360c54ada2fbd58bacbb1c1fd79d2fde80d Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:48:59 +0800 Subject: [PATCH 02/14] r8152: add three functions Replace some codes with the following three functions. - rtl_drop_queued_tx - rxdy_gated_en - r8152_power_cut_en Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 99 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f042a85b84e97..2d5e76159ca7d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1478,6 +1478,17 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) return usb_submit_urb(agg->urb, mem_flags); } +static void rtl_drop_queued_tx(struct r8152 *tp) +{ + struct net_device_stats *stats = &tp->netdev->stats; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&tp->tx_queue))) { + dev_kfree_skb(skb); + stats->tx_dropped++; + } +} + static void rtl8152_tx_timeout(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); @@ -1613,6 +1624,18 @@ static void rtl_set_eee_plus(struct r8152 *tp) } } +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); +} + static int rtl_enable(struct r8152 *tp) { u32 ocp_data; @@ -1624,9 +1647,7 @@ static int rtl_enable(struct r8152 *tp) ocp_data |= CR_RE | CR_TE; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); INIT_LIST_HEAD(&tp->rx_done); ret = 0; @@ -1681,8 +1702,6 @@ static int rtl8153_enable(struct r8152 *tp) static void rtl8152_disable(struct r8152 *tp) { - struct net_device_stats *stats = rtl8152_get_stats(tp->netdev); - struct sk_buff *skb; u32 ocp_data; int i; @@ -1690,17 +1709,12 @@ static void rtl8152_disable(struct r8152 *tp) ocp_data &= ~RCR_ACPT_ALL; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - while ((skb = skb_dequeue(&tp->tx_queue))) { - dev_kfree_skb(skb); - stats->tx_dropped++; - } + rtl_drop_queued_tx(tp); for (i = 0; i < RTL8152_MAX_TX; i++) usb_kill_urb(tp->tx_info[i].urb); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, true); for (i = 0; i < 1000; i++) { ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); @@ -1721,6 +1735,23 @@ static void rtl8152_disable(struct r8152 *tp) rtl8152_nic_reset(tp); } +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); + +} + static void rtl_clear_bp(struct r8152 *tp) { ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); @@ -1783,9 +1814,7 @@ static void r8152b_exit_oob(struct r8152 *tp) ocp_data &= ~RCR_ACPT_ALL; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, true); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); @@ -1909,9 +1938,7 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data |= RCR_APM | RCR_AM | RCR_AB; @@ -2007,10 +2034,7 @@ static void r8153_first_init(struct r8152 *tp) u32 ocp_data; int i; - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); - + rxdy_gated_en(tp, true); r8153_teredo_off(tp); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -2125,9 +2149,7 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data |= RCR_APM | RCR_AM | RCR_AB; @@ -2231,12 +2253,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) static void rtl8152_down(struct r8152 *tp) { - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data &= ~POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - + r8152_power_cut_en(tp, false); r8152b_disable_aldps(tp); r8152b_enter_oob(tp); r8152b_enable_aldps(tp); @@ -2399,13 +2416,8 @@ static void r8152b_init(struct r8152 *tp) r8152b_hw_phy_cfg(tp); - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data &= ~POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); + r8152_power_cut_en(tp, false); - 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); r8152b_exit_oob(tp); @@ -2659,17 +2671,8 @@ static void r8152b_get_version(struct r8152 *tp) static void rtl8152_unload(struct r8152 *tp) { - u32 ocp_data; - - if (tp->version != RTL_VER_01) { - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - 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); + if (tp->version != RTL_VER_01) + r8152_power_cut_en(tp, true); } static void rtl8153_unload(struct r8152 *tp) From b97027233db74a24eb3aca693ed3f85461c7f440 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:00 +0800 Subject: [PATCH 03/14] r8152: replace some types from int to bool Modify the following functions. - r8153_u1u2en - r8153_u2p3en - r8153_power_cut_en Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 2d5e76159ca7d..4888e4f4dd8f2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1989,7 +1989,7 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) sram_write(tp, SRAM_10M_AMP2, data); } -static void r8153_u1u2en(struct r8152 *tp, int enable) +static void r8153_u1u2en(struct r8152 *tp, bool enable) { u8 u1u2[8]; @@ -2001,7 +2001,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable) usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); } -static void r8153_u2p3en(struct r8152 *tp, int enable) +static void r8153_u2p3en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -2013,7 +2013,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable) ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); } -static void r8153_power_cut_en(struct r8152 *tp, int enable) +static void r8153_power_cut_en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -2261,8 +2261,8 @@ static void rtl8152_down(struct r8152 *tp) static void rtl8153_down(struct r8152 *tp) { - r8153_u1u2en(tp, 0); - r8153_power_cut_en(tp, 0); + r8153_u1u2en(tp, false); + r8153_power_cut_en(tp, false); r8153_disable_aldps(tp); r8153_enter_oob(tp); r8153_enable_aldps(tp); @@ -2455,7 +2455,7 @@ static void r8153_init(struct r8152 *tp) u32 ocp_data; int i; - r8153_u1u2en(tp, 0); + r8153_u1u2en(tp, false); for (i = 0; i < 500; i++) { if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & @@ -2471,7 +2471,7 @@ static void r8153_init(struct r8152 *tp) msleep(20); } - r8153_u2p3en(tp, 0); + r8153_u2p3en(tp, false); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); ocp_data &= ~TIMER11_EN; @@ -2496,8 +2496,8 @@ static void r8153_init(struct r8152 *tp) ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); - r8153_power_cut_en(tp, 0); - r8153_u1u2en(tp, 1); + r8153_power_cut_en(tp, false); + r8153_u1u2en(tp, true); r8153_first_init(tp); @@ -2677,7 +2677,7 @@ static void rtl8152_unload(struct r8152 *tp) static void rtl8153_unload(struct r8152 *tp) { - r8153_power_cut_en(tp, 1); + r8153_power_cut_en(tp, true); } static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) From 8a91c8246a847a2435a7ef361bfcd4c2b5be4ea2 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:01 +0800 Subject: [PATCH 04/14] r8152: load the default MAC address Except for RTL_VER_01, replace loading the MAC address from PLA_IDR with from PLA_BACKUP. The default MAC address may be modified by the other OS, so the PLA_IDR may be not the default MAC address. The data in the PLA_BACKUP address of the RTL_VER_01 may be destoryed, so load MAC address from PLA_IDR for RTL_VER_01. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 4888e4f4dd8f2..3847c3507624d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -889,11 +889,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); static inline void set_ethernet_addr(struct r8152 *tp) { struct net_device *dev = tp->netdev; + int ret; u8 node_id[8] = {0}; - if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0) + if (tp->version == RTL_VER_01) + ret = pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id); + else + ret = pla_ocp_read(tp, PLA_BACKUP, sizeof(node_id), node_id); + + if (ret < 0) { netif_notice(tp, probe, dev, "inet addr fail\n"); - else { + } else { + if (tp->version != RTL_VER_01) { + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, + CRWECR_CONFIG); + pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, + sizeof(node_id), node_id); + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, + CRWECR_NORAML); + } + memcpy(dev->dev_addr, node_id, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); } From d84130a10820d074fe52b066f459838324d3774c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:02 +0800 Subject: [PATCH 05/14] r8152: reduce the frequency of spin_lock Replace getting one item from a list with getting the whole list one time. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 47 +++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3847c3507624d..2a778faa96307 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1299,9 +1299,16 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) { + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; + unsigned long flags; int remain; u8 *tx_data; + __skb_queue_head_init(&skb_head); + spin_lock_irqsave(&tx_queue->lock, flags); + skb_queue_splice_init(tx_queue, &skb_head); + spin_unlock_irqrestore(&tx_queue->lock, flags); + tx_data = agg->head; agg->skb_num = agg->skb_len = 0; remain = rx_buf_sz; @@ -1311,14 +1318,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) struct sk_buff *skb; unsigned int len; - skb = skb_dequeue(&tp->tx_queue); + skb = __skb_dequeue(&skb_head); if (!skb) break; remain -= sizeof(*tx_desc); len = skb->len; if (remain < len) { - skb_queue_head(&tp->tx_queue, skb); + __skb_queue_head(&skb_head, skb); break; } @@ -1336,6 +1343,12 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); } + if (!skb_queue_empty(&skb_head)) { + spin_lock_irqsave(&tx_queue->lock, flags); + skb_queue_splice(&skb_head, tx_queue); + spin_unlock_irqrestore(&tx_queue->lock, flags); + } + netif_tx_lock(tp->netdev); if (netif_queue_stopped(tp->netdev) && @@ -1354,10 +1367,17 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) static void rx_bottom(struct r8152 *tp) { unsigned long flags; - struct list_head *cursor, *next; + struct list_head *cursor, *next, rx_queue; + if (list_empty(&tp->rx_done)) + return; + + INIT_LIST_HEAD(&rx_queue); spin_lock_irqsave(&tp->rx_lock, flags); - list_for_each_safe(cursor, next, &tp->rx_done) { + list_splice_init(&tp->rx_done, &rx_queue); + spin_unlock_irqrestore(&tp->rx_lock, flags); + + list_for_each_safe(cursor, next, &rx_queue) { struct rx_desc *rx_desc; struct rx_agg *agg; int len_used = 0; @@ -1366,7 +1386,6 @@ static void rx_bottom(struct r8152 *tp) int ret; list_del_init(cursor); - spin_unlock_irqrestore(&tp->rx_lock, flags); agg = list_entry(cursor, struct rx_agg, list); urb = agg->urb; @@ -1416,13 +1435,13 @@ static void rx_bottom(struct r8152 *tp) submit: ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); - spin_lock_irqsave(&tp->rx_lock, flags); if (ret && ret != -ENODEV) { - list_add_tail(&agg->list, next); + spin_lock_irqsave(&tp->rx_lock, flags); + list_add_tail(&agg->list, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); tasklet_schedule(&tp->tl); } } - spin_unlock_irqrestore(&tp->rx_lock, flags); } static void tx_bottom(struct r8152 *tp) @@ -1496,9 +1515,19 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) static void rtl_drop_queued_tx(struct r8152 *tp) { struct net_device_stats *stats = &tp->netdev->stats; + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; + unsigned long flags; struct sk_buff *skb; - while ((skb = skb_dequeue(&tp->tx_queue))) { + if (skb_queue_empty(tx_queue)) + return; + + __skb_queue_head_init(&skb_head); + spin_lock_irqsave(&tx_queue->lock, flags); + skb_queue_splice_init(tx_queue, &skb_head); + spin_unlock_irqrestore(&tx_queue->lock, flags); + + while ((skb = __skb_dequeue(&skb_head))) { dev_kfree_skb(skb); stats->tx_dropped++; } From f0cbe0ac87c123a80dac3b2df72ecb947ef63ad8 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:03 +0800 Subject: [PATCH 06/14] r8152: clear BMCR_PDOWN Modify the method of enabling the PHY to clear BMCR_PDOWN only. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 2a778faa96307..c7bae3920038f 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1845,7 +1845,14 @@ static inline void r8152b_enable_aldps(struct r8152 *tp) static void r8152b_hw_phy_cfg(struct r8152 *tp) { - r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); + u16 data; + + data = r8152_mdio_read(tp, MII_BMCR); + if (data & BMCR_PDOWN) { + data &= ~BMCR_PDOWN; + r8152_mdio_write(tp, MII_BMCR, data); + } + r8152b_disable_aldps(tp); } @@ -1995,7 +2002,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) u16 data; ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); - r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); + data = r8152_mdio_read(tp, MII_BMCR); + if (data & BMCR_PDOWN) { + data &= ~BMCR_PDOWN; + r8152_mdio_write(tp, MII_BMCR, data); + } if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); From aa66a5f1af163b6c90fca5a06c7fdab121b70cd2 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:04 +0800 Subject: [PATCH 07/14] r8152: combine PHY reset with set_speed PHY reset is necessary after some hw settings. However, it would cause the linking down, and so does the set_speed function. Combine the PHY reset with set_speed function. That could reduce the frequency of linking down and accessing the PHY register. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 57 ++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index c7bae3920038f..b3155da97f09d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -436,6 +436,7 @@ enum rtl8152_flags { RTL8152_SET_RX_MODE, WORK_ENABLE, RTL8152_LINK_CHG, + PHY_RESET, }; /* Define these values to match your device */ @@ -1796,6 +1797,29 @@ static void r8152_power_cut_en(struct r8152 *tp, bool enable) } +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; + } +} + static void rtl_clear_bp(struct r8152 *tp) { ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); @@ -1854,6 +1878,7 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) } r8152b_disable_aldps(tp); + set_bit(PHY_RESET, &tp->flags); } static void r8152b_exit_oob(struct r8152 *tp) @@ -2042,6 +2067,8 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) data = sram_read(tp, SRAM_10M_AMP2); data |= AMP_DN; sram_write(tp, SRAM_10M_AMP2, data); + + set_bit(PHY_RESET, &tp->flags); } static void r8153_u1u2en(struct r8152 *tp, bool enable) @@ -2295,12 +2322,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) bmcr = BMCR_ANENABLE | BMCR_ANRESTART; } + if (test_bit(PHY_RESET, &tp->flags)) + bmcr |= BMCR_RESET; + if (tp->mii.supports_gmii) r8152_mdio_write(tp, MII_CTRL1000, gbcr); r8152_mdio_write(tp, MII_ADVERTISE, anar); r8152_mdio_write(tp, MII_BMCR, bmcr); + 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; + } + } + out: return ret; @@ -2364,6 +2405,10 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); + + if (test_bit(PHY_RESET, &tp->flags)) + rtl_phy_reset(tp); + out1: return; } @@ -2459,7 +2504,6 @@ static void r8152b_enable_fc(struct r8152 *tp) static void r8152b_init(struct r8152 *tp) { u32 ocp_data; - int i; rtl_clear_bp(tp); @@ -2491,14 +2535,6 @@ static void r8152b_init(struct r8152 *tp) r8152b_enable_aldps(tp); r8152b_enable_fc(tp); - r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE | - BMCR_ANRESTART); - for (i = 0; i < 100; i++) { - udelay(100); - if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET)) - break; - } - /* enable rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~RX_AGG_DISABLE; @@ -2569,9 +2605,6 @@ static void r8153_init(struct r8152 *tp) r8153_enable_eee(tp); r8153_enable_aldps(tp); r8152b_enable_fc(tp); - - r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE | - BMCR_ANRESTART); } static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) From 7e9da48161506bb24d6072be9dfcd62ac8d95b88 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:05 +0800 Subject: [PATCH 08/14] r8152: move some functions from probe to open Add up method for rtl_ops and asign relative functions. Move clear_bp() and hw_phy_cfg() from init method to up method of rtl_ops. Call rtl_ops.up() for ndo_open() and rtl_ops.down for ndo_stop(). Replace allocating the memory in probe() with in ndo_open(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 45 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b3155da97f09d..828572a5b24a3 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -515,6 +515,7 @@ struct r8152 { void (*init)(struct r8152 *); int (*enable)(struct r8152 *); void (*disable)(struct r8152 *); + void (*up)(struct r8152 *); void (*down)(struct r8152 *); void (*unload)(struct r8152 *); } rtl_ops; @@ -1878,6 +1879,10 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) } r8152b_disable_aldps(tp); + + rtl_clear_bp(tp); + + r8152b_enable_aldps(tp); set_bit(PHY_RESET, &tp->flags); } @@ -1891,6 +1896,7 @@ static void r8152b_exit_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); rxdy_gated_en(tp, true); + r8152b_hw_phy_cfg(tp); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); @@ -2033,6 +2039,8 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } + r8153_clear_bp(tp); + if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); data &= ~CTAP_SHORT_EN; @@ -2418,6 +2426,12 @@ static int rtl8152_open(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; + res = alloc_all_mem(tp); + if (res) + goto out; + + tp->rtl_ops.up(tp); + rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); @@ -2431,9 +2445,11 @@ static int rtl8152_open(struct net_device *netdev) netif_device_detach(tp->netdev); netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", res); + free_all_mem(tp); } +out: return res; } @@ -2447,9 +2463,11 @@ static int rtl8152_close(struct net_device *netdev) cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); tasklet_disable(&tp->tl); - tp->rtl_ops.disable(tp); + tp->rtl_ops.down(tp); tasklet_enable(&tp->tl); + free_all_mem(tp); + return res; } @@ -2505,21 +2523,14 @@ static void r8152b_init(struct r8152 *tp) { u32 ocp_data; - rtl_clear_bp(tp); - 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); } - r8152b_hw_phy_cfg(tp); - r8152_power_cut_en(tp, false); - - r8152b_exit_oob(tp); - 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); @@ -2568,8 +2579,6 @@ static void r8153_init(struct r8152 *tp) ocp_data &= ~TIMER11_EN; ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); - r8153_clear_bp(tp); - 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); @@ -2590,8 +2599,6 @@ static void r8153_init(struct r8152 *tp) r8153_power_cut_en(tp, false); r8153_u1u2en(tp, true); - r8153_first_init(tp); - 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, @@ -2618,10 +2625,10 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); tasklet_disable(&tp->tl); + tp->rtl_ops.down(tp); + tasklet_enable(&tp->tl); } - tp->rtl_ops.down(tp); - return 0; } @@ -2632,6 +2639,7 @@ static int rtl8152_resume(struct usb_interface *intf) tp->rtl_ops.init(tp); netif_device_attach(tp->netdev); if (netif_running(tp->netdev)) { + tp->rtl_ops.up(tp); rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); @@ -2639,7 +2647,6 @@ static int rtl8152_resume(struct usb_interface *intf) netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); usb_submit_urb(tp->intr_urb, GFP_KERNEL); - tasklet_enable(&tp->tl); } return 0; @@ -2780,6 +2787,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8152b_init; ops->enable = rtl8152_enable; ops->disable = rtl8152_disable; + ops->up = r8152b_exit_oob; ops->down = rtl8152_down; ops->unload = rtl8152_unload; ret = 0; @@ -2788,6 +2796,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8152_disable; + ops->up = r8153_first_init; ops->down = rtl8153_down; ops->unload = rtl8153_unload; ret = 0; @@ -2803,6 +2812,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8152_disable; + ops->up = r8153_first_init; ops->down = rtl8153_down; ops->unload = rtl8153_unload; ret = 0; @@ -2870,10 +2880,6 @@ static int rtl8152_probe(struct usb_interface *intf, tp->rtl_ops.init(tp); set_ethernet_addr(tp); - ret = alloc_all_mem(tp); - if (ret) - goto out; - usb_set_intfdata(intf, tp); ret = register_netdev(netdev); @@ -2903,7 +2909,6 @@ static void rtl8152_disconnect(struct usb_interface *intf) tasklet_kill(&tp->tl); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); - free_all_mem(tp); free_netdev(tp->netdev); } } From 21ff2e8976b1be23eb0125ee83eb807ad40fb226 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:06 +0800 Subject: [PATCH 09/14] r8152: support WOL Support WOL for RTL8152 and RTL8153. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 118 +++++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 13 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 828572a5b24a3..5d520bee6c0c8 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -23,7 +23,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v1.04.0 (2014/01/15)" +#define DRIVER_VERSION "v1.05.0 (2014/02/18)" #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -62,6 +62,8 @@ #define PLA_RSTTELLY 0xe800 #define PLA_CR 0xe813 #define PLA_CRWECR 0xe81c +#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ +#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */ #define PLA_CONFIG5 0xe822 #define PLA_PHY_PWR 0xe84c #define PLA_OOB_CTRL 0xe84f @@ -216,7 +218,14 @@ /* PAL_BDC_CR */ #define ALDPS_PROXY_MODE 0x0001 +/* PLA_CONFIG34 */ +#define LINK_ON_WAKE_EN 0x0010 +#define LINK_OFF_WAKE_EN 0x0008 + /* PLA_CONFIG5 */ +#define BWF_EN 0x0040 +#define MWF_EN 0x0020 +#define UWF_EN 0x0010 #define LAN_WAKE_EN 0x0002 /* PLA_LED_FEATURE */ @@ -521,6 +530,7 @@ struct r8152 { } rtl_ops; int intr_interval; + u32 saved_wolopts; u32 msg_enable; u32 tx_qlen; u16 ocp_base; @@ -1798,6 +1808,74 @@ static void r8152_power_cut_en(struct r8152 *tp, bool enable) } +#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); +} + static void rtl_phy_reset(struct r8152 *tp) { u16 data; @@ -2002,10 +2080,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - ocp_data |= MAGIC_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); ocp_data |= CPCR_RX_VLAN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); @@ -2018,8 +2092,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -2217,10 +2289,6 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - ocp_data |= MAGIC_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); - 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); @@ -2237,8 +2305,6 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -2652,6 +2718,24 @@ static int rtl8152_resume(struct usb_interface *intf) return 0; } +static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct r8152 *tp = netdev_priv(dev); + + wol->supported = WAKE_ANY; + wol->wolopts = __rtl_get_wol(tp); +} + +static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct r8152 *tp = netdev_priv(dev); + + __rtl_set_wol(tp, wol->wolopts); + tp->saved_wolopts = wol->wolopts & WAKE_ANY; + + return 0; +} + static void rtl8152_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { @@ -2685,6 +2769,8 @@ static struct ethtool_ops ops = { .get_settings = rtl8152_get_settings, .set_settings = rtl8152_set_settings, .get_link = ethtool_op_get_link, + .get_wol = rtl8152_get_wol, + .set_wol = rtl8152_set_wol, }; static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -2888,6 +2974,12 @@ static int rtl8152_probe(struct usb_interface *intf, goto out1; } + 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); + netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; From 9a4be1bd04d6df0cb1a1a0fe49430b27152bb98f Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:07 +0800 Subject: [PATCH 10/14] r8152: support runtime suspend Support runtime suspend for RTL8152 and RTL8153. Move tx_bottom() from tasklet to delayed_work. That avoids to transmit tx packets after calling autosuspend. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 181 +++++++++++++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 23 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 5d520bee6c0c8..f303549b416a6 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -445,6 +445,7 @@ enum rtl8152_flags { RTL8152_SET_RX_MODE, WORK_ENABLE, RTL8152_LINK_CHG, + SELECTIVE_SUSPEND, PHY_RESET, }; @@ -877,11 +878,21 @@ static u16 sram_read(struct r8152 *tp, u16 addr) static int read_mii_word(struct net_device *netdev, int phy_id, int reg) { struct r8152 *tp = netdev_priv(netdev); + int ret; if (phy_id != R8152_PHY_ID) return -EINVAL; - return r8152_mdio_read(tp, reg); + 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; } static @@ -892,7 +903,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) if (phy_id != R8152_PHY_ID) return; + if (usb_autopm_get_interface(tp->intf) < 0) + return; + r8152_mdio_write(tp, reg, val); + + usb_autopm_put_interface(tp->intf); } static @@ -978,6 +994,8 @@ static void read_bulk_callback(struct urb *urb) if (!netif_carrier_ok(netdev)) return; + usb_mark_last_busy(tp->udev); + switch (status) { case 0: if (urb->actual_length < ETH_ZLEN) @@ -1045,6 +1063,8 @@ static void write_bulk_callback(struct urb *urb) list_add_tail(&agg->list, &tp->tx_free); spin_unlock_irqrestore(&tp->tx_lock, flags); + usb_autopm_put_interface_async(tp->intf); + if (!netif_carrier_ok(tp->netdev)) return; @@ -1055,7 +1075,7 @@ static void write_bulk_callback(struct urb *urb) return; if (!skb_queue_empty(&tp->tx_queue)) - tasklet_schedule(&tp->tl); + schedule_delayed_work(&tp->schedule, 0); } static void intr_callback(struct urb *urb) @@ -1313,7 +1333,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) { struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; unsigned long flags; - int remain; + int remain, ret; u8 *tx_data; __skb_queue_head_init(&skb_head); @@ -1361,19 +1381,28 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) spin_unlock_irqrestore(&tx_queue->lock, flags); } - netif_tx_lock(tp->netdev); + netif_tx_lock_bh(tp->netdev); if (netif_queue_stopped(tp->netdev) && skb_queue_len(&tp->tx_queue) < tp->tx_qlen) netif_wake_queue(tp->netdev); - netif_tx_unlock(tp->netdev); + netif_tx_unlock_bh(tp->netdev); + + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out_tx_fill; 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); - return usb_submit_urb(agg->urb, GFP_ATOMIC); + ret = usb_submit_urb(agg->urb, GFP_KERNEL); + if (ret < 0) + usb_autopm_put_interface(tp->intf); + +out_tx_fill: + return ret; } static void rx_bottom(struct r8152 *tp) @@ -1511,7 +1540,6 @@ static void bottom_half(unsigned long data) return; rx_bottom(tp); - tx_bottom(tp); } static @@ -1621,7 +1649,7 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, netif_stop_queue(netdev); if (!list_empty(&tp->tx_free)) - tasklet_schedule(&tp->tl); + schedule_delayed_work(&tp->schedule, 0); return NETDEV_TX_OK; } @@ -1876,6 +1904,25 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) device_set_wakeup_enable(&tp->udev->dev, false); } +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); + } +} + static void rtl_phy_reset(struct r8152 *tp) { u16 data; @@ -2467,6 +2514,9 @@ static void rtl_work_func_t(struct work_struct *work) { struct r8152 *tp = container_of(work, struct r8152, schedule.work); + if (usb_autopm_get_interface(tp->intf) < 0) + return; + if (!test_bit(WORK_ENABLE, &tp->flags)) goto out1; @@ -2479,12 +2529,14 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); + if (tp->speed & LINK_STATUS) + tx_bottom(tp); if (test_bit(PHY_RESET, &tp->flags)) rtl_phy_reset(tp); out1: - return; + usb_autopm_put_interface(tp->intf); } static int rtl8152_open(struct net_device *netdev) @@ -2496,6 +2548,21 @@ static int rtl8152_open(struct net_device *netdev) if (res) goto out; + 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); + } + tp->rtl_ops.up(tp); rtl8152_set_speed(tp, AUTONEG_ENABLE, @@ -2514,6 +2581,7 @@ static int rtl8152_open(struct net_device *netdev) free_all_mem(tp); } + usb_autopm_put_interface(tp->intf); out: return res; @@ -2528,9 +2596,26 @@ static int rtl8152_close(struct net_device *netdev) usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); - tasklet_disable(&tp->tl); - tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); + + res = usb_autopm_get_interface(tp->intf); + if (res < 0) { + rtl_drop_queued_tx(tp); + } else { + /* + * The autosuspend may have been enabled and wouldn't + * 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); + } free_all_mem(tp); @@ -2684,15 +2769,22 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) { struct r8152 *tp = usb_get_intfdata(intf); - netif_device_detach(tp->netdev); + if (PMSG_IS_AUTO(message)) + set_bit(SELECTIVE_SUSPEND, &tp->flags); + else + netif_device_detach(tp->netdev); if (netif_running(tp->netdev)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); - tasklet_disable(&tp->tl); - tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_runtime_suspend_enable(tp, true); + } else { + tasklet_disable(&tp->tl); + tp->rtl_ops.down(tp); + tasklet_enable(&tp->tl); + } } return 0; @@ -2702,13 +2794,23 @@ static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); - tp->rtl_ops.init(tp); - netif_device_attach(tp->netdev); + if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + tp->rtl_ops.init(tp); + netif_device_attach(tp->netdev); + } + if (netif_running(tp->netdev)) { - tp->rtl_ops.up(tp); - rtl8152_set_speed(tp, AUTONEG_ENABLE, + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_runtime_suspend_enable(tp, false); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + if (tp->speed & LINK_STATUS) + tp->rtl_ops.disable(tp); + } else { + tp->rtl_ops.up(tp); + rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); + } tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); @@ -2722,18 +2824,31 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct r8152 *tp = netdev_priv(dev); + if (usb_autopm_get_interface(tp->intf) < 0) + return; + wol->supported = WAKE_ANY; wol->wolopts = __rtl_get_wol(tp); + + usb_autopm_put_interface(tp->intf); } static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct r8152 *tp = netdev_priv(dev); + int ret; + + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out_set_wol; __rtl_set_wol(tp, wol->wolopts); tp->saved_wolopts = wol->wolopts & WAKE_ANY; - return 0; + usb_autopm_put_interface(tp->intf); + +out_set_wol: + return ret; } static void rtl8152_get_drvinfo(struct net_device *netdev, @@ -2760,8 +2875,18 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct r8152 *tp = netdev_priv(dev); + int ret; + + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out; - return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); + ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); + + usb_autopm_put_interface(tp->intf); + +out: + return ret; } static struct ethtool_ops ops = { @@ -2777,7 +2902,11 @@ 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); - int res = 0; + int res; + + res = usb_autopm_get_interface(tp->intf); + if (res < 0) + goto out; switch (cmd) { case SIOCGMIIPHY: @@ -2800,6 +2929,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) res = -EOPNOTSUPP; } + usb_autopm_put_interface(tp->intf); + +out: return res; } @@ -2962,6 +3094,8 @@ static int rtl8152_probe(struct usb_interface *intf, tp->mii.phy_id = R8152_PHY_ID; tp->mii.supports_gmii = 0; + intf->needs_remote_wakeup = 1; + r8152b_get_version(tp); tp->rtl_ops.init(tp); set_ethernet_addr(tp); @@ -3023,6 +3157,7 @@ static struct usb_driver rtl8152_driver = { .suspend = rtl8152_suspend, .resume = rtl8152_resume, .reset_resume = rtl8152_resume, + .supports_autosuspend = 1, }; module_usb_driver(rtl8152_driver); From da9bd117ffbf0eb10c9a9a3278c96e003293977a Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:08 +0800 Subject: [PATCH 11/14] r8152: disable teredo for RTL8152 Disable teredo for RTL8152 by default. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f303549b416a6..3ff11ed6ee516 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2021,6 +2021,7 @@ static void r8152b_exit_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); rxdy_gated_en(tp, true); + r8153_teredo_off(tp); r8152b_hw_phy_cfg(tp); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); From 9d9aafa1e8dd785d0b2e5e75e4cbbe56b13907d3 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:09 +0800 Subject: [PATCH 12/14] r8152: replace netif_rx with netif_receive_skb Replace netif_rx with netif_receive_skb to avoid disabling irq frequently for increasing the efficiency. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3ff11ed6ee516..ff02d5d8ec414 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1464,7 +1464,7 @@ static void rx_bottom(struct r8152 *tp) memcpy(skb->data, rx_data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); - netif_rx(skb); + netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += pkt_len; From a634782f6cff8cb321a1b118b1085a234f5a21ed Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:10 +0800 Subject: [PATCH 13/14] r8152: set disable_hub_initiated_lpm Set disable_hub_initiated_lpm = 1. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ff02d5d8ec414..db988428cefc2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3159,6 +3159,7 @@ static struct usb_driver rtl8152_driver = { .resume = rtl8152_resume, .reset_resume = rtl8152_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8152_driver); From a5ec27c1509b1dd2918aff8e6804056984fbf598 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 18 Feb 2014 21:49:11 +0800 Subject: [PATCH 14/14] r8152: support get_msglevel and set_msglevel Support get_msglevel and set_msglevel. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index db988428cefc2..0654bd3c45919 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2852,6 +2852,20 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return ret; } +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; +} + static void rtl8152_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { @@ -2895,6 +2909,8 @@ static struct ethtool_ops ops = { .get_settings = rtl8152_get_settings, .set_settings = rtl8152_set_settings, .get_link = ethtool_op_get_link, + .get_msglevel = rtl8152_get_msglevel, + .set_msglevel = rtl8152_set_msglevel, .get_wol = rtl8152_get_wol, .set_wol = rtl8152_set_wol, };