[U-Boot] [PATCHv2 0/5] net: ASIX AX88772B enablement

Hi all,
This series supersedes the earlier posted patches to support the AX88772B chip. I've split this up into a series as what started as a small patch to get the chip working turned into a journey through the usbeth stack and now not only reworks a lot of the ASIX code, but also touches other parts of the stack.
I want to thank Marek, Joe and Mike for their review, valueable feedback and guidance.
I've verified that we are now actually able to override the MAC address from the environment. All review feedback so far has been incorporated.
v2: Hopefully last round of this patches. - drop patch 2 - it's not a good idea - use correct malloc includes - introduce flags in the correct patches - now really constify asix_dongles[]
Lucas Stach (5): net: introduce transparent driver private in ueth_data net: asix: split out basic reset function net: asix: add write_hwaddr function net: asix: add read_mac function net: asix: add AX88772B support
drivers/usb/eth/asix.c | 180 ++++++++++++++++++++++++++++++++------------- drivers/usb/eth/smsc95xx.c | 48 ++++++++---- include/usb_ether.h | 8 +- 3 files changed, 165 insertions(+), 71 deletions(-)

Avoid clutter in ueth_data. Individual drivers should not mess with structures belonging to the core like this.
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com --- drivers/usb/eth/smsc95xx.c | 48 ++++++++++++++++++++++++++++++++-------------- include/usb_ether.h | 8 ++------ 2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index c62a8c1..e44dff6 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -25,6 +25,7 @@ #include <usb.h> #include <linux/mii.h> #include "usb_ether.h" +#include <malloc.h>
/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
@@ -146,6 +147,12 @@ /* local vars */ static int curr_eth_dev; /* index for name of next device detected */
+/* driver private */ +struct smsc95xx_private { + size_t rx_urb_size; /* maximum USB URB size */ + u32 mac_cr; /* MAC control register value */ + int have_hwaddr; /* 1 if we have a hardware MAC address */ +};
/* * Smsc95xx infrastructure commands @@ -377,6 +384,7 @@ static int smsc95xx_init_mac_address(struct eth_device *eth, static int smsc95xx_write_hwaddr(struct eth_device *eth) { struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct smsc95xx_private *priv = dev->dev_priv; u32 addr_lo = __get_unaligned_le32(ð->enetaddr[0]); u32 addr_hi = __get_unaligned_le16(ð->enetaddr[4]); int ret; @@ -392,7 +400,7 @@ static int smsc95xx_write_hwaddr(struct eth_device *eth) return ret;
debug("MAC %pM\n", eth->enetaddr); - dev->have_hwaddr = 1; + priv->have_hwaddr = 1; return 0; }
@@ -425,19 +433,22 @@ static int smsc95xx_set_csums(struct ueth_data *dev,
static void smsc95xx_set_multicast(struct ueth_data *dev) { + struct smsc95xx_private *priv = dev->dev_priv; + /* No multicast in u-boot */ - dev->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); }
/* starts the TX path */ static void smsc95xx_start_tx_path(struct ueth_data *dev) { + struct smsc95xx_private *priv = dev->dev_priv; u32 reg_val;
/* Enable Tx at MAC */ - dev->mac_cr |= MAC_CR_TXEN_; + priv->mac_cr |= MAC_CR_TXEN_;
- smsc95xx_write_reg(dev, MAC_CR, dev->mac_cr); + smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
/* Enable Tx at SCSRs */ reg_val = TX_CFG_ON_; @@ -447,8 +458,10 @@ static void smsc95xx_start_tx_path(struct ueth_data *dev) /* Starts the Receive path */ static void smsc95xx_start_rx_path(struct ueth_data *dev) { - dev->mac_cr |= MAC_CR_RXEN_; - smsc95xx_write_reg(dev, MAC_CR, dev->mac_cr); + struct smsc95xx_private *priv = dev->dev_priv; + + priv->mac_cr |= MAC_CR_RXEN_; + smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); }
/* @@ -462,6 +475,7 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) u32 burst_cap; int timeout; struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct smsc95xx_private *priv = (struct smsc95xx_private *)dev->dev_priv; #define TIMEOUT_RESOLUTION 50 /* ms */ int link_detected;
@@ -504,9 +518,9 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) debug("timeout waiting for PHY Reset\n"); return -1; } - if (!dev->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) - dev->have_hwaddr = 1; - if (!dev->have_hwaddr) { + if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) + priv->have_hwaddr = 1; + if (!priv->have_hwaddr) { puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); return -1; } @@ -532,16 +546,16 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) #ifdef TURBO_MODE if (dev->pusb_dev->speed == USB_SPEED_HIGH) { burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; + priv->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; } else { burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; - dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; + priv->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; } #else burst_cap = 0; - dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; + priv->rx_urb_size = MAX_SINGLE_PACKET_SIZE; #endif - debug("rx_urb_size=%ld\n", (ulong)dev->rx_urb_size); + debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); if (ret < 0) @@ -606,7 +620,7 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, MAC_CR, &dev->mac_cr); + ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr); if (ret < 0) return ret;
@@ -857,6 +871,12 @@ int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum, return 0; } dev->privptr = (void *)ss; + + /* alloc driver private */ + ss->dev_priv = calloc(1, sizeof(struct smsc95xx_private)); + if (!ss->dev_priv) + return 0; + return 1; }
diff --git a/include/usb_ether.h b/include/usb_ether.h index a7fb26b..7c7aecb 100644 --- a/include/usb_ether.h +++ b/include/usb_ether.h @@ -50,12 +50,8 @@ struct ueth_data { unsigned char protocol; /* .............. */ unsigned char irqinterval; /* Intervall for IRQ Pipe */
- /* private fields for each driver can go here if needed */ -#ifdef CONFIG_USB_ETHER_SMSC95XX - size_t rx_urb_size; /* maximum USB URB size */ - u32 mac_cr; /* MAC control register value */ - int have_hwaddr; /* 1 if we have a hardware MAC address */ -#endif + /* driver private */ + void *dev_priv; };
/*

Hi Lucas,
On Wed, Aug 22, 2012 at 4:04 PM, Lucas Stach dev@lynxeye.de wrote:
Avoid clutter in ueth_data. Individual drivers should not mess with structures belonging to the core like this.
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com
Failed checkpatch.pl.
Fixed locally and applied.
Thanks, -Joe

The basic device reset ensures that the device is ready to service commands and does not need to get redone before each network operation.
Split out the basic reset from asix_init() and instead call it from asix_eth_get_info(), so that it only gets called once.
Signed-off-by: Lucas Stach dev@lynxeye.de Acked-by: Joe Hershberger joe.hershberger@ni.com --- drivers/usb/eth/asix.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-)
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 8fb7fc8..50cbbbd 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -310,55 +310,60 @@ static int mii_nway_restart(struct ueth_data *dev) return r; }
-/* - * Asix callbacks - */ -static int asix_init(struct eth_device *eth, bd_t *bd) +static int asix_basic_reset(struct ueth_data *dev) { int embd_phy; - ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); u16 rx_ctl; - struct ueth_data *dev = (struct ueth_data *)eth->priv; - int timeout = 0; -#define TIMEOUT_RESOLUTION 50 /* ms */ - int link_detected; - - debug("** %s()\n", __func__);
if (asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0) - goto out_err; + return -1;
/* 0x10 is the phy id of the embedded 10/100 ethernet phy */ embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL) < 0) { debug("Select PHY #1 failed\n"); - goto out_err; + return -1; }
if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0) - goto out_err; + return -1;
if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0) - goto out_err; + return -1;
if (embd_phy) { if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0) - goto out_err; + return -1; } else { if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0) - goto out_err; + return -1; }
rx_ctl = asix_read_rx_ctl(dev); debug("RX_CTL is 0x%04x after software reset\n", rx_ctl); if (asix_write_rx_ctl(dev, 0x0000) < 0) - goto out_err; + return -1;
rx_ctl = asix_read_rx_ctl(dev); debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+ return 0; +} + +/* + * Asix callbacks + */ +static int asix_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + int timeout = 0; +#define TIMEOUT_RESOLUTION 50 /* ms */ + int link_detected; + + debug("** %s()\n", __func__); + /* Get the MAC address */ if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf) < 0) { @@ -635,5 +640,8 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, eth->halt = asix_halt; eth->priv = ss;
+ if (asix_basic_reset(ss)) + return 0; + return 1; }

