117364b80SDmitry Bezrukov // SPDX-License-Identifier: GPL-2.0-or-later 217364b80SDmitry Bezrukov /* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller 317364b80SDmitry Bezrukov * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 417364b80SDmitry Bezrukov * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 517364b80SDmitry Bezrukov * Copyright (C) 2002-2003 TiVo Inc. 617364b80SDmitry Bezrukov * Copyright (C) 2017-2018 ASIX 717364b80SDmitry Bezrukov * Copyright (C) 2018 Aquantia Corp. 817364b80SDmitry Bezrukov */ 917364b80SDmitry Bezrukov 1017364b80SDmitry Bezrukov #include <linux/module.h> 1117364b80SDmitry Bezrukov #include <linux/netdevice.h> 1217364b80SDmitry Bezrukov #include <linux/mii.h> 1317364b80SDmitry Bezrukov #include <linux/usb.h> 14df2d59a2SDmitry Bezrukov #include <linux/if_vlan.h> 1517364b80SDmitry Bezrukov #include <linux/usb/cdc.h> 1617364b80SDmitry Bezrukov #include <linux/usb/usbnet.h> 1717364b80SDmitry Bezrukov 18619fcb44SDmitry Bezrukov #include "aqc111.h" 19619fcb44SDmitry Bezrukov 20619fcb44SDmitry Bezrukov static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 21619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 22619fcb44SDmitry Bezrukov { 23619fcb44SDmitry Bezrukov int ret; 24619fcb44SDmitry Bezrukov 25619fcb44SDmitry Bezrukov ret = usbnet_read_cmd_nopm(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 26619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 27619fcb44SDmitry Bezrukov 28619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 29619fcb44SDmitry Bezrukov netdev_warn(dev->net, 30619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 31619fcb44SDmitry Bezrukov cmd, index, ret); 32619fcb44SDmitry Bezrukov 33619fcb44SDmitry Bezrukov return ret; 34619fcb44SDmitry Bezrukov } 35619fcb44SDmitry Bezrukov 36619fcb44SDmitry Bezrukov static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value, 37619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 38619fcb44SDmitry Bezrukov { 39619fcb44SDmitry Bezrukov int ret; 40619fcb44SDmitry Bezrukov 41619fcb44SDmitry Bezrukov ret = usbnet_read_cmd(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 42619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 43619fcb44SDmitry Bezrukov 44619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 45619fcb44SDmitry Bezrukov netdev_warn(dev->net, 46619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 47619fcb44SDmitry Bezrukov cmd, index, ret); 48619fcb44SDmitry Bezrukov 49619fcb44SDmitry Bezrukov return ret; 50619fcb44SDmitry Bezrukov } 51619fcb44SDmitry Bezrukov 52f3aa095aSDmitry Bezrukov static int aqc111_read16_cmd(struct usbnet *dev, u8 cmd, u16 value, 53f3aa095aSDmitry Bezrukov u16 index, u16 *data) 54f3aa095aSDmitry Bezrukov { 55f3aa095aSDmitry Bezrukov int ret = 0; 56f3aa095aSDmitry Bezrukov 57f3aa095aSDmitry Bezrukov ret = aqc111_read_cmd(dev, cmd, value, index, sizeof(*data), data); 58f3aa095aSDmitry Bezrukov le16_to_cpus(data); 59f3aa095aSDmitry Bezrukov 60f3aa095aSDmitry Bezrukov return ret; 61f3aa095aSDmitry Bezrukov } 62f3aa095aSDmitry Bezrukov 63619fcb44SDmitry Bezrukov static int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 64619fcb44SDmitry Bezrukov u16 value, u16 index, u16 size, const void *data) 65619fcb44SDmitry Bezrukov { 66619fcb44SDmitry Bezrukov int err = -ENOMEM; 67619fcb44SDmitry Bezrukov void *buf = NULL; 68619fcb44SDmitry Bezrukov 69619fcb44SDmitry Bezrukov netdev_dbg(dev->net, 70619fcb44SDmitry Bezrukov "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n", 71619fcb44SDmitry Bezrukov __func__, cmd, reqtype, value, index, size); 72619fcb44SDmitry Bezrukov 73619fcb44SDmitry Bezrukov if (data) { 74619fcb44SDmitry Bezrukov buf = kmemdup(data, size, GFP_KERNEL); 75619fcb44SDmitry Bezrukov if (!buf) 76619fcb44SDmitry Bezrukov goto out; 77619fcb44SDmitry Bezrukov } 78619fcb44SDmitry Bezrukov 79619fcb44SDmitry Bezrukov err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 80619fcb44SDmitry Bezrukov cmd, reqtype, value, index, buf, size, 81619fcb44SDmitry Bezrukov (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT : 82619fcb44SDmitry Bezrukov AQ_USB_SET_TIMEOUT); 83619fcb44SDmitry Bezrukov 84619fcb44SDmitry Bezrukov if (unlikely(err < 0)) 85619fcb44SDmitry Bezrukov netdev_warn(dev->net, 86619fcb44SDmitry Bezrukov "Failed to write(0x%x) reg index 0x%04x: %d\n", 87619fcb44SDmitry Bezrukov cmd, index, err); 88619fcb44SDmitry Bezrukov kfree(buf); 89619fcb44SDmitry Bezrukov 90619fcb44SDmitry Bezrukov out: 91619fcb44SDmitry Bezrukov return err; 92619fcb44SDmitry Bezrukov } 93619fcb44SDmitry Bezrukov 94619fcb44SDmitry Bezrukov static int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 95619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 96619fcb44SDmitry Bezrukov { 97619fcb44SDmitry Bezrukov int ret; 98619fcb44SDmitry Bezrukov 99619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 100619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 101619fcb44SDmitry Bezrukov 102619fcb44SDmitry Bezrukov return ret; 103619fcb44SDmitry Bezrukov } 104619fcb44SDmitry Bezrukov 105619fcb44SDmitry Bezrukov static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 106619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 107619fcb44SDmitry Bezrukov { 108619fcb44SDmitry Bezrukov int ret; 109619fcb44SDmitry Bezrukov 110619fcb44SDmitry Bezrukov if (usb_autopm_get_interface(dev->intf) < 0) 111619fcb44SDmitry Bezrukov return -ENODEV; 112619fcb44SDmitry Bezrukov 113619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 114619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 115619fcb44SDmitry Bezrukov 116619fcb44SDmitry Bezrukov usb_autopm_put_interface(dev->intf); 117619fcb44SDmitry Bezrukov 118619fcb44SDmitry Bezrukov return ret; 119619fcb44SDmitry Bezrukov } 120619fcb44SDmitry Bezrukov 121f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 122f3aa095aSDmitry Bezrukov u16 index, u16 *data) 123f3aa095aSDmitry Bezrukov { 124f3aa095aSDmitry Bezrukov u16 tmp = *data; 125f3aa095aSDmitry Bezrukov 126f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 127f3aa095aSDmitry Bezrukov 128f3aa095aSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 129f3aa095aSDmitry Bezrukov } 130f3aa095aSDmitry Bezrukov 131f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value, 132f3aa095aSDmitry Bezrukov u16 index, u16 *data) 133f3aa095aSDmitry Bezrukov { 134f3aa095aSDmitry Bezrukov u16 tmp = *data; 135f3aa095aSDmitry Bezrukov 136f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 137f3aa095aSDmitry Bezrukov 138f3aa095aSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 139f3aa095aSDmitry Bezrukov } 140f3aa095aSDmitry Bezrukov 14133cd597fSDmitry Bezrukov static int aqc111_write32_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 14233cd597fSDmitry Bezrukov u16 index, u32 *data) 14333cd597fSDmitry Bezrukov { 14433cd597fSDmitry Bezrukov u32 tmp = *data; 14533cd597fSDmitry Bezrukov 14633cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 14733cd597fSDmitry Bezrukov 14833cd597fSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 14933cd597fSDmitry Bezrukov } 15033cd597fSDmitry Bezrukov 15133cd597fSDmitry Bezrukov static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value, 15233cd597fSDmitry Bezrukov u16 index, u32 *data) 15333cd597fSDmitry Bezrukov { 15433cd597fSDmitry Bezrukov u32 tmp = *data; 15533cd597fSDmitry Bezrukov 15633cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 15733cd597fSDmitry Bezrukov 15833cd597fSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 15933cd597fSDmitry Bezrukov } 16033cd597fSDmitry Bezrukov 1617b8b0654SDmitry Bezrukov static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed) 1627b8b0654SDmitry Bezrukov { 1637b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 1647b8b0654SDmitry Bezrukov 1657b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 1667b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_PAUSE; 1677b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ASYM_PAUSE; 1687b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_DOWNSHIFT; 1697b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK; 1707b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= (3 << AQ_DSH_RETRIES_SHIFT) & 1717b8b0654SDmitry Bezrukov AQ_DSH_RETRIES_MASK; 1727b8b0654SDmitry Bezrukov 1737b8b0654SDmitry Bezrukov if (autoneg == AUTONEG_ENABLE) { 1747b8b0654SDmitry Bezrukov switch (speed) { 1757b8b0654SDmitry Bezrukov case SPEED_5000: 1767b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 1777b8b0654SDmitry Bezrukov /* fall-through */ 1787b8b0654SDmitry Bezrukov case SPEED_2500: 1797b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 1807b8b0654SDmitry Bezrukov /* fall-through */ 1817b8b0654SDmitry Bezrukov case SPEED_1000: 1827b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 1837b8b0654SDmitry Bezrukov /* fall-through */ 1847b8b0654SDmitry Bezrukov case SPEED_100: 1857b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 1867b8b0654SDmitry Bezrukov /* fall-through */ 1877b8b0654SDmitry Bezrukov } 1887b8b0654SDmitry Bezrukov } else { 1897b8b0654SDmitry Bezrukov switch (speed) { 1907b8b0654SDmitry Bezrukov case SPEED_5000: 1917b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 1927b8b0654SDmitry Bezrukov break; 1937b8b0654SDmitry Bezrukov case SPEED_2500: 1947b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 1957b8b0654SDmitry Bezrukov break; 1967b8b0654SDmitry Bezrukov case SPEED_1000: 1977b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 1987b8b0654SDmitry Bezrukov break; 1997b8b0654SDmitry Bezrukov case SPEED_100: 2007b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 2017b8b0654SDmitry Bezrukov break; 2027b8b0654SDmitry Bezrukov } 2037b8b0654SDmitry Bezrukov } 2047b8b0654SDmitry Bezrukov 2057b8b0654SDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg); 2067b8b0654SDmitry Bezrukov } 2077b8b0654SDmitry Bezrukov 208df2d59a2SDmitry Bezrukov static int aqc111_set_mac_addr(struct net_device *net, void *p) 209df2d59a2SDmitry Bezrukov { 210df2d59a2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 211df2d59a2SDmitry Bezrukov int ret = 0; 212df2d59a2SDmitry Bezrukov 213df2d59a2SDmitry Bezrukov ret = eth_mac_addr(net, p); 214df2d59a2SDmitry Bezrukov if (ret < 0) 215df2d59a2SDmitry Bezrukov return ret; 216df2d59a2SDmitry Bezrukov 217df2d59a2SDmitry Bezrukov /* Set the MAC address */ 218df2d59a2SDmitry Bezrukov return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 219df2d59a2SDmitry Bezrukov ETH_ALEN, net->dev_addr); 220df2d59a2SDmitry Bezrukov } 221df2d59a2SDmitry Bezrukov 2227cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 2237cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 2247cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 2254a3576d2SDmitry Bezrukov .ndo_start_xmit = usbnet_start_xmit, 2264a3576d2SDmitry Bezrukov .ndo_tx_timeout = usbnet_tx_timeout, 2274a3576d2SDmitry Bezrukov .ndo_get_stats64 = usbnet_get_stats64, 228df2d59a2SDmitry Bezrukov .ndo_set_mac_address = aqc111_set_mac_addr, 229df2d59a2SDmitry Bezrukov .ndo_validate_addr = eth_validate_addr, 2307cea2d40SDmitry Bezrukov }; 2317cea2d40SDmitry Bezrukov 232df2d59a2SDmitry Bezrukov static int aqc111_read_perm_mac(struct usbnet *dev) 233df2d59a2SDmitry Bezrukov { 234df2d59a2SDmitry Bezrukov u8 buf[ETH_ALEN]; 235df2d59a2SDmitry Bezrukov int ret; 236df2d59a2SDmitry Bezrukov 237df2d59a2SDmitry Bezrukov ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 238df2d59a2SDmitry Bezrukov if (ret < 0) 239df2d59a2SDmitry Bezrukov goto out; 240df2d59a2SDmitry Bezrukov 241df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->perm_addr, buf); 242df2d59a2SDmitry Bezrukov 243df2d59a2SDmitry Bezrukov return 0; 244df2d59a2SDmitry Bezrukov out: 245df2d59a2SDmitry Bezrukov return ret; 246df2d59a2SDmitry Bezrukov } 247df2d59a2SDmitry Bezrukov 24833cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 24933cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 25033cd597fSDmitry Bezrukov { 25133cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 25233cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 25333cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 25433cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 25533cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 25633cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 25733cd597fSDmitry Bezrukov 25833cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 25933cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 26033cd597fSDmitry Bezrukov } 26133cd597fSDmitry Bezrukov 2627cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 2637cea2d40SDmitry Bezrukov { 2647cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 2657b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 26633cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 2677cea2d40SDmitry Bezrukov int ret; 2687cea2d40SDmitry Bezrukov 2697cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 2707cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 2717cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 2727cea2d40SDmitry Bezrukov return -ENODEV; 2737cea2d40SDmitry Bezrukov } 2747cea2d40SDmitry Bezrukov 2757cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 2767cea2d40SDmitry Bezrukov 2777cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 2787cea2d40SDmitry Bezrukov if (ret < 0) { 2797cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 2807cea2d40SDmitry Bezrukov return ret; 2817cea2d40SDmitry Bezrukov } 2827cea2d40SDmitry Bezrukov 28333cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 28433cd597fSDmitry Bezrukov if (!aqc111_data) 28533cd597fSDmitry Bezrukov return -ENOMEM; 28633cd597fSDmitry Bezrukov 28733cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 28833cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 28933cd597fSDmitry Bezrukov 290df2d59a2SDmitry Bezrukov /* Init the MAC address */ 291df2d59a2SDmitry Bezrukov ret = aqc111_read_perm_mac(dev); 292df2d59a2SDmitry Bezrukov if (ret) 293df2d59a2SDmitry Bezrukov goto out; 294df2d59a2SDmitry Bezrukov 295df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 2964a3576d2SDmitry Bezrukov 297361459cdSDmitry Bezrukov /* Set Rx urb size */ 298361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 299361459cdSDmitry Bezrukov 3004a3576d2SDmitry Bezrukov /* Set TX needed headroom & tailroom */ 3014a3576d2SDmitry Bezrukov dev->net->needed_headroom += sizeof(u64); 3024a3576d2SDmitry Bezrukov dev->net->needed_tailroom += sizeof(u64); 3034a3576d2SDmitry Bezrukov 3047cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 3057cea2d40SDmitry Bezrukov 3064a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 3074a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 3084a3576d2SDmitry Bezrukov 3094a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 3104a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 3114a3576d2SDmitry Bezrukov 31233cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 3137b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 3147b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 3157b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 31633cd597fSDmitry Bezrukov 3177cea2d40SDmitry Bezrukov return 0; 318df2d59a2SDmitry Bezrukov 319df2d59a2SDmitry Bezrukov out: 320df2d59a2SDmitry Bezrukov kfree(aqc111_data); 321df2d59a2SDmitry Bezrukov return ret; 3227cea2d40SDmitry Bezrukov } 3237cea2d40SDmitry Bezrukov 3247cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 3257cea2d40SDmitry Bezrukov { 32633cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 327f3aa095aSDmitry Bezrukov u16 reg16; 328f3aa095aSDmitry Bezrukov 329f3aa095aSDmitry Bezrukov /* Force bz */ 330f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 331f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 332f3aa095aSDmitry Bezrukov 2, ®16); 333f3aa095aSDmitry Bezrukov reg16 = 0; 334f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 335f3aa095aSDmitry Bezrukov 2, ®16); 33633cd597fSDmitry Bezrukov 33733cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 3387b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 33933cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 34033cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 34133cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 34233cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 34333cd597fSDmitry Bezrukov 34433cd597fSDmitry Bezrukov kfree(aqc111_data); 345f3aa095aSDmitry Bezrukov } 346f3aa095aSDmitry Bezrukov 3477b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 3487b8b0654SDmitry Bezrukov { 3497b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 3507b8b0654SDmitry Bezrukov u64 *event_data = NULL; 3517b8b0654SDmitry Bezrukov int link = 0; 3527b8b0654SDmitry Bezrukov 3537b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 3547b8b0654SDmitry Bezrukov return; 3557b8b0654SDmitry Bezrukov 3567b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 3577b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 3587b8b0654SDmitry Bezrukov 3597b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 3607b8b0654SDmitry Bezrukov link = 1; 3617b8b0654SDmitry Bezrukov else 3627b8b0654SDmitry Bezrukov link = 0; 3637b8b0654SDmitry Bezrukov 3647b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 3657b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 3667b8b0654SDmitry Bezrukov aqc111_data->link = link; 3677b8b0654SDmitry Bezrukov 3687b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 3697b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 3707b8b0654SDmitry Bezrukov } 3717b8b0654SDmitry Bezrukov 3727b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 3737b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 3747b8b0654SDmitry Bezrukov { 3757b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 3767b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 3777b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 3787b8b0654SDmitry Bezrukov u8 queue_num = 0; 3797b8b0654SDmitry Bezrukov u16 reg16 = 0; 3807b8b0654SDmitry Bezrukov u8 reg8 = 0; 3817b8b0654SDmitry Bezrukov 3827b8b0654SDmitry Bezrukov buf[0] = 0x00; 3837b8b0654SDmitry Bezrukov buf[1] = 0xF8; 3847b8b0654SDmitry Bezrukov buf[2] = 0x07; 3857b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 3867b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 3877b8b0654SDmitry Bezrukov link_speed = 5000; 3887b8b0654SDmitry Bezrukov reg8 = 0x05; 3897b8b0654SDmitry Bezrukov reg16 = 0x001F; 3907b8b0654SDmitry Bezrukov break; 3917b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 3927b8b0654SDmitry Bezrukov link_speed = 2500; 3937b8b0654SDmitry Bezrukov reg16 = 0x003F; 3947b8b0654SDmitry Bezrukov break; 3957b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 3967b8b0654SDmitry Bezrukov link_speed = 1000; 3977b8b0654SDmitry Bezrukov reg16 = 0x009F; 3987b8b0654SDmitry Bezrukov break; 3997b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 4007b8b0654SDmitry Bezrukov link_speed = 100; 4017b8b0654SDmitry Bezrukov queue_num = 1; 4027b8b0654SDmitry Bezrukov reg16 = 0x063F; 4037b8b0654SDmitry Bezrukov buf[1] = 0xFB; 4047b8b0654SDmitry Bezrukov buf[2] = 0x4; 4057b8b0654SDmitry Bezrukov break; 4067b8b0654SDmitry Bezrukov } 4077b8b0654SDmitry Bezrukov 4087b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 4097b8b0654SDmitry Bezrukov 1, 1, ®8); 4107b8b0654SDmitry Bezrukov 4117b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 4127b8b0654SDmitry Bezrukov 4137b8b0654SDmitry Bezrukov switch (usb_speed) { 4147b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 4157b8b0654SDmitry Bezrukov usb_host = 3; 4167b8b0654SDmitry Bezrukov break; 4177b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 4187b8b0654SDmitry Bezrukov usb_host = 2; 4197b8b0654SDmitry Bezrukov break; 4207b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 4217b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 4227b8b0654SDmitry Bezrukov usb_host = 1; 4237b8b0654SDmitry Bezrukov queue_num = 0; 4247b8b0654SDmitry Bezrukov break; 4257b8b0654SDmitry Bezrukov default: 4267b8b0654SDmitry Bezrukov usb_host = 0; 4277b8b0654SDmitry Bezrukov break; 4287b8b0654SDmitry Bezrukov } 4297b8b0654SDmitry Bezrukov 4307b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 4317b8b0654SDmitry Bezrukov /* RX bulk configuration */ 4327b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 4337b8b0654SDmitry Bezrukov 4347b8b0654SDmitry Bezrukov /* Set high low water level */ 4357b8b0654SDmitry Bezrukov reg16 = 0x0810; 4367b8b0654SDmitry Bezrukov 4377b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 4387b8b0654SDmitry Bezrukov 2, ®16); 4397b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 4407b8b0654SDmitry Bezrukov } 4417b8b0654SDmitry Bezrukov 442*02031466SDmitry Bezrukov static void aqc111_configure_csum_offload(struct usbnet *dev) 443*02031466SDmitry Bezrukov { 444*02031466SDmitry Bezrukov u8 reg8 = 0; 445*02031466SDmitry Bezrukov 446*02031466SDmitry Bezrukov if (dev->net->features & NETIF_F_RXCSUM) { 447*02031466SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 448*02031466SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 449*02031466SDmitry Bezrukov } 450*02031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 451*02031466SDmitry Bezrukov 452*02031466SDmitry Bezrukov reg8 = 0; 453*02031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IP_CSUM) 454*02031466SDmitry Bezrukov reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; 455*02031466SDmitry Bezrukov 456*02031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IPV6_CSUM) 457*02031466SDmitry Bezrukov reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 458*02031466SDmitry Bezrukov 459*02031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 460*02031466SDmitry Bezrukov } 461*02031466SDmitry Bezrukov 4627b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 4637b8b0654SDmitry Bezrukov { 4647b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 4657b8b0654SDmitry Bezrukov u16 reg16 = 0; 4667b8b0654SDmitry Bezrukov u8 reg8 = 0; 4677b8b0654SDmitry Bezrukov 4687b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 4697b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 4707b8b0654SDmitry Bezrukov 4717b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 4727b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 4737b8b0654SDmitry Bezrukov 4747b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 4757b8b0654SDmitry Bezrukov 1, 1, ®8); 4767b8b0654SDmitry Bezrukov 4777b8b0654SDmitry Bezrukov reg8 = 0x0; 4787b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 4797b8b0654SDmitry Bezrukov 1, 1, ®8); 4807b8b0654SDmitry Bezrukov 4817b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 4827b8b0654SDmitry Bezrukov 1, 1, ®8); 4837b8b0654SDmitry Bezrukov 4847b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 4857b8b0654SDmitry Bezrukov 4867b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 4877b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 4887b8b0654SDmitry Bezrukov 4897b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 4907b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 4917b8b0654SDmitry Bezrukov 1, 1, ®8); 4927b8b0654SDmitry Bezrukov 4937b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 4947b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 4957b8b0654SDmitry Bezrukov 1, 1, ®8); 4967b8b0654SDmitry Bezrukov 4977b8b0654SDmitry Bezrukov reg16 = 0; 4987b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4997b8b0654SDmitry Bezrukov 2, ®16); 5007b8b0654SDmitry Bezrukov 5017b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 5027b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5037b8b0654SDmitry Bezrukov 2, ®16); 5047b8b0654SDmitry Bezrukov 505*02031466SDmitry Bezrukov aqc111_configure_csum_offload(dev); 506*02031466SDmitry Bezrukov 5077b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5087b8b0654SDmitry Bezrukov 2, ®16); 5097b8b0654SDmitry Bezrukov 5107b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 5117b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 5127b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5137b8b0654SDmitry Bezrukov 2, ®16); 5147b8b0654SDmitry Bezrukov 5157b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START; 5167b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5177b8b0654SDmitry Bezrukov 5187b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 5197b8b0654SDmitry Bezrukov } else { 5207b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5217b8b0654SDmitry Bezrukov 2, ®16); 5227b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 5237b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5247b8b0654SDmitry Bezrukov 2, ®16); 5257b8b0654SDmitry Bezrukov 5267b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5277b8b0654SDmitry Bezrukov reg16 &= ~SFR_RX_CTL_START; 5287b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5297b8b0654SDmitry Bezrukov 5307b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 5317b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5327b8b0654SDmitry Bezrukov 1, 1, ®8); 5337b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 5347b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5357b8b0654SDmitry Bezrukov 1, 1, ®8); 5367b8b0654SDmitry Bezrukov 5377b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 5387b8b0654SDmitry Bezrukov } 5397b8b0654SDmitry Bezrukov return 0; 5407b8b0654SDmitry Bezrukov } 5417b8b0654SDmitry Bezrukov 542f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 543f3aa095aSDmitry Bezrukov { 54433cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 545f3aa095aSDmitry Bezrukov u8 reg8 = 0; 546f3aa095aSDmitry Bezrukov 547361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 548361459cdSDmitry Bezrukov 5494a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 5504a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 5514a3576d2SDmitry Bezrukov 5524a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 5534a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 5544a3576d2SDmitry Bezrukov 55533cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 55633cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 55733cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 55833cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 55933cd597fSDmitry Bezrukov 560df2d59a2SDmitry Bezrukov /* Set the MAC address */ 561df2d59a2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 562df2d59a2SDmitry Bezrukov ETH_ALEN, dev->net->dev_addr); 563df2d59a2SDmitry Bezrukov 564f3aa095aSDmitry Bezrukov reg8 = 0xFF; 565f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 566f3aa095aSDmitry Bezrukov 567f3aa095aSDmitry Bezrukov reg8 = 0x0; 568f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 569f3aa095aSDmitry Bezrukov 570f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 571f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 572f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 573f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 574f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 575f3aa095aSDmitry Bezrukov 5767b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 5777b8b0654SDmitry Bezrukov 5787b8b0654SDmitry Bezrukov /* Phy advertise */ 5797b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 5807b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 5817b8b0654SDmitry Bezrukov 582f3aa095aSDmitry Bezrukov return 0; 583f3aa095aSDmitry Bezrukov } 584f3aa095aSDmitry Bezrukov 585f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 586f3aa095aSDmitry Bezrukov { 58733cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 588f3aa095aSDmitry Bezrukov u16 reg16 = 0; 589f3aa095aSDmitry Bezrukov 590f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 591f3aa095aSDmitry Bezrukov 2, ®16); 592f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 593f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 594f3aa095aSDmitry Bezrukov 2, ®16); 595f3aa095aSDmitry Bezrukov reg16 = 0; 596f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 597f3aa095aSDmitry Bezrukov 59833cd597fSDmitry Bezrukov /* Put PHY to low power*/ 59933cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 60033cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 60133cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 60233cd597fSDmitry Bezrukov 6037b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 6047b8b0654SDmitry Bezrukov 605f3aa095aSDmitry Bezrukov return 0; 6067cea2d40SDmitry Bezrukov } 6077cea2d40SDmitry Bezrukov 608*02031466SDmitry Bezrukov static void aqc111_rx_checksum(struct sk_buff *skb, u64 pkt_desc) 609*02031466SDmitry Bezrukov { 610*02031466SDmitry Bezrukov u32 pkt_type = 0; 611*02031466SDmitry Bezrukov 612*02031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_NONE; 613*02031466SDmitry Bezrukov /* checksum error bit is set */ 614*02031466SDmitry Bezrukov if (pkt_desc & AQ_RX_PD_L4_ERR || pkt_desc & AQ_RX_PD_L3_ERR) 615*02031466SDmitry Bezrukov return; 616*02031466SDmitry Bezrukov 617*02031466SDmitry Bezrukov pkt_type = pkt_desc & AQ_RX_PD_L4_TYPE_MASK; 618*02031466SDmitry Bezrukov /* It must be a TCP or UDP packet with a valid checksum */ 619*02031466SDmitry Bezrukov if (pkt_type == AQ_RX_PD_L4_TCP || pkt_type == AQ_RX_PD_L4_UDP) 620*02031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_UNNECESSARY; 621*02031466SDmitry Bezrukov } 622*02031466SDmitry Bezrukov 623361459cdSDmitry Bezrukov static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 624361459cdSDmitry Bezrukov { 625361459cdSDmitry Bezrukov struct sk_buff *new_skb = NULL; 626361459cdSDmitry Bezrukov u32 pkt_total_offset = 0; 627361459cdSDmitry Bezrukov u64 *pkt_desc_ptr = NULL; 628361459cdSDmitry Bezrukov u32 start_of_descs = 0; 629361459cdSDmitry Bezrukov u32 desc_offset = 0; /*RX Header Offset*/ 630361459cdSDmitry Bezrukov u16 pkt_count = 0; 631361459cdSDmitry Bezrukov u64 desc_hdr = 0; 632361459cdSDmitry Bezrukov u32 skb_len = 0; 633361459cdSDmitry Bezrukov 634361459cdSDmitry Bezrukov if (!skb) 635361459cdSDmitry Bezrukov goto err; 636361459cdSDmitry Bezrukov 637361459cdSDmitry Bezrukov if (skb->len == 0) 638361459cdSDmitry Bezrukov goto err; 639361459cdSDmitry Bezrukov 640361459cdSDmitry Bezrukov skb_len = skb->len; 641361459cdSDmitry Bezrukov /* RX Descriptor Header */ 642361459cdSDmitry Bezrukov skb_trim(skb, skb->len - sizeof(desc_hdr)); 643361459cdSDmitry Bezrukov desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); 644361459cdSDmitry Bezrukov 645361459cdSDmitry Bezrukov /* Check these packets */ 646361459cdSDmitry Bezrukov desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >> 647361459cdSDmitry Bezrukov AQ_RX_DH_DESC_OFFSET_SHIFT; 648361459cdSDmitry Bezrukov pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK; 649361459cdSDmitry Bezrukov start_of_descs = skb_len - ((pkt_count + 1) * sizeof(desc_hdr)); 650361459cdSDmitry Bezrukov 651361459cdSDmitry Bezrukov /* self check descs position */ 652361459cdSDmitry Bezrukov if (start_of_descs != desc_offset) 653361459cdSDmitry Bezrukov goto err; 654361459cdSDmitry Bezrukov 655361459cdSDmitry Bezrukov /* self check desc_offset from header*/ 656361459cdSDmitry Bezrukov if (desc_offset >= skb_len) 657361459cdSDmitry Bezrukov goto err; 658361459cdSDmitry Bezrukov 659361459cdSDmitry Bezrukov if (pkt_count == 0) 660361459cdSDmitry Bezrukov goto err; 661361459cdSDmitry Bezrukov 662361459cdSDmitry Bezrukov /* Get the first RX packet descriptor */ 663361459cdSDmitry Bezrukov pkt_desc_ptr = (u64 *)(skb->data + desc_offset); 664361459cdSDmitry Bezrukov 665361459cdSDmitry Bezrukov while (pkt_count--) { 666361459cdSDmitry Bezrukov u64 pkt_desc = le64_to_cpup(pkt_desc_ptr); 667361459cdSDmitry Bezrukov u32 pkt_len_with_padd = 0; 668361459cdSDmitry Bezrukov u32 pkt_len = 0; 669361459cdSDmitry Bezrukov 670361459cdSDmitry Bezrukov pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >> 671361459cdSDmitry Bezrukov AQ_RX_PD_LEN_SHIFT); 672361459cdSDmitry Bezrukov pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); 673361459cdSDmitry Bezrukov 674361459cdSDmitry Bezrukov pkt_total_offset += pkt_len_with_padd; 675361459cdSDmitry Bezrukov if (pkt_total_offset > desc_offset || 676361459cdSDmitry Bezrukov (pkt_count == 0 && pkt_total_offset != desc_offset)) { 677361459cdSDmitry Bezrukov goto err; 678361459cdSDmitry Bezrukov } 679361459cdSDmitry Bezrukov 680361459cdSDmitry Bezrukov if (pkt_desc & AQ_RX_PD_DROP || 681361459cdSDmitry Bezrukov !(pkt_desc & AQ_RX_PD_RX_OK) || 682361459cdSDmitry Bezrukov pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { 683361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 684361459cdSDmitry Bezrukov /* Next RX Packet Descriptor */ 685361459cdSDmitry Bezrukov pkt_desc_ptr++; 686361459cdSDmitry Bezrukov continue; 687361459cdSDmitry Bezrukov } 688361459cdSDmitry Bezrukov 689361459cdSDmitry Bezrukov /* Clone SKB */ 690361459cdSDmitry Bezrukov new_skb = skb_clone(skb, GFP_ATOMIC); 691361459cdSDmitry Bezrukov 692361459cdSDmitry Bezrukov if (!new_skb) 693361459cdSDmitry Bezrukov goto err; 694361459cdSDmitry Bezrukov 695361459cdSDmitry Bezrukov new_skb->len = pkt_len; 696361459cdSDmitry Bezrukov skb_pull(new_skb, AQ_RX_HW_PAD); 697361459cdSDmitry Bezrukov skb_set_tail_pointer(new_skb, new_skb->len); 698361459cdSDmitry Bezrukov 699361459cdSDmitry Bezrukov new_skb->truesize = SKB_TRUESIZE(new_skb->len); 700*02031466SDmitry Bezrukov aqc111_rx_checksum(new_skb, pkt_desc); 701361459cdSDmitry Bezrukov 702361459cdSDmitry Bezrukov usbnet_skb_return(dev, new_skb); 703361459cdSDmitry Bezrukov if (pkt_count == 0) 704361459cdSDmitry Bezrukov break; 705361459cdSDmitry Bezrukov 706361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 707361459cdSDmitry Bezrukov 708361459cdSDmitry Bezrukov /* Next RX Packet Header */ 709361459cdSDmitry Bezrukov pkt_desc_ptr++; 710361459cdSDmitry Bezrukov 711361459cdSDmitry Bezrukov new_skb = NULL; 712361459cdSDmitry Bezrukov } 713361459cdSDmitry Bezrukov 714361459cdSDmitry Bezrukov return 1; 715361459cdSDmitry Bezrukov 716361459cdSDmitry Bezrukov err: 717361459cdSDmitry Bezrukov return 0; 718361459cdSDmitry Bezrukov } 719361459cdSDmitry Bezrukov 7204a3576d2SDmitry Bezrukov static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 7214a3576d2SDmitry Bezrukov gfp_t flags) 7224a3576d2SDmitry Bezrukov { 7234a3576d2SDmitry Bezrukov int frame_size = dev->maxpacket; 7244a3576d2SDmitry Bezrukov struct sk_buff *new_skb = NULL; 7254a3576d2SDmitry Bezrukov u64 *tx_desc_ptr = NULL; 7264a3576d2SDmitry Bezrukov int padding_size = 0; 7274a3576d2SDmitry Bezrukov int headroom = 0; 7284a3576d2SDmitry Bezrukov int tailroom = 0; 7294a3576d2SDmitry Bezrukov u64 tx_desc = 0; 7304a3576d2SDmitry Bezrukov 7314a3576d2SDmitry Bezrukov /*Length of actual data*/ 7324a3576d2SDmitry Bezrukov tx_desc |= skb->len & AQ_TX_DESC_LEN_MASK; 7334a3576d2SDmitry Bezrukov 7344a3576d2SDmitry Bezrukov headroom = (skb->len + sizeof(tx_desc)) % 8; 7354a3576d2SDmitry Bezrukov if (headroom != 0) 7364a3576d2SDmitry Bezrukov padding_size = 8 - headroom; 7374a3576d2SDmitry Bezrukov 7384a3576d2SDmitry Bezrukov if (((skb->len + sizeof(tx_desc) + padding_size) % frame_size) == 0) { 7394a3576d2SDmitry Bezrukov padding_size += 8; 7404a3576d2SDmitry Bezrukov tx_desc |= AQ_TX_DESC_DROP_PADD; 7414a3576d2SDmitry Bezrukov } 7424a3576d2SDmitry Bezrukov 7434a3576d2SDmitry Bezrukov if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) && 7444a3576d2SDmitry Bezrukov skb_linearize(skb)) 7454a3576d2SDmitry Bezrukov return NULL; 7464a3576d2SDmitry Bezrukov 7474a3576d2SDmitry Bezrukov headroom = skb_headroom(skb); 7484a3576d2SDmitry Bezrukov tailroom = skb_tailroom(skb); 7494a3576d2SDmitry Bezrukov 7504a3576d2SDmitry Bezrukov if (!(headroom >= sizeof(tx_desc) && tailroom >= padding_size)) { 7514a3576d2SDmitry Bezrukov new_skb = skb_copy_expand(skb, sizeof(tx_desc), 7524a3576d2SDmitry Bezrukov padding_size, flags); 7534a3576d2SDmitry Bezrukov dev_kfree_skb_any(skb); 7544a3576d2SDmitry Bezrukov skb = new_skb; 7554a3576d2SDmitry Bezrukov if (!skb) 7564a3576d2SDmitry Bezrukov return NULL; 7574a3576d2SDmitry Bezrukov } 7584a3576d2SDmitry Bezrukov if (padding_size != 0) 7594a3576d2SDmitry Bezrukov skb_put_zero(skb, padding_size); 7604a3576d2SDmitry Bezrukov /* Copy TX header */ 7614a3576d2SDmitry Bezrukov tx_desc_ptr = skb_push(skb, sizeof(tx_desc)); 7624a3576d2SDmitry Bezrukov *tx_desc_ptr = cpu_to_le64(tx_desc); 7634a3576d2SDmitry Bezrukov 7644a3576d2SDmitry Bezrukov usbnet_set_skb_tx_stats(skb, 1, 0); 7654a3576d2SDmitry Bezrukov 7664a3576d2SDmitry Bezrukov return skb; 7674a3576d2SDmitry Bezrukov } 7684a3576d2SDmitry Bezrukov 76917364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 77017364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 7717cea2d40SDmitry Bezrukov .bind = aqc111_bind, 7727cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 7737b8b0654SDmitry Bezrukov .status = aqc111_status, 7747b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 775f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 776f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 7774a3576d2SDmitry Bezrukov .flags = FLAG_ETHER | FLAG_FRAMING_AX | 7784a3576d2SDmitry Bezrukov FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 779361459cdSDmitry Bezrukov .rx_fixup = aqc111_rx_fixup, 7804a3576d2SDmitry Bezrukov .tx_fixup = aqc111_tx_fixup, 78117364b80SDmitry Bezrukov }; 78217364b80SDmitry Bezrukov 78317364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 78417364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 78517364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 78617364b80SDmitry Bezrukov }, \ 78717364b80SDmitry Bezrukov { \ 78817364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 78917364b80SDmitry Bezrukov USB_CLASS_COMM, \ 79017364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 79117364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 79217364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 79317364b80SDmitry Bezrukov 79417364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 79517364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 79617364b80SDmitry Bezrukov { },/* END */ 79717364b80SDmitry Bezrukov }; 79817364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 79917364b80SDmitry Bezrukov 80017364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 80117364b80SDmitry Bezrukov .name = "aqc111", 80217364b80SDmitry Bezrukov .id_table = products, 80317364b80SDmitry Bezrukov .probe = usbnet_probe, 80417364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 80517364b80SDmitry Bezrukov }; 80617364b80SDmitry Bezrukov 80717364b80SDmitry Bezrukov module_usb_driver(aq_driver); 80817364b80SDmitry Bezrukov 80917364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 81017364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 811