Commit 38cbd6e7 authored by David S. Miller's avatar David S. Miller

Merge branch 'lan7800-improvements'

John Efstathiades says:

====================
LAN7800 driver improvements

This patch set introduces a number of improvements and fixes for
problems found during testing of a modification to add a NAPI-style
approach to packet handling to improve performance.

NOTE: the NAPI changes are not part of this patch set and the issues
      fixed by this patch set are not coupled to the NAPI changes.

Patch 1 fixes white space and style issues

Patch 2 removes an unused timer

Patch 3 introduces macros to set the internal packet FIFO flow
control levels, which makes it easier to update the levels in future.

Patch 4 removes an unused queue

Patch 5 (updated for v2) introduces function return value checks and
error propagation to various parts of the driver where a return
code was captured but then ignored.

This patch is completely different to patch 5 in version 1 of this patch
set. The changes in the v1 patch 5 are being set aside for the time
being.

Patch 6 updates the LAN7800 MAC reset code to ensure there is no
PHY register access in progress when the MAC is reset. This change
prevents a kernel exception that can otherwise occur.

Patch 7 fixes problems with system suspend and resume handling while
the device is transmitting and receiving data.

Patch 8 fixes problems with auto-suspend and resume handling and
depends on changes introduced by patch 7.

Patch 9 fixes problems with device disconnect handling that can result
in kernel exceptions and/or hang.