Hi Lucas,
On Wed, Aug 22, 2012 at 4:04 PM, Lucas Stach dev@lynxeye.de wrote:
The basic device reset ensures that the device is ready to service commands and does not need to get redone before each network operation.
Split out the basic reset from asix_init() and instead call it from asix_eth_get_info(), so that it only gets called once.
Signed-off-by: Lucas Stach dev@lynxeye.de Acked-by: Joe Hershberger joe.hershberger@ni.com
Applied, thanks.
-Joe

All ASIX chipsets aside from AX88172 are able to set the MAC address on the hardware level. Add a function to expose this ability.
To differentiate between chip types we now carry flags as driver private data. Also while touching the asix_dongles array constify this.
Signed-off-by: Lucas Stach dev@lynxeye.de --- drivers/usb/eth/asix.c | 61 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 50cbbbd..d5bfdb8 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -23,6 +23,7 @@ #include <usb.h> #include <linux/mii.h> #include "usb_ether.h" +#include <malloc.h>
/* ASIX AX8817X based USB 2.0 Ethernet Devices */ @@ -35,6 +36,7 @@ #define AX_CMD_WRITE_RX_CTL 0x10 #define AX_CMD_WRITE_IPG0 0x12 #define AX_CMD_READ_NODE_ID 0x13 +#define AX_CMD_WRITE_NODE_ID 0x14 #define AX_CMD_READ_PHY_ID 0x19 #define AX_CMD_WRITE_MEDIUM_MODE 0x1b #define AX_CMD_WRITE_GPIOS 0x1f @@ -97,9 +99,19 @@ #define AX_RX_URB_SIZE 2048 #define PHY_CONNECT_TIMEOUT 5000
+/* asix_flags defines */ +#define FLAG_NONE 0 +#define FLAG_TYPE_AX88172 (1U << 0) +#define FLAG_TYPE_AX88772 (1U << 1) + /* local vars */ static int curr_eth_dev; /* index for name of next device detected */
+/* driver private */ +struct asix_private { + int flags; +}; + /* * Asix infrastructure commands */ @@ -284,6 +296,21 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep) return ret; }
+static int asix_write_hwaddr(struct eth_device *eth) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + int ret; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); + + memcpy(buf, eth->enetaddr, ETH_ALEN); + + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf); + if (ret < 0) + debug("Failed to set MAC address: %02x\n", ret); + + return ret; +} + /* * mii commands */ @@ -539,19 +566,20 @@ void asix_eth_before_probe(void) struct asix_dongle { unsigned short vendor; unsigned short product; + int flags; };
-static struct asix_dongle asix_dongles[] = { - { 0x05ac, 0x1402 }, /* Apple USB Ethernet Adapter */ - { 0x07d1, 0x3c05 }, /* D-Link DUB-E100 H/W Ver B1 */ - { 0x0b95, 0x772a }, /* Cables-to-Go USB Ethernet Adapter */ - { 0x0b95, 0x7720 }, /* Trendnet TU2-ET100 V3.0R */ - { 0x0b95, 0x1720 }, /* SMC */ - { 0x0db0, 0xa877 }, /* MSI - ASIX 88772a */ - { 0x13b1, 0x0018 }, /* Linksys 200M v2.1 */ - { 0x1557, 0x7720 }, /* 0Q0 cable ethernet */ - { 0x2001, 0x3c05 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ - { 0x0000, 0x0000 } /* END - Do not remove */ +static const struct asix_dongle const asix_dongles[] = { + { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */ + { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */ + { 0x0b95, 0x772a, FLAG_TYPE_AX88772 }, /* Cables-to-Go USB Ethernet Adapter */ + { 0x0b95, 0x7720, FLAG_TYPE_AX88772 }, /* Trendnet TU2-ET100 V3.0R */ + { 0x0b95, 0x1720, FLAG_TYPE_AX88172 }, /* SMC */ + { 0x0db0, 0xa877, FLAG_TYPE_AX88772 }, /* MSI - ASIX 88772a */ + { 0x13b1, 0x0018, FLAG_TYPE_AX88172 }, /* Linksys 200M v2.1 */ + { 0x1557, 0x7720, FLAG_TYPE_AX88772 }, /* 0Q0 cable ethernet */ + { 0x2001, 0x3c05, FLAG_TYPE_AX88772 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ + { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */ };
/* Probe to see if a new device is actually an asix device */ @@ -588,6 +616,13 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, ss->subclass = iface_desc->bInterfaceSubClass; ss->protocol = iface_desc->bInterfaceProtocol;
+ /* alloc driver private */ + ss->dev_priv = calloc(1, sizeof(struct asix_private)); + if (!ss->dev_priv) + return 0; + + ((struct asix_private *)ss->dev_priv)->flags = asix_dongles[i].flags; + /* * We are expecting a minimum of 3 endpoints - in, out (bulk), and * int. We will ignore any others. @@ -629,6 +664,8 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, struct eth_device *eth) { + struct asix_private *priv = (struct asix_private *)ss->dev_priv; + if (!eth) { debug("%s: missing parameter.\n", __func__); return 0; @@ -638,6 +675,8 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, eth->send = asix_send; eth->recv = asix_recv; eth->halt = asix_halt; + if (!(priv->flags & FLAG_TYPE_AX88172)) + eth->write_hwaddr = asix_write_hwaddr; eth->priv = ss;
if (asix_basic_reset(ss))

Hi Lucas,
On Wed, Aug 22, 2012 at 4:04 PM, Lucas Stach dev@lynxeye.de wrote:
All ASIX chipsets aside from AX88172 are able to set the MAC address on the hardware level. Add a function to expose this ability.
To differentiate between chip types we now carry flags as driver private data. Also while touching the asix_dongles array constify this.
Signed-off-by: Lucas Stach dev@lynxeye.de
Acked-by: Joe Hershberger joe.hershberger@ni.com

Hi Lucas,
On Wed, Aug 22, 2012 at 4:04 PM, Lucas Stach dev@lynxeye.de wrote:
All ASIX chipsets aside from AX88172 are able to set the MAC address on the hardware level. Add a function to expose this ability.
To differentiate between chip types we now carry flags as driver private data. Also while touching the asix_dongles array constify this.
Signed-off-by: Lucas Stach dev@lynxeye.de
Failed checkpatch.pl
Fixed locally and applied.
Thanks, -Joe

Initial device MAC should be read while getting info about the device, so it's wrong to only read it in asix_init().
Add a dedicated function to read the initial MAC, which is also able to handle devices that have their initial MAC stored in EEPROM. Call this function inasix_eth_get_info().
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com --- drivers/usb/eth/asix.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index d5bfdb8..0d57de4 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -32,6 +32,7 @@ #define AX_CMD_READ_MII_REG 0x07 #define AX_CMD_WRITE_MII_REG 0x08 #define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_READ_EEPROM 0x0b #define AX_CMD_READ_RX_CTL 0x0f #define AX_CMD_WRITE_RX_CTL 0x10 #define AX_CMD_WRITE_IPG0 0x12 @@ -103,6 +104,7 @@ #define FLAG_NONE 0 #define FLAG_TYPE_AX88172 (1U << 0) #define FLAG_TYPE_AX88772 (1U << 1) +#define FLAG_EEPROM_MAC (1U << 2) /* initial mac address in eeprom */
/* local vars */ static int curr_eth_dev; /* index for name of next device detected */ @@ -337,6 +339,33 @@ static int mii_nway_restart(struct ueth_data *dev) return r; }
+static int asix_read_mac(struct eth_device *eth) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct asix_private *priv = (struct asix_private *)dev->dev_priv; + int i; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); + + if (priv->flags & FLAG_EEPROM_MAC) { + for (i = 0; i < (ETH_ALEN >> 1); i++) { + if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, + 0x04 + i, 0, 2, buf) < 0) { + debug("Failed to read SROM address 04h.\n"); + return -1; + } + memcpy((eth->enetaddr + i * 2), buf, 2); + } + } else { + if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf) < 0) { + debug("Failed to read MAC address.\n"); + return -1; + } + memcpy(eth->enetaddr, buf, ETH_ALEN); + } + + return 0; +} + static int asix_basic_reset(struct ueth_data *dev) { int embd_phy; @@ -391,18 +420,6 @@ static int asix_init(struct eth_device *eth, bd_t *bd)
debug("** %s()\n", __func__);
- /* Get the MAC address */ - if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, - 0, 0, ETH_ALEN, buf) < 0) { - debug("Failed to read MAC address.\n"); - goto out_err; - } - memcpy(eth->enetaddr, buf, ETH_ALEN); - debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - eth->enetaddr[0], eth->enetaddr[1], - eth->enetaddr[2], eth->enetaddr[3], - eth->enetaddr[4], eth->enetaddr[5]); - dev->phy_id = asix_get_phy_addr(dev); if (dev->phy_id < 0) debug("Failed to read phy id\n"); @@ -682,5 +699,10 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, if (asix_basic_reset(ss)) return 0;
+ /* Get the MAC address */ + if (asix_read_mac(eth)) + return 0; + debug("MAC %pM\n", eth->enetaddr); + return 1; }

Hi Lucas,
On Wed, Aug 22, 2012 at 4:05 PM, Lucas Stach dev@lynxeye.de wrote:
Initial device MAC should be read while getting info about the device, so it's wrong to only read it in asix_init().
Add a dedicated function to read the initial MAC, which is also able to handle devices that have their initial MAC stored in EEPROM. Call this function inasix_eth_get_info().
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com
Failed checkpatch.pl
Fixed locally and applied.
Thanks, -Joe

Add AX88772B ID together with two fixes needed to make this work.
1. The packet length check has to be adjusted, as all ASIX chips only use 11 bits to indicate the length. AX88772B uses the other bits to indicate unrelated things, which cause the check to fail. This fix is based on a fix for the Linux kernel by Marek Vasut. Linux upstream commit: bca0beb9363f8487ac902931a50eb00180a2d14a
2. AX88772B provides several bulk endpoints. Only the first IN/OUT endpoints work in the default configuration. So stop enumeration after we found them to avoid overwriting the endpoint config with a non-working one.
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com --- drivers/usb/eth/asix.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 0d57de4..2271cf2 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -104,7 +104,8 @@ #define FLAG_NONE 0 #define FLAG_TYPE_AX88172 (1U << 0) #define FLAG_TYPE_AX88772 (1U << 1) -#define FLAG_EEPROM_MAC (1U << 2) /* initial mac address in eeprom */ +#define FLAG_TYPE_AX88772B (1U << 2) +#define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */
/* local vars */ static int curr_eth_dev; /* index for name of next device detected */ @@ -542,13 +543,13 @@ static int asix_recv(struct eth_device *eth) } memcpy(&packet_len, buf_ptr, sizeof(packet_len)); le32_to_cpus(&packet_len); - if (((packet_len >> 16) ^ 0xffff) != (packet_len & 0xffff)) { + if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) { debug("Rx: malformed packet length: %#x (%#x:%#x)\n", - packet_len, (packet_len >> 16) ^ 0xffff, - packet_len & 0xffff); + packet_len, (~packet_len >> 16) & 0x7ff, + packet_len & 0x7ff); return -1; } - packet_len = packet_len & 0xffff; + packet_len = packet_len & 0x7ff; if (packet_len > actual_len - sizeof(packet_len)) { debug("Rx: too large packet: %d\n", packet_len); return -1; @@ -596,6 +597,7 @@ static const struct asix_dongle const asix_dongles[] = { { 0x13b1, 0x0018, FLAG_TYPE_AX88172 }, /* Linksys 200M v2.1 */ { 0x1557, 0x7720, FLAG_TYPE_AX88772 }, /* 0Q0 cable ethernet */ { 0x2001, 0x3c05, FLAG_TYPE_AX88772 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ + { 0x0b95, 0x772b, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC }, /* ASIX 88772B */ { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */ };
@@ -605,6 +607,7 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, { struct usb_interface *iface; struct usb_interface_descriptor *iface_desc; + int ep_in_found = 0, ep_out_found = 0; int i;
/* let's examine the device now */ @@ -648,13 +651,19 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, /* is it an BULK endpoint? */ if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { - if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) - ss->ep_in = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - else - ss->ep_out = - iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; + if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) { + if (!ep_in_found) { + ss->ep_in = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + ep_in_found = 1; + } + } else { + if (!ep_out_found) { + ss->ep_out = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + ep_out_found = 1; + } + } }
/* is it an interrupt endpoint? */

Hi Lucas,
On Wed, Aug 22, 2012 at 4:05 PM, Lucas Stach dev@lynxeye.de wrote:
Add AX88772B ID together with two fixes needed to make this work.
- The packet length check has to be adjusted, as all ASIX chips
only use 11 bits to indicate the length. AX88772B uses the other bits to indicate unrelated things, which cause the check to fail. This fix is based on a fix for the Linux kernel by Marek Vasut. Linux upstream commit: bca0beb9363f8487ac902931a50eb00180a2d14a
- AX88772B provides several bulk endpoints. Only the first
IN/OUT endpoints work in the default configuration. So stop enumeration after we found them to avoid overwriting the endpoint config with a non-working one.
Signed-off-by: Lucas Stach dev@lynxeye.de Reviewed-by: Marek Vasut marex@denx.de Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com
Failed checkpatch.pl
Fixed locally and applied.
Thanks, -Joe
participants (2)
-
Joe Hershberger
-
Lucas Stach