diff options
author | Christian Riesch <christian.riesch@omicron.at> | 2012-07-13 05:26:30 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-16 23:26:23 -0700 |
commit | 607740bc1605395c96b09416cdcc5e77c8976eed (patch) | |
tree | 684d41f965a2b5771a1dbef9501fa51a5fa73a23 /drivers/net/usb | |
parent | b4cdae20ef956fb80b231cbbcfcdb446fed763ca (diff) | |
download | linux-607740bc1605395c96b09416cdcc5e77c8976eed.tar.bz2 |
asix: Factor out common code
Allow the new driver for the AX88172A to share code with the
existing drivers for ASIX devices.
Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/usb/asix.h | 1532 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 1203 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c | 660 |
4 files changed, 64 insertions, 3333 deletions
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 2c8f7b4a5d8c..a9490d9a4e98 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_HSO) += hso.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o -asix-y := asix_devices.o +asix-y := asix_devices.o asix_common.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index 6564c32d3af0..790af241f197 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h @@ -20,6 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef _ASIX_H +#define _ASIX_H + // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages @@ -152,20 +155,6 @@ #define AX88172_EEPROM_LEN 0x40 #define AX88772_EEPROM_LEN 0xff -#define PHY_MODE_MARVELL 0x0000 -#define MII_MARVELL_LED_CTRL 0x0018 -#define MII_MARVELL_STATUS 0x001b -#define MII_MARVELL_CTRL 0x0014 - -#define MARVELL_LED_MANUAL 0x0019 - -#define MARVELL_STATUS_HWCFG 0x0004 - -#define MARVELL_CTRL_TXDELAY 0x0002 -#define MARVELL_CTRL_RXDELAY 0x0080 - -#define PHY_MODE_RTL8211CL 0x000C - /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ struct asix_data { u8 multi_filter[AX_MCAST_FILTER_SIZE]; @@ -175,1506 +164,49 @@ struct asix_data { u8 eeprom_len; }; -struct ax88172_int_data { - __le16 res1; - u8 link; - __le16 res2; - u8 status; - __le16 res3; -} __packed; - -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - goto out; - - err = usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_GET_TIMEOUT); - if (err == size) - memcpy(data, buf, size); - else if (err >= 0) - err = -EINVAL; - kfree(buf); - -out: - return err; -} - -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf = NULL; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - if (data) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - goto out; - } - - err = usb_control_msg( - dev->udev, - usb_sndctrlpipe(dev->udev, 0), - cmd, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_SET_TIMEOUT); - kfree(buf); - -out: - return err; -} - -static void asix_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - - if (status < 0) - printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - status); - - kfree(req); - usb_free_urb(urb); -} - -static void -asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - struct usb_ctrlrequest *req; - int status; - struct urb *urb; - - netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - netdev_err(dev->net, "Failed to allocate memory for control request\n"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = cmd; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(index); - req->wLength = cpu_to_le16(size); - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, size, - asix_async_cmd_callback, req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - netdev_err(dev->net, "Error submitting the control message: status=%d\n", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int offset = 0; - - while (offset + sizeof(u32) < skb->len) { - struct sk_buff *ax_skb; - u16 size; - u32 header = get_unaligned_le32(skb->data + offset); - - offset += sizeof(u32); - - /* get the packet length */ - size = (u16) (header & 0x7ff); - if (size != ((~header >> 16) & 0x07ff)) { - netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); - return 0; - } - - if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || - (size + offset > skb->len)) { - netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", - size); - return 0; - } - ax_skb = netdev_alloc_skb_ip_align(dev->net, size); - if (!ax_skb) - return 0; - - skb_put(ax_skb, size); - memcpy(ax_skb->data, skb->data + offset, size); - usbnet_skb_return(dev, ax_skb); - - offset += (size + 1) & 0xfffe; - } - - if (skb->len != offset) { - netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", - skb->len); - return 0; - } - return 1; -} - -static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 packet_len; - u32 padbytes = 0xffff0000; - - padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; - - /* We need to push 4 bytes in front of frame (packet_len) - * and maybe add 4 bytes after the end (if padlen is 4) - * - * Avoid skb_copy_expand() expensive call, using following rules : - * - We are allowed to push 4 bytes in headroom if skb_header_cloned() - * is false (and if we have 4 bytes of headroom) - * - We are allowed to put 4 bytes at tail if skb_cloned() - * is false (and if we have 4 bytes of tailroom) - * - * TCP packets for example are cloned, but skb_header_release() - * was called in tcp stack, allowing us to use headroom for our needs. - */ - if (!skb_header_cloned(skb) && - !(padlen && skb_cloned(skb)) && - headroom + tailroom >= 4 + padlen) { - /* following should not happen, but better be safe */ - if (headroom < 4 || - tailroom < padlen) { - skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - } - } else { - struct sk_buff *skb2; - - skb2 = skb_copy_expand(skb, 4, padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; - skb_push(skb, 4); - cpu_to_le32s(&packet_len); - skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); - - if (padlen) { - cpu_to_le32s(&padbytes); - memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); - skb_put(skb, sizeof(padbytes)); - } - return skb; -} - -static void asix_status(struct usbnet *dev, struct urb *urb) -{ - struct ax88172_int_data *event; - int link; - - if (urb->actual_length < 8) - return; - - event = urb->transfer_buffer; - link = event->link & 0x01; - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } -} - -static inline int asix_set_sw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable software MII access\n"); - return ret; -} - -static inline int asix_set_hw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable hardware MII access\n"); - return ret; -} - -static inline int asix_get_phy_addr(struct usbnet *dev) -{ - u8 buf[2]; - int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); - - netdev_dbg(dev->net, "asix_get_phy_addr()\n"); - - if (ret < 0) { - netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); - goto out; - } - netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", - *((__le16 *)buf)); - ret = buf[1]; - -out: - return ret; -} - -static int asix_sw_reset(struct usbnet *dev, u8 flags) -{ - int ret; - - ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); - - return ret; -} - -static u16 asix_read_rx_ctl(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); - goto out; - } - ret = le16_to_cpu(v); -out: - return ret; -} - -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static u16 asix_read_medium_status(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading Medium Status register: %02x\n", - ret); - return ret; /* TODO: callers not checking for error ret */ - } - - return le16_to_cpu(v); - -} - -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", - value, ret); - - if (sleep) - msleep(sleep); - - return ret; -} - -/* - * AX88772 & AX88178 have a 16-bit RX_CTL value - */ -static void asix_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u16 rx_ctl = AX_DEFAULT_RX_CTL; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= AX_RX_CTL_PRO; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= AX_RX_CTL_AMALL; - } else if (netdev_mc_empty(net)) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= AX_RX_CTL_AM; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - __le16 res; - - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, - (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); - - netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", - phy_id, loc, le16_to_cpu(res)); - - return le16_to_cpu(res); -} - -static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - __le16 res = cpu_to_le16(val); - - netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", - phy_id, loc, val); - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); -} - -/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ -static u32 asix_get_phyid(struct usbnet *dev) -{ - int phy_reg; - u32 phy_id; - int i; - - /* Poll for the rare case the FW or phy isn't ready yet. */ - for (i = 0; i < 100; i++) { - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg != 0 && phy_reg != 0xFFFF) - break; - mdelay(1); - } - - if (phy_reg <= 0 || phy_reg == 0xFFFF) - return 0; - - phy_id = (phy_reg & 0xffff) << 16; - - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); - if (phy_reg < 0) - return 0; - - phy_id |= (phy_reg & 0xffff); - - return phy_id; -} - -static void -asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt; - - if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { - wolinfo->supported = 0; - wolinfo->wolopts = 0; - return; - } - wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = 0; - if (opt & AX_MONITOR_LINK) - wolinfo->wolopts |= WAKE_PHY; - if (opt & AX_MONITOR_MAGIC) - wolinfo->wolopts |= WAKE_MAGIC; -} - -static int -asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt = 0; - - if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; - if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - - if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, NULL) < 0) - return -EINVAL; - - return 0; -} - -static int asix_get_eeprom_len(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - return data->eeprom_len; -} - -static int asix_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct usbnet *dev = netdev_priv(net); - __le16 *ebuf = (__le16 *)data; - int i; - - /* Crude hack to ensure that we don't overwrite memory - * if an odd length is supplied - */ - if (eeprom->len % 2) - return -EINVAL; - - eeprom->magic = AX_EEPROM_MAGIC; - - /* ax8817x returns 2 bytes from eeprom on read */ - for (i=0; i < eeprom->len / 2; i++) { - if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static void asix_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - strncpy (info->driver, DRIVER_NAME, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - info->eedump_len = data->eeprom_len; -} - -static u32 asix_get_link(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_link_ok(&dev->mii); -} - -static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -static int asix_set_mac_address(struct net_device *net, void *p) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - struct sockaddr *addr = p; - - if (netif_running(net)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); - - /* We use the 20 byte dev->data - * for our 6 byte mac buffer - * to avoid allocating memory that - * is tricky to free later */ - memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); - asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - - return 0; -} - -/* We need to override some ethtool_ops so we require our - own structure so we don't interfere with other usbnet - devices that may be connected at the same time. */ -static const struct ethtool_ops ax88172_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static void ax88172_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u8 rx_ctl = 0x8c; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (netdev_mc_empty(net)) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); +int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data); - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } +int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data); - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); +void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, + u16 index, u16 size, void *data); - rx_ctl |= 0x10; - } +int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb); - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} +struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags); -static int ax88172_link_reset(struct usbnet *dev) -{ - u8 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; +int asix_set_sw_mii(struct usbnet *dev); +int asix_set_hw_mii(struct usbnet *dev); - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88172_MEDIUM_DEFAULT; +int asix_get_phy_addr(struct usbnet *dev); - if (ecmd.duplex != DUPLEX_FULL) - mode |= ~AX88172_MEDIUM_FD; +int asix_sw_reset(struct usbnet *dev, u8 flags); - netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); +u16 asix_read_rx_ctl(struct usbnet *dev); +int asix_write_rx_ctl(struct usbnet *dev, u16 mode); - asix_write_medium_mode(dev, mode); - - return 0; -} - -static const struct net_device_ops ax88172_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = ax88172_set_multicast, -}; - -static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - u8 buf[ETH_ALEN]; - int i; - unsigned long gpio_bits = dev->driver_info->data; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88172_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); - if (ret < 0) - goto out; - msleep(5); - } - - ret = asix_write_rx_ctl(dev, 0x80); - if (ret < 0) - goto out; - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88172_netdev_ops; - dev->net->ethtool_ops = &ax88172_ethtool_ops; - dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ - dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - mii_nway_restart(&dev->mii); - - return 0; - -out: - return ret; -} - -static const struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; +u16 asix_read_medium_status(struct usbnet *dev); +int asix_write_medium_mode(struct usbnet *dev, u16 mode); -static int ax88772_link_reset(struct usbnet *dev) -{ - u16 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; +int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88772_MEDIUM_DEFAULT; +void asix_set_multicast(struct net_device *net); - if (ethtool_cmd_speed(&ecmd) != SPEED_100) - mode &= ~AX_MEDIUM_PS; +int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); +void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); - if (ecmd.duplex != DUPLEX_FULL) - mode &= ~AX_MEDIUM_FD; +void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); +int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); - 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); - - return 0; -} - -static int ax88772_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret, embd_phy; - u16 rx_ctl; - - ret = asix_write_gpio(dev, - AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); - if (ret < 0) - goto out; - - embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); - - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - goto out; - - msleep(150); - - if (embd_phy) { - ret = asix_sw_reset(dev, AX_SWRESET_IPRL); - if (ret < 0) - goto out; - } else { - ret = asix_sw_reset(dev, AX_SWRESET_PRTE); - if (ret < 0) - goto out; - } - - msleep(150); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after software reset", rx_ctl); - ret = asix_write_rx_ctl(dev, 0x0000); - if (ret < 0) - goto out; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); - - ret = asix_sw_reset(dev, AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); - mii_nway_restart(&dev->mii); - - ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); - if (ret < 0) - goto out; - - ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, - AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, - AX88772_IPG2_DEFAULT, 0, NULL); - if (ret < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out; - } - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - goto out; - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - goto out; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); - - rx_ctl = asix_read_medium_status(dev); - dbg("Medium Status is 0x%04x after all initializations", rx_ctl); - - return 0; - -out: - return ret; - -} - -static const struct net_device_ops ax88772_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = asix_set_multicast, -}; - -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret, embd_phy; - struct asix_data *data = (struct asix_data *)&dev->data; - u8 buf[ETH_ALEN]; - u32 phyid; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88772_netdev_ops; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ - dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ - - embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); - - /* Reset the PHY to normal operation mode */ - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - return ret; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); - - /* Read PHYID register *AFTER* the PHY was reset properly */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; -} - -static const struct ethtool_ops ax88178_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int marvell_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - u16 reg; - - netdev_dbg(dev->net, "marvell_phy_init()\n"); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); - netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, - MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); - - if (data->ledmode) { - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); - - reg &= 0xf8ff; - reg |= (1 + 0x0100); - asix_mdio_write(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL, reg); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); - reg &= 0xfc0f; - } - - return 0; -} - -static int rtl8211cl_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - - netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); - - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, - asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - - if (data->ledmode == 12) { - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - } - - return 0; -} - -static int marvell_led_status(struct usbnet *dev, u16 speed) -{ - u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); - - netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); - - /* Clear out the center LED bits - 0x03F0 */ - reg &= 0xfc0f; - - switch (speed) { - case SPEED_1000: - reg |= 0x03e0; - break; - case SPEED_100: - reg |= 0x03b0; - break; - default: - reg |= 0x02f0; - } - - netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); - asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); - - return 0; -} - -static int ax88178_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret; - __le16 eeprom; - u8 status; - int gpio0 = 0; - u32 phyid; - - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); - dbg("GPIO Status: 0x%04x", status); - - asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); - asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); - asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); - - dbg("EEPROM index 0x17 is 0x%04x", eeprom); - - if (eeprom == cpu_to_le16(0xffff)) { - data->phymode = PHY_MODE_MARVELL; - data->ledmode = 0; - gpio0 = 1; - } else { - data->phymode = le16_to_cpu(eeprom) & 0x7F; - data->ledmode = le16_to_cpu(eeprom) >> 8; - gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; - } - dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); - - /* Power up external GigaPHY through AX88178 GPIO pin */ - asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); - if ((le16_to_cpu(eeprom) >> 8) != 1) { - asix_write_gpio(dev, 0x003c, 30); - asix_write_gpio(dev, 0x001c, 300); - asix_write_gpio(dev, 0x003c, 30); - } else { - dbg("gpio phymode == 1 path"); - asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); - asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); - } - - /* Read PHYID register *AFTER* powering up PHY */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ - asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); - - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - asix_write_rx_ctl(dev, 0); - - if (data->phymode == PHY_MODE_MARVELL) { - marvell_phy_init(dev); - msleep(60); - } else if (data->phymode == PHY_MODE_RTL8211CL) - rtl8211cl_phy_init(dev); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - BMCR_RESET | BMCR_ANENABLE); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, - ADVERTISE_1000FULL); - - mii_nway_restart(&dev->mii); - - ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); - if (ret < 0) - return ret; - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - return ret; - - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - return ret; - - return 0; -} - -static int ax88178_link_reset(struct usbnet *dev) -{ - u16 mode; - 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 (speed == SPEED_1000) - mode |= AX_MEDIUM_GM; - else if (speed == SPEED_100) - mode |= AX_MEDIUM_PS; - else - mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); - - mode |= AX_MEDIUM_ENCK; - - if (ecmd.duplex == DUPLEX_FULL) - mode |= AX_MEDIUM_FD; - else - mode &= ~AX_MEDIUM_FD; - - 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, speed); - - return 0; -} - -static void ax88178_set_mfb(struct usbnet *dev) -{ - u16 mfb = AX_RX_CTL_MFB_16384; - u16 rxctl; - u16 medium; - int old_rx_urb_size = dev->rx_urb_size; - - if (dev->hard_mtu < 2048) { - dev->rx_urb_size = 2048; - mfb = AX_RX_CTL_MFB_2048; - } else if (dev->hard_mtu < 4096) { - dev->rx_urb_size = 4096; - mfb = AX_RX_CTL_MFB_4096; - } else if (dev->hard_mtu < 8192) { - dev->rx_urb_size = 8192; - mfb = AX_RX_CTL_MFB_8192; - } else if (dev->hard_mtu < 16384) { - dev->rx_urb_size = 16384; - mfb = AX_RX_CTL_MFB_16384; - } - - rxctl = asix_read_rx_ctl(dev); - asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); - - medium = asix_read_medium_status(dev); - if (dev->net->mtu > 1500) - medium |= AX_MEDIUM_JFE; - else - medium &= ~AX_MEDIUM_JFE; - asix_write_medium_mode(dev, medium); - - if (dev->rx_urb_size > old_rx_urb_size) - usbnet_unlink_rx_urbs(dev); -} - -static int ax88178_change_mtu(struct net_device *net, int new_mtu) -{ - struct usbnet *dev = netdev_priv(net); - int ll_mtu = new_mtu + net->hard_header_len + 4; - - netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); - - if (new_mtu <= 0 || ll_mtu > 16384) - return -EINVAL; - - if ((ll_mtu % dev->maxpacket) == 0) - return -EDOM; - - net->mtu = new_mtu; - dev->hard_mtu = net->mtu + net->hard_header_len; - ax88178_set_mfb(dev); - - return 0; -} - -static const struct net_device_ops ax88178_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = asix_set_multicast, - .ndo_do_ioctl = asix_ioctl, - .ndo_change_mtu = ax88178_change_mtu, -}; - -static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - u8 buf[ETH_ALEN]; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0xff; - dev->mii.supports_gmii = 1; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88178_netdev_ops; - dev->net->ethtool_ops = &ax88178_ethtool_ops; - - /* Blink LEDS so users know driver saw dongle */ - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; -} - -static const struct driver_info ax8817x_info = { - .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, -}; - -static const struct driver_info dlink_dub_e100_info = { - .description = "DLink DUB-E100 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x009f9d9f, -}; - -static const struct driver_info netgear_fa120_info = { - .description = "Netgear FA-120 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, -}; - -static const struct driver_info hawking_uf200_info = { - .description = "Hawking UF200 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x001f1d1f, -}; - -static const struct driver_info ax88772_info = { - .description = "ASIX AX88772 USB 2.0 Ethernet", - .bind = ax88772_bind, - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct driver_info ax88178_info = { - .description = "ASIX AX88178 USB 2.0 Ethernet", - .bind = ax88178_bind, - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct usb_device_id products [] = { -{ - // Linksys USB200M - USB_DEVICE (0x077b, 0x2226), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Netgear FA120 - USB_DEVICE (0x0846, 0x1040), - .driver_info = (unsigned long) &netgear_fa120_info, -}, { - // DLink DUB-E100 - USB_DEVICE (0x2001, 0x1a00), - .driver_info = (unsigned long) &dlink_dub_e100_info, -}, { - // Intellinet, ST Lab USB Ethernet - USB_DEVICE (0x0b95, 0x1720), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Hawking UF200, TrendNet TU2-ET100 - USB_DEVICE (0x07b8, 0x420a), - .driver_info = (unsigned long) &hawking_uf200_info, -}, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ATEN UC210T - USB_DEVICE (0x0557, 0x2009), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-KTX - USB_DEVICE (0x0411, 0x003d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-GT 10/100/1000 - USB_DEVICE (0x0411, 0x006e), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" - USB_DEVICE (0x6189, 0x182d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" - USB_DEVICE (0x0df6, 0x0056), - .driver_info = (unsigned long) &ax88178_info, -}, { - // corega FEther USB2-TX - USB_DEVICE (0x07aa, 0x0017), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Surecom EP-1427X-2 - USB_DEVICE (0x1189, 0x0893), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // goodway corp usb gwusb2e - USB_DEVICE (0x1631, 0x6200), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // JVC MP-PRX1 Port Replicator - USB_DEVICE (0x04f1, 0x3008), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ASIX AX88772B 10/100 - USB_DEVICE (0x0b95, 0x772b), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88178 10/100/1000 - USB_DEVICE (0x0b95, 0x1780), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Logitec LAN-GTJ/U2A - USB_DEVICE (0x0789, 0x0160), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Linksys USB200M Rev 2 - USB_DEVICE (0x13b1, 0x0018), - .driver_info = (unsigned long) &ax88772_info, -}, { - // 0Q0 cable ethernet - USB_DEVICE (0x1557, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 - USB_DEVICE (0x07d1, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 Alternate - USB_DEVICE (0x2001, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Linksys USB1000 - USB_DEVICE (0x1737, 0x0039), - .driver_info = (unsigned long) &ax88178_info, -}, { - // IO-DATA ETG-US2 - USB_DEVICE (0x04bb, 0x0930), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Belkin F5D5055 - USB_DEVICE(0x050d, 0x5055), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Apple USB Ethernet Adapter - USB_DEVICE(0x05ac, 0x1402), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Cables-to-Go USB Ethernet Adapter - USB_DEVICE(0x0b95, 0x772a), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ABOCOM for pci - USB_DEVICE(0x14ea, 0xab11), - .driver_info = (unsigned long) &ax88178_info, -}, { - // ASIX 88772a - USB_DEVICE(0x0db0, 0xa877), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Asus USB Ethernet Adapter - USB_DEVICE (0x0b95, 0x7e2b), - .driver_info = (unsigned long) &ax88772_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver asix_driver = { - .name = DRIVER_NAME, - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, - .supports_autosuspend = 1, - .disable_hub_initiated_lpm = 1, -}; +int asix_get_eeprom_len(struct net_device *net); +int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, + u8 *data); -module_usb_driver(asix_driver); +void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); -MODULE_AUTHOR("David Hollis"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); -MODULE_LICENSE("GPL"); +int asix_set_mac_address(struct net_device *net, void *p); +#endif /* _ASIX_H */ diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 6564c32d3af0..3c1429a25ca4 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -20,171 +20,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/kmod.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#include <linux/if_vlan.h> - -#define DRIVER_VERSION "22-Dec-2011" -#define DRIVER_NAME "asix" - -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - -#define AX_CMD_SET_SW_MII 0x06 -#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_WRITE_EEPROM 0x0c -#define AX_CMD_WRITE_ENABLE 0x0d -#define AX_CMD_WRITE_DISABLE 0x0e -#define AX_CMD_READ_RX_CTL 0x0f -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_READ_IPG012 0x11 -#define AX_CMD_WRITE_IPG0 0x12 -#define AX_CMD_WRITE_IPG1 0x13 -#define AX_CMD_READ_NODE_ID 0x13 -#define AX_CMD_WRITE_NODE_ID 0x14 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX88172_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_READ_MEDIUM_STATUS 0x1a -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_READ_MONITOR_MODE 0x1c -#define AX_CMD_WRITE_MONITOR_MODE 0x1d -#define AX_CMD_READ_GPIOS 0x1e -#define AX_CMD_WRITE_GPIOS 0x1f -#define AX_CMD_SW_RESET 0x20 -#define AX_CMD_SW_PHY_STATUS 0x21 -#define AX_CMD_SW_PHY_SELECT 0x22 - -#define AX_MONITOR_MODE 0x01 -#define AX_MONITOR_LINK 0x02 -#define AX_MONITOR_MAGIC 0x04 -#define AX_MONITOR_HSFS 0x10 - -/* AX88172 Medium Status Register values */ -#define AX88172_MEDIUM_FD 0x02 -#define AX88172_MEDIUM_TX 0x04 -#define AX88172_MEDIUM_FC 0x10 -#define AX88172_MEDIUM_DEFAULT \ - ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_SWRESET_CLEAR 0x00 -#define AX_SWRESET_RR 0x01 -#define AX_SWRESET_RT 0x02 -#define AX_SWRESET_PRTE 0x04 -#define AX_SWRESET_PRL 0x08 -#define AX_SWRESET_BZ 0x10 -#define AX_SWRESET_IPRL 0x20 -#define AX_SWRESET_IPPD 0x40 - -#define AX88772_IPG0_DEFAULT 0x15 -#define AX88772_IPG1_DEFAULT 0x0c -#define AX88772_IPG2_DEFAULT 0x12 - -/* AX88772 & AX88178 Medium Mode Register */ -#define AX_MEDIUM_PF 0x0080 -#define AX_MEDIUM_JFE 0x0040 -#define AX_MEDIUM_TFC 0x0020 -#define AX_MEDIUM_RFC 0x0010 -#define AX_MEDIUM_ENCK 0x0008 -#define AX_MEDIUM_AC 0x0004 -#define AX_MEDIUM_FD 0x0002 -#define AX_MEDIUM_GM 0x0001 -#define AX_MEDIUM_SM 0x1000 -#define AX_MEDIUM_SBP 0x0800 -#define AX_MEDIUM_PS 0x0200 -#define AX_MEDIUM_RE 0x0100 - -#define AX88178_MEDIUM_DEFAULT \ - (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ - AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ - AX_MEDIUM_RE) - -#define AX88772_MEDIUM_DEFAULT \ - (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ - AX_MEDIUM_TFC | AX_MEDIUM_PS | \ - AX_MEDIUM_AC | AX_MEDIUM_RE) - -/* AX88772 & AX88178 RX_CTL values */ -#define AX_RX_CTL_SO 0x0080 -#define AX_RX_CTL_AP 0x0020 -#define AX_RX_CTL_AM 0x0010 -#define AX_RX_CTL_AB 0x0008 -#define AX_RX_CTL_SEP 0x0004 -#define AX_RX_CTL_AMALL 0x0002 -#define AX_RX_CTL_PRO 0x0001 -#define AX_RX_CTL_MFB_2048 0x0000 -#define AX_RX_CTL_MFB_4096 0x0100 -#define AX_RX_CTL_MFB_8192 0x0200 -#define AX_RX_CTL_MFB_16384 0x0300 - -#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) - -/* GPIO 0 .. 2 toggles */ -#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ -#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ -#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ -#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ -#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ -#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ -#define AX_GPIO_RESERVED 0x40 /* Reserved */ -#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ - -#define AX_EEPROM_MAGIC 0xdeadbeef -#define AX88172_EEPROM_LEN 0x40 -#define AX88772_EEPROM_LEN 0xff - -#define PHY_MODE_MARVELL 0x0000 -#define MII_MARVELL_LED_CTRL 0x0018 -#define MII_MARVELL_STATUS 0x001b -#define MII_MARVELL_CTRL 0x0014 - -#define MARVELL_LED_MANUAL 0x0019 - -#define MARVELL_STATUS_HWCFG 0x0004 - -#define MARVELL_CTRL_TXDELAY 0x0002 -#define MARVELL_CTRL_RXDELAY 0x0080 - -#define PHY_MODE_RTL8211CL 0x000C - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct asix_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; - u8 mac_addr[ETH_ALEN]; - u8 phymode; - u8 ledmode; - u8 eeprom_len; -}; - -struct ax88172_int_data { - __le16 res1; - u8 link; - __le16 res2; - u8 status; - __le16 res3; -} __packed; - -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) +#include "asix.h" + +int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) { void *buf; int err = -ENOMEM; @@ -216,8 +55,8 @@ out: return err; } -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) +int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) { void *buf = NULL; int err = -ENOMEM; @@ -260,9 +99,8 @@ static void asix_async_cmd_callback(struct urb *urb) usb_free_urb(urb); } -static void -asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) +void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) { struct usb_ctrlrequest *req; int status; @@ -304,7 +142,7 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, } } -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { int offset = 0; @@ -347,8 +185,8 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } -static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) +struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags) { int padlen; int headroom = skb_headroom(skb); @@ -402,27 +240,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, return skb; } -static void asix_status(struct usbnet *dev, struct urb *urb) -{ - struct ax88172_int_data *event; - int link; - - if (urb->actual_length < 8) - return; - - event = urb->transfer_buffer; - link = event->link & 0x01; - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } -} - -static inline int asix_set_sw_mii(struct usbnet *dev) +int asix_set_sw_mii(struct usbnet *dev) { int ret; ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); @@ -431,7 +249,7 @@ static inline int asix_set_sw_mii(struct usbnet *dev) return ret; } -static inline int asix_set_hw_mii(struct usbnet *dev) +int asix_set_hw_mii(struct usbnet *dev) { int ret; ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); @@ -440,7 +258,7 @@ static inline int asix_set_hw_mii(struct usbnet *dev) return ret; } -static inline int asix_get_phy_addr(struct usbnet *dev) +int asix_get_phy_addr(struct usbnet *dev) { u8 buf[2]; int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); @@ -459,7 +277,7 @@ out: return ret; } -static int asix_sw_reset(struct usbnet *dev, u8 flags) +int asix_sw_reset(struct usbnet *dev, u8 flags) { int ret; @@ -470,7 +288,7 @@ static int asix_sw_reset(struct usbnet *dev, u8 flags) return ret; } -static u16 asix_read_rx_ctl(struct usbnet *dev) +u16 asix_read_rx_ctl(struct usbnet *dev) { __le16 v; int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); @@ -484,7 +302,7 @@ out: return ret; } -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) +int asix_write_rx_ctl(struct usbnet *dev, u16 mode) { int ret; @@ -497,7 +315,7 @@ static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) return ret; } -static u16 asix_read_medium_status(struct usbnet *dev) +u16 asix_read_medium_status(struct usbnet *dev) { __le16 v; int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); @@ -512,7 +330,7 @@ static u16 asix_read_medium_status(struct usbnet *dev) } -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) +int asix_write_medium_mode(struct usbnet *dev, u16 mode) { int ret; @@ -525,7 +343,7 @@ static int asix_write_medium_mode(struct usbnet *dev, u16 mode) return ret; } -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) +int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) { int ret; @@ -544,7 +362,7 @@ static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) /* * AX88772 & AX88178 have a 16-bit RX_CTL value */ -static void asix_set_multicast(struct net_device *net) +void asix_set_multicast(struct net_device *net) { struct usbnet *dev = netdev_priv(net); struct asix_data *data = (struct asix_data *)&dev->data; @@ -583,7 +401,7 @@ static void asix_set_multicast(struct net_device *net) asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); } -static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) +int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); __le16 res; @@ -601,8 +419,7 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) return le16_to_cpu(res); } -static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) { struct usbnet *dev = netdev_priv(netdev); __le16 res = cpu_to_le16(val); @@ -616,37 +433,7 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) mutex_unlock(&dev->phy_mutex); } -/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ -static u32 asix_get_phyid(struct usbnet *dev) -{ - int phy_reg; - u32 phy_id; - int i; - - /* Poll for the rare case the FW or phy isn't ready yet. */ - for (i = 0; i < 100; i++) { - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg != 0 && phy_reg != 0xFFFF) - break; - mdelay(1); - } - - if (phy_reg <= 0 || phy_reg == 0xFFFF) - return 0; - - phy_id = (phy_reg & 0xffff) << 16; - - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); - if (phy_reg < 0) - return 0; - - phy_id |= (phy_reg & 0xffff); - - return phy_id; -} - -static void -asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt; @@ -664,8 +451,7 @@ asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) wolinfo->wolopts |= WAKE_MAGIC; } -static int -asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt = 0; @@ -682,7 +468,7 @@ asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) return 0; } -static int asix_get_eeprom_len(struct net_device *net) +int asix_get_eeprom_len(struct net_device *net) { struct usbnet *dev = netdev_priv(net); struct asix_data *data = (struct asix_data *)&dev->data; @@ -690,8 +476,8 @@ static int asix_get_eeprom_len(struct net_device *net) return data->eeprom_len; } -static int asix_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 *data) +int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, + u8 *data) { struct usbnet *dev = netdev_priv(net); __le16 *ebuf = (__le16 *)data; @@ -714,8 +500,7 @@ static int asix_get_eeprom(struct net_device *net, return 0; } -static void asix_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) +void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) { struct usbnet *dev = netdev_priv(net); struct asix_data *data = (struct asix_data *)&dev->data; @@ -727,21 +512,7 @@ static void asix_get_drvinfo (struct net_device *net, info->eedump_len = data->eeprom_len; } -static u32 asix_get_link(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_link_ok(&dev->mii); -} - -static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); -} - -static int asix_set_mac_address(struct net_device *net, void *p) +int asix_set_mac_address(struct net_device *net, void *p) { struct usbnet *dev = netdev_priv(net); struct asix_data *data = (struct asix_data *)&dev->data; @@ -764,917 +535,3 @@ static int asix_set_mac_address(struct net_device *net, void *p) return 0; } - -/* We need to override some ethtool_ops so we require our - own structure so we don't interfere with other usbnet - devices that may be connected at the same time. */ -static const struct ethtool_ops ax88172_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static void ax88172_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u8 rx_ctl = 0x8c; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (netdev_mc_empty(net)) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= 0x10; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int ax88172_link_reset(struct usbnet *dev) -{ - u8 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88172_MEDIUM_DEFAULT; - - if (ecmd.duplex != DUPLEX_FULL) - mode |= ~AX88172_MEDIUM_FD; - - 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); - - return 0; -} - -static const struct net_device_ops ax88172_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = ax88172_set_multicast, -}; - -static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret = 0; - u8 buf[ETH_ALEN]; - int i; - unsigned long gpio_bits = dev->driver_info->data; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88172_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); - if (ret < 0) - goto out; - msleep(5); - } - - ret = asix_write_rx_ctl(dev, 0x80); - if (ret < 0) - goto out; - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88172_netdev_ops; - dev->net->ethtool_ops = &ax88172_ethtool_ops; - dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ - dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - mii_nway_restart(&dev->mii); - - return 0; - -out: - return ret; -} - -static const struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int ax88772_link_reset(struct usbnet *dev) -{ - u16 mode; - 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 (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: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); - - asix_write_medium_mode(dev, mode); - - return 0; -} - -static int ax88772_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret, embd_phy; - u16 rx_ctl; - - ret = asix_write_gpio(dev, - AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); - if (ret < 0) - goto out; - - embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); - - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - goto out; - - msleep(150); - - if (embd_phy) { - ret = asix_sw_reset(dev, AX_SWRESET_IPRL); - if (ret < 0) - goto out; - } else { - ret = asix_sw_reset(dev, AX_SWRESET_PRTE); - if (ret < 0) - goto out; - } - - msleep(150); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after software reset", rx_ctl); - ret = asix_write_rx_ctl(dev, 0x0000); - if (ret < 0) - goto out; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); - - ret = asix_sw_reset(dev, AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); - if (ret < 0) - goto out; - - msleep(150); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); - mii_nway_restart(&dev->mii); - - ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); - if (ret < 0) - goto out; - - ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, - AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, - AX88772_IPG2_DEFAULT, 0, NULL); - if (ret < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out; - } - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - goto out; - - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - goto out; - - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); - - rx_ctl = asix_read_medium_status(dev); - dbg("Medium Status is 0x%04x after all initializations", rx_ctl); - - return 0; - -out: - return ret; - -} - -static const struct net_device_ops ax88772_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_rx_mode = asix_set_multicast, -}; - -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret, embd_phy; - struct asix_data *data = (struct asix_data *)&dev->data; - u8 buf[ETH_ALEN]; - u32 phyid; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88772_netdev_ops; - dev->net->ethtool_ops = &ax88772_ethtool_ops; - dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ - dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ - - embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); - - /* Reset the PHY to normal operation mode */ - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); - if (ret < 0) { - dbg("Select PHY #1 failed: %d", ret); - return ret; - } - - ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); - if (ret < 0) - return ret; - - msleep(150); - - ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); - - /* Read PHYID register *AFTER* the PHY was reset properly */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; -} - -static const struct ethtool_ops ax88178_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int marvell_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - u16 reg; - - netdev_dbg(dev->net, "marvell_phy_init()\n"); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); - netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, - MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); - - if (data->ledmode) { - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); - - reg &= 0xf8ff; - reg |= (1 + 0x0100); - asix_mdio_write(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL, reg); - - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); - reg &= 0xfc0f; - } - - return 0; -} - -static int rtl8211cl_phy_init(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - - netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); - - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, - asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - - if (data->ledmode == 12) { - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); - asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); - } - - return 0; -} - -static int marvell_led_status(struct usbnet *dev, u16 speed) -{ - u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); - - netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); - - /* Clear out the center LED bits - 0x03F0 */ - reg &= 0xfc0f; - - switch (speed) { - case SPEED_1000: - reg |= 0x03e0; - break; - case SPEED_100: - reg |= 0x03b0; - break; - default: - reg |= 0x02f0; - } - - netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); - asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); - - return 0; -} - -static int ax88178_reset(struct usbnet *dev) -{ - struct asix_data *data = (struct asix_data *)&dev->data; - int ret; - __le16 eeprom; - u8 status; - int gpio0 = 0; - u32 phyid; - - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); - dbg("GPIO Status: 0x%04x", status); - - asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); - asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); - asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); - - dbg("EEPROM index 0x17 is 0x%04x", eeprom); - - if (eeprom == cpu_to_le16(0xffff)) { - data->phymode = PHY_MODE_MARVELL; - data->ledmode = 0; - gpio0 = 1; - } else { - data->phymode = le16_to_cpu(eeprom) & 0x7F; - data->ledmode = le16_to_cpu(eeprom) >> 8; - gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; - } - dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); - - /* Power up external GigaPHY through AX88178 GPIO pin */ - asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); - if ((le16_to_cpu(eeprom) >> 8) != 1) { - asix_write_gpio(dev, 0x003c, 30); - asix_write_gpio(dev, 0x001c, 300); - asix_write_gpio(dev, 0x003c, 30); - } else { - dbg("gpio phymode == 1 path"); - asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); - asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); - } - - /* Read PHYID register *AFTER* powering up PHY */ - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - - /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ - asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); - - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - asix_write_rx_ctl(dev, 0); - - if (data->phymode == PHY_MODE_MARVELL) { - marvell_phy_init(dev); - msleep(60); - } else if (data->phymode == PHY_MODE_RTL8211CL) - rtl8211cl_phy_init(dev); - - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - BMCR_RESET | BMCR_ANENABLE); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, - ADVERTISE_1000FULL); - - mii_nway_restart(&dev->mii); - - ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); - if (ret < 0) - return ret; - - /* Rewrite MAC address */ - memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); - ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - if (ret < 0) - return ret; - - ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); - if (ret < 0) - return ret; - - return 0; -} - -static int ax88178_link_reset(struct usbnet *dev) -{ - u16 mode; - 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 (speed == SPEED_1000) - mode |= AX_MEDIUM_GM; - else if (speed == SPEED_100) - mode |= AX_MEDIUM_PS; - else - mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); - - mode |= AX_MEDIUM_ENCK; - - if (ecmd.duplex == DUPLEX_FULL) - mode |= AX_MEDIUM_FD; - else - mode &= ~AX_MEDIUM_FD; - - 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, speed); - - return 0; -} - -static void ax88178_set_mfb(struct usbnet *dev) -{ - u16 mfb = AX_RX_CTL_MFB_16384; - u16 rxctl; - u16 medium; - int old_rx_urb_size = dev->rx_urb_size; - - if (dev->hard_mtu < 2048) { - dev->rx_urb_size = 2048; - mfb = AX_RX_CTL_MFB_2048; - } else if (dev->hard_mtu < 4096) { - dev->rx_urb_size = 4096; - mfb = AX_RX_CTL_MFB_4096; - } else if (dev->hard_mtu < 8192) { - dev->rx_urb_size = 8192; - mfb = AX_RX_CTL_MFB_8192; - } else if (dev->hard_mtu < 16384) { - dev->rx_urb_size = 16384; - mfb = AX_RX_CTL_MFB_16384; - } - - rxctl = asix_read_rx_ctl(dev); - asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); - - medium = asix_read_medium_status(dev); - if (dev->net->mtu > 1500) - medium |= AX_MEDIUM_JFE; - else - medium &= ~AX_MEDIUM_JFE; - asix_write_medium_mode(dev, medium); - - if (dev->rx_urb_size > old_rx_urb_size) - usbnet_unlink_rx_urbs(dev); -} - -static int ax88178_change_mtu(struct net_device *net, int new_mtu) -{ - struct usbnet *dev = netdev_priv(net); - int ll_mtu = new_mtu + net->hard_header_len + 4; - - netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); - - if (new_mtu <= 0 || ll_mtu > 16384) - return -EINVAL; - - if ((ll_mtu % dev->maxpacket) == 0) - return -EDOM; - - net->mtu = new_mtu; - dev->hard_mtu = net->mtu + net->hard_header_len; - ax88178_set_mfb(dev); - - return 0; -} - -static const struct net_device_ops ax88178_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = asix_set_multicast, - .ndo_do_ioctl = asix_ioctl, - .ndo_change_mtu = ax88178_change_mtu, -}; - -static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - u8 buf[ETH_ALEN]; - struct asix_data *data = (struct asix_data *)&dev->data; - - data->eeprom_len = AX88772_EEPROM_LEN; - - usbnet_get_endpoints(dev,intf); - - /* Get the MAC address */ - ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { - dbg("Failed to read MAC address: %d", ret); - return ret; - } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0xff; - dev->mii.supports_gmii = 1; - dev->mii.phy_id = asix_get_phy_addr(dev); - - dev->net->netdev_ops = &ax88178_netdev_ops; - dev->net->ethtool_ops = &ax88178_ethtool_ops; - - /* Blink LEDS so users know driver saw dongle */ - asix_sw_reset(dev, 0); - msleep(150); - - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); - - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; - } - - return 0; -} - -static const struct driver_info ax8817x_info = { - .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, -}; - -static const struct driver_info dlink_dub_e100_info = { - .description = "DLink DUB-E100 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x009f9d9f, -}; - -static const struct driver_info netgear_fa120_info = { - .description = "Netgear FA-120 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, -}; - -static const struct driver_info hawking_uf200_info = { - .description = "Hawking UF200 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x001f1d1f, -}; - -static const struct driver_info ax88772_info = { - .description = "ASIX AX88772 USB 2.0 Ethernet", - .bind = ax88772_bind, - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct driver_info ax88178_info = { - .description = "ASIX AX88178 USB 2.0 Ethernet", - .bind = ax88178_bind, - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, -}; - -static const struct usb_device_id products [] = { -{ - // Linksys USB200M - USB_DEVICE (0x077b, 0x2226), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Netgear FA120 - USB_DEVICE (0x0846, 0x1040), - .driver_info = (unsigned long) &netgear_fa120_info, -}, { - // DLink DUB-E100 - USB_DEVICE (0x2001, 0x1a00), - .driver_info = (unsigned long) &dlink_dub_e100_info, -}, { - // Intellinet, ST Lab USB Ethernet - USB_DEVICE (0x0b95, 0x1720), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Hawking UF200, TrendNet TU2-ET100 - USB_DEVICE (0x07b8, 0x420a), - .driver_info = (unsigned long) &hawking_uf200_info, -}, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ATEN UC210T - USB_DEVICE (0x0557, 0x2009), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-KTX - USB_DEVICE (0x0411, 0x003d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Buffalo LUA-U2-GT 10/100/1000 - USB_DEVICE (0x0411, 0x006e), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" - USB_DEVICE (0x6189, 0x182d), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" - USB_DEVICE (0x0df6, 0x0056), - .driver_info = (unsigned long) &ax88178_info, -}, { - // corega FEther USB2-TX - USB_DEVICE (0x07aa, 0x0017), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // Surecom EP-1427X-2 - USB_DEVICE (0x1189, 0x0893), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // goodway corp usb gwusb2e - USB_DEVICE (0x1631, 0x6200), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // JVC MP-PRX1 Port Replicator - USB_DEVICE (0x04f1, 0x3008), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ASIX AX88772B 10/100 - USB_DEVICE (0x0b95, 0x772b), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88178 10/100/1000 - USB_DEVICE (0x0b95, 0x1780), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Logitec LAN-GTJ/U2A - USB_DEVICE (0x0789, 0x0160), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Linksys USB200M Rev 2 - USB_DEVICE (0x13b1, 0x0018), - .driver_info = (unsigned long) &ax88772_info, -}, { - // 0Q0 cable ethernet - USB_DEVICE (0x1557, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 - USB_DEVICE (0x07d1, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 Alternate - USB_DEVICE (0x2001, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Linksys USB1000 - USB_DEVICE (0x1737, 0x0039), - .driver_info = (unsigned long) &ax88178_info, -}, { - // IO-DATA ETG-US2 - USB_DEVICE (0x04bb, 0x0930), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Belkin F5D5055 - USB_DEVICE(0x050d, 0x5055), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Apple USB Ethernet Adapter - USB_DEVICE(0x05ac, 0x1402), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Cables-to-Go USB Ethernet Adapter - USB_DEVICE(0x0b95, 0x772a), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ABOCOM for pci - USB_DEVICE(0x14ea, 0xab11), - .driver_info = (unsigned long) &ax88178_info, -}, { - // ASIX 88772a - USB_DEVICE(0x0db0, 0xa877), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Asus USB Ethernet Adapter - USB_DEVICE (0x0b95, 0x7e2b), - .driver_info = (unsigned long) &ax88772_info, -}, - { }, // END -}; -MODULE_DEVICE_TABLE(usb, products); - -static struct usb_driver asix_driver = { - .name = DRIVER_NAME, - .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, - .supports_autosuspend = 1, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(asix_driver); - -MODULE_AUTHOR("David Hollis"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 6564c32d3af0..8c513f7921f4 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -20,137 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - -#include <linux/module.h> -#include <linux/kmod.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/workqueue.h> -#include <linux/mii.h> -#include <linux/usb.h> -#include <linux/crc32.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#include <linux/if_vlan.h> - -#define DRIVER_VERSION "22-Dec-2011" -#define DRIVER_NAME "asix" - -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - -#define AX_CMD_SET_SW_MII 0x06 -#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_WRITE_EEPROM 0x0c -#define AX_CMD_WRITE_ENABLE 0x0d -#define AX_CMD_WRITE_DISABLE 0x0e -#define AX_CMD_READ_RX_CTL 0x0f -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_READ_IPG012 0x11 -#define AX_CMD_WRITE_IPG0 0x12 -#define AX_CMD_WRITE_IPG1 0x13 -#define AX_CMD_READ_NODE_ID 0x13 -#define AX_CMD_WRITE_NODE_ID 0x14 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX88172_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_READ_MEDIUM_STATUS 0x1a -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_READ_MONITOR_MODE 0x1c -#define AX_CMD_WRITE_MONITOR_MODE 0x1d -#define AX_CMD_READ_GPIOS 0x1e -#define AX_CMD_WRITE_GPIOS 0x1f -#define AX_CMD_SW_RESET 0x20 -#define AX_CMD_SW_PHY_STATUS 0x21 -#define AX_CMD_SW_PHY_SELECT 0x22 - -#define AX_MONITOR_MODE 0x01 -#define AX_MONITOR_LINK 0x02 -#define AX_MONITOR_MAGIC 0x04 -#define AX_MONITOR_HSFS 0x10 - -/* AX88172 Medium Status Register values */ -#define AX88172_MEDIUM_FD 0x02 -#define AX88172_MEDIUM_TX 0x04 -#define AX88172_MEDIUM_FC 0x10 -#define AX88172_MEDIUM_DEFAULT \ - ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_SWRESET_CLEAR 0x00 -#define AX_SWRESET_RR 0x01 -#define AX_SWRESET_RT 0x02 -#define AX_SWRESET_PRTE 0x04 -#define AX_SWRESET_PRL 0x08 -#define AX_SWRESET_BZ 0x10 -#define AX_SWRESET_IPRL 0x20 -#define AX_SWRESET_IPPD 0x40 - -#define AX88772_IPG0_DEFAULT 0x15 -#define AX88772_IPG1_DEFAULT 0x0c -#define AX88772_IPG2_DEFAULT 0x12 - -/* AX88772 & AX88178 Medium Mode Register */ -#define AX_MEDIUM_PF 0x0080 -#define AX_MEDIUM_JFE 0x0040 -#define AX_MEDIUM_TFC 0x0020 -#define AX_MEDIUM_RFC 0x0010 -#define AX_MEDIUM_ENCK 0x0008 -#define AX_MEDIUM_AC 0x0004 -#define AX_MEDIUM_FD 0x0002 -#define AX_MEDIUM_GM 0x0001 -#define AX_MEDIUM_SM 0x1000 -#define AX_MEDIUM_SBP 0x0800 -#define AX_MEDIUM_PS 0x0200 -#define AX_MEDIUM_RE 0x0100 - -#define AX88178_MEDIUM_DEFAULT \ - (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ - AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ - AX_MEDIUM_RE) - -#define AX88772_MEDIUM_DEFAULT \ - (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ - AX_MEDIUM_TFC | AX_MEDIUM_PS | \ - AX_MEDIUM_AC | AX_MEDIUM_RE) - -/* AX88772 & AX88178 RX_CTL values */ -#define AX_RX_CTL_SO 0x0080 -#define AX_RX_CTL_AP 0x0020 -#define AX_RX_CTL_AM 0x0010 -#define AX_RX_CTL_AB 0x0008 -#define AX_RX_CTL_SEP 0x0004 -#define AX_RX_CTL_AMALL 0x0002 -#define AX_RX_CTL_PRO 0x0001 -#define AX_RX_CTL_MFB_2048 0x0000 -#define AX_RX_CTL_MFB_4096 0x0100 -#define AX_RX_CTL_MFB_8192 0x0200 -#define AX_RX_CTL_MFB_16384 0x0300 - -#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) - -/* GPIO 0 .. 2 toggles */ -#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ -#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ -#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ -#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ -#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ -#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ -#define AX_GPIO_RESERVED 0x40 /* Reserved */ -#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ - -#define AX_EEPROM_MAGIC 0xdeadbeef -#define AX88172_EEPROM_LEN 0x40 -#define AX88772_EEPROM_LEN 0xff +#include "asix.h" #define PHY_MODE_MARVELL 0x0000 #define MII_MARVELL_LED_CTRL 0x0018 @@ -166,15 +36,6 @@ #define PHY_MODE_RTL8211CL 0x000C -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct asix_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; - u8 mac_addr[ETH_ALEN]; - u8 phymode; - u8 ledmode; - u8 eeprom_len; -}; - struct ax88172_int_data { __le16 res1; u8 link; @@ -183,225 +44,6 @@ struct ax88172_int_data { __le16 res3; } __packed; -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - goto out; - - err = usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_GET_TIMEOUT); - if (err == size) - memcpy(data, buf, size); - else if (err >= 0) - err = -EINVAL; - kfree(buf); - -out: - return err; -} - -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf = NULL; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - if (data) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - goto out; - } - - err = usb_control_msg( - dev->udev, - usb_sndctrlpipe(dev->udev, 0), - cmd, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - buf, - size, - USB_CTRL_SET_TIMEOUT); - kfree(buf); - -out: - return err; -} - -static void asix_async_cmd_callback(struct urb *urb) -{ - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - - if (status < 0) - printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - status); - - kfree(req); - usb_free_urb(urb); -} - -static void -asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - struct usb_ctrlrequest *req; - int status; - struct urb *urb; - - netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - netdev_err(dev->net, "Failed to allocate memory for control request\n"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = cmd; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(index); - req->wLength = cpu_to_le16(size); - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, size, - asix_async_cmd_callback, req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - netdev_err(dev->net, "Error submitting the control message: status=%d\n", - status); - kfree(req); - usb_free_urb(urb); - } -} - -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - int offset = 0; - - while (offset + sizeof(u32) < skb->len) { - struct sk_buff *ax_skb; - u16 size; - u32 header = get_unaligned_le32(skb->data + offset); - - offset += sizeof(u32); - - /* get the packet length */ - size = (u16) (header & 0x7ff); - if (size != ((~header >> 16) & 0x07ff)) { - netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); - return 0; - } - - if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || - (size + offset > skb->len)) { - netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", - size); - return 0; - } - ax_skb = netdev_alloc_skb_ip_align(dev->net, size); - if (!ax_skb) - return 0; - - skb_put(ax_skb, size); - memcpy(ax_skb->data, skb->data + offset, size); - usbnet_skb_return(dev, ax_skb); - - offset += (size + 1) & 0xfffe; - } - - if (skb->len != offset) { - netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", - skb->len); - return 0; - } - return 1; -} - -static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) -{ - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 packet_len; - u32 padbytes = 0xffff0000; - - padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; - - /* We need to push 4 bytes in front of frame (packet_len) - * and maybe add 4 bytes after the end (if padlen is 4) - * - * Avoid skb_copy_expand() expensive call, using following rules : - * - We are allowed to push 4 bytes in headroom if skb_header_cloned() - * is false (and if we have 4 bytes of headroom) - * - We are allowed to put 4 bytes at tail if skb_cloned() - * is false (and if we have 4 bytes of tailroom) - * - * TCP packets for example are cloned, but skb_header_release() - * was called in tcp stack, allowing us to use headroom for our needs. - */ - if (!skb_header_cloned(skb) && - !(padlen && skb_cloned(skb)) && - headroom + tailroom >= 4 + padlen) { - /* following should not happen, but better be safe */ - if (headroom < 4 || - tailroom < padlen) { - skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - } - } else { - struct sk_buff *skb2; - - skb2 = skb_copy_expand(skb, 4, padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; - } - - packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; - skb_push(skb, 4); - cpu_to_le32s(&packet_len); - skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); - - if (padlen) { - cpu_to_le32s(&padbytes); - memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); - skb_put(skb, sizeof(padbytes)); - } - return skb; -} - static void asix_status(struct usbnet *dev, struct urb *urb) { struct ax88172_int_data *event; @@ -422,200 +64,6 @@ static void asix_status(struct usbnet *dev, struct urb *urb) } } -static inline int asix_set_sw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable software MII access\n"); - return ret; -} - -static inline int asix_set_hw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable hardware MII access\n"); - return ret; -} - -static inline int asix_get_phy_addr(struct usbnet *dev) -{ - u8 buf[2]; - int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); - - netdev_dbg(dev->net, "asix_get_phy_addr()\n"); - - if (ret < 0) { - netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); - goto out; - } - netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", - *((__le16 *)buf)); - ret = buf[1]; - -out: - return ret; -} - -static int asix_sw_reset(struct usbnet *dev, u8 flags) -{ - int ret; - - ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); - - return ret; -} - -static u16 asix_read_rx_ctl(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); - goto out; - } - ret = le16_to_cpu(v); -out: - return ret; -} - -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static u16 asix_read_medium_status(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); - - if (ret < 0) { - netdev_err(dev->net, "Error reading Medium Status register: %02x\n", - ret); - return ret; /* TODO: callers not checking for error ret */ - } - - return le16_to_cpu(v); - -} - -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", - mode, ret); - - return ret; -} - -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) -{ - int ret; - - netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", - value, ret); - - if (sleep) - msleep(sleep); - - return ret; -} - -/* - * AX88772 & AX88178 have a 16-bit RX_CTL value - */ -static void asix_set_multicast(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u16 rx_ctl = AX_DEFAULT_RX_CTL; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= AX_RX_CTL_PRO; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= AX_RX_CTL_AMALL; - } else if (netdev_mc_empty(net)) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct netdev_hw_addr *ha; - u32 crc_bits; - - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); - - rx_ctl |= AX_RX_CTL_AM; - } - - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); -} - -static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) -{ - struct usbnet *dev = netdev_priv(netdev); - __le16 res; - - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, - (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); - - netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", - phy_id, loc, le16_to_cpu(res)); - - return le16_to_cpu(res); -} - -static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) -{ - struct usbnet *dev = netdev_priv(netdev); - __le16 res = cpu_to_le16(val); - - netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", - phy_id, loc, val); - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); -} - /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ static u32 asix_get_phyid(struct usbnet *dev) { @@ -645,88 +93,6 @@ static u32 asix_get_phyid(struct usbnet *dev) return phy_id; } -static void -asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt; - - if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { - wolinfo->supported = 0; - wolinfo->wolopts = 0; - return; - } - wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = 0; - if (opt & AX_MONITOR_LINK) - wolinfo->wolopts |= WAKE_PHY; - if (opt & AX_MONITOR_MAGIC) - wolinfo->wolopts |= WAKE_MAGIC; -} - -static int -asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) -{ - struct usbnet *dev = netdev_priv(net); - u8 opt = 0; - - if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; - if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - - if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, NULL) < 0) - return -EINVAL; - - return 0; -} - -static int asix_get_eeprom_len(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - return data->eeprom_len; -} - -static int asix_get_eeprom(struct net_device *net, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct usbnet *dev = netdev_priv(net); - __le16 *ebuf = (__le16 *)data; - int i; - - /* Crude hack to ensure that we don't overwrite memory - * if an odd length is supplied - */ - if (eeprom->len % 2) - return -EINVAL; - - eeprom->magic = AX_EEPROM_MAGIC; - - /* ax8817x returns 2 bytes from eeprom on read */ - for (i=0; i < eeprom->len / 2; i++) { - if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) - return -EINVAL; - } - return 0; -} - -static void asix_get_drvinfo (struct net_device *net, - struct ethtool_drvinfo *info) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - strncpy (info->driver, DRIVER_NAME, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - info->eedump_len = data->eeprom_len; -} - static u32 asix_get_link(struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -741,30 +107,6 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static int asix_set_mac_address(struct net_device *net, void *p) -{ - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - struct sockaddr *addr = p; - - if (netif_running(net)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); - - /* We use the 20 byte dev->data - * for our 6 byte mac buffer - * to avoid allocating memory that - * is tricky to free later */ - memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); - asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); - - return 0; -} - /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ |