summaryrefslogtreecommitdiff
path: root/drivers/net/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/Kconfig2
-rw-r--r--drivers/net/usb/asix.c28
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/cdc_ncm.c13
-rw-r--r--drivers/net/usb/dm9601.c6
-rw-r--r--drivers/net/usb/plusb.c32
-rw-r--r--drivers/net/usb/rndis_host.c39
-rw-r--r--drivers/net/usb/rtl8150.c11
-rw-r--r--drivers/net/usb/smsc75xx.c131
-rw-r--r--drivers/net/usb/smsc95xx.c90
-rw-r--r--drivers/net/usb/usbnet.c6
11 files changed, 167 insertions, 193 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 3ec22c307797..9d4f9117260f 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -258,7 +258,7 @@ config USB_NET_NET1080
optionally with LEDs that indicate traffic
config USB_NET_PLUSB
- tristate "Prolific PL-2301/2302 based cables"
+ tristate "Prolific PL-2301/2302/25A1 based cables"
# if the handshake/init/reset problems, from original 'plusb',
# are ever resolved ... then remove "experimental"
depends on USB_USBNET && EXPERIMENTAL
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6140b56cce53..6998aa6b7bb7 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net)
static int ax88172_link_reset(struct usbnet *dev)
{
u8 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev)
if (ecmd.duplex != DUPLEX_FULL)
mode |= ~AX88172_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
static int ax88772_link_reset(struct usbnet *dev)
{
u16 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88772_MEDIUM_DEFAULT;
- if (ecmd.speed != SPEED_100)
+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
mode &= ~AX_MEDIUM_PS;
if (ecmd.duplex != DUPLEX_FULL)
mode &= ~AX_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
static int ax88178_link_reset(struct usbnet *dev)
{
u16 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
struct asix_data *data = (struct asix_data *)&dev->data;
+ u32 speed;
netdev_dbg(dev->net, "ax88178_link_reset()\n");
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88178_MEDIUM_DEFAULT;
+ speed = ethtool_cmd_speed(&ecmd);
- if (ecmd.speed == SPEED_1000)
+ if (speed == SPEED_1000)
mode |= AX_MEDIUM_GM;
- else if (ecmd.speed == SPEED_100)
+ else if (speed == SPEED_100)
mode |= AX_MEDIUM_PS;
else
mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev)
else
mode &= ~AX_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
- marvell_led_status(dev, ecmd.speed);
+ marvell_led_status(dev, speed);
return 0;
}
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 97687d335903..d7221c4a5dcf 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -686,7 +686,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = DUPLEX_HALF;
cmd->port = PORT_TP;
cmd->phy_address = 0;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 1033ef6476a4..4ab557d0287d 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -54,13 +54,13 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
-#define DRIVER_VERSION "23-Apr-2011"
+#define DRIVER_VERSION "06-May-2011"
/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
/* Maximum NTB length */
-#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */
+#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */
#define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */
/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
@@ -722,7 +722,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
} else {
/* reset variables */
- skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC);
+ skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC);
if (skb_out == NULL) {
if (skb != NULL) {
dev_kfree_skb_any(skb);
@@ -861,8 +861,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
/* store last offset */
last_offset = offset;
- if ((last_offset < ctx->tx_max) && ((last_offset %
- le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) {
+ if (((last_offset < ctx->tx_max) && ((last_offset %
+ le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) ||
+ (((last_offset == ctx->tx_max) && ((ctx->tx_max %
+ le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) &&
+ (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) {
/* force short packet */
*(((u8 *)skb_out->data) + last_offset) = 0;
last_offset++;
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 5002f5be47be..1d93133e9b74 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
static int dm9601_link_reset(struct usbnet *dev)
{
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
- netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
- ecmd.speed, ecmd.duplex);
+ netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex);
return 0;
}
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index 823c53751307..217aec8a768f 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -45,6 +45,14 @@
* seems to get wedged under load. Prolific docs are weak, and
* don't identify differences between PL2301 and PL2302, much less
* anything to explain the different PL2302 versions observed.
+ *
+ * NOTE: pl2501 has several modes, including pl2301 and pl2302
+ * compatibility. Some docs suggest the difference between 2301
+ * and 2302 is only to make MS-Windows use a different driver...
+ *
+ * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on
+ * this chip are as usual incomplete about what control messages
+ * are supported.
*/
/*
@@ -86,16 +94,20 @@ pl_set_QuickLink_features(struct usbnet *dev, int val)
static int pl_reset(struct usbnet *dev)
{
+ int status;
+
/* some units seem to need this reset, others reject it utterly.
* FIXME be more like "naplink" or windows drivers.
*/
- (void) pl_set_QuickLink_features(dev,
+ status = pl_set_QuickLink_features(dev,
PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
+ if (status != 0 && netif_msg_probe(dev))
+ netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status);
return 0;
}
static const struct driver_info prolific_info = {
- .description = "Prolific PL-2301/PL-2302",
+ .description = "Prolific PL-2301/PL-2302/PL-25A1",
.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
.reset = pl_reset,
@@ -111,6 +123,7 @@ static const struct driver_info prolific_info = {
static const struct usb_device_id products [] = {
+/* full speed cables */
{
USB_DEVICE(0x067b, 0x0000), // PL-2301
.driver_info = (unsigned long) &prolific_info,
@@ -119,6 +132,15 @@ static const struct usb_device_id products [] = {
.driver_info = (unsigned long) &prolific_info,
},
+/* high speed cables */
+{
+ USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */
+ .driver_info = (unsigned long) &prolific_info,
+}, {
+ USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */
+ .driver_info = (unsigned long) &prolific_info,
+},
+
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
@@ -134,16 +156,16 @@ static struct usb_driver plusb_driver = {
static int __init plusb_init(void)
{
- return usb_register(&plusb_driver);
+ return usb_register(&plusb_driver);
}
module_init(plusb_init);
static void __exit plusb_exit(void)
{
- usb_deregister(&plusb_driver);
+ usb_deregister(&plusb_driver);
}
module_exit(plusb_exit);
MODULE_AUTHOR("David Brownell");
-MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver");
+MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 5994a25c56ac..255d6a424a6b 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
{
struct cdc_state *info = (void *) &dev->data;
+ struct usb_cdc_notification notification;
int master_ifnum;
int retval;
+ int partial;
unsigned count;
__le32 rsp;
u32 xid = 0, msg_len, request_id;
@@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
if (unlikely(retval < 0 || xid == 0))
return retval;
- // FIXME Seems like some devices discard responses when
- // we time out and cancel our "get response" requests...
- // so, this is fragile. Probably need to poll for status.
+ /* Some devices don't respond on the control channel until
+ * polled on the status channel, so do that first. */
+ if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) {
+ retval = usb_interrupt_msg(
+ dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->status->desc.bEndpointAddress),
+ &notification, sizeof(notification), &partial,
+ RNDIS_CONTROL_TIMEOUT_MS);
+ if (unlikely(retval < 0))
+ return retval;
+ }
- /* ignore status endpoint, just poll the control channel;
- * the request probably completed immediately
- */
+ /* Poll the control channel; the request probably completed immediately */
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
memset(buf, 0, CONTROL_BUFFER_SIZE);
@@ -581,17 +590,33 @@ static const struct driver_info rndis_info = {
.tx_fixup = rndis_tx_fixup,
};
+static const struct driver_info rndis_poll_status_info = {
+ .description = "RNDIS device (poll status before control)",
+ .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .data = RNDIS_DRIVER_DATA_POLL_STATUS,
+ .bind = rndis_bind,
+ .unbind = rndis_unbind,
+ .status = rndis_status,
+ .rx_fixup = rndis_rx_fixup,
+ .tx_fixup = rndis_tx_fixup,
+};
+
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
{
+ /* 2Wire HomePortal 1000SW */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042,
+ USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+ .driver_info = (unsigned long) &rndis_poll_status_info,
+}, {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
}, {
/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
- .driver_info = (unsigned long) &rndis_info,
+ .driver_info = (unsigned long) &rndis_poll_status_info,
}, {
/* RNDIS for tethering */
USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index e85c89c6706d..041fb7d43c4f 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -843,10 +843,11 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e
get_registers(dev, BMCR, 2, &bmcr);
get_registers(dev, ANLP, 2, &lpa);
if (bmcr & BMCR_ANENABLE) {
+ u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ?
+ SPEED_100 : SPEED_10);
+ ethtool_cmd_speed_set(ecmd, speed);
ecmd->autoneg = AUTONEG_ENABLE;
- ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
- SPEED_100 : SPEED_10;
- if (ecmd->speed == SPEED_100)
+ if (speed == SPEED_100)
ecmd->duplex = (lpa & LPA_100FULL) ?
DUPLEX_FULL : DUPLEX_HALF;
else
@@ -854,8 +855,8 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->speed = (bmcr & BMCR_SPEED100) ?
- SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10));
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
}
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 753ee6eb7edd..15b3d6888ae9 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -65,7 +65,6 @@ struct smsc75xx_priv {
struct usbnet *dev;
u32 rfe_ctl;
u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
- bool use_rx_csum;
struct mutex dataport_mutex;
spinlock_t rfe_ctl_lock;
struct work_struct set_multicast;
@@ -504,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
static int smsc75xx_link_reset(struct usbnet *dev)
{
struct mii_if_info *mii = &dev->mii;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
u16 lcladv, rmtadv;
int ret;
@@ -520,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)
lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
- netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x"
- " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+ netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x"
+ " rmtadv: %04x", ethtool_cmd_speed(&ecmd),
+ ecmd.duplex, lcladv, rmtadv);
return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
}
@@ -548,28 +548,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb)
"unexpected interrupt, intdata=0x%08X", intdata);
}
-/* Enable or disable Rx checksum offload engine */
-static int smsc75xx_set_rx_csum_offload(struct usbnet *dev)
-{
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
-
- if (pdata->use_rx_csum)
- pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
- else
- pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
-
- spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
-
- ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
- check_warn_return(ret, "Error writing RFE_CTL");
-
- return 0;
-}
-
static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)
{
return MAX_EEPROM_SIZE;
@@ -599,34 +577,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
}
-static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
- return pdata->use_rx_csum;
-}
-
-static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
- pdata->use_rx_csum = !!val;
-
- return smsc75xx_set_rx_csum_offload(dev);
-}
-
-static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
- else
- netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
static const struct ethtool_ops smsc75xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -638,12 +588,6 @@ 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_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_rx_csum = smsc75xx_ethtool_get_rx_csum,
- .set_rx_csum = smsc75xx_ethtool_set_rx_csum,
- .get_tso = ethtool_op_get_tso,
- .set_tso = smsc75xx_ethtool_set_tso,
};
static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -782,6 +726,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
return usbnet_change_mtu(netdev, new_mtu);
}
+/* Enable or disable Rx checksum offload engine */
+static int smsc75xx_set_features(struct net_device *netdev, u32 features)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
+
+ if (features & NETIF_F_RXCSUM)
+ pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
+ else
+ pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
+
+ spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
+ /* it's racing here! */
+
+ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+ check_warn_return(ret, "Error writing RFE_CTL");
+
+ return 0;
+}
+
static int smsc75xx_reset(struct usbnet *dev)
{
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
@@ -960,11 +928,7 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl);
/* Enable or disable checksum offload engines */
- ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE);
- ret = smsc75xx_set_rx_csum_offload(dev);
- check_warn_return(ret, "Failed to set rx csum offload: %d", ret);
-
- smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE);
+ smsc75xx_set_features(dev->net, dev->net->features);
smsc75xx_set_multicast(dev->net);
@@ -1037,6 +1001,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc75xx_ioctl,
.ndo_set_multicast_list = smsc75xx_set_multicast,
+ .ndo_set_features = smsc75xx_set_features,
};
static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -1065,10 +1030,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
- pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+ if (DEFAULT_TX_CSUM_ENABLE) {
+ dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ if (DEFAULT_TSO_ENABLE)
+ dev->net->features |= NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_TSO6;
+ }
+ if (DEFAULT_RX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_RXCSUM;
- /* We have to advertise SG otherwise TSO cannot be enabled */
- dev->net->features |= NETIF_F_SG;
+ dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
/* Init all registers */
ret = smsc75xx_reset(dev);
@@ -1091,10 +1063,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
}
}
-static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,
- u32 rx_cmd_b)
+static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
+ u32 rx_cmd_a, u32 rx_cmd_b)
{
- if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
+ if (!(dev->net->features & NETIF_F_RXCSUM) ||
+ unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
skb->ip_summed = CHECKSUM_NONE;
} else {
skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT));
@@ -1104,8 +1077,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,
static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
while (skb->len > 0) {
u32 rx_cmd_a, rx_cmd_b, align_count, size;
struct sk_buff *ax_skb;
@@ -1145,11 +1116,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
/* last frame in this batch */
if (skb->len == size) {
- if (pdata->use_rx_csum)
- smsc75xx_rx_csum_offload(skb, rx_cmd_a,
- rx_cmd_b);
- else
- skb->ip_summed = CHECKSUM_NONE;
+ smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a,
+ rx_cmd_b);
skb_trim(skb, skb->len - 4); /* remove fcs */
skb->truesize = size + sizeof(struct sk_buff);
@@ -1167,11 +1135,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
ax_skb->data = packet;
skb_set_tail_pointer(ax_skb, size);
- if (pdata->use_rx_csum)
- smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a,
- rx_cmd_b);
- else
- ax_skb->ip_summed = CHECKSUM_NONE;
+ smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a,
+ rx_cmd_b);
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
ax_skb->truesize = size + sizeof(struct sk_buff);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 48d4efdb4959..f74f3ce71526 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -52,8 +52,6 @@ struct smsc95xx_priv {
u32 hash_hi;
u32 hash_lo;
spinlock_t mac_cr_lock;
- bool use_tx_csum;
- bool use_rx_csum;
};
struct usb_context {
@@ -459,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
struct mii_if_info *mii = &dev->mii;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
unsigned long flags;
u16 lcladv, rmtadv;
u32 intdata;
@@ -474,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev)
lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
- netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n",
- ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+ netif_dbg(dev, link, dev->net,
+ "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
if (ecmd.duplex != DUPLEX_FULL) {
@@ -517,22 +516,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
}
/* Enable or disable Tx & Rx checksum offload engines */
-static int smsc95xx_set_csums(struct usbnet *dev)
+static int smsc95xx_set_features(struct net_device *netdev, u32 features)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ struct usbnet *dev = netdev_priv(netdev);
u32 read_buf;
- int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+ 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;
}
- if (pdata->use_tx_csum)
+ if (features & NETIF_F_HW_CSUM)
read_buf |= Tx_COE_EN_;
else
read_buf &= ~Tx_COE_EN_;
- if (pdata->use_rx_csum)
+ if (features & NETIF_F_RXCSUM)
read_buf |= Rx_COE_EN_;
else
read_buf &= ~Rx_COE_EN_;
@@ -576,43 +577,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev,
return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data);
}
-static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- return pdata->use_rx_csum;
-}
-
-static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- pdata->use_rx_csum = !!val;
-
- return smsc95xx_set_csums(dev);
-}
-
-static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- return pdata->use_tx_csum;
-}
-
-static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- pdata->use_tx_csum = !!val;
-
- ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
- return smsc95xx_set_csums(dev);
-}
-
static const struct ethtool_ops smsc95xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -624,10 +588,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = {
.get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
.get_eeprom = smsc95xx_ethtool_get_eeprom,
.set_eeprom = smsc95xx_ethtool_set_eeprom,
- .get_tx_csum = smsc95xx_ethtool_get_tx_csum,
- .set_tx_csum = smsc95xx_ethtool_set_tx_csum,
- .get_rx_csum = smsc95xx_ethtool_get_rx_csum,
- .set_rx_csum = smsc95xx_ethtool_set_rx_csum,
};
static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -755,7 +715,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
static int smsc95xx_reset(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- struct net_device *netdev = dev->net;
u32 read_buf, write_buf, burst_cap;
int ret = 0, timeout;
@@ -975,12 +934,7 @@ static int smsc95xx_reset(struct usbnet *dev)
}
/* Enable or disable checksum offload engines */
- ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
- ret = smsc95xx_set_csums(dev);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret);
- return ret;
- }
+ smsc95xx_set_features(dev->net, dev->net->features);
smsc95xx_set_multicast(dev->net);
@@ -1019,6 +973,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc95xx_ioctl,
.ndo_set_multicast_list = smsc95xx_set_multicast,
+ .ndo_set_features = smsc95xx_set_features,
};
static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -1045,8 +1000,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
spin_lock_init(&pdata->mac_cr_lock);
- pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
- pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+ if (DEFAULT_TX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_HW_CSUM;
+ if (DEFAULT_RX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_RXCSUM;
+
+ dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
smsc95xx_init_mac_address(dev);
@@ -1056,7 +1015,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->netdev_ops = &smsc95xx_netdev_ops;
dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
dev->net->flags |= IFF_MULTICAST;
- dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD;
+ dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
return 0;
}
@@ -1080,8 +1039,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
while (skb->len > 0) {
u32 header, align_count;
struct sk_buff *ax_skb;
@@ -1123,7 +1080,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
/* last frame in this batch */
if (skb->len == size) {
- if (pdata->use_rx_csum)
+ if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(skb);
skb_trim(skb, skb->len - 4); /* remove fcs */
skb->truesize = size + sizeof(struct sk_buff);
@@ -1141,7 +1098,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
ax_skb->data = packet;
skb_set_tail_pointer(ax_skb, size);
- if (pdata->use_rx_csum)
+ if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(ax_skb);
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
ax_skb->truesize = size + sizeof(struct sk_buff);
@@ -1174,8 +1131,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL);
+ bool csum = skb->ip_summed == CHECKSUM_PARTIAL;
int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
u32 tx_cmd_a, tx_cmd_b;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 9ab439d144ed..e6dd24466965 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1541,9 +1541,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
static int __init usbnet_init(void)
{
- /* compiler should optimize this out */
- BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
- < sizeof (struct skb_data));
+ /* Compiler should optimize this out. */
+ BUILD_BUG_ON(
+ FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data));
random_ether_addr(node_id);
return 0;