Commit 814ce148 authored by David S. Miller's avatar David S. Miller

Merge branch 'r8152'

Hayes Wang says:

====================
r8152: improvement and new features

Change some flows or behavior to improve the efficiency or make the
code readable. Besides, support WOL and runtime suspend.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b0b9ad71 a5ec27c1
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
/* Version Information */ /* 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 <nic_swsd@realtek.com>" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152" #define MODULENAME "r8152"
...@@ -62,6 +62,8 @@ ...@@ -62,6 +62,8 @@
#define PLA_RSTTELLY 0xe800 #define PLA_RSTTELLY 0xe800
#define PLA_CR 0xe813 #define PLA_CR 0xe813
#define PLA_CRWECR 0xe81c #define PLA_CRWECR 0xe81c
#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */
#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */
#define PLA_CONFIG5 0xe822 #define PLA_CONFIG5 0xe822
#define PLA_PHY_PWR 0xe84c #define PLA_PHY_PWR 0xe84c
#define PLA_OOB_CTRL 0xe84f #define PLA_OOB_CTRL 0xe84f
...@@ -216,7 +218,14 @@ ...@@ -216,7 +218,14 @@
/* PAL_BDC_CR */ /* PAL_BDC_CR */
#define ALDPS_PROXY_MODE 0x0001 #define ALDPS_PROXY_MODE 0x0001
/* PLA_CONFIG34 */
#define LINK_ON_WAKE_EN 0x0010
#define LINK_OFF_WAKE_EN 0x0008
/* PLA_CONFIG5 */ /* PLA_CONFIG5 */
#define BWF_EN 0x0040
#define MWF_EN 0x0020
#define UWF_EN 0x0010
#define LAN_WAKE_EN 0x0002 #define LAN_WAKE_EN 0x0002
/* PLA_LED_FEATURE */ /* PLA_LED_FEATURE */
...@@ -436,6 +445,8 @@ enum rtl8152_flags { ...@@ -436,6 +445,8 @@ enum rtl8152_flags {
RTL8152_SET_RX_MODE, RTL8152_SET_RX_MODE,
WORK_ENABLE, WORK_ENABLE,
RTL8152_LINK_CHG, RTL8152_LINK_CHG,
SELECTIVE_SUSPEND,
PHY_RESET,
}; };
/* Define these values to match your device */ /* Define these values to match your device */
...@@ -514,11 +525,13 @@ struct r8152 { ...@@ -514,11 +525,13 @@ struct r8152 {
void (*init)(struct r8152 *); void (*init)(struct r8152 *);
int (*enable)(struct r8152 *); int (*enable)(struct r8152 *);
void (*disable)(struct r8152 *); void (*disable)(struct r8152 *);
void (*up)(struct r8152 *);
void (*down)(struct r8152 *); void (*down)(struct r8152 *);
void (*unload)(struct r8152 *); void (*unload)(struct r8152 *);
} rtl_ops; } rtl_ops;
int intr_interval; int intr_interval;
u32 saved_wolopts;
u32 msg_enable; u32 msg_enable;
u32 tx_qlen; u32 tx_qlen;
u16 ocp_base; u16 ocp_base;
...@@ -865,11 +878,21 @@ static u16 sram_read(struct r8152 *tp, u16 addr) ...@@ -865,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) static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
{ {
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
int ret;
if (phy_id != R8152_PHY_ID) if (phy_id != R8152_PHY_ID)
return -EINVAL; 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 static
...@@ -880,7 +903,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) ...@@ -880,7 +903,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
if (phy_id != R8152_PHY_ID) if (phy_id != R8152_PHY_ID)
return; return;
if (usb_autopm_get_interface(tp->intf) < 0)
return;
r8152_mdio_write(tp, reg, val); r8152_mdio_write(tp, reg, val);
usb_autopm_put_interface(tp->intf);
} }
static static
...@@ -889,11 +917,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); ...@@ -889,11 +917,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) static inline void set_ethernet_addr(struct r8152 *tp)
{ {
struct net_device *dev = tp->netdev; struct net_device *dev = tp->netdev;
int ret;
u8 node_id[8] = {0}; 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"); 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->dev_addr, node_id, dev->addr_len);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
} }
...@@ -951,6 +994,8 @@ static void read_bulk_callback(struct urb *urb) ...@@ -951,6 +994,8 @@ static void read_bulk_callback(struct urb *urb)
if (!netif_carrier_ok(netdev)) if (!netif_carrier_ok(netdev))
return; return;
usb_mark_last_busy(tp->udev);
switch (status) { switch (status) {
case 0: case 0:
if (urb->actual_length < ETH_ZLEN) if (urb->actual_length < ETH_ZLEN)
...@@ -1018,6 +1063,8 @@ static void write_bulk_callback(struct urb *urb) ...@@ -1018,6 +1063,8 @@ static void write_bulk_callback(struct urb *urb)
list_add_tail(&agg->list, &tp->tx_free); list_add_tail(&agg->list, &tp->tx_free);
spin_unlock_irqrestore(&tp->tx_lock, flags); spin_unlock_irqrestore(&tp->tx_lock, flags);
usb_autopm_put_interface_async(tp->intf);
if (!netif_carrier_ok(tp->netdev)) if (!netif_carrier_ok(tp->netdev))
return; return;
...@@ -1028,7 +1075,7 @@ static void write_bulk_callback(struct urb *urb) ...@@ -1028,7 +1075,7 @@ static void write_bulk_callback(struct urb *urb)
return; return;
if (!skb_queue_empty(&tp->tx_queue)) if (!skb_queue_empty(&tp->tx_queue))
tasklet_schedule(&tp->tl); schedule_delayed_work(&tp->schedule, 0);
} }
static void intr_callback(struct urb *urb) static void intr_callback(struct urb *urb)
...@@ -1284,9 +1331,16 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) ...@@ -1284,9 +1331,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) static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
{ {
int remain; struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
unsigned long flags;
int remain, ret;
u8 *tx_data; 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; tx_data = agg->head;
agg->skb_num = agg->skb_len = 0; agg->skb_num = agg->skb_len = 0;
remain = rx_buf_sz; remain = rx_buf_sz;
...@@ -1296,14 +1350,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) ...@@ -1296,14 +1350,14 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
struct sk_buff *skb; struct sk_buff *skb;
unsigned int len; unsigned int len;
skb = skb_dequeue(&tp->tx_queue); skb = __skb_dequeue(&skb_head);
if (!skb) if (!skb)
break; break;
remain -= sizeof(*tx_desc); remain -= sizeof(*tx_desc);
len = skb->len; len = skb->len;
if (remain < len) { if (remain < len) {
skb_queue_head(&tp->tx_queue, skb); __skb_queue_head(&skb_head, skb);
break; break;
} }
...@@ -1321,28 +1375,50 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) ...@@ -1321,28 +1375,50 @@ 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); remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
} }
netif_tx_lock(tp->netdev); 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_bh(tp->netdev);
if (netif_queue_stopped(tp->netdev) && if (netif_queue_stopped(tp->netdev) &&
skb_queue_len(&tp->tx_queue) < tp->tx_qlen) skb_queue_len(&tp->tx_queue) < tp->tx_qlen)
netif_wake_queue(tp->netdev); 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), usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
agg->head, (int)(tx_data - (u8 *)agg->head), agg->head, (int)(tx_data - (u8 *)agg->head),
(usb_complete_t)write_bulk_callback, agg); (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) static void rx_bottom(struct r8152 *tp)
{ {
unsigned long flags; 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); 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_desc *rx_desc;
struct rx_agg *agg; struct rx_agg *agg;
int len_used = 0; int len_used = 0;
...@@ -1351,7 +1427,6 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1351,7 +1427,6 @@ static void rx_bottom(struct r8152 *tp)
int ret; int ret;
list_del_init(cursor); list_del_init(cursor);
spin_unlock_irqrestore(&tp->rx_lock, flags);
agg = list_entry(cursor, struct rx_agg, list); agg = list_entry(cursor, struct rx_agg, list);
urb = agg->urb; urb = agg->urb;
...@@ -1389,7 +1464,7 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1389,7 +1464,7 @@ static void rx_bottom(struct r8152 *tp)
memcpy(skb->data, rx_data, pkt_len); memcpy(skb->data, rx_data, pkt_len);
skb_put(skb, pkt_len); skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb); netif_receive_skb(skb);
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += pkt_len; stats->rx_bytes += pkt_len;
...@@ -1401,13 +1476,13 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1401,13 +1476,13 @@ static void rx_bottom(struct r8152 *tp)
submit: submit:
ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
spin_lock_irqsave(&tp->rx_lock, flags);
if (ret && ret != -ENODEV) { 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); tasklet_schedule(&tp->tl);
} }
} }
spin_unlock_irqrestore(&tp->rx_lock, flags);
} }
static void tx_bottom(struct r8152 *tp) static void tx_bottom(struct r8152 *tp)
...@@ -1465,7 +1540,6 @@ static void bottom_half(unsigned long data) ...@@ -1465,7 +1540,6 @@ static void bottom_half(unsigned long data)
return; return;
rx_bottom(tp); rx_bottom(tp);
tx_bottom(tp);
} }
static static
...@@ -1478,6 +1552,27 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) ...@@ -1478,6 +1552,27 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
return usb_submit_urb(agg->urb, 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_head skb_head, *tx_queue = &tp->tx_queue;
unsigned long flags;
struct sk_buff *skb;
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++;
}
}
static void rtl8152_tx_timeout(struct net_device *netdev) static void rtl8152_tx_timeout(struct net_device *netdev)
{ {
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
...@@ -1554,7 +1649,7 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, ...@@ -1554,7 +1649,7 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
netif_stop_queue(netdev); netif_stop_queue(netdev);
if (!list_empty(&tp->tx_free)) if (!list_empty(&tp->tx_free))
tasklet_schedule(&tp->tl); schedule_delayed_work(&tp->schedule, 0);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -1613,6 +1708,18 @@ static void rtl_set_eee_plus(struct r8152 *tp) ...@@ -1613,6 +1708,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) static int rtl_enable(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
...@@ -1624,9 +1731,7 @@ static int rtl_enable(struct r8152 *tp) ...@@ -1624,9 +1731,7 @@ static int rtl_enable(struct r8152 *tp)
ocp_data |= CR_RE | CR_TE; ocp_data |= CR_RE | CR_TE;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); rxdy_gated_en(tp, false);
ocp_data &= ~RXDY_GATED_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
INIT_LIST_HEAD(&tp->rx_done); INIT_LIST_HEAD(&tp->rx_done);
ret = 0; ret = 0;
...@@ -1681,8 +1786,6 @@ static int rtl8153_enable(struct r8152 *tp) ...@@ -1681,8 +1786,6 @@ static int rtl8153_enable(struct r8152 *tp)
static void rtl8152_disable(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; u32 ocp_data;
int i; int i;
...@@ -1690,17 +1793,12 @@ static void rtl8152_disable(struct r8152 *tp) ...@@ -1690,17 +1793,12 @@ static void rtl8152_disable(struct r8152 *tp)
ocp_data &= ~RCR_ACPT_ALL; ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
while ((skb = skb_dequeue(&tp->tx_queue))) { rtl_drop_queued_tx(tp);
dev_kfree_skb(skb);
stats->tx_dropped++;
}
for (i = 0; i < RTL8152_MAX_TX; i++) for (i = 0; i < RTL8152_MAX_TX; i++)
usb_kill_urb(tp->tx_info[i].urb); usb_kill_urb(tp->tx_info[i].urb);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); rxdy_gated_en(tp, true);
ocp_data |= RXDY_GATED_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
...@@ -1721,6 +1819,198 @@ static void rtl8152_disable(struct r8152 *tp) ...@@ -1721,6 +1819,198 @@ static void rtl8152_disable(struct r8152 *tp)
rtl8152_nic_reset(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);
}
#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_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;
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);
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)
{
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);
rtl_clear_bp(tp);
r8152b_enable_aldps(tp);
set_bit(PHY_RESET, &tp->flags);
}
static void r8152b_exit_oob(struct r8152 *tp) static void r8152b_exit_oob(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
...@@ -1730,9 +2020,9 @@ static void r8152b_exit_oob(struct r8152 *tp) ...@@ -1730,9 +2020,9 @@ static void r8152b_exit_oob(struct r8152 *tp)
ocp_data &= ~RCR_ACPT_ALL; ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); rxdy_gated_en(tp, true);
ocp_data |= RXDY_GATED_EN; r8153_teredo_off(tp);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); r8152b_hw_phy_cfg(tp);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
...@@ -1838,10 +2128,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ...@@ -1838,10 +2128,6 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); 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 = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
ocp_data |= CPCR_RX_VLAN; ocp_data |= CPCR_RX_VLAN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
...@@ -1854,36 +2140,26 @@ static void r8152b_enter_oob(struct r8152 *tp) ...@@ -1854,36 +2140,26 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; 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_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_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);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data |= RCR_APM | RCR_AM | RCR_AB; ocp_data |= RCR_APM | RCR_AM | RCR_AB;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); 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) static void r8153_hw_phy_cfg(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
u16 data; u16 data;
ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); 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);
}
r8153_clear_bp(tp);
if (tp->version == RTL_VER_03) { if (tp->version == RTL_VER_03) {
data = ocp_reg_read(tp, OCP_EEE_CFG); data = ocp_reg_read(tp, OCP_EEE_CFG);
...@@ -1919,9 +2195,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) ...@@ -1919,9 +2195,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
data = sram_read(tp, SRAM_10M_AMP2); data = sram_read(tp, SRAM_10M_AMP2);
data |= AMP_DN; data |= AMP_DN;
sram_write(tp, SRAM_10M_AMP2, data); sram_write(tp, SRAM_10M_AMP2, data);
set_bit(PHY_RESET, &tp->flags);
} }
static void r8153_u1u2en(struct r8152 *tp, int enable) static void r8153_u1u2en(struct r8152 *tp, bool enable)
{ {
u8 u1u2[8]; u8 u1u2[8];
...@@ -1933,7 +2211,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable) ...@@ -1933,7 +2211,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable)
usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); 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; u32 ocp_data;
...@@ -1945,7 +2223,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable) ...@@ -1945,7 +2223,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); 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; u32 ocp_data;
...@@ -1961,28 +2239,12 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable) ...@@ -1961,28 +2239,12 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); 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) static void r8153_first_init(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
int i; int i;
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); rxdy_gated_en(tp, true);
ocp_data |= RXDY_GATED_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
r8153_teredo_off(tp); r8153_teredo_off(tp);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
...@@ -2075,10 +2337,6 @@ static void r8153_enter_oob(struct r8152 *tp) ...@@ -2075,10 +2337,6 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); 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 = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
ocp_data &= ~TEREDO_WAKE_MASK; ocp_data &= ~TEREDO_WAKE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
...@@ -2095,11 +2353,7 @@ static void r8153_enter_oob(struct r8152 *tp) ...@@ -2095,11 +2353,7 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; 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_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_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);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data |= RCR_APM | RCR_AM | RCR_AB; ocp_data |= RCR_APM | RCR_AM | RCR_AB;
...@@ -2190,12 +2444,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) ...@@ -2190,12 +2444,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
bmcr = BMCR_ANENABLE | BMCR_ANRESTART; bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
} }
if (test_bit(PHY_RESET, &tp->flags))
bmcr |= BMCR_RESET;
if (tp->mii.supports_gmii) if (tp->mii.supports_gmii)
r8152_mdio_write(tp, MII_CTRL1000, gbcr); r8152_mdio_write(tp, MII_CTRL1000, gbcr);
r8152_mdio_write(tp, MII_ADVERTISE, anar); r8152_mdio_write(tp, MII_ADVERTISE, anar);
r8152_mdio_write(tp, MII_BMCR, bmcr); 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: out:
return ret; return ret;
...@@ -2203,12 +2471,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) ...@@ -2203,12 +2471,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
static void rtl8152_down(struct r8152 *tp) static void rtl8152_down(struct r8152 *tp)
{ {
u32 ocp_data; r8152_power_cut_en(tp, false);
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);
r8152b_disable_aldps(tp); r8152b_disable_aldps(tp);
r8152b_enter_oob(tp); r8152b_enter_oob(tp);
r8152b_enable_aldps(tp); r8152b_enable_aldps(tp);
...@@ -2216,8 +2479,8 @@ static void rtl8152_down(struct r8152 *tp) ...@@ -2216,8 +2479,8 @@ static void rtl8152_down(struct r8152 *tp)
static void rtl8153_down(struct r8152 *tp) static void rtl8153_down(struct r8152 *tp)
{ {
r8153_u1u2en(tp, 0); r8153_u1u2en(tp, false);
r8153_power_cut_en(tp, 0); r8153_power_cut_en(tp, false);
r8153_disable_aldps(tp); r8153_disable_aldps(tp);
r8153_enter_oob(tp); r8153_enter_oob(tp);
r8153_enable_aldps(tp); r8153_enable_aldps(tp);
...@@ -2252,6 +2515,9 @@ static void rtl_work_func_t(struct work_struct *work) ...@@ -2252,6 +2515,9 @@ static void rtl_work_func_t(struct work_struct *work)
{ {
struct r8152 *tp = container_of(work, struct r8152, schedule.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)) if (!test_bit(WORK_ENABLE, &tp->flags))
goto out1; goto out1;
...@@ -2264,8 +2530,14 @@ static void rtl_work_func_t(struct work_struct *work) ...@@ -2264,8 +2530,14 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
_rtl8152_set_rx_mode(tp->netdev); _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: out1:
return; usb_autopm_put_interface(tp->intf);
} }
static int rtl8152_open(struct net_device *netdev) static int rtl8152_open(struct net_device *netdev)
...@@ -2273,6 +2545,27 @@ static int rtl8152_open(struct net_device *netdev) ...@@ -2273,6 +2545,27 @@ static int rtl8152_open(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
int res = 0; int res = 0;
res = alloc_all_mem(tp);
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, rtl8152_set_speed(tp, AUTONEG_ENABLE,
tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL); DUPLEX_FULL);
...@@ -2286,9 +2579,12 @@ static int rtl8152_open(struct net_device *netdev) ...@@ -2286,9 +2579,12 @@ static int rtl8152_open(struct net_device *netdev)
netif_device_detach(tp->netdev); netif_device_detach(tp->netdev);
netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
res); res);
free_all_mem(tp);
} }
usb_autopm_put_interface(tp->intf);
out:
return res; return res;
} }
...@@ -2301,33 +2597,30 @@ static int rtl8152_close(struct net_device *netdev) ...@@ -2301,33 +2597,30 @@ static int rtl8152_close(struct net_device *netdev)
usb_kill_urb(tp->intr_urb); usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
netif_stop_queue(netdev); netif_stop_queue(netdev);
tasklet_disable(&tp->tl);
tp->rtl_ops.disable(tp);
tasklet_enable(&tp->tl);
return res; 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);
}
static void rtl_clear_bp(struct r8152 *tp) tasklet_disable(&tp->tl);
{ tp->rtl_ops.down(tp);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); tasklet_enable(&tp->tl);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); usb_autopm_put_interface(tp->intf);
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) free_all_mem(tp);
{
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); return res;
ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
rtl_clear_bp(tp);
} }
static void r8152b_enable_eee(struct r8152 *tp) static void r8152b_enable_eee(struct r8152 *tp)
...@@ -2378,18 +2671,9 @@ static void r8152b_enable_fc(struct r8152 *tp) ...@@ -2378,18 +2671,9 @@ static void r8152b_enable_fc(struct r8152 *tp)
r8152_mdio_write(tp, MII_ADVERTISE, anar); 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) static void r8152b_init(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
int i;
rtl_clear_bp(tp);
if (tp->version == RTL_VER_01) { if (tp->version == RTL_VER_01) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
...@@ -2397,17 +2681,7 @@ static void r8152b_init(struct r8152 *tp) ...@@ -2397,17 +2681,7 @@ static void r8152b_init(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
} }
r8152b_hw_phy_cfg(tp); r8152_power_cut_en(tp, false);
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);
r8152b_exit_oob(tp);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
...@@ -2424,14 +2698,6 @@ static void r8152b_init(struct r8152 *tp) ...@@ -2424,14 +2698,6 @@ static void r8152b_init(struct r8152 *tp)
r8152b_enable_aldps(tp); r8152b_enable_aldps(tp);
r8152b_enable_fc(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 */ /* enable rx aggregation */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
ocp_data &= ~RX_AGG_DISABLE; ocp_data &= ~RX_AGG_DISABLE;
...@@ -2443,7 +2709,7 @@ static void r8153_init(struct r8152 *tp) ...@@ -2443,7 +2709,7 @@ static void r8153_init(struct r8152 *tp)
u32 ocp_data; u32 ocp_data;
int i; int i;
r8153_u1u2en(tp, 0); r8153_u1u2en(tp, false);
for (i = 0; i < 500; i++) { for (i = 0; i < 500; i++) {
if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
...@@ -2459,14 +2725,12 @@ static void r8153_init(struct r8152 *tp) ...@@ -2459,14 +2725,12 @@ static void r8153_init(struct r8152 *tp)
msleep(20); msleep(20);
} }
r8153_u2p3en(tp, 0); r8153_u2p3en(tp, false);
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
ocp_data &= ~TIMER11_EN; ocp_data &= ~TIMER11_EN;
ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); 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 = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
ocp_data &= ~LED_MODE_MASK; ocp_data &= ~LED_MODE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
...@@ -2484,10 +2748,8 @@ static void r8153_init(struct r8152 *tp) ...@@ -2484,10 +2748,8 @@ static void r8153_init(struct r8152 *tp)
ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
r8153_power_cut_en(tp, 0); r8153_power_cut_en(tp, false);
r8153_u1u2en(tp, 1); 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_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_CTRL2, EEE_SPDWN_RATIO);
...@@ -2502,26 +2764,30 @@ static void r8153_init(struct r8152 *tp) ...@@ -2502,26 +2764,30 @@ static void r8153_init(struct r8152 *tp)
r8153_enable_eee(tp); r8153_enable_eee(tp);
r8153_enable_aldps(tp); r8153_enable_aldps(tp);
r8152b_enable_fc(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) static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct r8152 *tp = usb_get_intfdata(intf); 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)) { if (netif_running(tp->netdev)) {
clear_bit(WORK_ENABLE, &tp->flags); clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb); usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
tasklet_disable(&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);
}
} }
tp->rtl_ops.down(tp);
return 0; return 0;
} }
...@@ -2529,22 +2795,77 @@ static int rtl8152_resume(struct usb_interface *intf) ...@@ -2529,22 +2795,77 @@ static int rtl8152_resume(struct usb_interface *intf)
{ {
struct r8152 *tp = usb_get_intfdata(intf); struct r8152 *tp = usb_get_intfdata(intf);
tp->rtl_ops.init(tp); if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
netif_device_attach(tp->netdev); tp->rtl_ops.init(tp);
netif_device_attach(tp->netdev);
}
if (netif_running(tp->netdev)) { if (netif_running(tp->netdev)) {
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, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL); DUPLEX_FULL);
}
tp->speed = 0; tp->speed = 0;
netif_carrier_off(tp->netdev); netif_carrier_off(tp->netdev);
set_bit(WORK_ENABLE, &tp->flags); set_bit(WORK_ENABLE, &tp->flags);
usb_submit_urb(tp->intr_urb, GFP_KERNEL); usb_submit_urb(tp->intr_urb, GFP_KERNEL);
tasklet_enable(&tp->tl);
} }
return 0; return 0;
} }
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;
usb_autopm_put_interface(tp->intf);
out_set_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, static void rtl8152_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info) struct ethtool_drvinfo *info)
{ {
...@@ -2569,8 +2890,18 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) ...@@ -2569,8 +2890,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) static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct r8152 *tp = netdev_priv(dev); struct r8152 *tp = netdev_priv(dev);
int ret;
ret = usb_autopm_get_interface(tp->intf);
if (ret < 0)
goto out;
ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); usb_autopm_put_interface(tp->intf);
out:
return ret;
} }
static struct ethtool_ops ops = { static struct ethtool_ops ops = {
...@@ -2578,13 +2909,21 @@ static struct ethtool_ops ops = { ...@@ -2578,13 +2909,21 @@ static struct ethtool_ops ops = {
.get_settings = rtl8152_get_settings, .get_settings = rtl8152_get_settings,
.set_settings = rtl8152_set_settings, .set_settings = rtl8152_set_settings,
.get_link = ethtool_op_get_link, .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,
}; };
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{ {
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(rq); 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) { switch (cmd) {
case SIOCGMIIPHY: case SIOCGMIIPHY:
...@@ -2607,6 +2946,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) ...@@ -2607,6 +2946,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
res = -EOPNOTSUPP; res = -EOPNOTSUPP;
} }
usb_autopm_put_interface(tp->intf);
out:
return res; return res;
} }
...@@ -2659,22 +3001,13 @@ static void r8152b_get_version(struct r8152 *tp) ...@@ -2659,22 +3001,13 @@ static void r8152b_get_version(struct r8152 *tp)
static void rtl8152_unload(struct r8152 *tp) static void rtl8152_unload(struct r8152 *tp)
{ {
u32 ocp_data; if (tp->version != RTL_VER_01)
r8152_power_cut_en(tp, true);
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);
} }
static void rtl8153_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) static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
...@@ -2689,6 +3022,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ...@@ -2689,6 +3022,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8152b_init; ops->init = r8152b_init;
ops->enable = rtl8152_enable; ops->enable = rtl8152_enable;
ops->disable = rtl8152_disable; ops->disable = rtl8152_disable;
ops->up = r8152b_exit_oob;
ops->down = rtl8152_down; ops->down = rtl8152_down;
ops->unload = rtl8152_unload; ops->unload = rtl8152_unload;
ret = 0; ret = 0;
...@@ -2697,6 +3031,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ...@@ -2697,6 +3031,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8153_init; ops->init = r8153_init;
ops->enable = rtl8153_enable; ops->enable = rtl8153_enable;
ops->disable = rtl8152_disable; ops->disable = rtl8152_disable;
ops->up = r8153_first_init;
ops->down = rtl8153_down; ops->down = rtl8153_down;
ops->unload = rtl8153_unload; ops->unload = rtl8153_unload;
ret = 0; ret = 0;
...@@ -2712,6 +3047,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ...@@ -2712,6 +3047,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8153_init; ops->init = r8153_init;
ops->enable = rtl8153_enable; ops->enable = rtl8153_enable;
ops->disable = rtl8152_disable; ops->disable = rtl8152_disable;
ops->up = r8153_first_init;
ops->down = rtl8153_down; ops->down = rtl8153_down;
ops->unload = rtl8153_unload; ops->unload = rtl8153_unload;
ret = 0; ret = 0;
...@@ -2775,14 +3111,12 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -2775,14 +3111,12 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->mii.phy_id = R8152_PHY_ID; tp->mii.phy_id = R8152_PHY_ID;
tp->mii.supports_gmii = 0; tp->mii.supports_gmii = 0;
intf->needs_remote_wakeup = 1;
r8152b_get_version(tp); r8152b_get_version(tp);
tp->rtl_ops.init(tp); tp->rtl_ops.init(tp);
set_ethernet_addr(tp); set_ethernet_addr(tp);
ret = alloc_all_mem(tp);
if (ret)
goto out;
usb_set_intfdata(intf, tp); usb_set_intfdata(intf, tp);
ret = register_netdev(netdev); ret = register_netdev(netdev);
...@@ -2791,6 +3125,12 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -2791,6 +3125,12 @@ static int rtl8152_probe(struct usb_interface *intf,
goto out1; 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); netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0; return 0;
...@@ -2812,7 +3152,6 @@ static void rtl8152_disconnect(struct usb_interface *intf) ...@@ -2812,7 +3152,6 @@ static void rtl8152_disconnect(struct usb_interface *intf)
tasklet_kill(&tp->tl); tasklet_kill(&tp->tl);
unregister_netdev(tp->netdev); unregister_netdev(tp->netdev);
tp->rtl_ops.unload(tp); tp->rtl_ops.unload(tp);
free_all_mem(tp);
free_netdev(tp->netdev); free_netdev(tp->netdev);
} }
} }
...@@ -2835,6 +3174,8 @@ static struct usb_driver rtl8152_driver = { ...@@ -2835,6 +3174,8 @@ static struct usb_driver rtl8152_driver = {
.suspend = rtl8152_suspend, .suspend = rtl8152_suspend,
.resume = rtl8152_resume, .resume = rtl8152_resume,
.reset_resume = rtl8152_resume, .reset_resume = rtl8152_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
}; };
module_usb_driver(rtl8152_driver); module_usb_driver(rtl8152_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment