* [PATCH 1/6] smsc95xx: sleep before read for lengthy operations
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
During init, the device reset is unexpected to complete immediately,
so sleep before testing the condition rather than after it.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d45e539..ed1e551 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -763,12 +763,12 @@ static int smsc95xx_reset(struct usbnet *dev)
timeout = 0;
do {
+ msleep(10);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
- msleep(10);
timeout++;
} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
@@ -786,12 +786,12 @@ static int smsc95xx_reset(struct usbnet *dev)
timeout = 0;
do {
+ msleep(10);
ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
if (ret < 0) {
netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
return ret;
}
- msleep(10);
timeout++;
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/6] smsc95xx: remove unnecessary variables
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
Removes unnecessary variables as smsc95xx_write_reg takes its
value by parameter. Early versions passed this parameter by
reference.
Also replace hardcoded interrupt status value with a #define
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 29 +++++++++--------------------
drivers/net/usb/smsc95xx.h | 1 +
2 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index ed1e551..5d0256b 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -460,12 +460,10 @@ static int smsc95xx_link_reset(struct usbnet *dev)
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
unsigned long flags;
u16 lcladv, rmtadv;
- u32 intdata;
/* clear interrupt status */
smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
- intdata = 0xFFFFFFFF;
- smsc95xx_write_reg(dev, INT_STS, intdata);
+ smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
mii_check_media(mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -677,7 +675,6 @@ static void smsc95xx_start_tx_path(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
unsigned long flags;
- u32 reg_val;
/* Enable Tx at MAC */
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
@@ -687,8 +684,7 @@ static void smsc95xx_start_tx_path(struct usbnet *dev)
smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
/* Enable Tx at SCSRs */
- reg_val = TX_CFG_ON_;
- smsc95xx_write_reg(dev, TX_CFG, reg_val);
+ smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
}
/* Starts the Receive path */
@@ -753,8 +749,7 @@ static int smsc95xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
- write_buf = HW_CFG_LRST_;
- ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+ ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d\n",
ret);
@@ -777,8 +772,7 @@ static int smsc95xx_reset(struct usbnet *dev)
return ret;
}
- write_buf = PM_CTL_PHY_RST_;
- ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+ ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
return ret;
@@ -863,8 +857,7 @@ static int smsc95xx_reset(struct usbnet *dev)
"Read Value from BURST_CAP after writing: 0x%08x\n",
read_buf);
- read_buf = DEFAULT_BULK_IN_DELAY;
- ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+ ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
if (ret < 0) {
netdev_warn(dev->net, "ret = %d\n", ret);
return ret;
@@ -910,8 +903,7 @@ static int smsc95xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
- write_buf = 0xFFFFFFFF;
- ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+ ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write INT_STS register, ret=%d\n",
ret);
@@ -936,15 +928,13 @@ static int smsc95xx_reset(struct usbnet *dev)
}
/* Init Tx */
- write_buf = 0;
- ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+ ret = smsc95xx_write_reg(dev, FLOW, 0);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
return ret;
}
- read_buf = AFC_CFG_DEFAULT;
- ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+ ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
return ret;
@@ -959,8 +949,7 @@ static int smsc95xx_reset(struct usbnet *dev)
/* Init Rx */
/* Set Vlan */
- write_buf = (u32)ETH_P_8021Q;
- ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+ ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
if (ret < 0) {
netdev_warn(dev->net, "Failed to write VAN1: %d\n", ret);
return ret;
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
index 86bc449..a275b62 100644
--- a/drivers/net/usb/smsc95xx.h
+++ b/drivers/net/usb/smsc95xx.h
@@ -63,6 +63,7 @@
#define INT_STS_TDFO_ (0x00001000)
#define INT_STS_RXDF_ (0x00000800)
#define INT_STS_GPIOS_ (0x000007FF)
+#define INT_STS_CLEAR_ALL_ (0xFFFFFFFF)
#define RX_CFG (0x0C)
#define RX_FIFO_FLUSH_ (0x00000001)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/6] smsc95xx: check return code from control messages
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
This patch adds additional checks of the values returned by
smsc95xx_(read|write)_reg, and wraps their common patterns
in macros.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 331 ++++++++++++++++++++------------------------
1 file changed, 148 insertions(+), 183 deletions(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 5d0256b..d0ff01e 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -47,6 +47,15 @@
#define SMSC95XX_TX_OVERHEAD (8)
#define SMSC95XX_TX_OVERHEAD_CSUM (12)
+#define check_warn(ret, fmt, args...) \
+ ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
+
+#define check_warn_return(ret, fmt, args...) \
+ ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } })
+
+#define check_warn_goto_done(ret, fmt, args...) \
+ ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } })
+
struct smsc95xx_priv {
u32 mac_cr;
u32 hash_hi;
@@ -63,7 +72,8 @@ static bool turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
+static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data)
{
u32 *buf = kmalloc(4, GFP_KERNEL);
int ret;
@@ -88,7 +98,8 @@ static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
return ret;
}
-static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
+static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
+ u32 data)
{
u32 *buf = kmalloc(4, GFP_KERNEL);
int ret;
@@ -116,13 +127,15 @@ static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
/* Loop until the read is completed with timeout
* called with phy_mutex held */
-static int smsc95xx_phy_wait_not_busy(struct usbnet *dev)
+static int __must_check smsc95xx_phy_wait_not_busy(struct usbnet *dev)
{
unsigned long start_time = jiffies;
u32 val;
+ int ret;
do {
- smsc95xx_read_reg(dev, MII_ADDR, &val);
+ ret = smsc95xx_read_reg(dev, MII_ADDR, &val);
+ check_warn_return(ret, "Error reading MII_ACCESS");
if (!(val & MII_BUSY_))
return 0;
} while (!time_after(jiffies, start_time + HZ));
@@ -134,33 +147,32 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
{
struct usbnet *dev = netdev_priv(netdev);
u32 val, addr;
+ int ret;
mutex_lock(&dev->phy_mutex);
/* confirm MII not busy */
- if (smsc95xx_phy_wait_not_busy(dev)) {
- netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n");
- mutex_unlock(&dev->phy_mutex);
- return -EIO;
- }
+ ret = smsc95xx_phy_wait_not_busy(dev);
+ check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_read");
/* set the address, index & direction (read from PHY) */
phy_id &= dev->mii.phy_id_mask;
idx &= dev->mii.reg_num_mask;
addr = (phy_id << 11) | (idx << 6) | MII_READ_;
- smsc95xx_write_reg(dev, MII_ADDR, addr);
+ ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
+ check_warn_goto_done(ret, "Error writing MII_ADDR");
- if (smsc95xx_phy_wait_not_busy(dev)) {
- netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
- mutex_unlock(&dev->phy_mutex);
- return -EIO;
- }
+ ret = smsc95xx_phy_wait_not_busy(dev);
+ check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx);
- smsc95xx_read_reg(dev, MII_DATA, &val);
+ ret = smsc95xx_read_reg(dev, MII_DATA, &val);
+ check_warn_goto_done(ret, "Error reading MII_DATA");
- mutex_unlock(&dev->phy_mutex);
+ ret = (u16)(val & 0xFFFF);
- return (u16)(val & 0xFFFF);
+done:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
}
static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
@@ -168,38 +180,41 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
{
struct usbnet *dev = netdev_priv(netdev);
u32 val, addr;
+ int ret;
mutex_lock(&dev->phy_mutex);
/* confirm MII not busy */
- if (smsc95xx_phy_wait_not_busy(dev)) {
- netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n");
- mutex_unlock(&dev->phy_mutex);
- return;
- }
+ ret = smsc95xx_phy_wait_not_busy(dev);
+ check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_write");
val = regval;
- smsc95xx_write_reg(dev, MII_DATA, val);
+ ret = smsc95xx_write_reg(dev, MII_DATA, val);
+ check_warn_goto_done(ret, "Error writing MII_DATA");
/* set the address, index & direction (write to PHY) */
phy_id &= dev->mii.phy_id_mask;
idx &= dev->mii.reg_num_mask;
addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
- smsc95xx_write_reg(dev, MII_ADDR, addr);
+ ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
+ check_warn_goto_done(ret, "Error writing MII_ADDR");
- if (smsc95xx_phy_wait_not_busy(dev))
- netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
+ ret = smsc95xx_phy_wait_not_busy(dev);
+ check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx);
+done:
mutex_unlock(&dev->phy_mutex);
}
-static int smsc95xx_wait_eeprom(struct usbnet *dev)
+static int __must_check smsc95xx_wait_eeprom(struct usbnet *dev)
{
unsigned long start_time = jiffies;
u32 val;
+ int ret;
do {
- smsc95xx_read_reg(dev, E2P_CMD, &val);
+ ret = smsc95xx_read_reg(dev, E2P_CMD, &val);
+ check_warn_return(ret, "Error reading E2P_CMD");
if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
break;
udelay(40);
@@ -213,13 +228,15 @@ static int smsc95xx_wait_eeprom(struct usbnet *dev)
return 0;
}
-static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
+static int __must_check smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
{
unsigned long start_time = jiffies;
u32 val;
+ int ret;
do {
- smsc95xx_read_reg(dev, E2P_CMD, &val);
+ ret = smsc95xx_read_reg(dev, E2P_CMD, &val);
+ check_warn_return(ret, "Error reading E2P_CMD");
if (!(val & E2P_CMD_BUSY_))
return 0;
@@ -246,13 +263,15 @@ static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
for (i = 0; i < length; i++) {
val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
- smsc95xx_write_reg(dev, E2P_CMD, val);
+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
+ check_warn_return(ret, "Error writing E2P_CMD");
ret = smsc95xx_wait_eeprom(dev);
if (ret < 0)
return ret;
- smsc95xx_read_reg(dev, E2P_DATA, &val);
+ ret = smsc95xx_read_reg(dev, E2P_DATA, &val);
+ check_warn_return(ret, "Error reading E2P_DATA");
data[i] = val & 0xFF;
offset++;
@@ -276,7 +295,8 @@ static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
/* Issue write/erase enable command */
val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_;
- smsc95xx_write_reg(dev, E2P_CMD, val);
+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
+ check_warn_return(ret, "Error writing E2P_DATA");
ret = smsc95xx_wait_eeprom(dev);
if (ret < 0)
@@ -286,11 +306,13 @@ static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
/* Fill data register */
val = data[i];
- smsc95xx_write_reg(dev, E2P_DATA, val);
+ ret = smsc95xx_write_reg(dev, E2P_DATA, val);
+ check_warn_return(ret, "Error writing E2P_DATA");
/* Send "write" command */
val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_);
- smsc95xx_write_reg(dev, E2P_CMD, val);
+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
+ check_warn_return(ret, "Error writing E2P_CMD");
ret = smsc95xx_wait_eeprom(dev);
if (ret < 0)
@@ -308,14 +330,14 @@ static void smsc95xx_async_cmd_callback(struct urb *urb)
struct usbnet *dev = usb_context->dev;
int status = urb->status;
- if (status < 0)
- netdev_warn(dev->net, "async callback failed with %d\n", status);
+ check_warn(status, "async callback failed with %d\n", status);
kfree(usb_context);
usb_free_urb(urb);
}
-static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data)
+static int __must_check smsc95xx_write_reg_async(struct usbnet *dev, u16 index,
+ u32 *data)
{
struct usb_context *usb_context;
int status;
@@ -371,6 +393,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
struct usbnet *dev = netdev_priv(netdev);
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
unsigned long flags;
+ int ret;
pdata->hash_hi = 0;
pdata->hash_lo = 0;
@@ -411,21 +434,23 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
/* Initiate async writes, as we can't wait for completion here */
- smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi);
- smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo);
- smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
+ ret = smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi);
+ check_warn(ret, "failed to initiate async write to HASHH");
+
+ ret = smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo);
+ check_warn(ret, "failed to initiate async write to HASHL");
+
+ ret = smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
+ check_warn(ret, "failed to initiate async write to MAC_CR");
}
-static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
- u16 lcladv, u16 rmtadv)
+static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
+ u16 lcladv, u16 rmtadv)
{
u32 flow, afc_cfg = 0;
int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
- if (ret < 0) {
- netdev_warn(dev->net, "error reading AFC_CFG\n");
- return;
- }
+ check_warn_return(ret, "Error reading AFC_CFG");
if (duplex == DUPLEX_FULL) {
u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -449,8 +474,13 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
afc_cfg |= 0xF;
}
- smsc95xx_write_reg(dev, FLOW, flow);
- smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
+ ret = smsc95xx_write_reg(dev, FLOW, flow);
+ check_warn_return(ret, "Error writing FLOW");
+
+ ret = smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
+ check_warn_return(ret, "Error writing AFC_CFG");
+
+ return 0;
}
static int smsc95xx_link_reset(struct usbnet *dev)
@@ -460,10 +490,14 @@ static int smsc95xx_link_reset(struct usbnet *dev)
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
unsigned long flags;
u16 lcladv, rmtadv;
+ int ret;
/* clear interrupt status */
- smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
- smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
+ ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
+ check_warn_return(ret, "Error reading PHY_INT_SRC");
+
+ ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
+ check_warn_return(ret, "Error writing INT_STS");
mii_check_media(mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -484,9 +518,11 @@ static int smsc95xx_link_reset(struct usbnet *dev)
}
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
- smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ check_warn_return(ret, "Error writing MAC_CR");
- smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
+ ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
+ check_warn_return(ret, "Error updating PHY flow control");
return 0;
}
@@ -522,10 +558,7 @@ static int smsc95xx_set_features(struct net_device *netdev,
int ret;
ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read COE_CR: %d\n", ret);
if (features & NETIF_F_HW_CSUM)
read_buf |= Tx_COE_EN_;
@@ -538,10 +571,7 @@ static int smsc95xx_set_features(struct net_device *netdev,
read_buf &= ~Rx_COE_EN_;
ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write COE_CR: %d\n", ret);
netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
return 0;
@@ -656,53 +686,56 @@ static int smsc95xx_set_mac_address(struct usbnet *dev)
int ret;
ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write ADDRL: %d\n", ret);
ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write ADDRH: %d\n", ret);
return 0;
}
/* starts the TX path */
-static void smsc95xx_start_tx_path(struct usbnet *dev)
+static int smsc95xx_start_tx_path(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
unsigned long flags;
+ int ret;
/* Enable Tx at MAC */
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
pdata->mac_cr |= MAC_CR_TXEN_;
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
- smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ check_warn_return(ret, "Failed to write MAC_CR: %d\n", ret);
/* Enable Tx at SCSRs */
- smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
+ ret = smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
+ check_warn_return(ret, "Failed to write TX_CFG: %d\n", ret);
+
+ return 0;
}
/* Starts the Receive path */
-static void smsc95xx_start_rx_path(struct usbnet *dev)
+static int smsc95xx_start_rx_path(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
unsigned long flags;
+ int ret;
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
pdata->mac_cr |= MAC_CR_RXEN_;
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
- smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+ check_warn_return(ret, "Failed to write MAC_CR: %d\n", ret);
+
+ return 0;
}
static int smsc95xx_phy_initialize(struct usbnet *dev)
{
- int bmcr, timeout = 0;
+ int bmcr, ret, timeout = 0;
/* Initialize MII structure */
dev->mii.dev = dev->net;
@@ -731,7 +764,8 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
ADVERTISE_PAUSE_ASYM);
/* read to clear */
- smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
+ ret = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
+ check_warn_return(ret, "Failed to read PHY_INT_SRC during init");
smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
PHY_INT_MASK_DEFAULT_);
@@ -750,20 +784,13 @@ static int smsc95xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d\n",
- ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write HW_CFG_LRST_ bit in HW_CFG\n");
timeout = 0;
do {
msleep(10);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
timeout++;
} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
@@ -773,19 +800,13 @@ static int smsc95xx_reset(struct usbnet *dev)
}
ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write PM_CTRL: %d\n", ret);
timeout = 0;
do {
msleep(10);
ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read PM_CTRL: %d\n", ret);
timeout++;
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
@@ -802,10 +823,7 @@ static int smsc95xx_reset(struct usbnet *dev)
"MAC Address: %pM\n", dev->net->dev_addr);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG : 0x%08x\n", read_buf);
@@ -813,17 +831,10 @@ static int smsc95xx_reset(struct usbnet *dev)
read_buf |= HW_CFG_BIR_;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d\n",
- ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write HW_CFG_BIR_ bit in HW_CFG\n");
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
read_buf);
@@ -843,40 +854,28 @@ static int smsc95xx_reset(struct usbnet *dev)
"rx_urb_size=%ld\n", (ulong)dev->rx_urb_size);
ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write BURST_CAP: %d\n", ret);
ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read BURST_CAP: %d\n", ret);
+
netif_dbg(dev, ifup, dev->net,
"Read Value from BURST_CAP after writing: 0x%08x\n",
read_buf);
ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
- if (ret < 0) {
- netdev_warn(dev->net, "ret = %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write BULK_IN_DLY: %d\n", ret);
ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read BULK_IN_DLY: %d\n", ret);
+
netif_dbg(dev, ifup, dev->net,
"Read Value from BULK_IN_DLY after writing: 0x%08x\n",
read_buf);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG: 0x%08x\n", read_buf);
@@ -889,97 +888,66 @@ static int smsc95xx_reset(struct usbnet *dev)
read_buf |= NET_IP_ALIGN << 9;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG register, ret=%d\n",
- ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write HW_CFG: %d\n", ret);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write INT_STS register, ret=%d\n",
- ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write INT_STS: %d\n", ret);
ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read ID_REV: %d\n", ret);
netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write LED_GPIO_CFG register, ret=%d\n",
- ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d\n", ret);
/* Init Tx */
ret = smsc95xx_write_reg(dev, FLOW, 0);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write FLOW: %d\n", ret);
ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write AFC_CFG: %d\n", ret);
/* Don't need mac_cr_lock during initialisation */
ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read MAC_CR: %d\n", ret);
/* Init Rx */
/* Set Vlan */
ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write VAN1: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write VLAN1: %d\n", ret);
/* Enable or disable checksum offload engines */
- smsc95xx_set_features(dev->net, dev->net->features);
+ ret = smsc95xx_set_features(dev->net, dev->net->features);
+ check_warn_return(ret, "Failed to set checksum offload features");
smsc95xx_set_multicast(dev->net);
- if (smsc95xx_phy_initialize(dev) < 0)
- return -EIO;
+ ret = smsc95xx_phy_initialize(dev);
+ check_warn_return(ret, "Failed to init PHY");
ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to read INT_EP_CTL: %d\n", ret);
/* enable PHY interrupts */
read_buf |= INT_EP_CTL_PHY_INT_;
ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "Failed to write INT_EP_CTL: %d\n", ret);
- smsc95xx_start_tx_path(dev);
- smsc95xx_start_rx_path(dev);
+ ret = smsc95xx_start_tx_path(dev);
+ check_warn_return(ret, "Failed to start TX path");
+
+ ret = smsc95xx_start_rx_path(dev);
+ check_warn_return(ret, "Failed to start RX path");
netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n");
return 0;
@@ -1006,10 +974,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
ret = usbnet_get_endpoints(dev, intf);
- if (ret < 0) {
- netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
- return ret;
- }
+ check_warn_return(ret, "usbnet_get_endpoints failed: %d\n", ret);
dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
GFP_KERNEL);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 5/6] smsc95xx: enable power saving mode during system suspend
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
This patch enables the device to enter its lowest power SUSPEND2
state during system suspend, instead of staying up using full power.
Patch updated to not add two pointers to .suspend & .resume.
Patch updated to replace BUG_ON with WARN_ON_ONCE and return.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 28 +++++++++++++++++++++++++++-
drivers/net/usb/smsc95xx.h | 6 +++++-
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index f29860d..ba0360f 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1018,6 +1018,32 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
}
}
+static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ int ret;
+ u32 val;
+
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ ret = usbnet_suspend(intf, message);
+ check_warn_return(ret, "usbnet_suspend error");
+
+ netdev_info(dev->net, "entering SUSPEND2 mode");
+
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
+ val |= PM_CTL_SUS_MODE_2;
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+
+ return 0;
+}
+
static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
{
skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2);
@@ -1280,7 +1306,7 @@ static struct usb_driver smsc95xx_driver = {
.name = "smsc95xx",
.id_table = products,
.probe = usbnet_probe,
- .suspend = usbnet_suspend,
+ .suspend = smsc95xx_suspend,
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.disconnect = usbnet_disconnect,
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
index a275b62..89ad925 100644
--- a/drivers/net/usb/smsc95xx.h
+++ b/drivers/net/usb/smsc95xx.h
@@ -84,12 +84,16 @@
#define HW_CFG_BCE_ (0x00000002)
#define HW_CFG_SRST_ (0x00000001)
+#define RX_FIFO_INF (0x18)
+
#define PM_CTRL (0x20)
+#define PM_CTL_RES_CLR_WKP_STS (0x00000200)
#define PM_CTL_DEV_RDY_ (0x00000080)
#define PM_CTL_SUS_MODE_ (0x00000060)
#define PM_CTL_SUS_MODE_0 (0x00000000)
#define PM_CTL_SUS_MODE_1 (0x00000020)
-#define PM_CTL_SUS_MODE_2 (0x00000060)
+#define PM_CTL_SUS_MODE_2 (0x00000040)
+#define PM_CTL_SUS_MODE_3 (0x00000060)
#define PM_CTL_PHY_RST_ (0x00000010)
#define PM_CTL_WOL_EN_ (0x00000008)
#define PM_CTL_ED_EN_ (0x00000004)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/6] smsc95xx: fix resume when usb device is reset
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
This patch fixes an issue on some systems, where after suspend the
link is re-established but the ethernet interface does not resume.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d0ff01e..f29860d 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1282,6 +1282,7 @@ static struct usb_driver smsc95xx_driver = {
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .reset_resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 6/6] smsc95xx: add wol magic packet support
From: Steve Glendinning @ 2012-09-28 10:07 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348826832-1986-1-git-send-email-steve.glendinning@shawell.net>
This patch enables wake from system suspend on magic packet.
Patch updated to replace BUG_ON with WARN_ON_ONCE and return.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc95xx.c | 185 ++++++++++++++++++++++++++++++++++++++++++--
drivers/net/usb/smsc95xx.h | 5 ++
2 files changed, 182 insertions(+), 8 deletions(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index ba0360f..7479a57 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -46,6 +46,7 @@
#define SMSC95XX_INTERNAL_PHY_ID (1)
#define SMSC95XX_TX_OVERHEAD (8)
#define SMSC95XX_TX_OVERHEAD_CSUM (12)
+#define SUPPORTED_WAKE (WAKE_MAGIC)
#define check_warn(ret, fmt, args...) \
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@ -60,6 +61,7 @@ struct smsc95xx_priv {
u32 mac_cr;
u32 hash_hi;
u32 hash_lo;
+ u32 wolopts;
spinlock_t mac_cr_lock;
};
@@ -125,6 +127,30 @@ static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
return ret;
}
+static int smsc95xx_set_feature(struct usbnet *dev, u32 feature)
+{
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ cpu_to_le32s(&feature);
+
+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
+static int smsc95xx_clear_feature(struct usbnet *dev, u32 feature)
+{
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ cpu_to_le32s(&feature);
+
+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
/* Loop until the read is completed with timeout
* called with phy_mutex held */
static int __must_check smsc95xx_phy_wait_not_busy(struct usbnet *dev)
@@ -636,6 +662,26 @@ smsc95xx_ethtool_getregs(struct net_device *netdev, struct ethtool_regs *regs,
}
}
+static void smsc95xx_ethtool_get_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+ wolinfo->supported = SUPPORTED_WAKE;
+ wolinfo->wolopts = pdata->wolopts;
+}
+
+static int smsc95xx_ethtool_set_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+ pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
+ return 0;
+}
+
static const struct ethtool_ops smsc95xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -649,6 +695,8 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = {
.set_eeprom = smsc95xx_ethtool_set_eeprom,
.get_regs_len = smsc95xx_ethtool_getregslen,
.get_regs = smsc95xx_ethtool_getregs,
+ .get_wol = smsc95xx_ethtool_get_wol,
+ .set_wol = smsc95xx_ethtool_set_wol,
};
static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -1021,26 +1069,147 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
int ret;
u32 val;
- if (WARN_ON_ONCE(!dev))
- return -EINVAL;
-
ret = usbnet_suspend(intf, message);
check_warn_return(ret, "usbnet_suspend error");
- netdev_info(dev->net, "entering SUSPEND2 mode");
+ /* if no wol options set, enter lowest power SUSPEND2 mode */
+ if (!(pdata->wolopts & SUPPORTED_WAKE)) {
+ netdev_info(dev->net, "entering SUSPEND2 mode");
+
+ /* disable energy detect (link up) & wake up events */
+ ret = smsc95xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
+
+ ret = smsc95xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+
+ /* enter suspend2 mode */
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
+ val |= PM_CTL_SUS_MODE_2;
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+
+ return 0;
+ }
+
+ if (pdata->wolopts & WAKE_MAGIC) {
+ /* clear any pending magic packet status */
+ ret = smsc95xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ val |= WUCSR_MPR_;
+
+ ret = smsc95xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+ }
+
+ /* enable/disable magic packup wake */
+ ret = smsc95xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ if (pdata->wolopts & WAKE_MAGIC) {
+ netdev_info(dev->net, "enabling magic packet wakeup");
+ val |= WUCSR_MPEN_;
+ } else {
+ netdev_info(dev->net, "disabling magic packet wakeup");
+ val &= ~WUCSR_MPEN_;
+ }
+
+ ret = smsc95xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ /* enable wol wakeup source */
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ val |= PM_CTL_WOL_EN_;
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+
+ /* enable receiver */
+ smsc95xx_start_rx_path(dev);
+
+ /* some wol options are enabled, so enter SUSPEND0 */
+ netdev_info(dev->net, "entering SUSPEND0 mode");
ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
check_warn_return(ret, "Error reading PM_CTRL");
- val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
- val |= PM_CTL_SUS_MODE_2;
+ val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
+ val |= PM_CTL_SUS_MODE_0;
ret = smsc95xx_write_reg(dev, PM_CTRL, val);
check_warn_return(ret, "Error writing PM_CTRL");
+ /* clear wol status */
+ val &= ~PM_CTL_WUPS_;
+ val |= PM_CTL_WUPS_WOL_;
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+
+ /* read back PM_CTRL */
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ smsc95xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
+
+ return 0;
+}
+
+static int smsc95xx_resume(struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ int ret;
+ u32 val;
+
+ BUG_ON(!dev);
+
+ if (pdata->wolopts & WAKE_MAGIC) {
+ smsc95xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
+
+ /* Disable magic packup wake */
+ ret = smsc95xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ val &= ~WUCSR_MPEN_;
+
+ ret = smsc95xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ /* clear wake-up status */
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
+ check_warn_return(ret, "Error reading PM_CTRL");
+
+ val &= ~PM_CTL_WOL_EN_;
+ val |= PM_CTL_WUPS_;
+
+ ret = smsc95xx_write_reg(dev, PM_CTRL, val);
+ check_warn_return(ret, "Error writing PM_CTRL");
+ }
+
+ return usbnet_resume(intf);
+ check_warn_return(ret, "usbnet_resume error");
+
return 0;
}
@@ -1307,8 +1476,8 @@ static struct usb_driver smsc95xx_driver = {
.id_table = products,
.probe = usbnet_probe,
.suspend = smsc95xx_suspend,
- .resume = usbnet_resume,
- .reset_resume = usbnet_resume,
+ .resume = smsc95xx_resume,
+ .reset_resume = smsc95xx_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
index 89ad925..2ff9815 100644
--- a/drivers/net/usb/smsc95xx.h
+++ b/drivers/net/usb/smsc95xx.h
@@ -205,6 +205,11 @@
#define WUFF (0x128)
#define WUCSR (0x12C)
+#define WUCSR_GUE_ (0x00000200)
+#define WUCSR_WUFR_ (0x00000040)
+#define WUCSR_MPR_ (0x00000020)
+#define WUCSR_WAKE_EN_ (0x00000004)
+#define WUCSR_MPEN_ (0x00000002)
#define COE_CR (0x130)
#define Tx_COE_EN_ (0x00010000)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/4] smsc75xx: enhancements (V2)
From: Steve Glendinning @ 2012-09-28 10:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
This patchset makes a few enhancements to the smsc75xx driver
including improved power saving during suspend and support for
magic packet wol.
This patchset has been rebased against net-next/master but I
believe the first patch has already been included in net/master.
Steve Glendinning (4):
smsc75xx: fix resume after device reset
smsc75xx: add explicit test that device is READY
smsc75xx: enable power saving mode during system suspend
smsc75xx: add wol magic packet support
drivers/net/usb/smsc75xx.c | 239 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 237 insertions(+), 2 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/4] smsc75xx: fix resume after device reset
From: Steve Glendinning @ 2012-09-28 10:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348829873-30779-1-git-send-email-steve.glendinning@shawell.net>
On some systems this device fails to properly resume after suspend,
this patch fixes it by running the usbnet_resume handler.
I suspect this also fixes this bug:
http://code.google.com/p/chromium-os/issues/detail?id=31871
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index f5ab6e6..376143e 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1253,6 +1253,7 @@ static struct usb_driver smsc75xx_driver = {
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .reset_resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/4] smsc75xx: add explicit test that device is READY
From: Steve Glendinning @ 2012-09-28 10:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348829873-30779-1-git-send-email-steve.glendinning@shawell.net>
This patch adds an explicit test that the READY bit is set on
the device when attempting to initialize it.
If this bit is clear then the device hasn't succesfully started
all its clocks, and this patch helps make the resulting logged
error more helpful.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 376143e..1f45f7b 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -756,6 +756,26 @@ static int smsc75xx_set_features(struct net_device *netdev,
return 0;
}
+static int smsc75xx_wait_ready(struct usbnet *dev)
+{
+ int timeout = 0;
+
+ do {
+ u32 buf;
+ int ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
+ check_warn_return(ret, "Failed to read PMT_CTL: %d", ret);
+
+ if (buf & PMT_CTL_DEV_RDY)
+ return 0;
+
+ msleep(10);
+ timeout++;
+ } while (timeout < 100);
+
+ netdev_warn(dev->net, "timeout waiting for device ready");
+ return -EIO;
+}
+
static int smsc75xx_reset(struct usbnet *dev)
{
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
@@ -764,6 +784,9 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset");
+ ret = smsc75xx_wait_ready(dev);
+ check_warn_return(ret, "device not ready in smsc75xx_reset");
+
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
check_warn_return(ret, "Failed to read HW_CFG: %d", ret);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/4] smsc75xx: enable power saving mode during system suspend
From: Steve Glendinning @ 2012-09-28 10:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348829873-30779-1-git-send-email-steve.glendinning@shawell.net>
This patch instructs the device to enter its lowest power SUSPEND2
state during system suspend.
This patch also explicitly wakes the device after resume, which
should address reports of the device not automatically coming
back after system suspend:
Patch updated to change BUG_ON to WARN_ON_ONCE.
http://code.google.com/p/chromium-os/issues/detail?id=31871
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 57 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 54 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 1f45f7b..759e5770 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1106,6 +1106,57 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
}
}
+static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ int ret;
+ u32 val;
+
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ ret = usbnet_suspend(intf, message);
+ check_warn_return(ret, "usbnet_suspend error");
+
+ netdev_info(dev->net, "entering SUSPEND2 mode");
+
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
+ val |= PMT_CTL_SUS_MODE_2;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+
+ return 0;
+}
+
+static int smsc75xx_resume(struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ int ret;
+ u32 val;
+
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ netdev_info(dev->net, "resuming from SUSPEND2");
+
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val |= PMT_CTL_PHY_PWRUP;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+
+ ret = smsc75xx_wait_ready(dev);
+ check_warn_return(ret, "device not ready in smsc75xx_resume");
+
+ return usbnet_resume(intf);
+}
+
static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
u32 rx_cmd_a, u32 rx_cmd_b)
{
@@ -1274,9 +1325,9 @@ static struct usb_driver smsc75xx_driver = {
.name = SMSC_CHIPNAME,
.id_table = products,
.probe = usbnet_probe,
- .suspend = usbnet_suspend,
- .resume = usbnet_resume,
- .reset_resume = usbnet_resume,
+ .suspend = smsc75xx_suspend,
+ .resume = smsc75xx_resume,
+ .reset_resume = smsc75xx_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/4] smsc75xx: add wol magic packet support
From: Steve Glendinning @ 2012-09-28 10:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1348829873-30779-1-git-send-email-steve.glendinning@shawell.net>
This patch enables wake from system suspend on magic packet.
Patch updated to change BUG_ON to WARN_ON_ONCE.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 188 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 174 insertions(+), 14 deletions(-)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 759e5770..b77ae76 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -52,6 +52,7 @@
#define USB_PRODUCT_ID_LAN7500 (0x7500)
#define USB_PRODUCT_ID_LAN7505 (0x7505)
#define RXW_PADDING 2
+#define SUPPORTED_WAKE (WAKE_MAGIC)
#define check_warn(ret, fmt, args...) \
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@ -65,6 +66,7 @@
struct smsc75xx_priv {
struct usbnet *dev;
u32 rfe_ctl;
+ u32 wolopts;
u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
struct mutex dataport_mutex;
spinlock_t rfe_ctl_lock;
@@ -135,6 +137,30 @@ static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
return ret;
}
+static int smsc75xx_set_feature(struct usbnet *dev, u32 feature)
+{
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ cpu_to_le32s(&feature);
+
+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
+static int smsc75xx_clear_feature(struct usbnet *dev, u32 feature)
+{
+ if (WARN_ON_ONCE(!dev))
+ return -EINVAL;
+
+ cpu_to_le32s(&feature);
+
+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
/* Loop until the read is completed with timeout
* called with phy_mutex held */
static int smsc75xx_phy_wait_not_busy(struct usbnet *dev)
@@ -578,6 +604,26 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
}
+static void smsc75xx_ethtool_get_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+
+ wolinfo->supported = SUPPORTED_WAKE;
+ wolinfo->wolopts = pdata->wolopts;
+}
+
+static int smsc75xx_ethtool_set_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+
+ pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
+ return 0;
+}
+
static const struct ethtool_ops smsc75xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -589,6 +635,8 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {
.get_eeprom_len = smsc75xx_ethtool_get_eeprom_len,
.get_eeprom = smsc75xx_ethtool_get_eeprom,
.set_eeprom = smsc75xx_ethtool_set_eeprom,
+ .get_wol = smsc75xx_ethtool_get_wol,
+ .set_wol = smsc75xx_ethtool_set_wol,
};
static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -1109,47 +1157,159 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
int ret;
u32 val;
- if (WARN_ON_ONCE(!dev))
- return -EINVAL;
-
ret = usbnet_suspend(intf, message);
check_warn_return(ret, "usbnet_suspend error");
- netdev_info(dev->net, "entering SUSPEND2 mode");
+ /* if no wol options set, enter lowest power SUSPEND2 mode */
+ if (!(pdata->wolopts & SUPPORTED_WAKE)) {
+ netdev_info(dev->net, "entering SUSPEND2 mode");
+
+ /* disable energy detect (link up) & wake up events */
+ ret = smsc75xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ val &= ~(WUCSR_MPEN | WUCSR_WUEN);
+
+ ret = smsc75xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN);
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+
+ /* enter suspend2 mode */
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
+ val |= PMT_CTL_SUS_MODE_2;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+
+ return 0;
+ }
+
+ if (pdata->wolopts & WAKE_MAGIC) {
+ /* clear any pending magic packet status */
+ ret = smsc75xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ val |= WUCSR_MPR;
+ ret = smsc75xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+ }
+
+ /* enable/disable magic packup wake */
+ ret = smsc75xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
+
+ if (pdata->wolopts & WAKE_MAGIC) {
+ netdev_info(dev->net, "enabling magic packet wakeup");
+ val |= WUCSR_MPEN;
+ } else {
+ netdev_info(dev->net, "disabling magic packet wakeup");
+ val &= ~WUCSR_MPEN;
+ }
+
+ ret = smsc75xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ /* enable wol wakeup source */
ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
check_warn_return(ret, "Error reading PMT_CTL");
- val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
- val |= PMT_CTL_SUS_MODE_2;
+ val |= PMT_CTL_WOL_EN;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+
+ /* enable receiver */
+ ret = smsc75xx_read_reg(dev, MAC_RX, &val);
+ check_warn_return(ret, "Failed to read MAC_RX: %d", ret);
+
+ val |= MAC_RX_RXEN;
+
+ ret = smsc75xx_write_reg(dev, MAC_RX, val);
+ check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
+
+ /* some wol options are enabled, so enter SUSPEND0 */
+ netdev_info(dev->net, "entering SUSPEND0 mode");
+
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST));
+ val |= PMT_CTL_SUS_MODE_0;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+ /* clear wol status */
+ val &= ~PMT_CTL_WUPS;
+ val |= PMT_CTL_WUPS_WOL;
ret = smsc75xx_write_reg(dev, PMT_CTL, val);
check_warn_return(ret, "Error writing PMT_CTL");
+ /* read back PMT_CTL */
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ smsc75xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
+
return 0;
}
static int smsc75xx_resume(struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
int ret;
u32 val;
- if (WARN_ON_ONCE(!dev))
- return -EINVAL;
+ if (pdata->wolopts & WAKE_MAGIC) {
+ netdev_info(dev->net, "resuming from SUSPEND0");
- netdev_info(dev->net, "resuming from SUSPEND2");
+ smsc75xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL");
+ /* Disable magic packup wake */
+ ret = smsc75xx_read_reg(dev, WUCSR, &val);
+ check_warn_return(ret, "Error reading WUCSR");
- val |= PMT_CTL_PHY_PWRUP;
+ val &= ~WUCSR_MPEN;
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL");
+ ret = smsc75xx_write_reg(dev, WUCSR, val);
+ check_warn_return(ret, "Error writing WUCSR");
+
+ /* clear wake-up status */
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val &= ~PMT_CTL_WOL_EN;
+ val |= PMT_CTL_WUPS;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+ } else {
+ netdev_info(dev->net, "resuming from SUSPEND2");
+
+ ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
+ check_warn_return(ret, "Error reading PMT_CTL");
+
+ val |= PMT_CTL_PHY_PWRUP;
+
+ ret = smsc75xx_write_reg(dev, PMT_CTL, val);
+ check_warn_return(ret, "Error writing PMT_CTL");
+ }
ret = smsc75xx_wait_ready(dev);
check_warn_return(ret, "device not ready in smsc75xx_resume");
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
From: Richard Cochran @ 2012-09-28 11:11 UTC (permalink / raw)
To: Yevgeny Petrilin; +Cc: davem, netdev, eugenia
In-Reply-To: <1348826603-17439-4-git-send-email-yevgenyp@mellanox.com>
On Fri, Sep 28, 2012 at 12:03:23PM +0200, Yevgeny Petrilin wrote:
> From: Eugenia Emantayev <eugenia@mellanox.co.il>
>
...
> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> index edd9cb8..10fa453 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> @@ -1517,6 +1517,60 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
> return 0;
> }
>
> +static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
> +{
> + struct mlx4_en_priv *priv = netdev_priv(dev);
> + struct mlx4_en_dev *mdev = priv->mdev;
> + struct hwtstamp_config config;
> +
> + if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
> + return -EFAULT;
> +
> + /* reserved for future extensions */
> + if (config.flags)
> + return -EINVAL;
> +
> + /* device doesn't support time stamping */
> + if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS_EN))
> + return -EINVAL;
> +
> + /* TX HW timestamp */
> + switch (config.tx_type) {
> + case HWTSTAMP_TX_OFF:
> + case HWTSTAMP_TX_ON:
> + break;
> + default:
> + return -ERANGE;
> + }
> +
> + /* RX HW timestamp */
> + switch (config.rx_filter) {
> + case HWTSTAMP_FILTER_NONE:
> + case HWTSTAMP_FILTER_ALL:
> + break;
> + default:
Instead of rejecting the HWTSTAMP_FILTER_PTP_ codes out of hand, you
should just accept them, and return by promoting rx_filter to
HWTSTAMP_FILTER_ALL.
[ See Documentation/networking/timestamping.txt ]
> + return -ERANGE;
> + }
> +
> + if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
> + config.tx_type = HWTSTAMP_TX_OFF;
> + config.rx_filter = HWTSTAMP_FILTER_NONE;
> + }
> +
> + return copy_to_user(ifr->ifr_data, &config,
> + sizeof(config)) ? -EFAULT : 0;
> +}
...
> @@ -363,6 +368,9 @@ struct mlx4_en_dev {
> u32 priv_pdn;
> spinlock_t uar_lock;
> u8 mac_removed[MLX4_MAX_PORTS + 1];
> + struct cyclecounter cycles;
> + struct timecounter clock;
> + struct timecompare compare;
I am working on a patch to remove the timecompare stuff altogether
(after removing it from blackfin). It is and was a bad idea, I would
hate to see new drivers using it.
I strongly recommend just offering raw hardware time stamps in
nanosecond resolution. Also, why not expose your device as a PTP
Hardware Clock?
Thanks,
Richard
^ permalink raw reply
* Re: Possible networking regression in 3.6.0
From: Eric Dumazet @ 2012-09-28 11:26 UTC (permalink / raw)
To: Chris Clayton; +Cc: David Miller, netdev, gpiez
In-Reply-To: <50656C4A.8090302@googlemail.com>
On Fri, 2012-09-28 at 10:22 +0100, Chris Clayton wrote:
> No, the WinXP guest is configured with a fixed IP address
> (192.168.200.1). Subnet mask is 255.255.255.0, and default gateway is
> 192.168.200.254. DNS is 192.168.0.1.
>
I have no problem with such a setup, with a linux guest.
Could you send again a tcpdump, but including link-level header ?
(option -e)
Ideally, you could send two traces, one taken on tap0, and another taken
on eth0.
^ permalink raw reply
* Re: You have to fix this
From: Vipul Pandya @ 2012-09-28 11:59 UTC (permalink / raw)
To: David Miller; +Cc: netdev@vger.kernel.org
In-Reply-To: <20120927.183406.962014014858457666.davem@davemloft.net>
On 28-09-2012 04:04, David Miller wrote:
>
> You cannot put such monster sized local data objects on the stack:
>
> drivers/net/ethernet/chelsio/cxgb4/t4_hw.c: In function ‘t4_memory_rw.constprop.6’:
> drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:484:1: warning: the frame size of 2056 bytes is larger than 2048 bytes [-Wframe-larger-than=]
>
> That's because of this thing:
>
> __be32 data[MEMWIN0_APERTURE/sizeof(__be32)];
>
> I'm really surprised this didn't show up in any of your test builds.
> Or are you ignoring warnings that your changes add?
>
Thanks for pointing this out. We will send a patch for this soon.
I am not ignoring any warnings. I did build my tree different way as
shown below but did not get above warning message.
#> make
#> make allmodconfig
#> make allnoconfig
Please let me know how else would I get above warning message?
I missed doing make checkstack which doesn't display warning message but
lists the function names.
Thanks,
Vipul Pandya
^ permalink raw reply
* [PATCH] vlan: Make it possible to add vlan with id 4095
From: Paulius Zaleckas @ 2012-09-28 12:32 UTC (permalink / raw)
To: kaber, netdev
vconfig help tells that vlan_id should be 0-4095, but fails
with 4095.
There is an off-by-one bug while evaluating vlan_id.
Fix it by evaluating against count(4096), not mask(0x0fff = 4095).
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
---
net/8021q/vlan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 9096bcb..9e528bf 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -199,7 +199,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
char name[IFNAMSIZ];
int err;
- if (vlan_id >= VLAN_VID_MASK)
+ if (vlan_id >= VLAN_N_VID)
return -ERANGE;
err = vlan_check_real_dev(real_dev, vlan_id);
^ permalink raw reply related
* drivers/net/cris/eth_v10.c:1715:2: error: too many arguments to function 'e100rxtx_interrupt'
From: Fengguang Wu @ 2012-09-28 13:06 UTC (permalink / raw)
To: Jesper Nilsson; +Cc: kernel-janitors, netdev
Hi Jesper,
FYI, a rather old build bug that's introduced by
bafef0a cris build fixes: update eth_v10.c ethernet driver
All error/warnings:
drivers/net/cris/eth_v10.c: In function 'e100_netpoll':
drivers/net/cris/eth_v10.c:1715:2: error: too many arguments to function 'e100rxtx_interrupt'
drivers/net/cris/eth_v10.c:1131:1: note: declared here
vim +1715 drivers/net/cris/eth_v10.c
^1da177e (Linus Torvalds 2005-04-16 1710)
bafef0ae (Jesper Nilsson 2007-11-14 1711) #ifdef CONFIG_NET_POLL_CONTROLLER
bafef0ae (Jesper Nilsson 2007-11-14 1712) static void
bafef0ae (Jesper Nilsson 2007-11-14 1713) e100_netpoll(struct net_device* netdev)
bafef0ae (Jesper Nilsson 2007-11-14 1714) {
bafef0ae (Jesper Nilsson 2007-11-14 @1715) e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
bafef0ae (Jesper Nilsson 2007-11-14 1716) }
bafef0ae (Jesper Nilsson 2007-11-14 1717) #endif
bafef0ae (Jesper Nilsson 2007-11-14 1718)
^1da177e (Linus Torvalds 2005-04-16 1719) static int
^1da177e (Linus Torvalds 2005-04-16 1720) etrax_init_module(void)
^1da177e (Linus Torvalds 2005-04-16 1721) {
^1da177e (Linus Torvalds 2005-04-16 1722) return etrax_ethernet_init();
^1da177e (Linus Torvalds 2005-04-16 1723) }
---
0-DAY kernel build testing backend Open Source Technology Centre
Fengguang Wu, Yuanhan Liu Intel Corporation
^ permalink raw reply
* Re: [RFC PATCH net-next] tcp: introduce tcp_tw_interval to specifiy the time of TIME-WAIT
From: Neil Horman @ 2012-09-28 13:16 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, David S. Miller, Alexey Kuznetsov, Patrick McHardy,
Eric Dumazet
In-Reply-To: <1348813987.7264.41.camel@cr0>
On Fri, Sep 28, 2012 at 02:33:07PM +0800, Cong Wang wrote:
> On Thu, 2012-09-27 at 10:23 -0400, Neil Horman wrote:
> > On Thu, Sep 27, 2012 at 04:41:01PM +0800, Cong Wang wrote:
> > > Some customer requests this feature, as they stated:
> > >
> > > "This parameter is necessary, especially for software that continually
> > > creates many ephemeral processes which open sockets, to avoid socket
> > > exhaustion. In many cases, the risk of the exhaustion can be reduced by
> > > tuning reuse interval to allow sockets to be reusable earlier.
> > >
> > > In commercial Unix systems, this kind of parameters, such as
> > > tcp_timewait in AIX and tcp_time_wait_interval in HP-UX, have
> > > already been available. Their implementations allow users to tune
> > > how long they keep TCP connection as TIME-WAIT state on the
> > > millisecond time scale."
> > >
> > > We indeed have "tcp_tw_reuse" and "tcp_tw_recycle", but these tunings
> > > are not equivalent in that they cannot be tuned directly on the time
> > > scale nor in a safe way, as some combinations of tunings could still
> > > cause some problem in NAT. And, I think second scale is enough, we don't
> > > have to make it in millisecond time scale.
> > >
> > I think I have a little difficultly seeing how this does anything other than
> > pay lip service to actually having sockets spend time in TIME_WAIT state. That
> > is to say, while I see users using this to just make the pain stop. If we wait
> > less time than it takes to be sure that a connection isn't being reused (either
> > by waiting two segment lifetimes, or by checking timestamps), then you might as
> > well not wait at all. I see how its tempting to be able to say "Just don't wait
> > as long", but it seems that theres no difference between waiting half as long as
> > the RFC mandates, and waiting no time at all. Neither is a good idea.
>
> I don't think reducing TIME_WAIT is a good idea either, but there must
> be some reason behind as several UNIX provides a microsecond-scale
> tuning interface, or maybe in non-recycle mode, their RTO is much less
> than 2*MSL?
>
My guess? Cash was the reason. I certainly wasn't there for any of those
developments, but a setting like this just smells to me like some customer waved
some cash under IBM's/HP's/Sun's nose and said, "We'd like to get our tcp
sockets back to CLOSED state faster, what can you do for us?"
> >
> > Given the problem you're trying to solve here, I'll ask the standard question in
> > response: How does using SO_REUSEADDR not solve the problem? Alternatively, in
> > a pinch, why not reduce the tcp_max_tw_buckets sufficiently to start forcing
> > TIME_WAIT sockets back into CLOSED state?
> >
> > The code looks fine, but the idea really doesn't seem like a good plan to me.
> > I'm sure HPUX/Solaris/AIX/etc have done this in response to customer demand, but
> > that doesn't make it the right solution.
> >
>
> *I think* the customer doesn't want to modify their applications, so
> that is why they don't use SO_REUSERADDR.
>
Well, ok, thats a legitimate distro problem. What its not is an upstream
problem. Fixing the appilcation is the right thing to do, wether or not they
want to.
> I didn't know tcp_max_tw_buckets can do the trick, nor the customer, so
> this is a side effect of tcp_max_tw_buckets? Is it documented?
man 7 tcp:
tcp_max_tw_buckets (integer; default: see below; since Linux 2.4)
The maximum number of sockets in TIME_WAIT state allowed in the
system. This limit exists only to prevent simple
denial-of-service attacks. The default value of NR_FILE*2 is
adjusted depending on the memory in the system. If this number
is exceeded, the socket is closed and a warning is printed.
Neil
^ permalink raw reply
* [PATCH] flexcan: disable bus error interrupts for the i.MX28
From: Wolfgang Grandegger @ 2012-09-28 13:17 UTC (permalink / raw)
To: Linux Netdev List; +Cc: Linux-CAN, Hui Wang, Shawn Guo
Due to a bug in most Flexcan cores, the bus error interrupt needs
to be enabled. Otherwise we don't get any error warning or passive
interrupts. This is _not_ necessay for the i.MX28 and this patch
disables bus error interrupts if "berr-reporting" is not requested.
This avoids bus error flooding, which might harm, especially on
low-end systems.
To handle such quirks of the Flexcan cores, a hardware feature flag
has been introduced, also replacing the "hw_ver" variable. So far
nobody could tell what Flexcan core version is available on what
Freescale SOC, apart from the i.MX6Q and P1010, and which bugs or
features are present on the various "hw_rev".
CC: Hui Wang <jason77.wang@gmail.com>
CC: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
Concerning the bug, I know that the i.MX35 does have it. Maybe other
Flexcan cores than on the i.MX28 does *not* have it either. If you
have a chance, please check on the P1010, i.MX6Q, i.MX51, i.MX53,
etc.
Wolfgang.
drivers/net/can/flexcan.c | 29 +++++++++++++++++++----------
1 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index c5f1431..c78ecfc 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -144,6 +144,10 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
+/* FLEXCAN hardware feature flags */
+#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
+#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* Broken error state handling */
+
/* Structure of the message buffer */
struct flexcan_mb {
u32 can_ctrl;
@@ -178,7 +182,7 @@ struct flexcan_regs {
};
struct flexcan_devtype_data {
- u32 hw_ver; /* hardware controller version */
+ u32 features; /* hardware controller features */
};
struct flexcan_priv {
@@ -197,11 +201,11 @@ struct flexcan_priv {
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
- .hw_ver = 3,
+ .features = FLEXCAN_HAS_BROKEN_ERR_STATE,
};
-
+static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
- .hw_ver = 10,
+ .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_BROKEN_ERR_STATE,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
@@ -741,15 +745,19 @@ static int flexcan_chip_start(struct net_device *dev)
* enable tx and rx warning interrupt
* enable bus off interrupt
* (== FLEXCAN_CTRL_ERR_STATE)
- *
- * _note_: we enable the "error interrupt"
- * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any
- * warning or bus passive interrupts.
*/
reg_ctrl = flexcan_read(®s->ctrl);
reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
- FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK;
+ FLEXCAN_CTRL_ERR_STATE;
+ /*
+ * enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK),
+ * on most Flexcan cores, too. Otherwise we don't get
+ * any error warning or passive interrupts.
+ */
+ if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||
+ priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+ reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
/* save for later use */
priv->reg_ctrl_default = reg_ctrl;
@@ -772,7 +780,7 @@ static int flexcan_chip_start(struct net_device *dev)
flexcan_write(0x0, ®s->rx14mask);
flexcan_write(0x0, ®s->rx15mask);
- if (priv->devtype_data->hw_ver >= 10)
+ if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, ®s->rxfgmask);
flexcan_transceiver_switch(priv, 1);
@@ -954,6 +962,7 @@ static void __devexit unregister_flexcandev(struct net_device *dev)
static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
+ { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
{ /* sentinel */ },
};
--
1.7.7.6
^ permalink raw reply related
* Re: [PATCH] vlan: Make it possible to add vlan with id 4095
From: Paulius Zaleckas @ 2012-09-28 13:29 UTC (permalink / raw)
To: kaber, netdev
In-Reply-To: <20120928123258.9454.95197.stgit@localhost.localdomain>
On 09/28/2012 03:32 PM, Paulius Zaleckas wrote:
> vconfig help tells that vlan_id should be 0-4095, but fails
> with 4095.
>
> There is an off-by-one bug while evaluating vlan_id.
> Fix it by evaluating against count(4096), not mask(0x0fff = 4095).
On the other hand 4095 is reserved by 802.1Q...
http://en.wikipedia.org/wiki/IEEE_802.1Q
VLAN Identifier (VID): a 12-bit field specifying the VLAN to which the
frame belongs. The hexadecimal values of 0x000 and 0xFFF are reserved.
All other values may be used as VLAN identifiers, allowing up to 4,094
VLANs. The reserved value 0x000 indicates that the frame does not belong
to any VLAN; in this case, the 802.1Q tag specifies only a priority and
is referred to as a priority tag.
So maybe we should fix vconfig help?
^ permalink raw reply
* Re: [PATCH net-next 3/3] ipv4: gre: add GRO capability
From: Eric Dumazet @ 2012-09-28 14:04 UTC (permalink / raw)
To: Jesse Gross; +Cc: David Miller, netdev
In-Reply-To: <CAEP_g=8B7xZPxye0Kuu-EVKpTDt1a3nsJKb61aaYaqOGsYGx8w@mail.gmail.com>
On Thu, 2012-09-27 at 15:03 -0700, Jesse Gross wrote:
> We wouldn't actually do the decapsulation at the point of GRO. This
> is actually pretty similar to what we do with TCP - we merge TCP
> payloads even though we haven't done any real IP processing yet.
> However, we do check firewall rules later if we actually hit the IP
> stack. GRE would work the same way in this case.
>
> What I'm describing is pretty much exactly what NICs will be doing, so
> if that doesn't work we'll have a problem...
GRO ability to truly aggregate data is kind of limited to some
workloads. How NICs will handle interleaved flows I dont really know.
What you describe needs a serious GRO preliminary work, because it
depends on napi_gro_flush() being called from time to time, while we
need something else, more fine grained.
(I am pretty sure GRO needs some love from us, it looks like some
packets can stay a long time in gro_list. It would be nice if it was
able to reorder packets (from same flow) as well)
Anyway, my changes are self-contained in a new file and non intrusive.
As soon as we can provide a better alternative we can revert them ?
Thanks
^ permalink raw reply
* RE: [PATCH 3/3] net/mlx4_en: Add HW timestamping (TS) support
From: Yevgeny Petrilin @ 2012-09-28 14:10 UTC (permalink / raw)
To: Richard Cochran
Cc: davem@davemloft.net, netdev@vger.kernel.org, Eugenia Emantayev
In-Reply-To: <20120928111147.GA7474@netboy.at.omicron.at>
> > diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > index edd9cb8..10fa453 100644
> > --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> > @@ -1517,6 +1517,60 @@ static int mlx4_en_change_mtu(struct net_device
> *dev, int new_mtu)
> > return 0;
> > }
> >
> > +static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
> > +{
> > + struct mlx4_en_priv *priv = netdev_priv(dev);
> > + struct mlx4_en_dev *mdev = priv->mdev;
> > + struct hwtstamp_config config;
> > +
> > + if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
> > + return -EFAULT;
> > +
> > + /* reserved for future extensions */
> > + if (config.flags)
> > + return -EINVAL;
> > +
> > + /* device doesn't support time stamping */
> > + if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS_EN))
> > + return -EINVAL;
> > +
> > + /* TX HW timestamp */
> > + switch (config.tx_type) {
> > + case HWTSTAMP_TX_OFF:
> > + case HWTSTAMP_TX_ON:
> > + break;
> > + default:
> > + return -ERANGE;
> > + }
> > +
> > + /* RX HW timestamp */
> > + switch (config.rx_filter) {
> > + case HWTSTAMP_FILTER_NONE:
> > + case HWTSTAMP_FILTER_ALL:
> > + break;
> > + default:
>
> Instead of rejecting the HWTSTAMP_FILTER_PTP_ codes out of hand, you
> should just accept them, and return by promoting rx_filter to
> HWTSTAMP_FILTER_ALL.
>
> [ See Documentation/networking/timestamping.txt ]
>
> > + return -ERANGE;
> > + }
> > +
> > + if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
> > + config.tx_type = HWTSTAMP_TX_OFF;
> > + config.rx_filter = HWTSTAMP_FILTER_NONE;
> > + }
> > +
> > + return copy_to_user(ifr->ifr_data, &config,
> > + sizeof(config)) ? -EFAULT : 0;
> > +}
>
> ...
>
> > @@ -363,6 +368,9 @@ struct mlx4_en_dev {
> > u32 priv_pdn;
> > spinlock_t uar_lock;
> > u8 mac_removed[MLX4_MAX_PORTS + 1];
> > + struct cyclecounter cycles;
> > + struct timecounter clock;
> > + struct timecompare compare;
>
> I am working on a patch to remove the timecompare stuff altogether
> (after removing it from blackfin). It is and was a bad idea, I would
> hate to see new drivers using it.
>
> I strongly recommend just offering raw hardware time stamps in
> nanosecond resolution. Also, why not expose your device as a PTP
> Hardware Clock?
>
> Thanks,
> Richard
Hello Richard,
Thanks for your feedback,
Will address all your comments in V1 of this patchset.
Thanks,
Yevgeny
^ permalink raw reply
* network-namespace and unix-domain-sockets
From: Dilip Daya @ 2012-09-28 14:12 UTC (permalink / raw)
To: ebiederm; +Cc: Linux Netdev List
[-- Attachment #1: Type: text/plain, Size: 1269 bytes --]
Hi Eric,
=> kernel 3.6.0-rc6 + network-namespace + unix-domain-sockets
srv/cli sample programs at:
<http://tkhanson.net/cgit.cgi/misc.git/plain/unixdomain/Unix_domain_sockets.html>
Executing UNIX domain sockets between two network-namespaces fails but
successful if both srv and cli are executed within a network-namespace.
Test results:
(1) Executing both srv and cli within default/host network-namespace:
On host/default netns:
# ./cli
testing...
^C
On host/default netns:
# ./srv
read 11 bytes: testing...
EOF
(2) Executing srv in default/host netns and cli within netns named
netns0:
On host/default netns:
# ip netns
netns1
netns0
On host/default netns:
# ./srv
Within netns name netns0:
# ip netns exec netns0 ./cli
connect error: Connection refused
=> I find difference between __unix_find_socket_byname() and
*unix_find_socket_byinode()
---
if (!net_eq(sock_net(s), net))
continue;
---
=> Is there an explanation for why __unix_find_socket_byname() was left
netns aware and *unix_find_socket_byinode() is not netns aware ?
=> Please see attached patch. Is this valid? or will it break something?
I've tested network namespaces with this patch applied and I did not
find any issues.
-DilipD.
[-- Attachment #2: unix_sockets_netns.patch --]
[-- Type: text/x-patch, Size: 2248 bytes --]
--- linux-3.6-rc6/net/unix/af_unix.c_orig 2012-09-27 14:25:27.000000000 -0400
+++ linux-3.6-rc6/net/unix/af_unix.c 2012-09-27 14:44:41.000000000 -0400
@@ -258,8 +258,7 @@ static inline void unix_insert_socket(st
spin_unlock(&unix_table_lock);
}
-static struct sock *__unix_find_socket_byname(struct net *net,
- struct sockaddr_un *sunname,
+static struct sock *__unix_find_socket_byname(struct sockaddr_un *sunname,
int len, int type, unsigned int hash)
{
struct sock *s;
@@ -268,9 +267,6 @@ static struct sock *__unix_find_socket_b
sk_for_each(s, node, &unix_socket_table[hash ^ type]) {
struct unix_sock *u = unix_sk(s);
- if (!net_eq(sock_net(s), net))
- continue;
-
if (u->addr->len == len &&
!memcmp(u->addr->name, sunname, len))
goto found;
@@ -280,15 +276,14 @@ found:
return s;
}
-static inline struct sock *unix_find_socket_byname(struct net *net,
- struct sockaddr_un *sunname,
+static inline struct sock *unix_find_socket_byname(struct sockaddr_un *sunname,
int len, int type,
unsigned int hash)
{
struct sock *s;
spin_lock(&unix_table_lock);
- s = __unix_find_socket_byname(net, sunname, len, type, hash);
+ s = __unix_find_socket_byname(sunname, len, type, hash);
if (s)
sock_hold(s);
spin_unlock(&unix_table_lock);
@@ -740,7 +735,7 @@ retry:
spin_lock(&unix_table_lock);
ordernum = (ordernum+1)&0xFFFFF;
- if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type,
+ if (__unix_find_socket_byname(addr->name, addr->len, sock->type,
addr->hash)) {
spin_unlock(&unix_table_lock);
/*
@@ -805,7 +800,7 @@ static struct sock *unix_find_other(stru
}
} else {
err = -ECONNREFUSED;
- u = unix_find_socket_byname(net, sunname, len, type, hash);
+ u = unix_find_socket_byname(sunname, len, type, hash);
if (u) {
struct dentry *dentry;
dentry = unix_sk(u)->path.dentry;
@@ -913,7 +908,7 @@ static int unix_bind(struct socket *sock
} else {
spin_lock(&unix_table_lock);
err = -EADDRINUSE;
- if (__unix_find_socket_byname(net, sunaddr, addr_len,
+ if (__unix_find_socket_byname(sunaddr, addr_len,
sk->sk_type, hash)) {
unix_release_addr(addr);
goto out_unlock;
^ permalink raw reply
* Re: Possible networking regression in 3.6.0
From: Chris Clayton @ 2012-09-28 14:28 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev, gpiez
In-Reply-To: <1348831592.5093.2251.camel@edumazet-glaptop>
On 09/28/12 12:26, Eric Dumazet wrote:
> On Fri, 2012-09-28 at 10:22 +0100, Chris Clayton wrote:
>
>> No, the WinXP guest is configured with a fixed IP address
>> (192.168.200.1). Subnet mask is 255.255.255.0, and default gateway is
>> 192.168.200.254. DNS is 192.168.0.1.
>>
>
> I have no problem with such a setup, with a linux guest.
>
> Could you send again a tcpdump, but including link-level header ?
> (option -e)
>
> Ideally, you could send two traces, one taken on tap0, and another taken
> on eth0.
>
Two traces
Trace 1 - tap0 (192.168.200.254) whilst pinging router (192.168.0.1)from
KVM guest (192.168.200.1):
15:03:14.953599 52:54:0c:3b:17:38 > Broadcast, ethertype ARP (0x0806),
length 42: Request who-has 192.168.200.254 tell 192.168.200.1, length 28
15:03:14.953617 9e:c3:0c:c8:65:8d > 52:54:0c:3b:17:38, ethertype ARP
(0x0806), length 42: Reply 192.168.200.254 is-at 9e:c3:0c:c8:65:8d,
length 28
15:03:14.953725 52:54:0c:3b:17:38 > 9e:c3:0c:c8:65:8d, ethertype IPv4
(0x0800), length 74: 192.168.200.1 > 192.168.0.1: ICMP echo request, id
512, seq 5376, length 40
15:03:20.427278 52:54:0c:3b:17:38 > 9e:c3:0c:c8:65:8d, ethertype IPv4
(0x0800), length 74: 192.168.200.1 > 192.168.0.1: ICMP echo request, id
512, seq 5632, length 40
15:03:25.942215 52:54:0c:3b:17:38 > 9e:c3:0c:c8:65:8d, ethertype IPv4
(0x0800), length 74: 192.168.200.1 > 192.168.0.1: ICMP echo request, id
512, seq 5888, length 40
15:03:31.455578 52:54:0c:3b:17:38 > 9e:c3:0c:c8:65:8d, ethertype IPv4
(0x0800), length 74: 192.168.200.1 > 192.168.0.1: ICMP echo request, id
512, seq 6144, length 40
Trace 2 - eth0 (192.168.0.40) whilst pinging router (192.168.0.1)from
KVM guest (192.168.200.1):
15:04:06.427863 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype IPv4
(0x0800), length 74: 192.168.0.40 > 192.168.0.1: ICMP echo request, id
512, seq 6400, length 40
15:04:06.432100 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype IPv4
(0x0800), length 74: 192.168.0.1 > 192.168.0.40: ICMP echo reply, id
512, seq 6400, length 40
15:04:11.430877 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype ARP
(0x0806), length 60: Request who-has 192.168.0.40 tell 192.168.0.1,
length 46
15:04:11.430898 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype ARP
(0x0806), length 42: Reply 192.168.0.40 is-at 5c:9a:d8:5c:63:31, length 28
15:04:11.567319 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype IPv4
(0x0800), length 74: 192.168.0.40 > 192.168.0.1: ICMP echo request, id
512, seq 6656, length 40
15:04:11.571534 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype IPv4
(0x0800), length 74: 192.168.0.1 > 192.168.0.40: ICMP echo reply, id
512, seq 6656, length 40
15:04:16.577137 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype ARP
(0x0806), length 42: Request who-has 192.168.0.1 tell 192.168.0.40,
length 28
15:04:16.580373 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype ARP
(0x0806), length 60: Reply 192.168.0.1 is-at 00:1f:33:80:09:44, length 46
15:04:17.083328 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype IPv4
(0x0800), length 74: 192.168.0.40 > 192.168.0.1: ICMP echo request, id
512, seq 6912, length 40
15:04:17.086854 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype IPv4
(0x0800), length 74: 192.168.0.1 > 192.168.0.40: ICMP echo reply, id
512, seq 6912, length 40
15:04:22.585766 5c:9a:d8:5c:63:31 > 00:1f:33:80:09:44, ethertype IPv4
(0x0800), length 74: 192.168.0.40 > 192.168.0.1: ICMP echo request, id
512, seq 7168, length 40
15:04:22.589989 00:1f:33:80:09:44 > 5c:9a:d8:5c:63:31, ethertype IPv4
(0x0800), length 74: 192.168.0.1 > 192.168.0.40: ICMP echo reply, id
512, seq 7168, length 40
15:04:32.240422 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 446: 192.168.0.112.2704 > 239.255.255.250.1900: UDP,
length 404
15:04:32.241404 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 455: 192.168.0.112.2704 > 239.255.255.250.1900: UDP,
length 413
15:04:32.242915 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 494: 192.168.0.112.2704 > 239.255.255.250.1900: UDP,
length 452
15:04:32.243986 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 490: 192.168.0.112.1434 > 239.255.255.250.1900: UDP,
length 448
15:04:32.245476 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 486: 192.168.0.112.2901 > 239.255.255.250.1900: UDP,
length 444
15:04:32.246545 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 486: 192.168.0.112.3828 > 239.255.255.250.1900: UDP,
length 444
15:04:32.342459 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 446: 192.168.0.112.4445 > 239.255.255.250.1900: UDP,
length 404
15:04:32.343506 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 455: 192.168.0.112.4445 > 239.255.255.250.1900: UDP,
length 413
15:04:32.345017 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 494: 192.168.0.112.4445 > 239.255.255.250.1900: UDP,
length 452
15:04:32.346087 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 490: 192.168.0.112.2735 > 239.255.255.250.1900: UDP,
length 448
15:04:32.348314 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 486: 192.168.0.112.4940 > 239.255.255.250.1900: UDP,
length 444
15:04:32.349362 00:19:fb:be:cb:55 > 01:00:5e:7f:ff:fa, ethertype IPv4
(0x0800), length 486: 192.168.0.112.1029 > 239.255.255.250.1900: UDP,
length 444
The second trace seems to contain some upnp-related traffic involving my
satellite TV box. If it would help, I can turn that off when my wife
isn't watching TV, and run the traces again.
Chris
>
>
>
>
^ permalink raw reply
* [net-next PATCH 1/4] be2net: remove type argument of be_cmd_mac_addr_query()
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
In-Reply-To: <1348843184-22214-1-git-send-email-sathya.perla@emulex.com>
All invocations of this routine use the same type value.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_cmds.c | 4 ++--
drivers/net/ethernet/emulex/benet/be_cmds.h | 2 +-
drivers/net/ethernet/emulex/benet/be_main.c | 18 ++++++------------
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 701b3e9..6fbfb20 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -717,7 +717,7 @@ int be_cmd_eq_create(struct be_adapter *adapter,
/* Use MCC */
int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
- u8 type, bool permanent, u32 if_handle, u32 pmac_id)
+ bool permanent, u32 if_handle, u32 pmac_id)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_mac_query *req;
@@ -734,7 +734,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req), wrb, NULL);
- req->type = type;
+ req->type = MAC_ADDRESS_TYPE_NETWORK;
if (permanent) {
req->permanent = 1;
} else {
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 250f19b..1f5b839 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1687,7 +1687,7 @@ struct be_cmd_req_set_ext_fat_caps {
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_fw_wait_ready(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
- u8 type, bool permanent, u32 if_handle, u32 pmac_id);
+ bool permanent, u32 if_handle, u32 pmac_id);
extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
u32 if_id, u32 *pmac_id, u32 domain);
extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id,
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 84379f4..fa17430 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -241,9 +241,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- status = be_cmd_mac_addr_query(adapter, current_mac,
- MAC_ADDRESS_TYPE_NETWORK, false,
- adapter->if_handle, 0);
+ status = be_cmd_mac_addr_query(adapter, current_mac, false,
+ adapter->if_handle, 0);
if (status)
goto err;
@@ -2693,21 +2692,16 @@ static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
status = be_cmd_get_mac_from_list(adapter, mac,
active_mac, pmac_id, 0);
if (*active_mac) {
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK,
- false, if_handle,
- *pmac_id);
+ status = be_cmd_mac_addr_query(adapter, mac, false,
+ if_handle, *pmac_id);
}
} else if (be_physfn(adapter)) {
/* For BE3, for PF get permanent MAC */
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, true,
- 0, 0);
+ status = be_cmd_mac_addr_query(adapter, mac, true, 0, 0);
*active_mac = false;
} else {
/* For BE3, for VF get soft MAC assigned by PF*/
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, false,
+ status = be_cmd_mac_addr_query(adapter, mac, false,
if_handle, 0);
*active_mac = true;
}
--
1.7.4
^ permalink raw reply related
* [net-next PATCH 0/4] fixes v2
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
Resending the patch series minus the patch to remove the AMAP macros.
Pls apply.
Sathya Perla (4):
be2net: remove type argument of be_cmd_mac_addr_query()
be2net: fix wrong handling of be_setup() failure in be_probe()
be2net: cleanup code related to be_link_status_query()
be2net: fixup log messages
drivers/net/ethernet/emulex/benet/be.h | 1 -
drivers/net/ethernet/emulex/benet/be_cmds.c | 53 +++++++++++++++------
drivers/net/ethernet/emulex/benet/be_cmds.h | 6 +-
drivers/net/ethernet/emulex/benet/be_ethtool.c | 57 +++++------------------
drivers/net/ethernet/emulex/benet/be_main.c | 60 ++++++++++++++---------
5 files changed, 89 insertions(+), 88 deletions(-)
--
1.7.4
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox