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 208*a4017cc2SDmitry Bezrukov static int aqc111_change_mtu(struct net_device *net, int new_mtu) 209*a4017cc2SDmitry Bezrukov { 210*a4017cc2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 211*a4017cc2SDmitry Bezrukov u16 reg16 = 0; 212*a4017cc2SDmitry Bezrukov u8 buf[5]; 213*a4017cc2SDmitry Bezrukov 214*a4017cc2SDmitry Bezrukov net->mtu = new_mtu; 215*a4017cc2SDmitry Bezrukov dev->hard_mtu = net->mtu + net->hard_header_len; 216*a4017cc2SDmitry Bezrukov 217*a4017cc2SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 218*a4017cc2SDmitry Bezrukov 2, ®16); 219*a4017cc2SDmitry Bezrukov if (net->mtu > 1500) 220*a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 221*a4017cc2SDmitry Bezrukov else 222*a4017cc2SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_JUMBO_EN; 223*a4017cc2SDmitry Bezrukov 224*a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 225*a4017cc2SDmitry Bezrukov 2, ®16); 226*a4017cc2SDmitry Bezrukov 227*a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) { 228*a4017cc2SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[2], 5); 229*a4017cc2SDmitry Bezrukov /* RX bulk configuration */ 230*a4017cc2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 231*a4017cc2SDmitry Bezrukov 5, 5, buf); 232*a4017cc2SDmitry Bezrukov } 233*a4017cc2SDmitry Bezrukov 234*a4017cc2SDmitry Bezrukov /* Set high low water level */ 235*a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 236*a4017cc2SDmitry Bezrukov reg16 = 0x0810; 237*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 238*a4017cc2SDmitry Bezrukov reg16 = 0x1020; 239*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 240*a4017cc2SDmitry Bezrukov reg16 = 0x1420; 241*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 242*a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 243*a4017cc2SDmitry Bezrukov 244*a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 245*a4017cc2SDmitry Bezrukov 2, ®16); 246*a4017cc2SDmitry Bezrukov 247*a4017cc2SDmitry Bezrukov return 0; 248*a4017cc2SDmitry Bezrukov } 249*a4017cc2SDmitry 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 2647cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 2657cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 2667cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 2674a3576d2SDmitry Bezrukov .ndo_start_xmit = usbnet_start_xmit, 2684a3576d2SDmitry Bezrukov .ndo_tx_timeout = usbnet_tx_timeout, 2694a3576d2SDmitry Bezrukov .ndo_get_stats64 = usbnet_get_stats64, 270*a4017cc2SDmitry Bezrukov .ndo_change_mtu = aqc111_change_mtu, 271df2d59a2SDmitry Bezrukov .ndo_set_mac_address = aqc111_set_mac_addr, 272df2d59a2SDmitry Bezrukov .ndo_validate_addr = eth_validate_addr, 2737cea2d40SDmitry Bezrukov }; 2747cea2d40SDmitry Bezrukov 275df2d59a2SDmitry Bezrukov static int aqc111_read_perm_mac(struct usbnet *dev) 276df2d59a2SDmitry Bezrukov { 277df2d59a2SDmitry Bezrukov u8 buf[ETH_ALEN]; 278df2d59a2SDmitry Bezrukov int ret; 279df2d59a2SDmitry Bezrukov 280df2d59a2SDmitry Bezrukov ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 281df2d59a2SDmitry Bezrukov if (ret < 0) 282df2d59a2SDmitry Bezrukov goto out; 283df2d59a2SDmitry Bezrukov 284df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->perm_addr, buf); 285df2d59a2SDmitry Bezrukov 286df2d59a2SDmitry Bezrukov return 0; 287df2d59a2SDmitry Bezrukov out: 288df2d59a2SDmitry Bezrukov return ret; 289df2d59a2SDmitry Bezrukov } 290df2d59a2SDmitry Bezrukov 29133cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 29233cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 29333cd597fSDmitry Bezrukov { 29433cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 29533cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 29633cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 29733cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 29833cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 29933cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 30033cd597fSDmitry Bezrukov 30133cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 30233cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 30333cd597fSDmitry Bezrukov } 30433cd597fSDmitry Bezrukov 3057cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 3067cea2d40SDmitry Bezrukov { 3077cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 3087b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 30933cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 3107cea2d40SDmitry Bezrukov int ret; 3117cea2d40SDmitry Bezrukov 3127cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 3137cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 3147cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 3157cea2d40SDmitry Bezrukov return -ENODEV; 3167cea2d40SDmitry Bezrukov } 3177cea2d40SDmitry Bezrukov 3187cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 3197cea2d40SDmitry Bezrukov 3207cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 3217cea2d40SDmitry Bezrukov if (ret < 0) { 3227cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 3237cea2d40SDmitry Bezrukov return ret; 3247cea2d40SDmitry Bezrukov } 3257cea2d40SDmitry Bezrukov 32633cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 32733cd597fSDmitry Bezrukov if (!aqc111_data) 32833cd597fSDmitry Bezrukov return -ENOMEM; 32933cd597fSDmitry Bezrukov 33033cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 33133cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 33233cd597fSDmitry Bezrukov 333df2d59a2SDmitry Bezrukov /* Init the MAC address */ 334df2d59a2SDmitry Bezrukov ret = aqc111_read_perm_mac(dev); 335df2d59a2SDmitry Bezrukov if (ret) 336df2d59a2SDmitry Bezrukov goto out; 337df2d59a2SDmitry Bezrukov 338df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 3394a3576d2SDmitry Bezrukov 340361459cdSDmitry Bezrukov /* Set Rx urb size */ 341361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 342361459cdSDmitry Bezrukov 3434a3576d2SDmitry Bezrukov /* Set TX needed headroom & tailroom */ 3444a3576d2SDmitry Bezrukov dev->net->needed_headroom += sizeof(u64); 3454a3576d2SDmitry Bezrukov dev->net->needed_tailroom += sizeof(u64); 3464a3576d2SDmitry Bezrukov 347*a4017cc2SDmitry Bezrukov dev->net->max_mtu = 16334; 348*a4017cc2SDmitry Bezrukov 3497cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 3507cea2d40SDmitry Bezrukov 3514a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 3524a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 3534a3576d2SDmitry Bezrukov 3544a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 3554a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 3564a3576d2SDmitry Bezrukov 35733cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 3587b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 3597b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 3607b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 36133cd597fSDmitry Bezrukov 3627cea2d40SDmitry Bezrukov return 0; 363df2d59a2SDmitry Bezrukov 364df2d59a2SDmitry Bezrukov out: 365df2d59a2SDmitry Bezrukov kfree(aqc111_data); 366df2d59a2SDmitry Bezrukov return ret; 3677cea2d40SDmitry Bezrukov } 3687cea2d40SDmitry Bezrukov 3697cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 3707cea2d40SDmitry Bezrukov { 37133cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 372f3aa095aSDmitry Bezrukov u16 reg16; 373f3aa095aSDmitry Bezrukov 374f3aa095aSDmitry Bezrukov /* Force bz */ 375f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 376f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 377f3aa095aSDmitry Bezrukov 2, ®16); 378f3aa095aSDmitry Bezrukov reg16 = 0; 379f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 380f3aa095aSDmitry Bezrukov 2, ®16); 38133cd597fSDmitry Bezrukov 38233cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 3837b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 38433cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 38533cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 38633cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 38733cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 38833cd597fSDmitry Bezrukov 38933cd597fSDmitry Bezrukov kfree(aqc111_data); 390f3aa095aSDmitry Bezrukov } 391f3aa095aSDmitry Bezrukov 3927b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 3937b8b0654SDmitry Bezrukov { 3947b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 3957b8b0654SDmitry Bezrukov u64 *event_data = NULL; 3967b8b0654SDmitry Bezrukov int link = 0; 3977b8b0654SDmitry Bezrukov 3987b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 3997b8b0654SDmitry Bezrukov return; 4007b8b0654SDmitry Bezrukov 4017b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 4027b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 4037b8b0654SDmitry Bezrukov 4047b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 4057b8b0654SDmitry Bezrukov link = 1; 4067b8b0654SDmitry Bezrukov else 4077b8b0654SDmitry Bezrukov link = 0; 4087b8b0654SDmitry Bezrukov 4097b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 4107b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 4117b8b0654SDmitry Bezrukov aqc111_data->link = link; 4127b8b0654SDmitry Bezrukov 4137b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 4147b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 4157b8b0654SDmitry Bezrukov } 4167b8b0654SDmitry Bezrukov 4177b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 4187b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 4197b8b0654SDmitry Bezrukov { 4207b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 4217b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 4227b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 4237b8b0654SDmitry Bezrukov u8 queue_num = 0; 4247b8b0654SDmitry Bezrukov u16 reg16 = 0; 4257b8b0654SDmitry Bezrukov u8 reg8 = 0; 4267b8b0654SDmitry Bezrukov 4277b8b0654SDmitry Bezrukov buf[0] = 0x00; 4287b8b0654SDmitry Bezrukov buf[1] = 0xF8; 4297b8b0654SDmitry Bezrukov buf[2] = 0x07; 4307b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 4317b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 4327b8b0654SDmitry Bezrukov link_speed = 5000; 4337b8b0654SDmitry Bezrukov reg8 = 0x05; 4347b8b0654SDmitry Bezrukov reg16 = 0x001F; 4357b8b0654SDmitry Bezrukov break; 4367b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 4377b8b0654SDmitry Bezrukov link_speed = 2500; 4387b8b0654SDmitry Bezrukov reg16 = 0x003F; 4397b8b0654SDmitry Bezrukov break; 4407b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 4417b8b0654SDmitry Bezrukov link_speed = 1000; 4427b8b0654SDmitry Bezrukov reg16 = 0x009F; 4437b8b0654SDmitry Bezrukov break; 4447b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 4457b8b0654SDmitry Bezrukov link_speed = 100; 4467b8b0654SDmitry Bezrukov queue_num = 1; 4477b8b0654SDmitry Bezrukov reg16 = 0x063F; 4487b8b0654SDmitry Bezrukov buf[1] = 0xFB; 4497b8b0654SDmitry Bezrukov buf[2] = 0x4; 4507b8b0654SDmitry Bezrukov break; 4517b8b0654SDmitry Bezrukov } 4527b8b0654SDmitry Bezrukov 4537b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 4547b8b0654SDmitry Bezrukov 1, 1, ®8); 4557b8b0654SDmitry Bezrukov 4567b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 4577b8b0654SDmitry Bezrukov 4587b8b0654SDmitry Bezrukov switch (usb_speed) { 4597b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 4607b8b0654SDmitry Bezrukov usb_host = 3; 4617b8b0654SDmitry Bezrukov break; 4627b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 4637b8b0654SDmitry Bezrukov usb_host = 2; 4647b8b0654SDmitry Bezrukov break; 4657b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 4667b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 4677b8b0654SDmitry Bezrukov usb_host = 1; 4687b8b0654SDmitry Bezrukov queue_num = 0; 4697b8b0654SDmitry Bezrukov break; 4707b8b0654SDmitry Bezrukov default: 4717b8b0654SDmitry Bezrukov usb_host = 0; 4727b8b0654SDmitry Bezrukov break; 4737b8b0654SDmitry Bezrukov } 4747b8b0654SDmitry Bezrukov 475*a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) 476*a4017cc2SDmitry Bezrukov queue_num = 2; /* For Jumbo packet 16KB */ 477*a4017cc2SDmitry Bezrukov 4787b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 4797b8b0654SDmitry Bezrukov /* RX bulk configuration */ 4807b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 4817b8b0654SDmitry Bezrukov 4827b8b0654SDmitry Bezrukov /* Set high low water level */ 483*a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 4847b8b0654SDmitry Bezrukov reg16 = 0x0810; 485*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 486*a4017cc2SDmitry Bezrukov reg16 = 0x1020; 487*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 488*a4017cc2SDmitry Bezrukov reg16 = 0x1420; 489*a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 490*a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 4917b8b0654SDmitry Bezrukov 4927b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 4937b8b0654SDmitry Bezrukov 2, ®16); 4947b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 4957b8b0654SDmitry Bezrukov } 4967b8b0654SDmitry Bezrukov 49702031466SDmitry Bezrukov static void aqc111_configure_csum_offload(struct usbnet *dev) 49802031466SDmitry Bezrukov { 49902031466SDmitry Bezrukov u8 reg8 = 0; 50002031466SDmitry Bezrukov 50102031466SDmitry Bezrukov if (dev->net->features & NETIF_F_RXCSUM) { 50202031466SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 50302031466SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 50402031466SDmitry Bezrukov } 50502031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 50602031466SDmitry Bezrukov 50702031466SDmitry Bezrukov reg8 = 0; 50802031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IP_CSUM) 50902031466SDmitry Bezrukov reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; 51002031466SDmitry Bezrukov 51102031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IPV6_CSUM) 51202031466SDmitry Bezrukov reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 51302031466SDmitry Bezrukov 51402031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 51502031466SDmitry Bezrukov } 51602031466SDmitry Bezrukov 5177b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 5187b8b0654SDmitry Bezrukov { 5197b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 5207b8b0654SDmitry Bezrukov u16 reg16 = 0; 5217b8b0654SDmitry Bezrukov u8 reg8 = 0; 5227b8b0654SDmitry Bezrukov 5237b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 5247b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 5257b8b0654SDmitry Bezrukov 5267b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 5277b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 5287b8b0654SDmitry Bezrukov 5297b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 5307b8b0654SDmitry Bezrukov 1, 1, ®8); 5317b8b0654SDmitry Bezrukov 5327b8b0654SDmitry Bezrukov reg8 = 0x0; 5337b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 5347b8b0654SDmitry Bezrukov 1, 1, ®8); 5357b8b0654SDmitry Bezrukov 5367b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 5377b8b0654SDmitry Bezrukov 1, 1, ®8); 5387b8b0654SDmitry Bezrukov 5397b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 5407b8b0654SDmitry Bezrukov 5417b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 5427b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5437b8b0654SDmitry Bezrukov 5447b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 5457b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 5467b8b0654SDmitry Bezrukov 1, 1, ®8); 5477b8b0654SDmitry Bezrukov 5487b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 5497b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5507b8b0654SDmitry Bezrukov 1, 1, ®8); 5517b8b0654SDmitry Bezrukov 5527b8b0654SDmitry Bezrukov reg16 = 0; 5537b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5547b8b0654SDmitry Bezrukov 2, ®16); 5557b8b0654SDmitry Bezrukov 5567b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 5577b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5587b8b0654SDmitry Bezrukov 2, ®16); 5597b8b0654SDmitry Bezrukov 56002031466SDmitry Bezrukov aqc111_configure_csum_offload(dev); 56102031466SDmitry Bezrukov 5627b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5637b8b0654SDmitry Bezrukov 2, ®16); 5647b8b0654SDmitry Bezrukov 565*a4017cc2SDmitry Bezrukov if (dev->net->mtu > 1500) 566*a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 567*a4017cc2SDmitry Bezrukov 5687b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 5697b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 5707b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5717b8b0654SDmitry Bezrukov 2, ®16); 5727b8b0654SDmitry Bezrukov 5737b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START; 5747b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5757b8b0654SDmitry Bezrukov 5767b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 5777b8b0654SDmitry Bezrukov } else { 5787b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5797b8b0654SDmitry Bezrukov 2, ®16); 5807b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 5817b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 5827b8b0654SDmitry Bezrukov 2, ®16); 5837b8b0654SDmitry Bezrukov 5847b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5857b8b0654SDmitry Bezrukov reg16 &= ~SFR_RX_CTL_START; 5867b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 5877b8b0654SDmitry Bezrukov 5887b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 5897b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5907b8b0654SDmitry Bezrukov 1, 1, ®8); 5917b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 5927b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 5937b8b0654SDmitry Bezrukov 1, 1, ®8); 5947b8b0654SDmitry Bezrukov 5957b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 5967b8b0654SDmitry Bezrukov } 5977b8b0654SDmitry Bezrukov return 0; 5987b8b0654SDmitry Bezrukov } 5997b8b0654SDmitry Bezrukov 600f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 601f3aa095aSDmitry Bezrukov { 60233cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 603f3aa095aSDmitry Bezrukov u8 reg8 = 0; 604f3aa095aSDmitry Bezrukov 605361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 606361459cdSDmitry Bezrukov 6074a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 6084a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 6094a3576d2SDmitry Bezrukov 6104a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 6114a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 6124a3576d2SDmitry Bezrukov 61333cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 61433cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 61533cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 61633cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 61733cd597fSDmitry Bezrukov 618df2d59a2SDmitry Bezrukov /* Set the MAC address */ 619df2d59a2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 620df2d59a2SDmitry Bezrukov ETH_ALEN, dev->net->dev_addr); 621df2d59a2SDmitry Bezrukov 622f3aa095aSDmitry Bezrukov reg8 = 0xFF; 623f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 624f3aa095aSDmitry Bezrukov 625f3aa095aSDmitry Bezrukov reg8 = 0x0; 626f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 627f3aa095aSDmitry Bezrukov 628f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 629f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 630f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 631f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 632f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 633f3aa095aSDmitry Bezrukov 6347b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 6357b8b0654SDmitry Bezrukov 6367b8b0654SDmitry Bezrukov /* Phy advertise */ 6377b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 6387b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 6397b8b0654SDmitry Bezrukov 640f3aa095aSDmitry Bezrukov return 0; 641f3aa095aSDmitry Bezrukov } 642f3aa095aSDmitry Bezrukov 643f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 644f3aa095aSDmitry Bezrukov { 64533cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 646f3aa095aSDmitry Bezrukov u16 reg16 = 0; 647f3aa095aSDmitry Bezrukov 648f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 649f3aa095aSDmitry Bezrukov 2, ®16); 650f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 651f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 652f3aa095aSDmitry Bezrukov 2, ®16); 653f3aa095aSDmitry Bezrukov reg16 = 0; 654f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 655f3aa095aSDmitry Bezrukov 65633cd597fSDmitry Bezrukov /* Put PHY to low power*/ 65733cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 65833cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 65933cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 66033cd597fSDmitry Bezrukov 6617b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 6627b8b0654SDmitry Bezrukov 663f3aa095aSDmitry Bezrukov return 0; 6647cea2d40SDmitry Bezrukov } 6657cea2d40SDmitry Bezrukov 66602031466SDmitry Bezrukov static void aqc111_rx_checksum(struct sk_buff *skb, u64 pkt_desc) 66702031466SDmitry Bezrukov { 66802031466SDmitry Bezrukov u32 pkt_type = 0; 66902031466SDmitry Bezrukov 67002031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_NONE; 67102031466SDmitry Bezrukov /* checksum error bit is set */ 67202031466SDmitry Bezrukov if (pkt_desc & AQ_RX_PD_L4_ERR || pkt_desc & AQ_RX_PD_L3_ERR) 67302031466SDmitry Bezrukov return; 67402031466SDmitry Bezrukov 67502031466SDmitry Bezrukov pkt_type = pkt_desc & AQ_RX_PD_L4_TYPE_MASK; 67602031466SDmitry Bezrukov /* It must be a TCP or UDP packet with a valid checksum */ 67702031466SDmitry Bezrukov if (pkt_type == AQ_RX_PD_L4_TCP || pkt_type == AQ_RX_PD_L4_UDP) 67802031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_UNNECESSARY; 67902031466SDmitry Bezrukov } 68002031466SDmitry Bezrukov 681361459cdSDmitry Bezrukov static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 682361459cdSDmitry Bezrukov { 683361459cdSDmitry Bezrukov struct sk_buff *new_skb = NULL; 684361459cdSDmitry Bezrukov u32 pkt_total_offset = 0; 685361459cdSDmitry Bezrukov u64 *pkt_desc_ptr = NULL; 686361459cdSDmitry Bezrukov u32 start_of_descs = 0; 687361459cdSDmitry Bezrukov u32 desc_offset = 0; /*RX Header Offset*/ 688361459cdSDmitry Bezrukov u16 pkt_count = 0; 689361459cdSDmitry Bezrukov u64 desc_hdr = 0; 690361459cdSDmitry Bezrukov u32 skb_len = 0; 691361459cdSDmitry Bezrukov 692361459cdSDmitry Bezrukov if (!skb) 693361459cdSDmitry Bezrukov goto err; 694361459cdSDmitry Bezrukov 695361459cdSDmitry Bezrukov if (skb->len == 0) 696361459cdSDmitry Bezrukov goto err; 697361459cdSDmitry Bezrukov 698361459cdSDmitry Bezrukov skb_len = skb->len; 699361459cdSDmitry Bezrukov /* RX Descriptor Header */ 700361459cdSDmitry Bezrukov skb_trim(skb, skb->len - sizeof(desc_hdr)); 701361459cdSDmitry Bezrukov desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); 702361459cdSDmitry Bezrukov 703361459cdSDmitry Bezrukov /* Check these packets */ 704361459cdSDmitry Bezrukov desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >> 705361459cdSDmitry Bezrukov AQ_RX_DH_DESC_OFFSET_SHIFT; 706361459cdSDmitry Bezrukov pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK; 707361459cdSDmitry Bezrukov start_of_descs = skb_len - ((pkt_count + 1) * sizeof(desc_hdr)); 708361459cdSDmitry Bezrukov 709361459cdSDmitry Bezrukov /* self check descs position */ 710361459cdSDmitry Bezrukov if (start_of_descs != desc_offset) 711361459cdSDmitry Bezrukov goto err; 712361459cdSDmitry Bezrukov 713361459cdSDmitry Bezrukov /* self check desc_offset from header*/ 714361459cdSDmitry Bezrukov if (desc_offset >= skb_len) 715361459cdSDmitry Bezrukov goto err; 716361459cdSDmitry Bezrukov 717361459cdSDmitry Bezrukov if (pkt_count == 0) 718361459cdSDmitry Bezrukov goto err; 719361459cdSDmitry Bezrukov 720361459cdSDmitry Bezrukov /* Get the first RX packet descriptor */ 721361459cdSDmitry Bezrukov pkt_desc_ptr = (u64 *)(skb->data + desc_offset); 722361459cdSDmitry Bezrukov 723361459cdSDmitry Bezrukov while (pkt_count--) { 724361459cdSDmitry Bezrukov u64 pkt_desc = le64_to_cpup(pkt_desc_ptr); 725361459cdSDmitry Bezrukov u32 pkt_len_with_padd = 0; 726361459cdSDmitry Bezrukov u32 pkt_len = 0; 727361459cdSDmitry Bezrukov 728361459cdSDmitry Bezrukov pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >> 729361459cdSDmitry Bezrukov AQ_RX_PD_LEN_SHIFT); 730361459cdSDmitry Bezrukov pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); 731361459cdSDmitry Bezrukov 732361459cdSDmitry Bezrukov pkt_total_offset += pkt_len_with_padd; 733361459cdSDmitry Bezrukov if (pkt_total_offset > desc_offset || 734361459cdSDmitry Bezrukov (pkt_count == 0 && pkt_total_offset != desc_offset)) { 735361459cdSDmitry Bezrukov goto err; 736361459cdSDmitry Bezrukov } 737361459cdSDmitry Bezrukov 738361459cdSDmitry Bezrukov if (pkt_desc & AQ_RX_PD_DROP || 739361459cdSDmitry Bezrukov !(pkt_desc & AQ_RX_PD_RX_OK) || 740361459cdSDmitry Bezrukov pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { 741361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 742361459cdSDmitry Bezrukov /* Next RX Packet Descriptor */ 743361459cdSDmitry Bezrukov pkt_desc_ptr++; 744361459cdSDmitry Bezrukov continue; 745361459cdSDmitry Bezrukov } 746361459cdSDmitry Bezrukov 747361459cdSDmitry Bezrukov /* Clone SKB */ 748361459cdSDmitry Bezrukov new_skb = skb_clone(skb, GFP_ATOMIC); 749361459cdSDmitry Bezrukov 750361459cdSDmitry Bezrukov if (!new_skb) 751361459cdSDmitry Bezrukov goto err; 752361459cdSDmitry Bezrukov 753361459cdSDmitry Bezrukov new_skb->len = pkt_len; 754361459cdSDmitry Bezrukov skb_pull(new_skb, AQ_RX_HW_PAD); 755361459cdSDmitry Bezrukov skb_set_tail_pointer(new_skb, new_skb->len); 756361459cdSDmitry Bezrukov 757361459cdSDmitry Bezrukov new_skb->truesize = SKB_TRUESIZE(new_skb->len); 75802031466SDmitry Bezrukov aqc111_rx_checksum(new_skb, pkt_desc); 759361459cdSDmitry Bezrukov 760361459cdSDmitry Bezrukov usbnet_skb_return(dev, new_skb); 761361459cdSDmitry Bezrukov if (pkt_count == 0) 762361459cdSDmitry Bezrukov break; 763361459cdSDmitry Bezrukov 764361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 765361459cdSDmitry Bezrukov 766361459cdSDmitry Bezrukov /* Next RX Packet Header */ 767361459cdSDmitry Bezrukov pkt_desc_ptr++; 768361459cdSDmitry Bezrukov 769361459cdSDmitry Bezrukov new_skb = NULL; 770361459cdSDmitry Bezrukov } 771361459cdSDmitry Bezrukov 772361459cdSDmitry Bezrukov return 1; 773361459cdSDmitry Bezrukov 774361459cdSDmitry Bezrukov err: 775361459cdSDmitry Bezrukov return 0; 776361459cdSDmitry Bezrukov } 777361459cdSDmitry Bezrukov 7784a3576d2SDmitry Bezrukov static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 7794a3576d2SDmitry Bezrukov gfp_t flags) 7804a3576d2SDmitry Bezrukov { 7814a3576d2SDmitry Bezrukov int frame_size = dev->maxpacket; 7824a3576d2SDmitry Bezrukov struct sk_buff *new_skb = NULL; 7834a3576d2SDmitry Bezrukov u64 *tx_desc_ptr = NULL; 7844a3576d2SDmitry Bezrukov int padding_size = 0; 7854a3576d2SDmitry Bezrukov int headroom = 0; 7864a3576d2SDmitry Bezrukov int tailroom = 0; 7874a3576d2SDmitry Bezrukov u64 tx_desc = 0; 7884a3576d2SDmitry Bezrukov 7894a3576d2SDmitry Bezrukov /*Length of actual data*/ 7904a3576d2SDmitry Bezrukov tx_desc |= skb->len & AQ_TX_DESC_LEN_MASK; 7914a3576d2SDmitry Bezrukov 7924a3576d2SDmitry Bezrukov headroom = (skb->len + sizeof(tx_desc)) % 8; 7934a3576d2SDmitry Bezrukov if (headroom != 0) 7944a3576d2SDmitry Bezrukov padding_size = 8 - headroom; 7954a3576d2SDmitry Bezrukov 7964a3576d2SDmitry Bezrukov if (((skb->len + sizeof(tx_desc) + padding_size) % frame_size) == 0) { 7974a3576d2SDmitry Bezrukov padding_size += 8; 7984a3576d2SDmitry Bezrukov tx_desc |= AQ_TX_DESC_DROP_PADD; 7994a3576d2SDmitry Bezrukov } 8004a3576d2SDmitry Bezrukov 8014a3576d2SDmitry Bezrukov if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) && 8024a3576d2SDmitry Bezrukov skb_linearize(skb)) 8034a3576d2SDmitry Bezrukov return NULL; 8044a3576d2SDmitry Bezrukov 8054a3576d2SDmitry Bezrukov headroom = skb_headroom(skb); 8064a3576d2SDmitry Bezrukov tailroom = skb_tailroom(skb); 8074a3576d2SDmitry Bezrukov 8084a3576d2SDmitry Bezrukov if (!(headroom >= sizeof(tx_desc) && tailroom >= padding_size)) { 8094a3576d2SDmitry Bezrukov new_skb = skb_copy_expand(skb, sizeof(tx_desc), 8104a3576d2SDmitry Bezrukov padding_size, flags); 8114a3576d2SDmitry Bezrukov dev_kfree_skb_any(skb); 8124a3576d2SDmitry Bezrukov skb = new_skb; 8134a3576d2SDmitry Bezrukov if (!skb) 8144a3576d2SDmitry Bezrukov return NULL; 8154a3576d2SDmitry Bezrukov } 8164a3576d2SDmitry Bezrukov if (padding_size != 0) 8174a3576d2SDmitry Bezrukov skb_put_zero(skb, padding_size); 8184a3576d2SDmitry Bezrukov /* Copy TX header */ 8194a3576d2SDmitry Bezrukov tx_desc_ptr = skb_push(skb, sizeof(tx_desc)); 8204a3576d2SDmitry Bezrukov *tx_desc_ptr = cpu_to_le64(tx_desc); 8214a3576d2SDmitry Bezrukov 8224a3576d2SDmitry Bezrukov usbnet_set_skb_tx_stats(skb, 1, 0); 8234a3576d2SDmitry Bezrukov 8244a3576d2SDmitry Bezrukov return skb; 8254a3576d2SDmitry Bezrukov } 8264a3576d2SDmitry Bezrukov 82717364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 82817364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 8297cea2d40SDmitry Bezrukov .bind = aqc111_bind, 8307cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 8317b8b0654SDmitry Bezrukov .status = aqc111_status, 8327b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 833f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 834f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 8354a3576d2SDmitry Bezrukov .flags = FLAG_ETHER | FLAG_FRAMING_AX | 8364a3576d2SDmitry Bezrukov FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 837361459cdSDmitry Bezrukov .rx_fixup = aqc111_rx_fixup, 8384a3576d2SDmitry Bezrukov .tx_fixup = aqc111_tx_fixup, 83917364b80SDmitry Bezrukov }; 84017364b80SDmitry Bezrukov 84117364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 84217364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 84317364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 84417364b80SDmitry Bezrukov }, \ 84517364b80SDmitry Bezrukov { \ 84617364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 84717364b80SDmitry Bezrukov USB_CLASS_COMM, \ 84817364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 84917364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 85017364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 85117364b80SDmitry Bezrukov 85217364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 85317364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 85417364b80SDmitry Bezrukov { },/* END */ 85517364b80SDmitry Bezrukov }; 85617364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 85717364b80SDmitry Bezrukov 85817364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 85917364b80SDmitry Bezrukov .name = "aqc111", 86017364b80SDmitry Bezrukov .id_table = products, 86117364b80SDmitry Bezrukov .probe = usbnet_probe, 86217364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 86317364b80SDmitry Bezrukov }; 86417364b80SDmitry Bezrukov 86517364b80SDmitry Bezrukov module_usb_driver(aq_driver); 86617364b80SDmitry Bezrukov 86717364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 86817364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 869