Patch 10 limits the rate at which driver warning messages are emitted.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fbd029df df0d6f7a
...@@ -46,6 +46,19 @@ ...@@ -46,6 +46,19 @@
#define MAX_RX_FIFO_SIZE (12 * 1024) #define MAX_RX_FIFO_SIZE (12 * 1024)
#define MAX_TX_FIFO_SIZE (12 * 1024) #define MAX_TX_FIFO_SIZE (12 * 1024)
#define FLOW_THRESHOLD(n) ((((n) + 511) / 512) & 0x7F)
#define FLOW_CTRL_THRESHOLD(on, off) ((FLOW_THRESHOLD(on) << 0) | \
(FLOW_THRESHOLD(off) << 8))
/* Flow control turned on when Rx FIFO level rises above this level (bytes) */
#define FLOW_ON_SS 9216
#define FLOW_ON_HS 8704
/* Flow control turned off when Rx FIFO level falls below this level (bytes) */
#define FLOW_OFF_SS 4096
#define FLOW_OFF_HS 1024
#define DEFAULT_BURST_CAP_SIZE (MAX_TX_FIFO_SIZE) #define DEFAULT_BURST_CAP_SIZE (MAX_TX_FIFO_SIZE)
#define DEFAULT_BULK_IN_DELAY (0x0800) #define DEFAULT_BULK_IN_DELAY (0x0800)
#define MAX_SINGLE_PACKET_SIZE (9000) #define MAX_SINGLE_PACKET_SIZE (9000)
...@@ -87,6 +100,12 @@ ...@@ -87,6 +100,12 @@
/* statistic update interval (mSec) */ /* statistic update interval (mSec) */
#define STAT_UPDATE_TIMER (1 * 1000) #define STAT_UPDATE_TIMER (1 * 1000)
/* time to wait for MAC or FCT to stop (jiffies) */
#define HW_DISABLE_TIMEOUT (HZ / 10)
/* time to wait between polling MAC or FCT state (ms) */
#define HW_DISABLE_DELAY_MS 1
/* defines interrupts from interrupt EP */ /* defines interrupts from interrupt EP */
#define MAX_INT_EP (32) #define MAX_INT_EP (32)
#define INT_EP_INTEP (31) #define INT_EP_INTEP (31)
...@@ -341,6 +360,7 @@ struct usb_context { ...@@ -341,6 +360,7 @@ struct usb_context {
#define EVENT_DEV_ASLEEP 7 #define EVENT_DEV_ASLEEP 7
#define EVENT_DEV_OPEN 8 #define EVENT_DEV_OPEN 8
#define EVENT_STAT_UPDATE 9 #define EVENT_STAT_UPDATE 9
#define EVENT_DEV_DISCONNECT 10
struct statstage { struct statstage {
struct mutex access_lock; /* for stats access */ struct mutex access_lock; /* for stats access */
...@@ -370,7 +390,6 @@ struct lan78xx_net { ...@@ -370,7 +390,6 @@ struct lan78xx_net {
struct sk_buff_head rxq; struct sk_buff_head rxq;
struct sk_buff_head txq; struct sk_buff_head txq;
struct sk_buff_head done; struct sk_buff_head done;
struct sk_buff_head rxq_pause;
struct sk_buff_head txq_pend; struct sk_buff_head txq_pend;
struct tasklet_struct bh; struct tasklet_struct bh;
...@@ -381,8 +400,9 @@ struct lan78xx_net { ...@@ -381,8 +400,9 @@ struct lan78xx_net {
struct urb *urb_intr; struct urb *urb_intr;
struct usb_anchor deferred; struct usb_anchor deferred;
struct mutex dev_mutex; /* serialise open/stop wrt suspend/resume */
struct mutex phy_mutex; /* for phy access */ struct mutex phy_mutex; /* for phy access */
unsigned pipe_in, pipe_out, pipe_intr; unsigned int pipe_in, pipe_out, pipe_intr;
u32 hard_mtu; /* count any extra framing */ u32 hard_mtu; /* count any extra framing */
size_t rx_urb_size; /* size for rx urbs */ size_t rx_urb_size; /* size for rx urbs */
...@@ -392,8 +412,7 @@ struct lan78xx_net { ...@@ -392,8 +412,7 @@ struct lan78xx_net {
wait_queue_head_t *wait; wait_queue_head_t *wait;
unsigned char suspend_count; unsigned char suspend_count;
unsigned maxpacket; unsigned int maxpacket;
struct timer_list delay;
struct timer_list stat_monitor; struct timer_list stat_monitor;
unsigned long data[5]; unsigned long data[5];
...@@ -426,9 +445,13 @@ MODULE_PARM_DESC(msg_level, "Override default message level"); ...@@ -426,9 +445,13 @@ MODULE_PARM_DESC(msg_level, "Override default message level");
static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
{ {
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); u32 *buf;
int ret; int ret;
if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
return -ENODEV;
buf = kmalloc(sizeof(u32), GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -439,7 +462,7 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) ...@@ -439,7 +462,7 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
if (likely(ret >= 0)) { if (likely(ret >= 0)) {
le32_to_cpus(buf); le32_to_cpus(buf);
*data = *buf; *data = *buf;
} else { } else if (net_ratelimit()) {
netdev_warn(dev->net, netdev_warn(dev->net,
"Failed to read register index 0x%08x. ret = %d", "Failed to read register index 0x%08x. ret = %d",
index, ret); index, ret);
...@@ -452,9 +475,13 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) ...@@ -452,9 +475,13 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data) static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
{ {
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); u32 *buf;
int ret; int ret;
if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
return -ENODEV;
buf = kmalloc(sizeof(u32), GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -465,7 +492,8 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data) ...@@ -465,7 +492,8 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
USB_VENDOR_REQUEST_WRITE_REGISTER, USB_VENDOR_REQUEST_WRITE_REGISTER,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, buf, 4, USB_CTRL_SET_TIMEOUT); 0, index, buf, 4, USB_CTRL_SET_TIMEOUT);
if (unlikely(ret < 0)) { if (unlikely(ret < 0) &&
net_ratelimit()) {
netdev_warn(dev->net, netdev_warn(dev->net,
"Failed to write register index 0x%08x. ret = %d", "Failed to write register index 0x%08x. ret = %d",
index, ret); index, ret);
...@@ -476,6 +504,26 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data) ...@@ -476,6 +504,26 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
return ret; return ret;
} }
static int lan78xx_update_reg(struct lan78xx_net *dev, u32 reg, u32 mask,
u32 data)
{
int ret;
u32 buf;
ret = lan78xx_read_reg(dev, reg, &buf);
if (ret < 0)
return ret;
buf &= ~mask;
buf |= (mask & data);
ret = lan78xx_write_reg(dev, reg, buf);
if (ret < 0)
return ret;
return 0;
}
static int lan78xx_read_stats(struct lan78xx_net *dev, static int lan78xx_read_stats(struct lan78xx_net *dev,
struct lan78xx_statstage *data) struct lan78xx_statstage *data)
{ {
...@@ -501,7 +549,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, ...@@ -501,7 +549,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
if (likely(ret >= 0)) { if (likely(ret >= 0)) {
src = (u32 *)stats; src = (u32 *)stats;
dst = (u32 *)data; dst = (u32 *)data;
for (i = 0; i < sizeof(*stats)/sizeof(u32); i++) { for (i = 0; i < sizeof(*stats) / sizeof(u32); i++) {
le32_to_cpus(&src[i]); le32_to_cpus(&src[i]);
dst[i] = src[i]; dst[i] = src[i];
} }
...@@ -515,10 +563,11 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, ...@@ -515,10 +563,11 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
return ret; return ret;
} }
#define check_counter_rollover(struct1, dev_stats, member) { \ #define check_counter_rollover(struct1, dev_stats, member) \
if (struct1->member < dev_stats.saved.member) \ do { \
dev_stats.rollover_count.member++; \ if ((struct1)->member < (dev_stats).saved.member) \
} (dev_stats).rollover_count.member++; \
} while (0)
static void lan78xx_check_stat_rollover(struct lan78xx_net *dev, static void lan78xx_check_stat_rollover(struct lan78xx_net *dev,
struct lan78xx_statstage *stats) struct lan78xx_statstage *stats)
...@@ -959,7 +1008,7 @@ static int lan78xx_dataport_wait_not_busy(struct lan78xx_net *dev) ...@@ -959,7 +1008,7 @@ static int lan78xx_dataport_wait_not_busy(struct lan78xx_net *dev)
usleep_range(40, 100); usleep_range(40, 100);
} }
netdev_warn(dev->net, "lan78xx_dataport_wait_not_busy timed out"); netdev_warn(dev->net, "%s timed out", __func__);
return -EIO; return -EIO;
} }
...@@ -1067,9 +1116,10 @@ static void lan78xx_set_multicast(struct net_device *netdev) ...@@ -1067,9 +1116,10 @@ static void lan78xx_set_multicast(struct net_device *netdev)
for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++)
pdata->mchash_table[i] = 0; pdata->mchash_table[i] = 0;
/* pfilter_table[0] has own HW address */ /* pfilter_table[0] has own HW address */
for (i = 1; i < NUM_OF_MAF; i++) { for (i = 1; i < NUM_OF_MAF; i++) {
pdata->pfilter_table[i][0] = pdata->pfilter_table[i][0] = 0;
pdata->pfilter_table[i][1] = 0; pdata->pfilter_table[i][1] = 0;
} }
...@@ -1134,9 +1184,9 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex, ...@@ -1134,9 +1184,9 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
flow |= FLOW_CR_RX_FCEN_; flow |= FLOW_CR_RX_FCEN_;
if (dev->udev->speed == USB_SPEED_SUPER) if (dev->udev->speed == USB_SPEED_SUPER)
fct_flow = 0x817; fct_flow = FLOW_CTRL_THRESHOLD(FLOW_ON_SS, FLOW_OFF_SS);
else if (dev->udev->speed == USB_SPEED_HIGH) else if (dev->udev->speed == USB_SPEED_HIGH)
fct_flow = 0x211; fct_flow = FLOW_CTRL_THRESHOLD(FLOW_ON_HS, FLOW_OFF_HS);
netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s", netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s",
(cap & FLOW_CTRL_RX ? "enabled" : "disabled"), (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
...@@ -1150,6 +1200,52 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex, ...@@ -1150,6 +1200,52 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
return 0; return 0;
} }
static int lan78xx_mac_reset(struct lan78xx_net *dev)
{
unsigned long start_time = jiffies;
u32 val;
int ret;
mutex_lock(&dev->phy_mutex);
/* Resetting the device while there is activity on the MDIO
* bus can result in the MAC interface locking up and not
* completing register access transactions.
*/
ret = lan78xx_phy_wait_not_busy(dev);
if (ret < 0)
goto done;
ret = lan78xx_read_reg(dev, MAC_CR, &val);
if (ret < 0)
goto done;
val |= MAC_CR_RST_;
ret = lan78xx_write_reg(dev, MAC_CR, val);
if (ret < 0)
goto done;
/* Wait for the reset to complete before allowing any further
* MAC register accesses otherwise the MAC may lock up.
*/
do {
ret = lan78xx_read_reg(dev, MAC_CR, &val);
if (ret < 0)
goto done;
if (!(val & MAC_CR_RST_)) {
ret = 0;
goto done;
}
} while (!time_after(jiffies, start_time + HZ));
ret = -ETIMEDOUT;
done:
mutex_unlock(&dev->phy_mutex);
return ret;
}
static int lan78xx_link_reset(struct lan78xx_net *dev) static int lan78xx_link_reset(struct lan78xx_net *dev)
{ {
struct phy_device *phydev = dev->net->phydev; struct phy_device *phydev = dev->net->phydev;
...@@ -1160,7 +1256,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -1160,7 +1256,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
/* clear LAN78xx interrupt status */ /* clear LAN78xx interrupt status */
ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_); ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return -EIO; return ret;
mutex_lock(&phydev->lock); mutex_lock(&phydev->lock);
phy_read_status(phydev); phy_read_status(phydev);
...@@ -1171,13 +1267,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -1171,13 +1267,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
dev->link_on = false; dev->link_on = false;
/* reset MAC */ /* reset MAC */
ret = lan78xx_read_reg(dev, MAC_CR, &buf); ret = lan78xx_mac_reset(dev);
if (unlikely(ret < 0)) if (ret < 0)
return -EIO; return ret;
buf |= MAC_CR_RST_;
ret = lan78xx_write_reg(dev, MAC_CR, buf);
if (unlikely(ret < 0))
return -EIO;
del_timer(&dev->stat_monitor); del_timer(&dev->stat_monitor);
} else if (link && !dev->link_on) { } else if (link && !dev->link_on) {
...@@ -1189,18 +1281,30 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -1189,18 +1281,30 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
if (ecmd.base.speed == 1000) { if (ecmd.base.speed == 1000) {
/* disable U2 */ /* disable U2 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf); ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf &= ~USB_CFG1_DEV_U2_INIT_EN_; buf &= ~USB_CFG1_DEV_U2_INIT_EN_;
ret = lan78xx_write_reg(dev, USB_CFG1, buf); ret = lan78xx_write_reg(dev, USB_CFG1, buf);
if (ret < 0)
return ret;
/* enable U1 */ /* enable U1 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf); ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG1_DEV_U1_INIT_EN_; buf |= USB_CFG1_DEV_U1_INIT_EN_;
ret = lan78xx_write_reg(dev, USB_CFG1, buf); ret = lan78xx_write_reg(dev, USB_CFG1, buf);
if (ret < 0)
return ret;
} else { } else {
/* enable U1 & U2 */ /* enable U1 & U2 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf); ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG1_DEV_U2_INIT_EN_; buf |= USB_CFG1_DEV_U2_INIT_EN_;
buf |= USB_CFG1_DEV_U1_INIT_EN_; buf |= USB_CFG1_DEV_U1_INIT_EN_;
ret = lan78xx_write_reg(dev, USB_CFG1, buf); ret = lan78xx_write_reg(dev, USB_CFG1, buf);
if (ret < 0)
return ret;
} }
} }
...@@ -1218,6 +1322,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -1218,6 +1322,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
ret = lan78xx_update_flowcontrol(dev, ecmd.base.duplex, ladv, ret = lan78xx_update_flowcontrol(dev, ecmd.base.duplex, ladv,
radv); radv);
if (ret < 0)
return ret;
if (!timer_pending(&dev->stat_monitor)) { if (!timer_pending(&dev->stat_monitor)) {
dev->delta = 1; dev->delta = 1;
...@@ -1228,7 +1334,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -1228,7 +1334,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
tasklet_schedule(&dev->bh); tasklet_schedule(&dev->bh);
} }
return ret; return 0;
} }
/* some work can't be done in tasklets, so we use keventd /* some work can't be done in tasklets, so we use keventd
...@@ -1264,9 +1370,10 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb) ...@@ -1264,9 +1370,10 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb)
generic_handle_irq(dev->domain_data.phyirq); generic_handle_irq(dev->domain_data.phyirq);
local_irq_enable(); local_irq_enable();
} }
} else } else {
netdev_warn(dev->net, netdev_warn(dev->net,
"unexpected interrupt: 0x%08x\n", intdata); "unexpected interrupt: 0x%08x\n", intdata);
}
} }
static int lan78xx_ethtool_get_eeprom_len(struct net_device *netdev) static int lan78xx_ethtool_get_eeprom_len(struct net_device *netdev)
...@@ -2267,11 +2374,16 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -2267,11 +2374,16 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu)
int ll_mtu = new_mtu + netdev->hard_header_len; int ll_mtu = new_mtu + netdev->hard_header_len;
int old_hard_mtu = dev->hard_mtu; int old_hard_mtu = dev->hard_mtu;
int old_rx_urb_size = dev->rx_urb_size; int old_rx_urb_size = dev->rx_urb_size;
int ret;
/* no second zero-length packet read wanted after mtu-sized packets */ /* no second zero-length packet read wanted after mtu-sized packets */
if ((ll_mtu % dev->maxpacket) == 0) if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM; return -EDOM;
ret = usb_autopm_get_interface(dev->intf);
if (ret < 0)
return ret;
lan78xx_set_rx_max_frame_length(dev, new_mtu + VLAN_ETH_HLEN); lan78xx_set_rx_max_frame_length(dev, new_mtu + VLAN_ETH_HLEN);
netdev->mtu = new_mtu; netdev->mtu = new_mtu;
...@@ -2287,6 +2399,8 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -2287,6 +2399,8 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu)
} }
} }
usb_autopm_put_interface(dev->intf);
return 0; return 0;
} }
...@@ -2443,26 +2557,186 @@ static void lan78xx_init_ltm(struct lan78xx_net *dev) ...@@ -2443,26 +2557,186 @@ static void lan78xx_init_ltm(struct lan78xx_net *dev)
lan78xx_write_reg(dev, LTM_INACTIVE1, regs[5]); lan78xx_write_reg(dev, LTM_INACTIVE1, regs[5]);
} }
static int lan78xx_start_hw(struct lan78xx_net *dev, u32 reg, u32 hw_enable)
{
return lan78xx_update_reg(dev, reg, hw_enable, hw_enable);
}
static int lan78xx_stop_hw(struct lan78xx_net *dev, u32 reg, u32 hw_enabled,
u32 hw_disabled)
{
unsigned long timeout;
bool stopped = true;
int ret;
u32 buf;
/* Stop the h/w block (if not already stopped) */
ret = lan78xx_read_reg(dev, reg, &buf);
if (ret < 0)
return ret;
if (buf & hw_enabled) {
buf &= ~hw_enabled;
ret = lan78xx_write_reg(dev, reg, buf);
if (ret < 0)
return ret;
stopped = false;
timeout = jiffies + HW_DISABLE_TIMEOUT;
do {
ret = lan78xx_read_reg(dev, reg, &buf);
if (ret < 0)
return ret;
if (buf & hw_disabled)
stopped = true;
else
msleep(HW_DISABLE_DELAY_MS);
} while (!stopped && !time_after(jiffies, timeout));
}
ret = stopped ? 0 : -ETIME;
return ret;
}
static int lan78xx_flush_fifo(struct lan78xx_net *dev, u32 reg, u32 fifo_flush)
{
return lan78xx_update_reg(dev, reg, fifo_flush, fifo_flush);
}
static int lan78xx_start_tx_path(struct lan78xx_net *dev)
{
int ret;
netif_dbg(dev, drv, dev->net, "start tx path");
/* Start the MAC transmitter */
ret = lan78xx_start_hw(dev, MAC_TX, MAC_TX_TXEN_);
if (ret < 0)
return ret;
/* Start the Tx FIFO */
ret = lan78xx_start_hw(dev, FCT_TX_CTL, FCT_TX_CTL_EN_);
if (ret < 0)
return ret;
return 0;
}
static int lan78xx_stop_tx_path(struct lan78xx_net *dev)
{
int ret;
netif_dbg(dev, drv, dev->net, "stop tx path");
/* Stop the Tx FIFO */
ret = lan78xx_stop_hw(dev, FCT_TX_CTL, FCT_TX_CTL_EN_, FCT_TX_CTL_DIS_);
if (ret < 0)
return ret;
/* Stop the MAC transmitter */
ret = lan78xx_stop_hw(dev, MAC_TX, MAC_TX_TXEN_, MAC_TX_TXD_);
if (ret < 0)
return ret;
return 0;
}
/* The caller must ensure the Tx path is stopped before calling
* lan78xx_flush_tx_fifo().
*/
static int lan78xx_flush_tx_fifo(struct lan78xx_net *dev)
{
return lan78xx_flush_fifo(dev, FCT_TX_CTL, FCT_TX_CTL_RST_);
}
static int lan78xx_start_rx_path(struct lan78xx_net *dev)
{
int ret;
netif_dbg(dev, drv, dev->net, "start rx path");
/* Start the Rx FIFO */
ret = lan78xx_start_hw(dev, FCT_RX_CTL, FCT_RX_CTL_EN_);
if (ret < 0)
return ret;
/* Start the MAC receiver*/
ret = lan78xx_start_hw(dev, MAC_RX, MAC_RX_RXEN_);
if (ret < 0)
return ret;
return 0;
}
static int lan78xx_stop_rx_path(struct lan78xx_net *dev)
{
int ret;
netif_dbg(dev, drv, dev->net, "stop rx path");
/* Stop the MAC receiver */
ret = lan78xx_stop_hw(dev, MAC_RX, MAC_RX_RXEN_, MAC_RX_RXD_);
if (ret < 0)
return ret;
/* Stop the Rx FIFO */
ret = lan78xx_stop_hw(dev, FCT_RX_CTL, FCT_RX_CTL_EN_, FCT_RX_CTL_DIS_);
if (ret < 0)
return ret;
return 0;
}
/* The caller must ensure the Rx path is stopped before calling
* lan78xx_flush_rx_fifo().
*/
static int lan78xx_flush_rx_fifo(struct lan78xx_net *dev)
{
return lan78xx_flush_fifo(dev, FCT_RX_CTL, FCT_RX_CTL_RST_);
}
static int lan78xx_reset(struct lan78xx_net *dev) static int lan78xx_reset(struct lan78xx_net *dev)
{ {
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
u32 buf;
int ret = 0;
unsigned long timeout; unsigned long timeout;
int ret;
u32 buf;
u8 sig; u8 sig;
ret = lan78xx_read_reg(dev, HW_CFG, &buf); ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
buf |= HW_CFG_LRST_; buf |= HW_CFG_LRST_;
ret = lan78xx_write_reg(dev, HW_CFG, buf); ret = lan78xx_write_reg(dev, HW_CFG, buf);
if (ret < 0)
return ret;
timeout = jiffies + HZ; timeout = jiffies + HZ;
do { do {
mdelay(1); mdelay(1);
ret = lan78xx_read_reg(dev, HW_CFG, &buf); ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
netdev_warn(dev->net, netdev_warn(dev->net,
"timeout on completion of LiteReset"); "timeout on completion of LiteReset");
return -EIO; ret = -ETIMEDOUT;
return ret;
} }
} while (buf & HW_CFG_LRST_); } while (buf & HW_CFG_LRST_);
...@@ -2470,13 +2744,22 @@ static int lan78xx_reset(struct lan78xx_net *dev) ...@@ -2470,13 +2744,22 @@ static int lan78xx_reset(struct lan78xx_net *dev)
/* save DEVID for later usage */ /* save DEVID for later usage */
ret = lan78xx_read_reg(dev, ID_REV, &buf); ret = lan78xx_read_reg(dev, ID_REV, &buf);
if (ret < 0)
return ret;
dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16; dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16;
dev->chiprev = buf & ID_REV_CHIP_REV_MASK_; dev->chiprev = buf & ID_REV_CHIP_REV_MASK_;
/* Respond to the IN token with a NAK */ /* Respond to the IN token with a NAK */
ret = lan78xx_read_reg(dev, USB_CFG0, &buf); ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG_BIR_; buf |= USB_CFG_BIR_;
ret = lan78xx_write_reg(dev, USB_CFG0, buf); ret = lan78xx_write_reg(dev, USB_CFG0, buf);
if (ret < 0)
return ret;
/* Init LTM */ /* Init LTM */
lan78xx_init_ltm(dev); lan78xx_init_ltm(dev);
...@@ -2499,53 +2782,105 @@ static int lan78xx_reset(struct lan78xx_net *dev) ...@@ -2499,53 +2782,105 @@ static int lan78xx_reset(struct lan78xx_net *dev)
} }
ret = lan78xx_write_reg(dev, BURST_CAP, buf); ret = lan78xx_write_reg(dev, BURST_CAP, buf);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); ret = lan78xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, HW_CFG, &buf); ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
buf |= HW_CFG_MEF_; buf |= HW_CFG_MEF_;
ret = lan78xx_write_reg(dev, HW_CFG, buf); ret = lan78xx_write_reg(dev, HW_CFG, buf);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, USB_CFG0, &buf); ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG_BCE_; buf |= USB_CFG_BCE_;
ret = lan78xx_write_reg(dev, USB_CFG0, buf); ret = lan78xx_write_reg(dev, USB_CFG0, buf);
if (ret < 0)
return ret;
/* set FIFO sizes */ /* set FIFO sizes */
buf = (MAX_RX_FIFO_SIZE - 512) / 512; buf = (MAX_RX_FIFO_SIZE - 512) / 512;
ret = lan78xx_write_reg(dev, FCT_RX_FIFO_END, buf); ret = lan78xx_write_reg(dev, FCT_RX_FIFO_END, buf);
if (ret < 0)
return ret;
buf = (MAX_TX_FIFO_SIZE - 512) / 512; buf = (MAX_TX_FIFO_SIZE - 512) / 512;
ret = lan78xx_write_reg(dev, FCT_TX_FIFO_END, buf); ret = lan78xx_write_reg(dev, FCT_TX_FIFO_END, buf);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_); ret = lan78xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, FLOW, 0); ret = lan78xx_write_reg(dev, FLOW, 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, FCT_FLOW, 0); ret = lan78xx_write_reg(dev, FCT_FLOW, 0);
if (ret < 0)
return ret;
/* Don't need rfe_ctl_lock during initialisation */ /* Don't need rfe_ctl_lock during initialisation */
ret = lan78xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); ret = lan78xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
if (ret < 0)
return ret;
pdata->rfe_ctl |= RFE_CTL_BCAST_EN_ | RFE_CTL_DA_PERFECT_; pdata->rfe_ctl |= RFE_CTL_BCAST_EN_ | RFE_CTL_DA_PERFECT_;
ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
if (ret < 0)
return ret;
/* Enable or disable checksum offload engines */ /* Enable or disable checksum offload engines */
lan78xx_set_features(dev->net, dev->net->features); ret = lan78xx_set_features(dev->net, dev->net->features);
if (ret < 0)
return ret;
lan78xx_set_multicast(dev->net); lan78xx_set_multicast(dev->net);
/* reset PHY */ /* reset PHY */
ret = lan78xx_read_reg(dev, PMT_CTL, &buf); ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
buf |= PMT_CTL_PHY_RST_; buf |= PMT_CTL_PHY_RST_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf); ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
return ret;
timeout = jiffies + HZ; timeout = jiffies + HZ;
do { do {
mdelay(1); mdelay(1);
ret = lan78xx_read_reg(dev, PMT_CTL, &buf); ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
netdev_warn(dev->net, "timeout waiting for PHY Reset"); netdev_warn(dev->net, "timeout waiting for PHY Reset");
return -EIO; ret = -ETIMEDOUT;
return ret;
} }
} while ((buf & PMT_CTL_PHY_RST_) || !(buf & PMT_CTL_READY_)); } while ((buf & PMT_CTL_PHY_RST_) || !(buf & PMT_CTL_READY_));
ret = lan78xx_read_reg(dev, MAC_CR, &buf); ret = lan78xx_read_reg(dev, MAC_CR, &buf);
if (ret < 0)
return ret;
/* LAN7801 only has RGMII mode */ /* LAN7801 only has RGMII mode */
if (dev->chipid == ID_REV_CHIP_ID_7801_) if (dev->chipid == ID_REV_CHIP_ID_7801_)
buf &= ~MAC_CR_GMII_EN_; buf &= ~MAC_CR_GMII_EN_;
...@@ -2559,27 +2894,13 @@ static int lan78xx_reset(struct lan78xx_net *dev) ...@@ -2559,27 +2894,13 @@ static int lan78xx_reset(struct lan78xx_net *dev)
} }
} }
ret = lan78xx_write_reg(dev, MAC_CR, buf); ret = lan78xx_write_reg(dev, MAC_CR, buf);
if (ret < 0)
ret = lan78xx_read_reg(dev, MAC_TX, &buf); return ret;
buf |= MAC_TX_TXEN_;
ret = lan78xx_write_reg(dev, MAC_TX, buf);
ret = lan78xx_read_reg(dev, FCT_TX_CTL, &buf);
buf |= FCT_TX_CTL_EN_;
ret = lan78xx_write_reg(dev, FCT_TX_CTL, buf);
ret = lan78xx_set_rx_max_frame_length(dev, ret = lan78xx_set_rx_max_frame_length(dev,
dev->net->mtu + VLAN_ETH_HLEN); dev->net->mtu + VLAN_ETH_HLEN);
ret = lan78xx_read_reg(dev, MAC_RX, &buf); return ret;
buf |= MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
ret = lan78xx_read_reg(dev, FCT_RX_CTL, &buf);
buf |= FCT_RX_CTL_EN_;
ret = lan78xx_write_reg(dev, FCT_RX_CTL, buf);
return 0;
} }
static void lan78xx_init_stats(struct lan78xx_net *dev) static void lan78xx_init_stats(struct lan78xx_net *dev)
...@@ -2613,9 +2934,13 @@ static int lan78xx_open(struct net_device *net) ...@@ -2613,9 +2934,13 @@ static int lan78xx_open(struct net_device *net)
struct lan78xx_net *dev = netdev_priv(net); struct lan78xx_net *dev = netdev_priv(net);
int ret; int ret;
netif_dbg(dev, ifup, dev->net, "open device");
ret = usb_autopm_get_interface(dev->intf); ret = usb_autopm_get_interface(dev->intf);
if (ret < 0) if (ret < 0)
goto out; return ret;
mutex_lock(&dev->dev_mutex);
phy_start(net->phydev); phy_start(net->phydev);
...@@ -2631,6 +2956,20 @@ static int lan78xx_open(struct net_device *net) ...@@ -2631,6 +2956,20 @@ static int lan78xx_open(struct net_device *net)
} }
} }
ret = lan78xx_flush_rx_fifo(dev);
if (ret < 0)
goto done;
ret = lan78xx_flush_tx_fifo(dev);
if (ret < 0)
goto done;
ret = lan78xx_start_tx_path(dev);
if (ret < 0)
goto done;
ret = lan78xx_start_rx_path(dev);
if (ret < 0)
goto done;
lan78xx_init_stats(dev); lan78xx_init_stats(dev);
set_bit(EVENT_DEV_OPEN, &dev->flags); set_bit(EVENT_DEV_OPEN, &dev->flags);
...@@ -2641,9 +2980,10 @@ static int lan78xx_open(struct net_device *net) ...@@ -2641,9 +2980,10 @@ static int lan78xx_open(struct net_device *net)
lan78xx_defer_kevent(dev, EVENT_LINK_RESET); lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
done: done:
mutex_unlock(&dev->dev_mutex);
usb_autopm_put_interface(dev->intf); usb_autopm_put_interface(dev->intf);
out:
return ret; return ret;
} }
...@@ -2660,53 +3000,74 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev) ...@@ -2660,53 +3000,74 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev)
temp = unlink_urbs(dev, &dev->txq) + unlink_urbs(dev, &dev->rxq); temp = unlink_urbs(dev, &dev->txq) + unlink_urbs(dev, &dev->rxq);
/* maybe wait for deletions to finish. */ /* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq) && while (!skb_queue_empty(&dev->rxq) ||
!skb_queue_empty(&dev->txq) && !skb_queue_empty(&dev->txq)) {
!skb_queue_empty(&dev->done)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net, netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp); "waited for %d urb completions", temp);
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
dev->wait = NULL; dev->wait = NULL;
remove_wait_queue(&unlink_wakeup, &wait); remove_wait_queue(&unlink_wakeup, &wait);
while (!skb_queue_empty(&dev->done)) {
struct skb_data *entry;
struct sk_buff *skb;
skb = skb_dequeue(&dev->done);
entry = (struct skb_data *)(skb->cb);
usb_free_urb(entry->urb);
dev_kfree_skb(skb);
}
} }
static int lan78xx_stop(struct net_device *net) static int lan78xx_stop(struct net_device *net)
{ {
struct lan78xx_net *dev = netdev_priv(net); struct lan78xx_net *dev = netdev_priv(net);
netif_dbg(dev, ifup, dev->net, "stop device");
mutex_lock(&dev->dev_mutex);
if (timer_pending(&dev->stat_monitor)) if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor); del_timer_sync(&dev->stat_monitor);
if (net->phydev)
phy_stop(net->phydev);
clear_bit(EVENT_DEV_OPEN, &dev->flags); clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue(net); netif_stop_queue(net);
tasklet_kill(&dev->bh);
lan78xx_terminate_urbs(dev);
netif_info(dev, ifdown, dev->net, netif_info(dev, ifdown, dev->net,
"stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
net->stats.rx_packets, net->stats.tx_packets, net->stats.rx_packets, net->stats.tx_packets,
net->stats.rx_errors, net->stats.tx_errors); net->stats.rx_errors, net->stats.tx_errors);
lan78xx_terminate_urbs(dev); /* ignore errors that occur stopping the Tx and Rx data paths */
lan78xx_stop_tx_path(dev);
lan78xx_stop_rx_path(dev);
usb_kill_urb(dev->urb_intr); if (net->phydev)
phy_stop(net->phydev);
skb_queue_purge(&dev->rxq_pause); usb_kill_urb(dev->urb_intr);
/* deferred work (task, timer, softirq) must also stop. /* deferred work (task, timer, softirq) must also stop.
* can't flush_scheduled_work() until we drop rtnl (later), * can't flush_scheduled_work() until we drop rtnl (later),
* else workers could deadlock; so make workers a NOP. * else workers could deadlock; so make workers a NOP.
*/ */
dev->flags = 0; clear_bit(EVENT_TX_HALT, &dev->flags);
clear_bit(EVENT_RX_HALT, &dev->flags);
clear_bit(EVENT_LINK_RESET, &dev->flags);
clear_bit(EVENT_STAT_UPDATE, &dev->flags);
cancel_delayed_work_sync(&dev->wq); cancel_delayed_work_sync(&dev->wq);
tasklet_kill(&dev->bh);
usb_autopm_put_interface(dev->intf); usb_autopm_put_interface(dev->intf);
mutex_unlock(&dev->dev_mutex);
return 0; return 0;
} }
...@@ -2795,16 +3156,23 @@ static void tx_complete(struct urb *urb) ...@@ -2795,16 +3156,23 @@ static void tx_complete(struct urb *urb)
/* software-driven interface shutdown */ /* software-driven interface shutdown */
case -ECONNRESET: case -ECONNRESET:
case -ESHUTDOWN: case -ESHUTDOWN:
netif_dbg(dev, tx_err, dev->net,
"tx err interface gone %d\n",
entry->urb->status);
break; break;
case -EPROTO: case -EPROTO:
case -ETIME: case -ETIME:
case -EILSEQ: case -EILSEQ:
netif_stop_queue(dev->net); netif_stop_queue(dev->net);
netif_dbg(dev, tx_err, dev->net,
"tx err queue stopped %d\n",
entry->urb->status);
break; break;
default: default:
netif_dbg(dev, tx_err, dev->net, netif_dbg(dev, tx_err, dev->net,
"tx err %d\n", entry->urb->status); "unknown tx err %d\n",
entry->urb->status);
break; break;
} }
} }
...@@ -2829,6 +3197,9 @@ lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -2829,6 +3197,9 @@ lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net)
struct lan78xx_net *dev = netdev_priv(net); struct lan78xx_net *dev = netdev_priv(net);
struct sk_buff *skb2 = NULL; struct sk_buff *skb2 = NULL;
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags))
schedule_delayed_work(&dev->wq, 0);
if (skb) { if (skb) {
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
skb2 = lan78xx_tx_prep(dev, skb, GFP_ATOMIC); skb2 = lan78xx_tx_prep(dev, skb, GFP_ATOMIC);
...@@ -2988,11 +3359,6 @@ static void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) ...@@ -2988,11 +3359,6 @@ static void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb)
{ {
int status; int status;
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
skb_queue_tail(&dev->rxq_pause, skb);
return;
}
dev->net->stats.rx_packets++; dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len; dev->net->stats.rx_bytes += skb->len;
...@@ -3140,6 +3506,7 @@ static int rx_submit(struct lan78xx_net *dev, struct urb *urb, gfp_t flags) ...@@ -3140,6 +3506,7 @@ static int rx_submit(struct lan78xx_net *dev, struct urb *urb, gfp_t flags)
lan78xx_defer_kevent(dev, EVENT_RX_HALT); lan78xx_defer_kevent(dev, EVENT_RX_HALT);
break; break;
case -ENODEV: case -ENODEV:
case -ENOENT:
netif_dbg(dev, ifdown, dev->net, "device gone\n"); netif_dbg(dev, ifdown, dev->net, "device gone\n");
netif_device_detach(dev->net); netif_device_detach(dev->net);
break; break;
...@@ -3340,6 +3707,12 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) ...@@ -3340,6 +3707,12 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
lan78xx_defer_kevent(dev, EVENT_TX_HALT); lan78xx_defer_kevent(dev, EVENT_TX_HALT);
usb_autopm_put_interface_async(dev->intf); usb_autopm_put_interface_async(dev->intf);
break; break;
case -ENODEV:
case -ENOENT:
netif_dbg(dev, tx_err, dev->net,
"tx: submit urb err %d (disconnected?)", ret);
netif_device_detach(dev->net);
break;
default: default:
usb_autopm_put_interface_async(dev->intf); usb_autopm_put_interface_async(dev->intf);
netif_dbg(dev, tx_err, dev->net, netif_dbg(dev, tx_err, dev->net,
...@@ -3356,9 +3729,10 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) ...@@ -3356,9 +3729,10 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
if (skb) if (skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
usb_free_urb(urb); usb_free_urb(urb);
} else } else {
netif_dbg(dev, tx_queued, dev->net, netif_dbg(dev, tx_queued, dev->net,
"> tx, len %d, type 0x%x\n", length, skb->protocol); "> tx, len %d, type 0x%x\n", length, skb->protocol);
}
} }
static void lan78xx_rx_bh(struct lan78xx_net *dev) static void lan78xx_rx_bh(struct lan78xx_net *dev)
...@@ -3421,8 +3795,7 @@ static void lan78xx_bh(struct tasklet_struct *t) ...@@ -3421,8 +3795,7 @@ static void lan78xx_bh(struct tasklet_struct *t)
if (!skb_queue_empty(&dev->txq_pend)) if (!skb_queue_empty(&dev->txq_pend))
lan78xx_tx_bh(dev); lan78xx_tx_bh(dev);
if (!timer_pending(&dev->delay) && if (!test_bit(EVENT_RX_HALT, &dev->flags))
!test_bit(EVENT_RX_HALT, &dev->flags))
lan78xx_rx_bh(dev); lan78xx_rx_bh(dev);
} }
} }
...@@ -3434,18 +3807,20 @@ static void lan78xx_delayedwork(struct work_struct *work) ...@@ -3434,18 +3807,20 @@ static void lan78xx_delayedwork(struct work_struct *work)
dev = container_of(work, struct lan78xx_net, wq.work); dev = container_of(work, struct lan78xx_net, wq.work);
if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
return;
if (usb_autopm_get_interface(dev->intf) < 0)
return;
if (test_bit(EVENT_TX_HALT, &dev->flags)) { if (test_bit(EVENT_TX_HALT, &dev->flags)) {
unlink_urbs(dev, &dev->txq); unlink_urbs(dev, &dev->txq);
status = usb_autopm_get_interface(dev->intf);
if (status < 0)
goto fail_pipe;
status = usb_clear_halt(dev->udev, dev->pipe_out); status = usb_clear_halt(dev->udev, dev->pipe_out);
usb_autopm_put_interface(dev->intf);
if (status < 0 && if (status < 0 &&
status != -EPIPE && status != -EPIPE &&
status != -ESHUTDOWN) { status != -ESHUTDOWN) {
if (netif_msg_tx_err(dev)) if (netif_msg_tx_err(dev))
fail_pipe:
netdev_err(dev->net, netdev_err(dev->net,
"can't clear tx halt, status %d\n", "can't clear tx halt, status %d\n",
status); status);
...@@ -3455,18 +3830,14 @@ static void lan78xx_delayedwork(struct work_struct *work) ...@@ -3455,18 +3830,14 @@ static void lan78xx_delayedwork(struct work_struct *work)
netif_wake_queue(dev->net); netif_wake_queue(dev->net);
} }
} }
if (test_bit(EVENT_RX_HALT, &dev->flags)) { if (test_bit(EVENT_RX_HALT, &dev->flags)) {
unlink_urbs(dev, &dev->rxq); unlink_urbs(dev, &dev->rxq);
status = usb_autopm_get_interface(dev->intf);
if (status < 0)
goto fail_halt;
status = usb_clear_halt(dev->udev, dev->pipe_in); status = usb_clear_halt(dev->udev, dev->pipe_in);
usb_autopm_put_interface(dev->intf);
if (status < 0 && if (status < 0 &&
status != -EPIPE && status != -EPIPE &&
status != -ESHUTDOWN) { status != -ESHUTDOWN) {
if (netif_msg_rx_err(dev)) if (netif_msg_rx_err(dev))
fail_halt:
netdev_err(dev->net, netdev_err(dev->net,
"can't clear rx halt, status %d\n", "can't clear rx halt, status %d\n",
status); status);
...@@ -3480,16 +3851,9 @@ static void lan78xx_delayedwork(struct work_struct *work) ...@@ -3480,16 +3851,9 @@ static void lan78xx_delayedwork(struct work_struct *work)
int ret = 0; int ret = 0;
clear_bit(EVENT_LINK_RESET, &dev->flags); clear_bit(EVENT_LINK_RESET, &dev->flags);
status = usb_autopm_get_interface(dev->intf);
if (status < 0)
goto skip_reset;
if (lan78xx_link_reset(dev) < 0) { if (lan78xx_link_reset(dev) < 0) {
usb_autopm_put_interface(dev->intf);
skip_reset:
netdev_info(dev->net, "link reset failed (%d)\n", netdev_info(dev->net, "link reset failed (%d)\n",
ret); ret);
} else {
usb_autopm_put_interface(dev->intf);
} }
} }
...@@ -3503,6 +3867,8 @@ static void lan78xx_delayedwork(struct work_struct *work) ...@@ -3503,6 +3867,8 @@ static void lan78xx_delayedwork(struct work_struct *work)
dev->delta = min((dev->delta * 2), 50); dev->delta = min((dev->delta * 2), 50);
} }
usb_autopm_put_interface(dev->intf);
} }
static void intr_complete(struct urb *urb) static void intr_complete(struct urb *urb)
...@@ -3518,6 +3884,7 @@ static void intr_complete(struct urb *urb) ...@@ -3518,6 +3884,7 @@ static void intr_complete(struct urb *urb)
/* software-driven interface shutdown */ /* software-driven interface shutdown */
case -ENOENT: /* urb killed */ case -ENOENT: /* urb killed */
case -ENODEV: /* hardware gone */
case -ESHUTDOWN: /* hardware gone */ case -ESHUTDOWN: /* hardware gone */
netif_dbg(dev, ifdown, dev->net, netif_dbg(dev, ifdown, dev->net,
"intr shutdown, code %d\n", status); "intr shutdown, code %d\n", status);
...@@ -3531,14 +3898,29 @@ static void intr_complete(struct urb *urb) ...@@ -3531,14 +3898,29 @@ static void intr_complete(struct urb *urb)
break; break;
} }
if (!netif_running(dev->net)) if (!netif_device_present(dev->net) ||
!netif_running(dev->net)) {
netdev_warn(dev->net, "not submitting new status URB");
return; return;
}
memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_ATOMIC);
if (status != 0)
switch (status) {
case 0:
break;
case -ENODEV:
case -ENOENT:
netif_dbg(dev, timer, dev->net,
"intr resubmit %d (disconnect?)", status);
netif_device_detach(dev->net);
break;
default:
netif_err(dev, timer, dev->net, netif_err(dev, timer, dev->net,
"intr resubmit --> %d\n", status); "intr resubmit --> %d\n", status);
break;
}
} }
static void lan78xx_disconnect(struct usb_interface *intf) static void lan78xx_disconnect(struct usb_interface *intf)
...@@ -3553,8 +3935,15 @@ static void lan78xx_disconnect(struct usb_interface *intf) ...@@ -3553,8 +3935,15 @@ static void lan78xx_disconnect(struct usb_interface *intf)
if (!dev) if (!dev)
return; return;
set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
net = dev->net; net = dev->net;
unregister_netdev(net);
cancel_delayed_work_sync(&dev->wq);
phydev = net->phydev; phydev = net->phydev;
phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0); phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
...@@ -3565,12 +3954,11 @@ static void lan78xx_disconnect(struct usb_interface *intf) ...@@ -3565,12 +3954,11 @@ static void lan78xx_disconnect(struct usb_interface *intf)
if (phy_is_pseudo_fixed_link(phydev)) if (phy_is_pseudo_fixed_link(phydev))
fixed_phy_unregister(phydev); fixed_phy_unregister(phydev);
unregister_netdev(net);
cancel_delayed_work_sync(&dev->wq);
usb_scuttle_anchored_urbs(&dev->deferred); usb_scuttle_anchored_urbs(&dev->deferred);
if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor);
lan78xx_unbind(dev, intf); lan78xx_unbind(dev, intf);
usb_kill_urb(dev->urb_intr); usb_kill_urb(dev->urb_intr);
...@@ -3632,8 +4020,8 @@ static int lan78xx_probe(struct usb_interface *intf, ...@@ -3632,8 +4020,8 @@ static int lan78xx_probe(struct usb_interface *intf,
struct net_device *netdev; struct net_device *netdev;
struct usb_device *udev; struct usb_device *udev;
int ret; int ret;
unsigned maxp; unsigned int maxp;
unsigned period; unsigned int period;
u8 *buf = NULL; u8 *buf = NULL;
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
...@@ -3659,9 +4047,9 @@ static int lan78xx_probe(struct usb_interface *intf, ...@@ -3659,9 +4047,9 @@ static int lan78xx_probe(struct usb_interface *intf,
skb_queue_head_init(&dev->rxq); skb_queue_head_init(&dev->rxq);
skb_queue_head_init(&dev->txq); skb_queue_head_init(&dev->txq);
skb_queue_head_init(&dev->done); skb_queue_head_init(&dev->done);
skb_queue_head_init(&dev->rxq_pause);
skb_queue_head_init(&dev->txq_pend); skb_queue_head_init(&dev->txq_pend);
mutex_init(&dev->phy_mutex); mutex_init(&dev->phy_mutex);
mutex_init(&dev->dev_mutex);
tasklet_setup(&dev->bh, lan78xx_bh); tasklet_setup(&dev->bh, lan78xx_bh);
INIT_DELAYED_WORK(&dev->wq, lan78xx_delayedwork); INIT_DELAYED_WORK(&dev->wq, lan78xx_delayedwork);
...@@ -3798,37 +4186,119 @@ static u16 lan78xx_wakeframe_crc16(const u8 *buf, int len) ...@@ -3798,37 +4186,119 @@ static u16 lan78xx_wakeframe_crc16(const u8 *buf, int len)
return crc; return crc;
} }
static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) static int lan78xx_set_auto_suspend(struct lan78xx_net *dev)
{ {
u32 buf; u32 buf;
int mask_index; int ret;
u16 crc;
u32 temp_wucsr; ret = lan78xx_stop_tx_path(dev);
u32 temp_pmt_ctl; if (ret < 0)
return ret;
ret = lan78xx_stop_rx_path(dev);
if (ret < 0)
return ret;
/* auto suspend (selective suspend) */
ret = lan78xx_write_reg(dev, WUCSR, 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUCSR2, 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
if (ret < 0)
return ret;
/* set goodframe wakeup */
ret = lan78xx_read_reg(dev, WUCSR, &buf);
if (ret < 0)
return ret;
buf |= WUCSR_RFE_WAKE_EN_;
buf |= WUCSR_STORE_WAKE_;
ret = lan78xx_write_reg(dev, WUCSR, buf);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
buf &= ~PMT_CTL_RES_CLR_WKP_EN_;
buf |= PMT_CTL_RES_CLR_WKP_STS_;
buf |= PMT_CTL_PHY_WAKE_EN_;
buf |= PMT_CTL_WOL_EN_;
buf &= ~PMT_CTL_SUS_MODE_MASK_;
buf |= PMT_CTL_SUS_MODE_3_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
buf |= PMT_CTL_WUPS_MASK_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
return ret;
ret = lan78xx_start_rx_path(dev);
return ret;
}
static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
{
const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E }; const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E };
const u8 ipv6_multicast[3] = { 0x33, 0x33 }; const u8 ipv6_multicast[3] = { 0x33, 0x33 };
const u8 arp_type[2] = { 0x08, 0x06 }; const u8 arp_type[2] = { 0x08, 0x06 };
u32 temp_pmt_ctl;
int mask_index;
u32 temp_wucsr;
u32 buf;
u16 crc;
int ret;
lan78xx_read_reg(dev, MAC_TX, &buf); ret = lan78xx_stop_tx_path(dev);
buf &= ~MAC_TX_TXEN_; if (ret < 0)
lan78xx_write_reg(dev, MAC_TX, buf); return ret;
lan78xx_read_reg(dev, MAC_RX, &buf); ret = lan78xx_stop_rx_path(dev);
buf &= ~MAC_RX_RXEN_; if (ret < 0)
lan78xx_write_reg(dev, MAC_RX, buf); return ret;
lan78xx_write_reg(dev, WUCSR, 0); ret = lan78xx_write_reg(dev, WUCSR, 0);
lan78xx_write_reg(dev, WUCSR2, 0); if (ret < 0)
lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL); return ret;
ret = lan78xx_write_reg(dev, WUCSR2, 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
if (ret < 0)
return ret;
temp_wucsr = 0; temp_wucsr = 0;
temp_pmt_ctl = 0; temp_pmt_ctl = 0;
lan78xx_read_reg(dev, PMT_CTL, &temp_pmt_ctl);
ret = lan78xx_read_reg(dev, PMT_CTL, &temp_pmt_ctl);
if (ret < 0)
return ret;
temp_pmt_ctl &= ~PMT_CTL_RES_CLR_WKP_EN_; temp_pmt_ctl &= ~PMT_CTL_RES_CLR_WKP_EN_;
temp_pmt_ctl |= PMT_CTL_RES_CLR_WKP_STS_; temp_pmt_ctl |= PMT_CTL_RES_CLR_WKP_STS_;
for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++) for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++) {
lan78xx_write_reg(dev, WUF_CFG(mask_index), 0); ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), 0);
if (ret < 0)
return ret;
}
mask_index = 0; mask_index = 0;
if (wol & WAKE_PHY) { if (wol & WAKE_PHY) {
...@@ -3857,30 +4327,52 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) ...@@ -3857,30 +4327,52 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
/* set WUF_CFG & WUF_MASK for IPv4 Multicast */ /* set WUF_CFG & WUF_MASK for IPv4 Multicast */
crc = lan78xx_wakeframe_crc16(ipv4_multicast, 3); crc = lan78xx_wakeframe_crc16(ipv4_multicast, 3);
lan78xx_write_reg(dev, WUF_CFG(mask_index), ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
WUF_CFGX_EN_ | WUF_CFGX_EN_ |
WUF_CFGX_TYPE_MCAST_ | WUF_CFGX_TYPE_MCAST_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) | (0 << WUF_CFGX_OFFSET_SHIFT_) |
(crc & WUF_CFGX_CRC16_MASK_)); (crc & WUF_CFGX_CRC16_MASK_));
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 7);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
if (ret < 0)
return ret;
lan78xx_write_reg(dev, WUF_MASK0(mask_index), 7);
lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
mask_index++; mask_index++;
/* for IPv6 Multicast */ /* for IPv6 Multicast */
crc = lan78xx_wakeframe_crc16(ipv6_multicast, 2); crc = lan78xx_wakeframe_crc16(ipv6_multicast, 2);
lan78xx_write_reg(dev, WUF_CFG(mask_index), ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
WUF_CFGX_EN_ | WUF_CFGX_EN_ |
WUF_CFGX_TYPE_MCAST_ | WUF_CFGX_TYPE_MCAST_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) | (0 << WUF_CFGX_OFFSET_SHIFT_) |
(crc & WUF_CFGX_CRC16_MASK_)); (crc & WUF_CFGX_CRC16_MASK_));
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 3);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
if (ret < 0)
return ret;
lan78xx_write_reg(dev, WUF_MASK0(mask_index), 3);
lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
mask_index++; mask_index++;
temp_pmt_ctl |= PMT_CTL_WOL_EN_; temp_pmt_ctl |= PMT_CTL_WOL_EN_;
...@@ -3901,16 +4393,27 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) ...@@ -3901,16 +4393,27 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
* for packettype (offset 12,13) = ARP (0x0806) * for packettype (offset 12,13) = ARP (0x0806)
*/ */
crc = lan78xx_wakeframe_crc16(arp_type, 2); crc = lan78xx_wakeframe_crc16(arp_type, 2);
lan78xx_write_reg(dev, WUF_CFG(mask_index), ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
WUF_CFGX_EN_ | WUF_CFGX_EN_ |
WUF_CFGX_TYPE_ALL_ | WUF_CFGX_TYPE_ALL_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) | (0 << WUF_CFGX_OFFSET_SHIFT_) |
(crc & WUF_CFGX_CRC16_MASK_)); (crc & WUF_CFGX_CRC16_MASK_));
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 0x3000);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
if (ret < 0)
return ret;
lan78xx_write_reg(dev, WUF_MASK0(mask_index), 0x3000);
lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
mask_index++; mask_index++;
temp_pmt_ctl |= PMT_CTL_WOL_EN_; temp_pmt_ctl |= PMT_CTL_WOL_EN_;
...@@ -3918,7 +4421,9 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) ...@@ -3918,7 +4421,9 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_;
} }
lan78xx_write_reg(dev, WUCSR, temp_wucsr); ret = lan78xx_write_reg(dev, WUCSR, temp_wucsr);
if (ret < 0)
return ret;
/* when multiple WOL bits are set */ /* when multiple WOL bits are set */
if (hweight_long((unsigned long)wol) > 1) { if (hweight_long((unsigned long)wol) > 1) {
...@@ -3926,28 +4431,40 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) ...@@ -3926,28 +4431,40 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_;
temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_;
} }
lan78xx_write_reg(dev, PMT_CTL, temp_pmt_ctl); ret = lan78xx_write_reg(dev, PMT_CTL, temp_pmt_ctl);
if (ret < 0)
return ret;
/* clear WUPS */ /* clear WUPS */
lan78xx_read_reg(dev, PMT_CTL, &buf); ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
buf |= PMT_CTL_WUPS_MASK_; buf |= PMT_CTL_WUPS_MASK_;
lan78xx_write_reg(dev, PMT_CTL, buf);
lan78xx_read_reg(dev, MAC_RX, &buf); ret = lan78xx_write_reg(dev, PMT_CTL, buf);
buf |= MAC_RX_RXEN_; if (ret < 0)
lan78xx_write_reg(dev, MAC_RX, buf); return ret;
return 0; ret = lan78xx_start_rx_path(dev);
return ret;
} }
static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct lan78xx_net *dev = usb_get_intfdata(intf); struct lan78xx_net *dev = usb_get_intfdata(intf);
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); bool dev_open;
u32 buf;
int ret; int ret;
if (!dev->suspend_count++) { mutex_lock(&dev->dev_mutex);
netif_dbg(dev, ifdown, dev->net,
"suspending: pm event %#x", message.event);
dev_open = test_bit(EVENT_DEV_OPEN, &dev->flags);
if (dev_open) {
spin_lock_irq(&dev->txq.lock); spin_lock_irq(&dev->txq.lock);
/* don't autosuspend while transmitting */ /* don't autosuspend while transmitting */
if ((skb_queue_len(&dev->txq) || if ((skb_queue_len(&dev->txq) ||
...@@ -3961,129 +4478,207 @@ static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -3961,129 +4478,207 @@ static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message)
spin_unlock_irq(&dev->txq.lock); spin_unlock_irq(&dev->txq.lock);
} }
/* stop TX & RX */ /* stop RX */
ret = lan78xx_read_reg(dev, MAC_TX, &buf); ret = lan78xx_stop_rx_path(dev);
buf &= ~MAC_TX_TXEN_; if (ret < 0)
ret = lan78xx_write_reg(dev, MAC_TX, buf); goto out;
ret = lan78xx_read_reg(dev, MAC_RX, &buf);
buf &= ~MAC_RX_RXEN_; ret = lan78xx_flush_rx_fifo(dev);
ret = lan78xx_write_reg(dev, MAC_RX, buf); if (ret < 0)
goto out;
/* stop Tx */
ret = lan78xx_stop_tx_path(dev);
if (ret < 0)
goto out;
/* empty out the rx and queues */ /* empty out the Rx and Tx queues */
netif_device_detach(dev->net); netif_device_detach(dev->net);
lan78xx_terminate_urbs(dev); lan78xx_terminate_urbs(dev);
usb_kill_urb(dev->urb_intr); usb_kill_urb(dev->urb_intr);
/* reattach */ /* reattach */
netif_device_attach(dev->net); netif_device_attach(dev->net);
}
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) {
del_timer(&dev->stat_monitor); del_timer(&dev->stat_monitor);
if (PMSG_IS_AUTO(message)) { if (PMSG_IS_AUTO(message)) {
/* auto suspend (selective suspend) */ ret = lan78xx_set_auto_suspend(dev);
ret = lan78xx_read_reg(dev, MAC_TX, &buf); if (ret < 0)
buf &= ~MAC_TX_TXEN_; goto out;
ret = lan78xx_write_reg(dev, MAC_TX, buf); } else {
ret = lan78xx_read_reg(dev, MAC_RX, &buf); struct lan78xx_priv *pdata;
buf &= ~MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
ret = lan78xx_write_reg(dev, WUCSR, 0);
ret = lan78xx_write_reg(dev, WUCSR2, 0);
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
/* set goodframe wakeup */ pdata = (struct lan78xx_priv *)(dev->data[0]);
ret = lan78xx_read_reg(dev, WUCSR, &buf); netif_carrier_off(dev->net);
ret = lan78xx_set_suspend(dev, pdata->wol);
if (ret < 0)
goto out;
}
} else {
/* Interface is down; don't allow WOL and PHY
* events to wake up the host
*/
u32 buf;
buf |= WUCSR_RFE_WAKE_EN_; set_bit(EVENT_DEV_ASLEEP, &dev->flags);
buf |= WUCSR_STORE_WAKE_;
ret = lan78xx_write_reg(dev, WUCSR, buf); ret = lan78xx_write_reg(dev, WUCSR, 0);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR2, 0);
if (ret < 0)
goto out;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf); ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
goto out;
buf &= ~PMT_CTL_RES_CLR_WKP_EN_; buf &= ~PMT_CTL_RES_CLR_WKP_EN_;
buf |= PMT_CTL_RES_CLR_WKP_STS_; buf |= PMT_CTL_RES_CLR_WKP_STS_;
buf |= PMT_CTL_PHY_WAKE_EN_;
buf |= PMT_CTL_WOL_EN_;
buf &= ~PMT_CTL_SUS_MODE_MASK_; buf &= ~PMT_CTL_SUS_MODE_MASK_;
buf |= PMT_CTL_SUS_MODE_3_; buf |= PMT_CTL_SUS_MODE_3_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf); ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
goto out;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf); ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
goto out;
buf |= PMT_CTL_WUPS_MASK_; buf |= PMT_CTL_WUPS_MASK_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf); ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
ret = lan78xx_read_reg(dev, MAC_RX, &buf); goto out;
buf |= MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
} else {
lan78xx_set_suspend(dev, pdata->wol);
}
} }
ret = 0; ret = 0;
out: out:
mutex_unlock(&dev->dev_mutex);
return ret; return ret;
} }
static int lan78xx_resume(struct usb_interface *intf) static bool lan78xx_submit_deferred_urbs(struct lan78xx_net *dev)
{ {
struct lan78xx_net *dev = usb_get_intfdata(intf); bool pipe_halted = false;
struct sk_buff *skb; struct urb *urb;
struct urb *res;
while ((urb = usb_get_from_anchor(&dev->deferred))) {
struct sk_buff *skb = urb->context;
int ret; int ret;
u32 buf;
if (!timer_pending(&dev->stat_monitor)) { if (!netif_device_present(dev->net) ||
dev->delta = 1; !netif_carrier_ok(dev->net) ||
mod_timer(&dev->stat_monitor, pipe_halted) {
jiffies + STAT_UPDATE_TIMER); usb_free_urb(urb);
dev_kfree_skb(skb);
continue;
} }
if (!--dev->suspend_count) { ret = usb_submit_urb(urb, GFP_ATOMIC);
/* resume interrupt URBs */
if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags))
usb_submit_urb(dev->urb_intr, GFP_NOIO);
spin_lock_irq(&dev->txq.lock); if (ret == 0) {
while ((res = usb_get_from_anchor(&dev->deferred))) {
skb = (struct sk_buff *)res->context;
ret = usb_submit_urb(res, GFP_ATOMIC);
if (ret < 0) {
dev_kfree_skb_any(skb);
usb_free_urb(res);
usb_autopm_put_interface_async(dev->intf);
} else {
netif_trans_update(dev->net); netif_trans_update(dev->net);
lan78xx_queue_skb(&dev->txq, skb, tx_start); lan78xx_queue_skb(&dev->txq, skb, tx_start);
} else {
usb_free_urb(urb);
dev_kfree_skb(skb);
if (ret == -EPIPE) {
netif_stop_queue(dev->net);
pipe_halted = true;
} else if (ret == -ENODEV) {
netif_device_detach(dev->net);
}
} }
} }
return pipe_halted;
}
static int lan78xx_resume(struct usb_interface *intf)
{
struct lan78xx_net *dev = usb_get_intfdata(intf);
bool dev_open;
int ret;
mutex_lock(&dev->dev_mutex);
netif_dbg(dev, ifup, dev->net, "resuming device");
dev_open = test_bit(EVENT_DEV_OPEN, &dev->flags);
if (dev_open) {
bool pipe_halted = false;
ret = lan78xx_flush_tx_fifo(dev);
if (ret < 0)
goto out;
if (dev->urb_intr) {
int ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL);
if (ret < 0) {
if (ret == -ENODEV)
netif_device_detach(dev->net);
netdev_warn(dev->net, "Failed to submit intr URB");
}
}
spin_lock_irq(&dev->txq.lock);
if (netif_device_present(dev->net)) {
pipe_halted = lan78xx_submit_deferred_urbs(dev);
if (pipe_halted)
lan78xx_defer_kevent(dev, EVENT_TX_HALT);
}
clear_bit(EVENT_DEV_ASLEEP, &dev->flags); clear_bit(EVENT_DEV_ASLEEP, &dev->flags);
spin_unlock_irq(&dev->txq.lock); spin_unlock_irq(&dev->txq.lock);
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { if (!pipe_halted &&
if (!(skb_queue_len(&dev->txq) >= dev->tx_qlen)) netif_device_present(dev->net) &&
(skb_queue_len(&dev->txq) < dev->tx_qlen))
netif_start_queue(dev->net); netif_start_queue(dev->net);
ret = lan78xx_start_tx_path(dev);
if (ret < 0)
goto out;
tasklet_schedule(&dev->bh); tasklet_schedule(&dev->bh);
if (!timer_pending(&dev->stat_monitor)) {
dev->delta = 1;
mod_timer(&dev->stat_monitor,
jiffies + STAT_UPDATE_TIMER);
} }
} else {
clear_bit(EVENT_DEV_ASLEEP, &dev->flags);
} }
ret = lan78xx_write_reg(dev, WUCSR2, 0); ret = lan78xx_write_reg(dev, WUCSR2, 0);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR, 0); ret = lan78xx_write_reg(dev, WUCSR, 0);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL); ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR2, WUCSR2_NS_RCD_ | ret = lan78xx_write_reg(dev, WUCSR2, WUCSR2_NS_RCD_ |
WUCSR2_ARP_RCD_ | WUCSR2_ARP_RCD_ |
WUCSR2_IPV6_TCPSYN_RCD_ | WUCSR2_IPV6_TCPSYN_RCD_ |
WUCSR2_IPV4_TCPSYN_RCD_); WUCSR2_IPV4_TCPSYN_RCD_);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR, WUCSR_EEE_TX_WAKE_ | ret = lan78xx_write_reg(dev, WUCSR, WUCSR_EEE_TX_WAKE_ |
WUCSR_EEE_RX_WAKE_ | WUCSR_EEE_RX_WAKE_ |
...@@ -4092,23 +4687,32 @@ static int lan78xx_resume(struct usb_interface *intf) ...@@ -4092,23 +4687,32 @@ static int lan78xx_resume(struct usb_interface *intf)
WUCSR_WUFR_ | WUCSR_WUFR_ |
WUCSR_MPR_ | WUCSR_MPR_ |
WUCSR_BCST_FR_); WUCSR_BCST_FR_);
if (ret < 0)
goto out;
ret = lan78xx_read_reg(dev, MAC_TX, &buf); ret = 0;
buf |= MAC_TX_TXEN_; out:
ret = lan78xx_write_reg(dev, MAC_TX, buf); mutex_unlock(&dev->dev_mutex);
return 0; return ret;
} }
static int lan78xx_reset_resume(struct usb_interface *intf) static int lan78xx_reset_resume(struct usb_interface *intf)
{ {
struct lan78xx_net *dev = usb_get_intfdata(intf); struct lan78xx_net *dev = usb_get_intfdata(intf);
int ret;
lan78xx_reset(dev); netif_dbg(dev, ifup, dev->net, "(reset) resuming device");
ret = lan78xx_reset(dev);
if (ret < 0)
return ret;
phy_start(dev->net->phydev); phy_start(dev->net->phydev);
return lan78xx_resume(intf); ret = lan78xx_resume(intf);
return ret;
} }
static const struct usb_device_id products[] = { static const struct usb_device_id products[] = {
......
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