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 @@
#define MAX_RX_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_BULK_IN_DELAY (0x0800)
#define MAX_SINGLE_PACKET_SIZE (9000)
......@@ -87,6 +100,12 @@
/* statistic update interval (mSec) */
#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 */
#define MAX_INT_EP (32)
#define INT_EP_INTEP (31)
......@@ -341,6 +360,7 @@ struct usb_context {
#define EVENT_DEV_ASLEEP 7
#define EVENT_DEV_OPEN 8
#define EVENT_STAT_UPDATE 9
#define EVENT_DEV_DISCONNECT 10
struct statstage {
struct mutex access_lock; /* for stats access */
......@@ -370,7 +390,6 @@ struct lan78xx_net {
struct sk_buff_head rxq;
struct sk_buff_head txq;
struct sk_buff_head done;
struct sk_buff_head rxq_pause;
struct sk_buff_head txq_pend;
struct tasklet_struct bh;
......@@ -381,8 +400,9 @@ struct lan78xx_net {
struct urb *urb_intr;
struct usb_anchor deferred;
struct mutex dev_mutex; /* serialise open/stop wrt suspend/resume */
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 */
size_t rx_urb_size; /* size for rx urbs */
......@@ -392,8 +412,7 @@ struct lan78xx_net {
wait_queue_head_t *wait;
unsigned char suspend_count;
unsigned maxpacket;
struct timer_list delay;
unsigned int maxpacket;
struct timer_list stat_monitor;
unsigned long data[5];
......@@ -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)
{
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
u32 *buf;
int ret;
if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
return -ENODEV;
buf = kmalloc(sizeof(u32), GFP_KERNEL);
if (!buf)
return -ENOMEM;
......@@ -439,7 +462,7 @@ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
if (likely(ret >= 0)) {
le32_to_cpus(buf);
*data = *buf;
} else {
} else if (net_ratelimit()) {
netdev_warn(dev->net,
"Failed to read register index 0x%08x. ret = %d",
index, ret);
......@@ -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)
{
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
u32 *buf;
int ret;
if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
return -ENODEV;
buf = kmalloc(sizeof(u32), GFP_KERNEL);
if (!buf)
return -ENOMEM;
......@@ -465,7 +492,8 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
USB_VENDOR_REQUEST_WRITE_REGISTER,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, buf, 4, USB_CTRL_SET_TIMEOUT);
if (unlikely(ret < 0)) {
if (unlikely(ret < 0) &&
net_ratelimit()) {
netdev_warn(dev->net,
"Failed to write register index 0x%08x. ret = %d",
index, ret);
......@@ -476,6 +504,26 @@ static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
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,
struct lan78xx_statstage *data)
{
......@@ -501,7 +549,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
if (likely(ret >= 0)) {
src = (u32 *)stats;
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]);
dst[i] = src[i];
}
......@@ -515,10 +563,11 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
return ret;
}
#define check_counter_rollover(struct1, dev_stats, member) { \
if (struct1->member < dev_stats.saved.member) \
dev_stats.rollover_count.member++; \
}
#define check_counter_rollover(struct1, dev_stats, member) \
do { \
if ((struct1)->member < (dev_stats).saved.member) \
(dev_stats).rollover_count.member++; \
} while (0)
static void lan78xx_check_stat_rollover(struct lan78xx_net *dev,
struct lan78xx_statstage *stats)
......@@ -844,9 +893,9 @@ static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset,
for (i = 0; i < length; i++) {
lan78xx_write_reg(dev, OTP_ADDR1,
((offset + i) >> 8) & OTP_ADDR1_15_11);
((offset + i) >> 8) & OTP_ADDR1_15_11);
lan78xx_write_reg(dev, OTP_ADDR2,
((offset + i) & OTP_ADDR2_10_3));
((offset + i) & OTP_ADDR2_10_3));
lan78xx_write_reg(dev, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
......@@ -900,9 +949,9 @@ static int lan78xx_write_raw_otp(struct lan78xx_net *dev, u32 offset,
for (i = 0; i < length; i++) {
lan78xx_write_reg(dev, OTP_ADDR1,
((offset + i) >> 8) & OTP_ADDR1_15_11);
((offset + i) >> 8) & OTP_ADDR1_15_11);
lan78xx_write_reg(dev, OTP_ADDR2,
((offset + i) & OTP_ADDR2_10_3));
((offset + i) & OTP_ADDR2_10_3));
lan78xx_write_reg(dev, OTP_PRGM_DATA, data[i]);
lan78xx_write_reg(dev, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
......@@ -959,7 +1008,7 @@ static int lan78xx_dataport_wait_not_busy(struct lan78xx_net *dev)
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;
}
......@@ -972,7 +1021,7 @@ static int lan78xx_dataport_write(struct lan78xx_net *dev, u32 ram_select,
int i, ret;
if (usb_autopm_get_interface(dev->intf) < 0)
return 0;
return 0;
mutex_lock(&pdata->dataport_mutex);
......@@ -1045,9 +1094,9 @@ static void lan78xx_deferred_multicast_write(struct work_struct *param)
for (i = 1; i < NUM_OF_MAF; i++) {
lan78xx_write_reg(dev, MAF_HI(i), 0);
lan78xx_write_reg(dev, MAF_LO(i),
pdata->pfilter_table[i][1]);
pdata->pfilter_table[i][1]);
lan78xx_write_reg(dev, MAF_HI(i),
pdata->pfilter_table[i][0]);
pdata->pfilter_table[i][0]);
}
lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
......@@ -1066,11 +1115,12 @@ static void lan78xx_set_multicast(struct net_device *netdev)
RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_);
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 */
for (i = 1; i < NUM_OF_MAF; i++) {
pdata->pfilter_table[i][0] =
pdata->pfilter_table[i][1] = 0;
pdata->pfilter_table[i][0] = 0;
pdata->pfilter_table[i][1] = 0;
}
pdata->rfe_ctl |= RFE_CTL_BCAST_EN_;
......@@ -1134,9 +1184,9 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
flow |= FLOW_CR_RX_FCEN_;
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)
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",
(cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
......@@ -1150,6 +1200,52 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
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)
{
struct phy_device *phydev = dev->net->phydev;
......@@ -1160,7 +1256,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
/* clear LAN78xx interrupt status */
ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_);
if (unlikely(ret < 0))
return -EIO;
return ret;
mutex_lock(&phydev->lock);
phy_read_status(phydev);
......@@ -1171,13 +1267,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
dev->link_on = false;
/* reset MAC */
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
if (unlikely(ret < 0))
return -EIO;
buf |= MAC_CR_RST_;
ret = lan78xx_write_reg(dev, MAC_CR, buf);
if (unlikely(ret < 0))
return -EIO;
ret = lan78xx_mac_reset(dev);
if (ret < 0)
return ret;
del_timer(&dev->stat_monitor);
} else if (link && !dev->link_on) {
......@@ -1189,18 +1281,30 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
if (ecmd.base.speed == 1000) {
/* disable U2 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf &= ~USB_CFG1_DEV_U2_INIT_EN_;
ret = lan78xx_write_reg(dev, USB_CFG1, buf);
if (ret < 0)
return ret;
/* enable U1 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG1_DEV_U1_INIT_EN_;
ret = lan78xx_write_reg(dev, USB_CFG1, buf);
if (ret < 0)
return ret;
} else {
/* enable U1 & U2 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG1_DEV_U2_INIT_EN_;
buf |= USB_CFG1_DEV_U1_INIT_EN_;
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)
ret = lan78xx_update_flowcontrol(dev, ecmd.base.duplex, ladv,
radv);
if (ret < 0)
return ret;
if (!timer_pending(&dev->stat_monitor)) {
dev->delta = 1;
......@@ -1228,7 +1334,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
tasklet_schedule(&dev->bh);
}
return ret;
return 0;
}
/* 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)
generic_handle_irq(dev->domain_data.phyirq);
local_irq_enable();
}
} else
} else {
netdev_warn(dev->net,
"unexpected interrupt: 0x%08x\n", intdata);
}
}
static int lan78xx_ethtool_get_eeprom_len(struct net_device *netdev)
......@@ -1355,7 +1462,7 @@ static void lan78xx_get_wol(struct net_device *netdev,
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
if (usb_autopm_get_interface(dev->intf) < 0)
return;
return;
ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
if (unlikely(ret < 0)) {
......@@ -2003,7 +2110,7 @@ static int lan8835_fixup(struct phy_device *phydev)
/* RGMII MAC TXC Delay Enable */
lan78xx_write_reg(dev, MAC_RGMII_ID,
MAC_RGMII_ID_TXC_DELAY_EN_);
MAC_RGMII_ID_TXC_DELAY_EN_);
/* RGMII TX DLL Tune Adjust */
lan78xx_write_reg(dev, RGMII_TX_BYP_DLL, 0x3D00);
......@@ -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 old_hard_mtu = dev->hard_mtu;
int old_rx_urb_size = dev->rx_urb_size;
int ret;
/* no second zero-length packet read wanted after mtu-sized packets */
if ((ll_mtu % dev->maxpacket) == 0)
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);
netdev->mtu = 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;
}
......@@ -2443,26 +2557,186 @@ static void lan78xx_init_ltm(struct lan78xx_net *dev)
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)
{
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
u32 buf;
int ret = 0;
unsigned long timeout;
int ret;
u32 buf;
u8 sig;
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
buf |= HW_CFG_LRST_;
ret = lan78xx_write_reg(dev, HW_CFG, buf);
if (ret < 0)
return ret;
timeout = jiffies + HZ;
do {
mdelay(1);
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
if (time_after(jiffies, timeout)) {
netdev_warn(dev->net,
"timeout on completion of LiteReset");
return -EIO;
ret = -ETIMEDOUT;
return ret;
}
} while (buf & HW_CFG_LRST_);
......@@ -2470,13 +2744,22 @@ static int lan78xx_reset(struct lan78xx_net *dev)
/* save DEVID for later usage */
ret = lan78xx_read_reg(dev, ID_REV, &buf);
if (ret < 0)
return ret;
dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16;
dev->chiprev = buf & ID_REV_CHIP_REV_MASK_;
/* Respond to the IN token with a NAK */
ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG_BIR_;
ret = lan78xx_write_reg(dev, USB_CFG0, buf);
if (ret < 0)
return ret;
/* Init LTM */
lan78xx_init_ltm(dev);
......@@ -2499,53 +2782,105 @@ static int lan78xx_reset(struct lan78xx_net *dev)
}
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);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
return ret;
buf |= HW_CFG_MEF_;
ret = lan78xx_write_reg(dev, HW_CFG, buf);
if (ret < 0)
return ret;
ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
if (ret < 0)
return ret;
buf |= USB_CFG_BCE_;
ret = lan78xx_write_reg(dev, USB_CFG0, buf);
if (ret < 0)
return ret;
/* set FIFO sizes */
buf = (MAX_RX_FIFO_SIZE - 512) / 512;
ret = lan78xx_write_reg(dev, FCT_RX_FIFO_END, buf);
if (ret < 0)
return ret;
buf = (MAX_TX_FIFO_SIZE - 512) / 512;
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_);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, FLOW, 0);
if (ret < 0)
return ret;
ret = lan78xx_write_reg(dev, FCT_FLOW, 0);
if (ret < 0)
return ret;
/* Don't need rfe_ctl_lock during initialisation */
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_;
ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
if (ret < 0)
return ret;
/* 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);
/* reset PHY */
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
buf |= PMT_CTL_PHY_RST_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
return ret;
timeout = jiffies + HZ;
do {
mdelay(1);
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
return ret;
if (time_after(jiffies, timeout)) {
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_));
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
if (ret < 0)
return ret;
/* LAN7801 only has RGMII mode */
if (dev->chipid == ID_REV_CHIP_ID_7801_)
buf &= ~MAC_CR_GMII_EN_;
......@@ -2559,27 +2894,13 @@ static int lan78xx_reset(struct lan78xx_net *dev)
}
}
ret = lan78xx_write_reg(dev, MAC_CR, buf);
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
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);
if (ret < 0)
return ret;
ret = lan78xx_set_rx_max_frame_length(dev,
dev->net->mtu + VLAN_ETH_HLEN);
ret = lan78xx_read_reg(dev, MAC_RX, &buf);
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;
return ret;
}
static void lan78xx_init_stats(struct lan78xx_net *dev)
......@@ -2613,9 +2934,13 @@ static int lan78xx_open(struct net_device *net)
struct lan78xx_net *dev = netdev_priv(net);
int ret;
netif_dbg(dev, ifup, dev->net, "open device");
ret = usb_autopm_get_interface(dev->intf);
if (ret < 0)
goto out;
return ret;
mutex_lock(&dev->dev_mutex);
phy_start(net->phydev);
......@@ -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);
set_bit(EVENT_DEV_OPEN, &dev->flags);
......@@ -2641,9 +2980,10 @@ static int lan78xx_open(struct net_device *net)
lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
done:
mutex_unlock(&dev->dev_mutex);
usb_autopm_put_interface(dev->intf);
out:
return ret;
}
......@@ -2660,53 +3000,74 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev)
temp = unlink_urbs(dev, &dev->txq) + unlink_urbs(dev, &dev->rxq);
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq) &&
!skb_queue_empty(&dev->txq) &&
!skb_queue_empty(&dev->done)) {
while (!skb_queue_empty(&dev->rxq) ||
!skb_queue_empty(&dev->txq)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
"waited for %d urb completions", temp);
}
set_current_state(TASK_RUNNING);
dev->wait = NULL;
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)
{
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))
del_timer_sync(&dev->stat_monitor);
if (net->phydev)
phy_stop(net->phydev);
clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue(net);
tasklet_kill(&dev->bh);
lan78xx_terminate_urbs(dev);
netif_info(dev, ifdown, dev->net,
"stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
net->stats.rx_packets, net->stats.tx_packets,
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.
* can't flush_scheduled_work() until we drop rtnl (later),
* 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);
tasklet_kill(&dev->bh);
usb_autopm_put_interface(dev->intf);
mutex_unlock(&dev->dev_mutex);
return 0;
}
......@@ -2795,16 +3156,23 @@ static void tx_complete(struct urb *urb)
/* software-driven interface shutdown */
case -ECONNRESET:
case -ESHUTDOWN:
netif_dbg(dev, tx_err, dev->net,
"tx err interface gone %d\n",
entry->urb->status);
break;
case -EPROTO:
case -ETIME:
case -EILSEQ:
netif_stop_queue(dev->net);
netif_dbg(dev, tx_err, dev->net,
"tx err queue stopped %d\n",
entry->urb->status);
break;
default:
netif_dbg(dev, tx_err, dev->net,
"tx err %d\n", entry->urb->status);
"unknown tx err %d\n",
entry->urb->status);
break;
}
}
......@@ -2829,6 +3197,9 @@ lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net)
struct lan78xx_net *dev = netdev_priv(net);
struct sk_buff *skb2 = NULL;
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags))
schedule_delayed_work(&dev->wq, 0);
if (skb) {
skb_tx_timestamp(skb);
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)
{
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_bytes += skb->len;
......@@ -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);
break;
case -ENODEV:
case -ENOENT:
netif_dbg(dev, ifdown, dev->net, "device gone\n");
netif_device_detach(dev->net);
break;
......@@ -3340,6 +3707,12 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
lan78xx_defer_kevent(dev, EVENT_TX_HALT);
usb_autopm_put_interface_async(dev->intf);
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:
usb_autopm_put_interface_async(dev->intf);
netif_dbg(dev, tx_err, dev->net,
......@@ -3356,9 +3729,10 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
if (skb)
dev_kfree_skb_any(skb);
usb_free_urb(urb);
} else
} else {
netif_dbg(dev, tx_queued, dev->net,
"> tx, len %d, type 0x%x\n", length, skb->protocol);
}
}
static void lan78xx_rx_bh(struct lan78xx_net *dev)
......@@ -3421,8 +3795,7 @@ static void lan78xx_bh(struct tasklet_struct *t)
if (!skb_queue_empty(&dev->txq_pend))
lan78xx_tx_bh(dev);
if (!timer_pending(&dev->delay) &&
!test_bit(EVENT_RX_HALT, &dev->flags))
if (!test_bit(EVENT_RX_HALT, &dev->flags))
lan78xx_rx_bh(dev);
}
}
......@@ -3434,18 +3807,20 @@ static void lan78xx_delayedwork(struct work_struct *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)) {
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);
usb_autopm_put_interface(dev->intf);
if (status < 0 &&
status != -EPIPE &&
status != -ESHUTDOWN) {
if (netif_msg_tx_err(dev))
fail_pipe:
netdev_err(dev->net,
"can't clear tx halt, status %d\n",
status);
......@@ -3455,18 +3830,14 @@ static void lan78xx_delayedwork(struct work_struct *work)
netif_wake_queue(dev->net);
}
}
if (test_bit(EVENT_RX_HALT, &dev->flags)) {
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);
usb_autopm_put_interface(dev->intf);
if (status < 0 &&
status != -EPIPE &&
status != -ESHUTDOWN) {
if (netif_msg_rx_err(dev))
fail_halt:
netdev_err(dev->net,
"can't clear rx halt, status %d\n",
status);
......@@ -3480,16 +3851,9 @@ static void lan78xx_delayedwork(struct work_struct *work)
int ret = 0;
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) {
usb_autopm_put_interface(dev->intf);
skip_reset:
netdev_info(dev->net, "link reset failed (%d)\n",
ret);
} else {
usb_autopm_put_interface(dev->intf);
}
}
......@@ -3503,6 +3867,8 @@ static void lan78xx_delayedwork(struct work_struct *work)
dev->delta = min((dev->delta * 2), 50);
}
usb_autopm_put_interface(dev->intf);
}
static void intr_complete(struct urb *urb)
......@@ -3518,6 +3884,7 @@ static void intr_complete(struct urb *urb)
/* software-driven interface shutdown */
case -ENOENT: /* urb killed */
case -ENODEV: /* hardware gone */
case -ESHUTDOWN: /* hardware gone */
netif_dbg(dev, ifdown, dev->net,
"intr shutdown, code %d\n", status);
......@@ -3531,14 +3898,29 @@ static void intr_complete(struct urb *urb)
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;
}
memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
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,
"intr resubmit --> %d\n", status);
break;
}
}
static void lan78xx_disconnect(struct usb_interface *intf)
......@@ -3553,8 +3935,15 @@ static void lan78xx_disconnect(struct usb_interface *intf)
if (!dev)
return;
set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
udev = interface_to_usbdev(intf);
net = dev->net;
unregister_netdev(net);
cancel_delayed_work_sync(&dev->wq);
phydev = net->phydev;
phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
......@@ -3565,12 +3954,11 @@ static void lan78xx_disconnect(struct usb_interface *intf)
if (phy_is_pseudo_fixed_link(phydev))
fixed_phy_unregister(phydev);
unregister_netdev(net);
cancel_delayed_work_sync(&dev->wq);
usb_scuttle_anchored_urbs(&dev->deferred);
if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor);
lan78xx_unbind(dev, intf);
usb_kill_urb(dev->urb_intr);
......@@ -3632,8 +4020,8 @@ static int lan78xx_probe(struct usb_interface *intf,
struct net_device *netdev;
struct usb_device *udev;
int ret;
unsigned maxp;
unsigned period;
unsigned int maxp;
unsigned int period;
u8 *buf = NULL;
udev = interface_to_usbdev(intf);
......@@ -3659,9 +4047,9 @@ static int lan78xx_probe(struct usb_interface *intf,
skb_queue_head_init(&dev->rxq);
skb_queue_head_init(&dev->txq);
skb_queue_head_init(&dev->done);
skb_queue_head_init(&dev->rxq_pause);
skb_queue_head_init(&dev->txq_pend);
mutex_init(&dev->phy_mutex);
mutex_init(&dev->dev_mutex);
tasklet_setup(&dev->bh, lan78xx_bh);
INIT_DELAYED_WORK(&dev->wq, lan78xx_delayedwork);
......@@ -3798,37 +4186,119 @@ static u16 lan78xx_wakeframe_crc16(const u8 *buf, int len)
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;
int mask_index;
u16 crc;
u32 temp_wucsr;
u32 temp_pmt_ctl;
int ret;
ret = lan78xx_stop_tx_path(dev);
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 ipv6_multicast[3] = { 0x33, 0x33 };
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);
buf &= ~MAC_TX_TXEN_;
lan78xx_write_reg(dev, MAC_TX, buf);
lan78xx_read_reg(dev, MAC_RX, &buf);
buf &= ~MAC_RX_RXEN_;
lan78xx_write_reg(dev, MAC_RX, buf);
ret = lan78xx_stop_tx_path(dev);
if (ret < 0)
return ret;
ret = lan78xx_stop_rx_path(dev);
if (ret < 0)
return ret;
lan78xx_write_reg(dev, WUCSR, 0);
lan78xx_write_reg(dev, WUCSR2, 0);
lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
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;
temp_wucsr = 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_STS_;
for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++)
lan78xx_write_reg(dev, WUF_CFG(mask_index), 0);
for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++) {
ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), 0);
if (ret < 0)
return ret;
}
mask_index = 0;
if (wol & WAKE_PHY) {
......@@ -3857,30 +4327,52 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
/* set WUF_CFG & WUF_MASK for IPv4 Multicast */
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_TYPE_MCAST_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) |
(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++;
/* for IPv6 Multicast */
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_TYPE_MCAST_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) |
(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++;
temp_pmt_ctl |= PMT_CTL_WOL_EN_;
......@@ -3901,16 +4393,27 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
* for packettype (offset 12,13) = ARP (0x0806)
*/
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_TYPE_ALL_ |
(0 << WUF_CFGX_OFFSET_SHIFT_) |
(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++;
temp_pmt_ctl |= PMT_CTL_WOL_EN_;
......@@ -3918,7 +4421,9 @@ static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
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 */
if (hweight_long((unsigned long)wol) > 1) {
......@@ -3926,33 +4431,45 @@ 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_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 */
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_;
lan78xx_write_reg(dev, PMT_CTL, buf);
lan78xx_read_reg(dev, MAC_RX, &buf);
buf |= MAC_RX_RXEN_;
lan78xx_write_reg(dev, MAC_RX, buf);
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
return ret;
return 0;
ret = lan78xx_start_rx_path(dev);
return ret;
}
static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message)
{
struct lan78xx_net *dev = usb_get_intfdata(intf);
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
u32 buf;
bool dev_open;
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);
/* don't autosuspend while transmitting */
if ((skb_queue_len(&dev->txq) ||
skb_queue_len(&dev->txq_pend)) &&
PMSG_IS_AUTO(message)) {
PMSG_IS_AUTO(message)) {
spin_unlock_irq(&dev->txq.lock);
ret = -EBUSY;
goto out;
......@@ -3961,129 +4478,207 @@ static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message)
spin_unlock_irq(&dev->txq.lock);
}
/* stop TX & RX */
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
buf &= ~MAC_TX_TXEN_;
ret = lan78xx_write_reg(dev, MAC_TX, buf);
ret = lan78xx_read_reg(dev, MAC_RX, &buf);
buf &= ~MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
/* stop RX */
ret = lan78xx_stop_rx_path(dev);
if (ret < 0)
goto out;
/* empty out the rx and queues */
ret = lan78xx_flush_rx_fifo(dev);
if (ret < 0)
goto out;
/* stop Tx */
ret = lan78xx_stop_tx_path(dev);
if (ret < 0)
goto out;
/* empty out the Rx and Tx queues */
netif_device_detach(dev->net);
lan78xx_terminate_urbs(dev);
usb_kill_urb(dev->urb_intr);
/* reattach */
netif_device_attach(dev->net);
}
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) {
del_timer(&dev->stat_monitor);
if (PMSG_IS_AUTO(message)) {
/* auto suspend (selective suspend) */
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
buf &= ~MAC_TX_TXEN_;
ret = lan78xx_write_reg(dev, MAC_TX, buf);
ret = lan78xx_read_reg(dev, MAC_RX, &buf);
buf &= ~MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
ret = lan78xx_set_auto_suspend(dev);
if (ret < 0)
goto out;
} else {
struct lan78xx_priv *pdata;
pdata = (struct lan78xx_priv *)(dev->data[0]);
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;
ret = lan78xx_write_reg(dev, WUCSR, 0);
ret = lan78xx_write_reg(dev, WUCSR2, 0);
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
set_bit(EVENT_DEV_ASLEEP, &dev->flags);
/* set goodframe wakeup */
ret = lan78xx_read_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);
if (ret < 0)
goto out;
buf &= ~PMT_CTL_RES_CLR_WKP_EN_;
buf |= PMT_CTL_RES_CLR_WKP_STS_;
buf &= ~PMT_CTL_SUS_MODE_MASK_;
buf |= PMT_CTL_SUS_MODE_3_;
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
goto out;
buf |= WUCSR_RFE_WAKE_EN_;
buf |= WUCSR_STORE_WAKE_;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR, buf);
buf |= PMT_CTL_WUPS_MASK_;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
if (ret < 0)
goto out;
}
buf &= ~PMT_CTL_RES_CLR_WKP_EN_;
buf |= PMT_CTL_RES_CLR_WKP_STS_;
ret = 0;
out:
mutex_unlock(&dev->dev_mutex);
buf |= PMT_CTL_PHY_WAKE_EN_;
buf |= PMT_CTL_WOL_EN_;
buf &= ~PMT_CTL_SUS_MODE_MASK_;
buf |= PMT_CTL_SUS_MODE_3_;
return ret;
}
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
static bool lan78xx_submit_deferred_urbs(struct lan78xx_net *dev)
{
bool pipe_halted = false;
struct urb *urb;
ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
while ((urb = usb_get_from_anchor(&dev->deferred))) {
struct sk_buff *skb = urb->context;
int ret;
buf |= PMT_CTL_WUPS_MASK_;
if (!netif_device_present(dev->net) ||
!netif_carrier_ok(dev->net) ||
pipe_halted) {
usb_free_urb(urb);
dev_kfree_skb(skb);
continue;
}
ret = lan78xx_write_reg(dev, PMT_CTL, buf);
ret = usb_submit_urb(urb, GFP_ATOMIC);
ret = lan78xx_read_reg(dev, MAC_RX, &buf);
buf |= MAC_RX_RXEN_;
ret = lan78xx_write_reg(dev, MAC_RX, buf);
if (ret == 0) {
netif_trans_update(dev->net);
lan78xx_queue_skb(&dev->txq, skb, tx_start);
} else {
lan78xx_set_suspend(dev, pdata->wol);
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);
}
}
}
ret = 0;
out:
return ret;
return pipe_halted;
}
static int lan78xx_resume(struct usb_interface *intf)
{
struct lan78xx_net *dev = usb_get_intfdata(intf);
struct sk_buff *skb;
struct urb *res;
bool dev_open;
int ret;
u32 buf;
if (!timer_pending(&dev->stat_monitor)) {
dev->delta = 1;
mod_timer(&dev->stat_monitor,
jiffies + STAT_UPDATE_TIMER);
}
mutex_lock(&dev->dev_mutex);
if (!--dev->suspend_count) {
/* resume interrupt URBs */
if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags))
usb_submit_urb(dev->urb_intr, GFP_NOIO);
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);
spin_lock_irq(&dev->txq.lock);
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);
lan78xx_queue_skb(&dev->txq, skb, tx_start);
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);
spin_unlock_irq(&dev->txq.lock);
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
if (!(skb_queue_len(&dev->txq) >= dev->tx_qlen))
netif_start_queue(dev->net);
tasklet_schedule(&dev->bh);
if (!pipe_halted &&
netif_device_present(dev->net) &&
(skb_queue_len(&dev->txq) < dev->tx_qlen))
netif_start_queue(dev->net);
ret = lan78xx_start_tx_path(dev);
if (ret < 0)
goto out;
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);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR, 0);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR2, WUCSR2_NS_RCD_ |
WUCSR2_ARP_RCD_ |
WUCSR2_IPV6_TCPSYN_RCD_ |
WUCSR2_IPV4_TCPSYN_RCD_);
if (ret < 0)
goto out;
ret = lan78xx_write_reg(dev, WUCSR, WUCSR_EEE_TX_WAKE_ |
WUCSR_EEE_RX_WAKE_ |
......@@ -4092,23 +4687,32 @@ static int lan78xx_resume(struct usb_interface *intf)
WUCSR_WUFR_ |
WUCSR_MPR_ |
WUCSR_BCST_FR_);
if (ret < 0)
goto out;
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
buf |= MAC_TX_TXEN_;
ret = lan78xx_write_reg(dev, MAC_TX, buf);
ret = 0;
out:
mutex_unlock(&dev->dev_mutex);
return 0;
return ret;
}
static int lan78xx_reset_resume(struct usb_interface *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);
return lan78xx_resume(intf);
ret = lan78xx_resume(intf);
return ret;
}
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