diff options
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 85 |
1 files changed, 40 insertions, 45 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 3c5bd1e4ee..00267f282c 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -5,8 +5,9 @@ #include <command.h> #include <init.h> #include <net.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> +#include <asm/unaligned.h> #include <malloc.h> #include <asm/byteorder.h> #include <errno.h> @@ -23,8 +24,6 @@ #define MAX_SINGLE_PACKET_SIZE (2048) #define LAN95XX_EEPROM_MAGIC (0x9500) #define EEPROM_MAC_OFFSET (0x01) -#define DEFAULT_TX_CSUM_ENABLE (1) -#define DEFAULT_RX_CSUM_ENABLE (1) #define SMSC95XX_INTERNAL_PHY_ID (1) #define SMSC95XX_TX_OVERHEAD (8) #define SMSC95XX_TX_OVERHEAD_CSUM (12) @@ -45,25 +44,25 @@ struct smsc95xx_priv { u32 mac_cr; - int use_tx_csum; - int use_rx_csum; + __le32 *iobuf; }; static int turbo_mode = 0; static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); int ret; ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, data, 4, USB_CTRL_GET_TIMEOUT); + 00, index, pdata->iobuf, 4, USB_CTRL_GET_TIMEOUT); if (ret < 0) netdev_warn(dev->net, "Failed to read register index 0x%08x\n", index); - - le32_to_cpus(data); + else + *data = le32_to_cpup(pdata->iobuf); debug("%s: 0x%08x 0x%08x\n", __func__, index, *data); @@ -72,14 +71,15 @@ static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); int ret; - cpu_to_le32s(&data); + *pdata->iobuf = cpu_to_le32(data); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, &data, 4, USB_CTRL_SET_TIMEOUT); + 00, index, pdata->iobuf, 4, USB_CTRL_SET_TIMEOUT); if (ret < 0) netdev_warn(dev->net, "Failed to write register index 0x%08x\n", index); @@ -319,10 +319,9 @@ static void smsc95xx_set_multicast(struct usbnet *dev) smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); } -/* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct usbnet *dev) +/* Disable Tx & Rx IP checksum offload engines */ +static int smsc95xx_disable_csums(struct usbnet *dev) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); u32 read_buf; int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { @@ -330,15 +329,8 @@ static int smsc95xx_set_csums(struct usbnet *dev) return ret; } - if (pdata->use_tx_csum) - read_buf |= Tx_COE_EN_; - else - read_buf &= ~Tx_COE_EN_; - - if (pdata->use_rx_csum) - read_buf |= Rx_COE_EN_; - else - read_buf &= ~Rx_COE_EN_; + read_buf &= ~Tx_COE_EN_; + read_buf &= ~Rx_COE_EN_; ret = smsc95xx_write_reg(dev, COE_CR, read_buf); if (ret < 0) { @@ -669,7 +661,13 @@ static int smsc95xx_reset(struct usbnet *dev) return ret; } - ret = smsc95xx_set_csums(dev); + /* + * barebox network stack doesn't care for hardware checksum offloading, + * so this enabling them doesn't help and indeed introduces breakage: + * The driver will be unaware of the two byte COE trailer and thus packet + * sizes reported will be 2 bytes more than what was actually transmitted. + */ + ret = smsc95xx_disable_csums(dev); if (ret < 0) { netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); return ret; @@ -723,8 +721,7 @@ static int smsc95xx_bind(struct usbnet *dev) return -ENOMEM; } - pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + pdata->iobuf = dma_alloc(4); /* Init all registers */ ret = smsc95xx_reset(dev); @@ -757,8 +754,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len) unsigned char *packet; u16 size; - memcpy(&header, buf, sizeof(header)); - le32_to_cpus(&header); + header = get_unaligned_le32(buf); buf += 4 + NET_IP_ALIGN; len -= 4 + NET_IP_ALIGN; packet = buf; @@ -767,6 +763,12 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len) size = (u16)((header & RX_STS_FL_) >> 16); align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + if (unlikely(size > len)) { + netif_dbg(dev, rx_err, dev->net, + "size err header=0x%08x\n", header); + return 0; + } + if (header & RX_STS_ES_) { netif_dbg(dev, rx_err, dev->net, "Error header=0x%08x\n", header); @@ -784,14 +786,17 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len) return 1; } - net_receive(&dev->edev, packet, len - 4); + net_receive(&dev->edev, packet, size - 4); } len -= size; + buf += size; /* padding bytes before the next frame starts */ - if (len) + if (len) { len -= align_count; + buf += align_count; + } } if (len < 0) { @@ -801,28 +806,18 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len) return 1; } -#if 0 -static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) -{ - int len = skb->data - skb->head; - u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len); - u16 low_16 = (u16)(skb->csum_start - len); - return (high_16 << 16) | low_16; -} -#endif + static int smsc95xx_tx_fixup(struct usbnet *dev, void *buf, int len, void *nbuf, int *nlen) { u32 tx_cmd_a, tx_cmd_b; - tx_cmd_a = (u32)(len) | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - cpu_to_le32s(&tx_cmd_a); - memcpy(nbuf, &tx_cmd_a, 4); + tx_cmd_b = (u32)len; + tx_cmd_a = tx_cmd_b | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - tx_cmd_b = (u32)(len); - cpu_to_le32s(&tx_cmd_b); - memcpy(nbuf + 4, &tx_cmd_b, 4); + put_unaligned_le32(tx_cmd_a, nbuf); + put_unaligned_le32(tx_cmd_b, nbuf + 4); memcpy(nbuf + 8, buf, len); |