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 208a4017cc2SDmitry Bezrukov static int aqc111_change_mtu(struct net_device *net, int new_mtu) 209a4017cc2SDmitry Bezrukov { 210a4017cc2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 211a4017cc2SDmitry Bezrukov u16 reg16 = 0; 212a4017cc2SDmitry Bezrukov u8 buf[5]; 213a4017cc2SDmitry Bezrukov 214a4017cc2SDmitry Bezrukov net->mtu = new_mtu; 215a4017cc2SDmitry Bezrukov dev->hard_mtu = net->mtu + net->hard_header_len; 216a4017cc2SDmitry Bezrukov 217a4017cc2SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 218a4017cc2SDmitry Bezrukov 2, ®16); 219a4017cc2SDmitry Bezrukov if (net->mtu > 1500) 220a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 221a4017cc2SDmitry Bezrukov else 222a4017cc2SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_JUMBO_EN; 223a4017cc2SDmitry Bezrukov 224a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 225a4017cc2SDmitry Bezrukov 2, ®16); 226a4017cc2SDmitry Bezrukov 227a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) { 228a4017cc2SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[2], 5); 229a4017cc2SDmitry Bezrukov /* RX bulk configuration */ 230a4017cc2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 231a4017cc2SDmitry Bezrukov 5, 5, buf); 232a4017cc2SDmitry Bezrukov } 233a4017cc2SDmitry Bezrukov 234a4017cc2SDmitry Bezrukov /* Set high low water level */ 235a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 236a4017cc2SDmitry Bezrukov reg16 = 0x0810; 237a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 238a4017cc2SDmitry Bezrukov reg16 = 0x1020; 239a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 240a4017cc2SDmitry Bezrukov reg16 = 0x1420; 241a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 242a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 243a4017cc2SDmitry Bezrukov 244a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 245a4017cc2SDmitry Bezrukov 2, ®16); 246a4017cc2SDmitry Bezrukov 247a4017cc2SDmitry Bezrukov return 0; 248a4017cc2SDmitry Bezrukov } 249a4017cc2SDmitry Bezrukov 250df2d59a2SDmitry Bezrukov static int aqc111_set_mac_addr(struct net_device *net, void *p) 251df2d59a2SDmitry Bezrukov { 252df2d59a2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 253df2d59a2SDmitry Bezrukov int ret = 0; 254df2d59a2SDmitry Bezrukov 255df2d59a2SDmitry Bezrukov ret = eth_mac_addr(net, p); 256df2d59a2SDmitry Bezrukov if (ret < 0) 257df2d59a2SDmitry Bezrukov return ret; 258df2d59a2SDmitry Bezrukov 259df2d59a2SDmitry Bezrukov /* Set the MAC address */ 260df2d59a2SDmitry Bezrukov return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 261df2d59a2SDmitry Bezrukov ETH_ALEN, net->dev_addr); 262df2d59a2SDmitry Bezrukov } 263df2d59a2SDmitry Bezrukov 264*6649d2a6SDmitry Bezrukov static int aqc111_set_features(struct net_device *net, 265*6649d2a6SDmitry Bezrukov netdev_features_t features) 266*6649d2a6SDmitry Bezrukov { 267*6649d2a6SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 268*6649d2a6SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 269*6649d2a6SDmitry Bezrukov netdev_features_t changed = net->features ^ features; 270*6649d2a6SDmitry Bezrukov u8 reg8 = 0; 271*6649d2a6SDmitry Bezrukov 272*6649d2a6SDmitry Bezrukov if (changed & NETIF_F_IP_CSUM) { 273*6649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 274*6649d2a6SDmitry Bezrukov reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP; 275*6649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 276*6649d2a6SDmitry Bezrukov 1, 1, ®8); 277*6649d2a6SDmitry Bezrukov } 278*6649d2a6SDmitry Bezrukov 279*6649d2a6SDmitry Bezrukov if (changed & NETIF_F_IPV6_CSUM) { 280*6649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 281*6649d2a6SDmitry Bezrukov reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 282*6649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 283*6649d2a6SDmitry Bezrukov 1, 1, ®8); 284*6649d2a6SDmitry Bezrukov } 285*6649d2a6SDmitry Bezrukov 286*6649d2a6SDmitry Bezrukov if (changed & NETIF_F_RXCSUM) { 287*6649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 288*6649d2a6SDmitry Bezrukov if (features & NETIF_F_RXCSUM) { 289*6649d2a6SDmitry Bezrukov aqc111_data->rx_checksum = 1; 290*6649d2a6SDmitry Bezrukov reg8 &= ~(SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 291*6649d2a6SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6); 292*6649d2a6SDmitry Bezrukov } else { 293*6649d2a6SDmitry Bezrukov aqc111_data->rx_checksum = 0; 294*6649d2a6SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 295*6649d2a6SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 296*6649d2a6SDmitry Bezrukov } 297*6649d2a6SDmitry Bezrukov 298*6649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 299*6649d2a6SDmitry Bezrukov 1, 1, ®8); 300*6649d2a6SDmitry Bezrukov } 301*6649d2a6SDmitry Bezrukov return 0; 302*6649d2a6SDmitry Bezrukov } 303*6649d2a6SDmitry Bezrukov 3047cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 3057cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 3067cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 3074a3576d2SDmitry Bezrukov .ndo_start_xmit = usbnet_start_xmit, 3084a3576d2SDmitry Bezrukov .ndo_tx_timeout = usbnet_tx_timeout, 3094a3576d2SDmitry Bezrukov .ndo_get_stats64 = usbnet_get_stats64, 310a4017cc2SDmitry Bezrukov .ndo_change_mtu = aqc111_change_mtu, 311df2d59a2SDmitry Bezrukov .ndo_set_mac_address = aqc111_set_mac_addr, 312df2d59a2SDmitry Bezrukov .ndo_validate_addr = eth_validate_addr, 313*6649d2a6SDmitry Bezrukov .ndo_set_features = aqc111_set_features, 3147cea2d40SDmitry Bezrukov }; 3157cea2d40SDmitry Bezrukov 316df2d59a2SDmitry Bezrukov static int aqc111_read_perm_mac(struct usbnet *dev) 317df2d59a2SDmitry Bezrukov { 318df2d59a2SDmitry Bezrukov u8 buf[ETH_ALEN]; 319df2d59a2SDmitry Bezrukov int ret; 320df2d59a2SDmitry Bezrukov 321df2d59a2SDmitry Bezrukov ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 322df2d59a2SDmitry Bezrukov if (ret < 0) 323df2d59a2SDmitry Bezrukov goto out; 324df2d59a2SDmitry Bezrukov 325df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->perm_addr, buf); 326df2d59a2SDmitry Bezrukov 327df2d59a2SDmitry Bezrukov return 0; 328df2d59a2SDmitry Bezrukov out: 329df2d59a2SDmitry Bezrukov return ret; 330df2d59a2SDmitry Bezrukov } 331df2d59a2SDmitry Bezrukov 33233cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 33333cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 33433cd597fSDmitry Bezrukov { 33533cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 33633cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 33733cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 33833cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 33933cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 34033cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 34133cd597fSDmitry Bezrukov 34233cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 34333cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 34433cd597fSDmitry Bezrukov } 34533cd597fSDmitry Bezrukov 3467cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 3477cea2d40SDmitry Bezrukov { 3487cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 3497b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 35033cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 3517cea2d40SDmitry Bezrukov int ret; 3527cea2d40SDmitry Bezrukov 3537cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 3547cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 3557cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 3567cea2d40SDmitry Bezrukov return -ENODEV; 3577cea2d40SDmitry Bezrukov } 3587cea2d40SDmitry Bezrukov 3597cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 3607cea2d40SDmitry Bezrukov 3617cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 3627cea2d40SDmitry Bezrukov if (ret < 0) { 3637cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 3647cea2d40SDmitry Bezrukov return ret; 3657cea2d40SDmitry Bezrukov } 3667cea2d40SDmitry Bezrukov 36733cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 36833cd597fSDmitry Bezrukov if (!aqc111_data) 36933cd597fSDmitry Bezrukov return -ENOMEM; 37033cd597fSDmitry Bezrukov 37133cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 37233cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 37333cd597fSDmitry Bezrukov 374df2d59a2SDmitry Bezrukov /* Init the MAC address */ 375df2d59a2SDmitry Bezrukov ret = aqc111_read_perm_mac(dev); 376df2d59a2SDmitry Bezrukov if (ret) 377df2d59a2SDmitry Bezrukov goto out; 378df2d59a2SDmitry Bezrukov 379df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 3804a3576d2SDmitry Bezrukov 381361459cdSDmitry Bezrukov /* Set Rx urb size */ 382361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 383361459cdSDmitry Bezrukov 3844a3576d2SDmitry Bezrukov /* Set TX needed headroom & tailroom */ 3854a3576d2SDmitry Bezrukov dev->net->needed_headroom += sizeof(u64); 3864a3576d2SDmitry Bezrukov dev->net->needed_tailroom += sizeof(u64); 3874a3576d2SDmitry Bezrukov 388a4017cc2SDmitry Bezrukov dev->net->max_mtu = 16334; 389a4017cc2SDmitry Bezrukov 3907cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 3917cea2d40SDmitry Bezrukov 3924a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 3934a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 3944a3576d2SDmitry Bezrukov 3954a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 3964a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 3974a3576d2SDmitry Bezrukov 39833cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 3997b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 4007b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 4017b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 40233cd597fSDmitry Bezrukov 4037cea2d40SDmitry Bezrukov return 0; 404df2d59a2SDmitry Bezrukov 405df2d59a2SDmitry Bezrukov out: 406df2d59a2SDmitry Bezrukov kfree(aqc111_data); 407df2d59a2SDmitry Bezrukov return ret; 4087cea2d40SDmitry Bezrukov } 4097cea2d40SDmitry Bezrukov 4107cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 4117cea2d40SDmitry Bezrukov { 41233cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 413f3aa095aSDmitry Bezrukov u16 reg16; 414f3aa095aSDmitry Bezrukov 415f3aa095aSDmitry Bezrukov /* Force bz */ 416f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 417f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 418f3aa095aSDmitry Bezrukov 2, ®16); 419f3aa095aSDmitry Bezrukov reg16 = 0; 420f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 421f3aa095aSDmitry Bezrukov 2, ®16); 42233cd597fSDmitry Bezrukov 42333cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 4247b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 42533cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 42633cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 42733cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 42833cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 42933cd597fSDmitry Bezrukov 43033cd597fSDmitry Bezrukov kfree(aqc111_data); 431f3aa095aSDmitry Bezrukov } 432f3aa095aSDmitry Bezrukov 4337b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 4347b8b0654SDmitry Bezrukov { 4357b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 4367b8b0654SDmitry Bezrukov u64 *event_data = NULL; 4377b8b0654SDmitry Bezrukov int link = 0; 4387b8b0654SDmitry Bezrukov 4397b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 4407b8b0654SDmitry Bezrukov return; 4417b8b0654SDmitry Bezrukov 4427b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 4437b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 4447b8b0654SDmitry Bezrukov 4457b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 4467b8b0654SDmitry Bezrukov link = 1; 4477b8b0654SDmitry Bezrukov else 4487b8b0654SDmitry Bezrukov link = 0; 4497b8b0654SDmitry Bezrukov 4507b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 4517b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 4527b8b0654SDmitry Bezrukov aqc111_data->link = link; 4537b8b0654SDmitry Bezrukov 4547b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 4557b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 4567b8b0654SDmitry Bezrukov } 4577b8b0654SDmitry Bezrukov 4587b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 4597b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 4607b8b0654SDmitry Bezrukov { 4617b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 4627b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 4637b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 4647b8b0654SDmitry Bezrukov u8 queue_num = 0; 4657b8b0654SDmitry Bezrukov u16 reg16 = 0; 4667b8b0654SDmitry Bezrukov u8 reg8 = 0; 4677b8b0654SDmitry Bezrukov 4687b8b0654SDmitry Bezrukov buf[0] = 0x00; 4697b8b0654SDmitry Bezrukov buf[1] = 0xF8; 4707b8b0654SDmitry Bezrukov buf[2] = 0x07; 4717b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 4727b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 4737b8b0654SDmitry Bezrukov link_speed = 5000; 4747b8b0654SDmitry Bezrukov reg8 = 0x05; 4757b8b0654SDmitry Bezrukov reg16 = 0x001F; 4767b8b0654SDmitry Bezrukov break; 4777b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 4787b8b0654SDmitry Bezrukov link_speed = 2500; 4797b8b0654SDmitry Bezrukov reg16 = 0x003F; 4807b8b0654SDmitry Bezrukov break; 4817b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 4827b8b0654SDmitry Bezrukov link_speed = 1000; 4837b8b0654SDmitry Bezrukov reg16 = 0x009F; 4847b8b0654SDmitry Bezrukov break; 4857b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 4867b8b0654SDmitry Bezrukov link_speed = 100; 4877b8b0654SDmitry Bezrukov queue_num = 1; 4887b8b0654SDmitry Bezrukov reg16 = 0x063F; 4897b8b0654SDmitry Bezrukov buf[1] = 0xFB; 4907b8b0654SDmitry Bezrukov buf[2] = 0x4; 4917b8b0654SDmitry Bezrukov break; 4927b8b0654SDmitry Bezrukov } 4937b8b0654SDmitry Bezrukov 4947b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 4957b8b0654SDmitry Bezrukov 1, 1, ®8); 4967b8b0654SDmitry Bezrukov 4977b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 4987b8b0654SDmitry Bezrukov 4997b8b0654SDmitry Bezrukov switch (usb_speed) { 5007b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 5017b8b0654SDmitry Bezrukov usb_host = 3; 5027b8b0654SDmitry Bezrukov break; 5037b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 5047b8b0654SDmitry Bezrukov usb_host = 2; 5057b8b0654SDmitry Bezrukov break; 5067b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 5077b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 5087b8b0654SDmitry Bezrukov usb_host = 1; 5097b8b0654SDmitry Bezrukov queue_num = 0; 5107b8b0654SDmitry Bezrukov break; 5117b8b0654SDmitry Bezrukov default: 5127b8b0654SDmitry Bezrukov usb_host = 0; 5137b8b0654SDmitry Bezrukov break; 5147b8b0654SDmitry Bezrukov } 5157b8b0654SDmitry Bezrukov 516a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) 517a4017cc2SDmitry Bezrukov queue_num = 2; /* For Jumbo packet 16KB */ 518a4017cc2SDmitry Bezrukov 5197b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 5207b8b0654SDmitry Bezrukov /* RX bulk configuration */ 5217b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 5227b8b0654SDmitry Bezrukov 5237b8b0654SDmitry Bezrukov /* Set high low water level */ 524a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 5257b8b0654SDmitry Bezrukov reg16 = 0x0810; 526a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 527a4017cc2SDmitry Bezrukov reg16 = 0x1020; 528a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 529a4017cc2SDmitry Bezrukov reg16 = 0x1420; 530a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 531a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 5327b8b0654SDmitry Bezrukov 5337b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 5347b8b0654SDmitry Bezrukov 2, ®16); 5357b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 5367b8b0654SDmitry Bezrukov } 5377b8b0654SDmitry Bezrukov 53802031466SDmitry Bezrukov static void aqc111_configure_csum_offload(struct usbnet *dev) 53902031466SDmitry Bezrukov { 54002031466SDmitry Bezrukov u8 reg8 = 0; 54102031466SDmitry Bezrukov 54202031466SDmitry Bezrukov if (dev->net->features & NETIF_F_RXCSUM) { 54302031466SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 54402031466SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 54502031466SDmitry Bezrukov } 54602031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 54702031466SDmitry Bezrukov 54802031466SDmitry Bezrukov reg8 = 0; 54902031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IP_CSUM) 55002031466SDmitry Bezrukov reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; 55102031466SDmitry Bezrukov 55202031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IPV6_CSUM) 55302031466SDmitry Bezrukov reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 55402031466SDmitry Bezrukov 55502031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 55602031466SDmitry Bezrukov } 55702031466SDmitry Bezrukov 5587b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 5597b8b0654SDmitry Bezrukov { 5607b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 5617b8b0654SDmitry Bezrukov u16 reg16 = 0; 5627b8b0654SDmitry Bezrukov u8 reg8 = 0; 5637b8b0654SDmitry Bezrukov 5647b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 5657b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 5667b8b0654SDmitry Bezrukov 5677b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 5687b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 5697b8b0654SDmitry Bezrukov 5707b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 5717b8b0654SDmitry Bezrukov 1, 1, ®8); 5727b8b0654SDmitry Bezrukov 5737b8b0654SDmitry Bezrukov reg8 = 0x0; 5747b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 5757b8b0654SDmitry Bezrukov 1, 1, ®8); 5767b8b0654SDmitry Bezrukov 5777b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 5787b8b0654SDmitry Bezrukov 1, 1, ®8); 5797b8b0654SDmitry Bezrukov 5807b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 5817b8b0654SDmitry Bezrukov 5827b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 5837b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5847b8b0654SDmitry Bezrukov 5857b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 5867b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 5877b8b0654SDmitry Bezrukov 1, 1, ®8); 5887b8b0654SDmitry Bezrukov 5897b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 5907b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5917b8b0654SDmitry Bezrukov 1, 1, ®8); 5927b8b0654SDmitry Bezrukov 5937b8b0654SDmitry Bezrukov reg16 = 0; 5947b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5957b8b0654SDmitry Bezrukov 2, ®16); 5967b8b0654SDmitry Bezrukov 5977b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 5987b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5997b8b0654SDmitry Bezrukov 2, ®16); 6007b8b0654SDmitry Bezrukov 60102031466SDmitry Bezrukov aqc111_configure_csum_offload(dev); 60202031466SDmitry Bezrukov 6037b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 6047b8b0654SDmitry Bezrukov 2, ®16); 6057b8b0654SDmitry Bezrukov 606a4017cc2SDmitry Bezrukov if (dev->net->mtu > 1500) 607a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 608a4017cc2SDmitry Bezrukov 6097b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 6107b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 6117b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 6127b8b0654SDmitry Bezrukov 2, ®16); 6137b8b0654SDmitry Bezrukov 6147b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START; 6157b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 6167b8b0654SDmitry Bezrukov 6177b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 6187b8b0654SDmitry Bezrukov } else { 6197b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 6207b8b0654SDmitry Bezrukov 2, ®16); 6217b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 6227b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 6237b8b0654SDmitry Bezrukov 2, ®16); 6247b8b0654SDmitry Bezrukov 6257b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 6267b8b0654SDmitry Bezrukov reg16 &= ~SFR_RX_CTL_START; 6277b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 6287b8b0654SDmitry Bezrukov 6297b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 6307b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 6317b8b0654SDmitry Bezrukov 1, 1, ®8); 6327b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 6337b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 6347b8b0654SDmitry Bezrukov 1, 1, ®8); 6357b8b0654SDmitry Bezrukov 6367b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 6377b8b0654SDmitry Bezrukov } 6387b8b0654SDmitry Bezrukov return 0; 6397b8b0654SDmitry Bezrukov } 6407b8b0654SDmitry Bezrukov 641f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 642f3aa095aSDmitry Bezrukov { 64333cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 644f3aa095aSDmitry Bezrukov u8 reg8 = 0; 645f3aa095aSDmitry Bezrukov 646361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 647361459cdSDmitry Bezrukov 6484a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 6494a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 6504a3576d2SDmitry Bezrukov 6514a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 6524a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 6534a3576d2SDmitry Bezrukov 65433cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 65533cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 65633cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 65733cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 65833cd597fSDmitry Bezrukov 659df2d59a2SDmitry Bezrukov /* Set the MAC address */ 660df2d59a2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 661df2d59a2SDmitry Bezrukov ETH_ALEN, dev->net->dev_addr); 662df2d59a2SDmitry Bezrukov 663f3aa095aSDmitry Bezrukov reg8 = 0xFF; 664f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 665f3aa095aSDmitry Bezrukov 666f3aa095aSDmitry Bezrukov reg8 = 0x0; 667f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 668f3aa095aSDmitry Bezrukov 669f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 670f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 671f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 672f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 673f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 674f3aa095aSDmitry Bezrukov 6757b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 6767b8b0654SDmitry Bezrukov 6777b8b0654SDmitry Bezrukov /* Phy advertise */ 6787b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 6797b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 6807b8b0654SDmitry Bezrukov 681f3aa095aSDmitry Bezrukov return 0; 682f3aa095aSDmitry Bezrukov } 683f3aa095aSDmitry Bezrukov 684f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 685f3aa095aSDmitry Bezrukov { 68633cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 687f3aa095aSDmitry Bezrukov u16 reg16 = 0; 688f3aa095aSDmitry Bezrukov 689f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 690f3aa095aSDmitry Bezrukov 2, ®16); 691f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 692f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 693f3aa095aSDmitry Bezrukov 2, ®16); 694f3aa095aSDmitry Bezrukov reg16 = 0; 695f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 696f3aa095aSDmitry Bezrukov 69733cd597fSDmitry Bezrukov /* Put PHY to low power*/ 69833cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 69933cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 70033cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 70133cd597fSDmitry Bezrukov 7027b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 7037b8b0654SDmitry Bezrukov 704f3aa095aSDmitry Bezrukov return 0; 7057cea2d40SDmitry Bezrukov } 7067cea2d40SDmitry Bezrukov 70702031466SDmitry Bezrukov static void aqc111_rx_checksum(struct sk_buff *skb, u64 pkt_desc) 70802031466SDmitry Bezrukov { 70902031466SDmitry Bezrukov u32 pkt_type = 0; 71002031466SDmitry Bezrukov 71102031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_NONE; 71202031466SDmitry Bezrukov /* checksum error bit is set */ 71302031466SDmitry Bezrukov if (pkt_desc & AQ_RX_PD_L4_ERR || pkt_desc & AQ_RX_PD_L3_ERR) 71402031466SDmitry Bezrukov return; 71502031466SDmitry Bezrukov 71602031466SDmitry Bezrukov pkt_type = pkt_desc & AQ_RX_PD_L4_TYPE_MASK; 71702031466SDmitry Bezrukov /* It must be a TCP or UDP packet with a valid checksum */ 71802031466SDmitry Bezrukov if (pkt_type == AQ_RX_PD_L4_TCP || pkt_type == AQ_RX_PD_L4_UDP) 71902031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_UNNECESSARY; 72002031466SDmitry Bezrukov } 72102031466SDmitry Bezrukov 722361459cdSDmitry Bezrukov static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 723361459cdSDmitry Bezrukov { 724*6649d2a6SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 725361459cdSDmitry Bezrukov struct sk_buff *new_skb = NULL; 726361459cdSDmitry Bezrukov u32 pkt_total_offset = 0; 727361459cdSDmitry Bezrukov u64 *pkt_desc_ptr = NULL; 728361459cdSDmitry Bezrukov u32 start_of_descs = 0; 729361459cdSDmitry Bezrukov u32 desc_offset = 0; /*RX Header Offset*/ 730361459cdSDmitry Bezrukov u16 pkt_count = 0; 731361459cdSDmitry Bezrukov u64 desc_hdr = 0; 732361459cdSDmitry Bezrukov u32 skb_len = 0; 733361459cdSDmitry Bezrukov 734361459cdSDmitry Bezrukov if (!skb) 735361459cdSDmitry Bezrukov goto err; 736361459cdSDmitry Bezrukov 737361459cdSDmitry Bezrukov if (skb->len == 0) 738361459cdSDmitry Bezrukov goto err; 739361459cdSDmitry Bezrukov 740361459cdSDmitry Bezrukov skb_len = skb->len; 741361459cdSDmitry Bezrukov /* RX Descriptor Header */ 742361459cdSDmitry Bezrukov skb_trim(skb, skb->len - sizeof(desc_hdr)); 743361459cdSDmitry Bezrukov desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); 744361459cdSDmitry Bezrukov 745361459cdSDmitry Bezrukov /* Check these packets */ 746361459cdSDmitry Bezrukov desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >> 747361459cdSDmitry Bezrukov AQ_RX_DH_DESC_OFFSET_SHIFT; 748361459cdSDmitry Bezrukov pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK; 749361459cdSDmitry Bezrukov start_of_descs = skb_len - ((pkt_count + 1) * sizeof(desc_hdr)); 750361459cdSDmitry Bezrukov 751361459cdSDmitry Bezrukov /* self check descs position */ 752361459cdSDmitry Bezrukov if (start_of_descs != desc_offset) 753361459cdSDmitry Bezrukov goto err; 754361459cdSDmitry Bezrukov 755361459cdSDmitry Bezrukov /* self check desc_offset from header*/ 756361459cdSDmitry Bezrukov if (desc_offset >= skb_len) 757361459cdSDmitry Bezrukov goto err; 758361459cdSDmitry Bezrukov 759361459cdSDmitry Bezrukov if (pkt_count == 0) 760361459cdSDmitry Bezrukov goto err; 761361459cdSDmitry Bezrukov 762361459cdSDmitry Bezrukov /* Get the first RX packet descriptor */ 763361459cdSDmitry Bezrukov pkt_desc_ptr = (u64 *)(skb->data + desc_offset); 764361459cdSDmitry Bezrukov 765361459cdSDmitry Bezrukov while (pkt_count--) { 766361459cdSDmitry Bezrukov u64 pkt_desc = le64_to_cpup(pkt_desc_ptr); 767361459cdSDmitry Bezrukov u32 pkt_len_with_padd = 0; 768361459cdSDmitry Bezrukov u32 pkt_len = 0; 769361459cdSDmitry Bezrukov 770361459cdSDmitry Bezrukov pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >> 771361459cdSDmitry Bezrukov AQ_RX_PD_LEN_SHIFT); 772361459cdSDmitry Bezrukov pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); 773361459cdSDmitry Bezrukov 774361459cdSDmitry Bezrukov pkt_total_offset += pkt_len_with_padd; 775361459cdSDmitry Bezrukov if (pkt_total_offset > desc_offset || 776361459cdSDmitry Bezrukov (pkt_count == 0 && pkt_total_offset != desc_offset)) { 777361459cdSDmitry Bezrukov goto err; 778361459cdSDmitry Bezrukov } 779361459cdSDmitry Bezrukov 780361459cdSDmitry Bezrukov if (pkt_desc & AQ_RX_PD_DROP || 781361459cdSDmitry Bezrukov !(pkt_desc & AQ_RX_PD_RX_OK) || 782361459cdSDmitry Bezrukov pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { 783361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 784361459cdSDmitry Bezrukov /* Next RX Packet Descriptor */ 785361459cdSDmitry Bezrukov pkt_desc_ptr++; 786361459cdSDmitry Bezrukov continue; 787361459cdSDmitry Bezrukov } 788361459cdSDmitry Bezrukov 789361459cdSDmitry Bezrukov /* Clone SKB */ 790361459cdSDmitry Bezrukov new_skb = skb_clone(skb, GFP_ATOMIC); 791361459cdSDmitry Bezrukov 792361459cdSDmitry Bezrukov if (!new_skb) 793361459cdSDmitry Bezrukov goto err; 794361459cdSDmitry Bezrukov 795361459cdSDmitry Bezrukov new_skb->len = pkt_len; 796361459cdSDmitry Bezrukov skb_pull(new_skb, AQ_RX_HW_PAD); 797361459cdSDmitry Bezrukov skb_set_tail_pointer(new_skb, new_skb->len); 798361459cdSDmitry Bezrukov 799361459cdSDmitry Bezrukov new_skb->truesize = SKB_TRUESIZE(new_skb->len); 800*6649d2a6SDmitry Bezrukov if (aqc111_data->rx_checksum) 80102031466SDmitry Bezrukov aqc111_rx_checksum(new_skb, pkt_desc); 802361459cdSDmitry Bezrukov 803361459cdSDmitry Bezrukov usbnet_skb_return(dev, new_skb); 804361459cdSDmitry Bezrukov if (pkt_count == 0) 805361459cdSDmitry Bezrukov break; 806361459cdSDmitry Bezrukov 807361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 808361459cdSDmitry Bezrukov 809361459cdSDmitry Bezrukov /* Next RX Packet Header */ 810361459cdSDmitry Bezrukov pkt_desc_ptr++; 811361459cdSDmitry Bezrukov 812361459cdSDmitry Bezrukov new_skb = NULL; 813361459cdSDmitry Bezrukov } 814361459cdSDmitry Bezrukov 815361459cdSDmitry Bezrukov return 1; 816361459cdSDmitry Bezrukov 817361459cdSDmitry Bezrukov err: 818361459cdSDmitry Bezrukov return 0; 819361459cdSDmitry Bezrukov } 820361459cdSDmitry Bezrukov 8214a3576d2SDmitry Bezrukov static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 8224a3576d2SDmitry Bezrukov gfp_t flags) 8234a3576d2SDmitry Bezrukov { 8244a3576d2SDmitry Bezrukov int frame_size = dev->maxpacket; 8254a3576d2SDmitry Bezrukov struct sk_buff *new_skb = NULL; 8264a3576d2SDmitry Bezrukov u64 *tx_desc_ptr = NULL; 8274a3576d2SDmitry Bezrukov int padding_size = 0; 8284a3576d2SDmitry Bezrukov int headroom = 0; 8294a3576d2SDmitry Bezrukov int tailroom = 0; 8304a3576d2SDmitry Bezrukov u64 tx_desc = 0; 8314a3576d2SDmitry Bezrukov 8324a3576d2SDmitry Bezrukov /*Length of actual data*/ 8334a3576d2SDmitry Bezrukov tx_desc |= skb->len & AQ_TX_DESC_LEN_MASK; 8344a3576d2SDmitry Bezrukov 8354a3576d2SDmitry Bezrukov headroom = (skb->len + sizeof(tx_desc)) % 8; 8364a3576d2SDmitry Bezrukov if (headroom != 0) 8374a3576d2SDmitry Bezrukov padding_size = 8 - headroom; 8384a3576d2SDmitry Bezrukov 8394a3576d2SDmitry Bezrukov if (((skb->len + sizeof(tx_desc) + padding_size) % frame_size) == 0) { 8404a3576d2SDmitry Bezrukov padding_size += 8; 8414a3576d2SDmitry Bezrukov tx_desc |= AQ_TX_DESC_DROP_PADD; 8424a3576d2SDmitry Bezrukov } 8434a3576d2SDmitry Bezrukov 8444a3576d2SDmitry Bezrukov if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) && 8454a3576d2SDmitry Bezrukov skb_linearize(skb)) 8464a3576d2SDmitry Bezrukov return NULL; 8474a3576d2SDmitry Bezrukov 8484a3576d2SDmitry Bezrukov headroom = skb_headroom(skb); 8494a3576d2SDmitry Bezrukov tailroom = skb_tailroom(skb); 8504a3576d2SDmitry Bezrukov 8514a3576d2SDmitry Bezrukov if (!(headroom >= sizeof(tx_desc) && tailroom >= padding_size)) { 8524a3576d2SDmitry Bezrukov new_skb = skb_copy_expand(skb, sizeof(tx_desc), 8534a3576d2SDmitry Bezrukov padding_size, flags); 8544a3576d2SDmitry Bezrukov dev_kfree_skb_any(skb); 8554a3576d2SDmitry Bezrukov skb = new_skb; 8564a3576d2SDmitry Bezrukov if (!skb) 8574a3576d2SDmitry Bezrukov return NULL; 8584a3576d2SDmitry Bezrukov } 8594a3576d2SDmitry Bezrukov if (padding_size != 0) 8604a3576d2SDmitry Bezrukov skb_put_zero(skb, padding_size); 8614a3576d2SDmitry Bezrukov /* Copy TX header */ 8624a3576d2SDmitry Bezrukov tx_desc_ptr = skb_push(skb, sizeof(tx_desc)); 8634a3576d2SDmitry Bezrukov *tx_desc_ptr = cpu_to_le64(tx_desc); 8644a3576d2SDmitry Bezrukov 8654a3576d2SDmitry Bezrukov usbnet_set_skb_tx_stats(skb, 1, 0); 8664a3576d2SDmitry Bezrukov 8674a3576d2SDmitry Bezrukov return skb; 8684a3576d2SDmitry Bezrukov } 8694a3576d2SDmitry Bezrukov 87017364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 87117364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 8727cea2d40SDmitry Bezrukov .bind = aqc111_bind, 8737cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 8747b8b0654SDmitry Bezrukov .status = aqc111_status, 8757b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 876f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 877f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 8784a3576d2SDmitry Bezrukov .flags = FLAG_ETHER | FLAG_FRAMING_AX | 8794a3576d2SDmitry Bezrukov FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 880361459cdSDmitry Bezrukov .rx_fixup = aqc111_rx_fixup, 8814a3576d2SDmitry Bezrukov .tx_fixup = aqc111_tx_fixup, 88217364b80SDmitry Bezrukov }; 88317364b80SDmitry Bezrukov 88417364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 88517364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 88617364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 88717364b80SDmitry Bezrukov }, \ 88817364b80SDmitry Bezrukov { \ 88917364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 89017364b80SDmitry Bezrukov USB_CLASS_COMM, \ 89117364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 89217364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 89317364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 89417364b80SDmitry Bezrukov 89517364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 89617364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 89717364b80SDmitry Bezrukov { },/* END */ 89817364b80SDmitry Bezrukov }; 89917364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 90017364b80SDmitry Bezrukov 90117364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 90217364b80SDmitry Bezrukov .name = "aqc111", 90317364b80SDmitry Bezrukov .id_table = products, 90417364b80SDmitry Bezrukov .probe = usbnet_probe, 90517364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 90617364b80SDmitry Bezrukov }; 90717364b80SDmitry Bezrukov 90817364b80SDmitry Bezrukov module_usb_driver(aq_driver); 90917364b80SDmitry Bezrukov 91017364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 91117364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 912