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> 14*df2d59a2SDmitry 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*df2d59a2SDmitry Bezrukov static int aqc111_set_mac_addr(struct net_device *net, void *p) 209*df2d59a2SDmitry Bezrukov { 210*df2d59a2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 211*df2d59a2SDmitry Bezrukov int ret = 0; 212*df2d59a2SDmitry Bezrukov 213*df2d59a2SDmitry Bezrukov ret = eth_mac_addr(net, p); 214*df2d59a2SDmitry Bezrukov if (ret < 0) 215*df2d59a2SDmitry Bezrukov return ret; 216*df2d59a2SDmitry Bezrukov 217*df2d59a2SDmitry Bezrukov /* Set the MAC address */ 218*df2d59a2SDmitry Bezrukov return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 219*df2d59a2SDmitry Bezrukov ETH_ALEN, net->dev_addr); 220*df2d59a2SDmitry Bezrukov } 221*df2d59a2SDmitry Bezrukov 2227cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 2237cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 2247cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 225*df2d59a2SDmitry Bezrukov .ndo_set_mac_address = aqc111_set_mac_addr, 226*df2d59a2SDmitry Bezrukov .ndo_validate_addr = eth_validate_addr, 2277cea2d40SDmitry Bezrukov }; 2287cea2d40SDmitry Bezrukov 229*df2d59a2SDmitry Bezrukov static int aqc111_read_perm_mac(struct usbnet *dev) 230*df2d59a2SDmitry Bezrukov { 231*df2d59a2SDmitry Bezrukov u8 buf[ETH_ALEN]; 232*df2d59a2SDmitry Bezrukov int ret; 233*df2d59a2SDmitry Bezrukov 234*df2d59a2SDmitry Bezrukov ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 235*df2d59a2SDmitry Bezrukov if (ret < 0) 236*df2d59a2SDmitry Bezrukov goto out; 237*df2d59a2SDmitry Bezrukov 238*df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->perm_addr, buf); 239*df2d59a2SDmitry Bezrukov 240*df2d59a2SDmitry Bezrukov return 0; 241*df2d59a2SDmitry Bezrukov out: 242*df2d59a2SDmitry Bezrukov return ret; 243*df2d59a2SDmitry Bezrukov } 244*df2d59a2SDmitry Bezrukov 24533cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 24633cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 24733cd597fSDmitry Bezrukov { 24833cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 24933cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 25033cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 25133cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 25233cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 25333cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 25433cd597fSDmitry Bezrukov 25533cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 25633cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 25733cd597fSDmitry Bezrukov } 25833cd597fSDmitry Bezrukov 2597cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 2607cea2d40SDmitry Bezrukov { 2617cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 2627b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 26333cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 2647cea2d40SDmitry Bezrukov int ret; 2657cea2d40SDmitry Bezrukov 2667cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 2677cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 2687cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 2697cea2d40SDmitry Bezrukov return -ENODEV; 2707cea2d40SDmitry Bezrukov } 2717cea2d40SDmitry Bezrukov 2727cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 2737cea2d40SDmitry Bezrukov 2747cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 2757cea2d40SDmitry Bezrukov if (ret < 0) { 2767cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 2777cea2d40SDmitry Bezrukov return ret; 2787cea2d40SDmitry Bezrukov } 2797cea2d40SDmitry Bezrukov 28033cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 28133cd597fSDmitry Bezrukov if (!aqc111_data) 28233cd597fSDmitry Bezrukov return -ENOMEM; 28333cd597fSDmitry Bezrukov 28433cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 28533cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 28633cd597fSDmitry Bezrukov 287*df2d59a2SDmitry Bezrukov /* Init the MAC address */ 288*df2d59a2SDmitry Bezrukov ret = aqc111_read_perm_mac(dev); 289*df2d59a2SDmitry Bezrukov if (ret) 290*df2d59a2SDmitry Bezrukov goto out; 291*df2d59a2SDmitry Bezrukov 292*df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 2937cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 2947cea2d40SDmitry Bezrukov 29533cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 2967b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 2977b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 2987b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 29933cd597fSDmitry Bezrukov 3007cea2d40SDmitry Bezrukov return 0; 301*df2d59a2SDmitry Bezrukov 302*df2d59a2SDmitry Bezrukov out: 303*df2d59a2SDmitry Bezrukov kfree(aqc111_data); 304*df2d59a2SDmitry Bezrukov return ret; 3057cea2d40SDmitry Bezrukov } 3067cea2d40SDmitry Bezrukov 3077cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 3087cea2d40SDmitry Bezrukov { 30933cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 310f3aa095aSDmitry Bezrukov u16 reg16; 311f3aa095aSDmitry Bezrukov 312f3aa095aSDmitry Bezrukov /* Force bz */ 313f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 314f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 315f3aa095aSDmitry Bezrukov 2, ®16); 316f3aa095aSDmitry Bezrukov reg16 = 0; 317f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 318f3aa095aSDmitry Bezrukov 2, ®16); 31933cd597fSDmitry Bezrukov 32033cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 3217b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 32233cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 32333cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 32433cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 32533cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 32633cd597fSDmitry Bezrukov 32733cd597fSDmitry Bezrukov kfree(aqc111_data); 328f3aa095aSDmitry Bezrukov } 329f3aa095aSDmitry Bezrukov 3307b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 3317b8b0654SDmitry Bezrukov { 3327b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 3337b8b0654SDmitry Bezrukov u64 *event_data = NULL; 3347b8b0654SDmitry Bezrukov int link = 0; 3357b8b0654SDmitry Bezrukov 3367b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 3377b8b0654SDmitry Bezrukov return; 3387b8b0654SDmitry Bezrukov 3397b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 3407b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 3417b8b0654SDmitry Bezrukov 3427b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 3437b8b0654SDmitry Bezrukov link = 1; 3447b8b0654SDmitry Bezrukov else 3457b8b0654SDmitry Bezrukov link = 0; 3467b8b0654SDmitry Bezrukov 3477b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 3487b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 3497b8b0654SDmitry Bezrukov aqc111_data->link = link; 3507b8b0654SDmitry Bezrukov 3517b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 3527b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 3537b8b0654SDmitry Bezrukov } 3547b8b0654SDmitry Bezrukov 3557b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 3567b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 3577b8b0654SDmitry Bezrukov { 3587b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 3597b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 3607b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 3617b8b0654SDmitry Bezrukov u8 queue_num = 0; 3627b8b0654SDmitry Bezrukov u16 reg16 = 0; 3637b8b0654SDmitry Bezrukov u8 reg8 = 0; 3647b8b0654SDmitry Bezrukov 3657b8b0654SDmitry Bezrukov buf[0] = 0x00; 3667b8b0654SDmitry Bezrukov buf[1] = 0xF8; 3677b8b0654SDmitry Bezrukov buf[2] = 0x07; 3687b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 3697b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 3707b8b0654SDmitry Bezrukov link_speed = 5000; 3717b8b0654SDmitry Bezrukov reg8 = 0x05; 3727b8b0654SDmitry Bezrukov reg16 = 0x001F; 3737b8b0654SDmitry Bezrukov break; 3747b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 3757b8b0654SDmitry Bezrukov link_speed = 2500; 3767b8b0654SDmitry Bezrukov reg16 = 0x003F; 3777b8b0654SDmitry Bezrukov break; 3787b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 3797b8b0654SDmitry Bezrukov link_speed = 1000; 3807b8b0654SDmitry Bezrukov reg16 = 0x009F; 3817b8b0654SDmitry Bezrukov break; 3827b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 3837b8b0654SDmitry Bezrukov link_speed = 100; 3847b8b0654SDmitry Bezrukov queue_num = 1; 3857b8b0654SDmitry Bezrukov reg16 = 0x063F; 3867b8b0654SDmitry Bezrukov buf[1] = 0xFB; 3877b8b0654SDmitry Bezrukov buf[2] = 0x4; 3887b8b0654SDmitry Bezrukov break; 3897b8b0654SDmitry Bezrukov } 3907b8b0654SDmitry Bezrukov 3917b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 3927b8b0654SDmitry Bezrukov 1, 1, ®8); 3937b8b0654SDmitry Bezrukov 3947b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 3957b8b0654SDmitry Bezrukov 3967b8b0654SDmitry Bezrukov switch (usb_speed) { 3977b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 3987b8b0654SDmitry Bezrukov usb_host = 3; 3997b8b0654SDmitry Bezrukov break; 4007b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 4017b8b0654SDmitry Bezrukov usb_host = 2; 4027b8b0654SDmitry Bezrukov break; 4037b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 4047b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 4057b8b0654SDmitry Bezrukov usb_host = 1; 4067b8b0654SDmitry Bezrukov queue_num = 0; 4077b8b0654SDmitry Bezrukov break; 4087b8b0654SDmitry Bezrukov default: 4097b8b0654SDmitry Bezrukov usb_host = 0; 4107b8b0654SDmitry Bezrukov break; 4117b8b0654SDmitry Bezrukov } 4127b8b0654SDmitry Bezrukov 4137b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 4147b8b0654SDmitry Bezrukov /* RX bulk configuration */ 4157b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 4167b8b0654SDmitry Bezrukov 4177b8b0654SDmitry Bezrukov /* Set high low water level */ 4187b8b0654SDmitry Bezrukov reg16 = 0x0810; 4197b8b0654SDmitry Bezrukov 4207b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 4217b8b0654SDmitry Bezrukov 2, ®16); 4227b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 4237b8b0654SDmitry Bezrukov } 4247b8b0654SDmitry Bezrukov 4257b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 4267b8b0654SDmitry Bezrukov { 4277b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 4287b8b0654SDmitry Bezrukov u16 reg16 = 0; 4297b8b0654SDmitry Bezrukov u8 reg8 = 0; 4307b8b0654SDmitry Bezrukov 4317b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 4327b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 4337b8b0654SDmitry Bezrukov 4347b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 4357b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 4367b8b0654SDmitry Bezrukov 4377b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 4387b8b0654SDmitry Bezrukov 1, 1, ®8); 4397b8b0654SDmitry Bezrukov 4407b8b0654SDmitry Bezrukov reg8 = 0x0; 4417b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 4427b8b0654SDmitry Bezrukov 1, 1, ®8); 4437b8b0654SDmitry Bezrukov 4447b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 4457b8b0654SDmitry Bezrukov 1, 1, ®8); 4467b8b0654SDmitry Bezrukov 4477b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 4487b8b0654SDmitry Bezrukov 4497b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 4507b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 4517b8b0654SDmitry Bezrukov 4527b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 4537b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 4547b8b0654SDmitry Bezrukov 1, 1, ®8); 4557b8b0654SDmitry Bezrukov 4567b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 4577b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 4587b8b0654SDmitry Bezrukov 1, 1, ®8); 4597b8b0654SDmitry Bezrukov 4607b8b0654SDmitry Bezrukov reg16 = 0; 4617b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4627b8b0654SDmitry Bezrukov 2, ®16); 4637b8b0654SDmitry Bezrukov 4647b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 4657b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4667b8b0654SDmitry Bezrukov 2, ®16); 4677b8b0654SDmitry Bezrukov 4687b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4697b8b0654SDmitry Bezrukov 2, ®16); 4707b8b0654SDmitry Bezrukov 4717b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 4727b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 4737b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4747b8b0654SDmitry Bezrukov 2, ®16); 4757b8b0654SDmitry Bezrukov 4767b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START; 4777b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 4787b8b0654SDmitry Bezrukov 4797b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 4807b8b0654SDmitry Bezrukov } else { 4817b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4827b8b0654SDmitry Bezrukov 2, ®16); 4837b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 4847b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4857b8b0654SDmitry Bezrukov 2, ®16); 4867b8b0654SDmitry Bezrukov 4877b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 4887b8b0654SDmitry Bezrukov reg16 &= ~SFR_RX_CTL_START; 4897b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 4907b8b0654SDmitry Bezrukov 4917b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 4927b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 4937b8b0654SDmitry Bezrukov 1, 1, ®8); 4947b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 4957b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 4967b8b0654SDmitry Bezrukov 1, 1, ®8); 4977b8b0654SDmitry Bezrukov 4987b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 4997b8b0654SDmitry Bezrukov } 5007b8b0654SDmitry Bezrukov return 0; 5017b8b0654SDmitry Bezrukov } 5027b8b0654SDmitry Bezrukov 503f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 504f3aa095aSDmitry Bezrukov { 50533cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 506f3aa095aSDmitry Bezrukov u8 reg8 = 0; 507f3aa095aSDmitry Bezrukov 50833cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 50933cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 51033cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 51133cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 51233cd597fSDmitry Bezrukov 513*df2d59a2SDmitry Bezrukov /* Set the MAC address */ 514*df2d59a2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 515*df2d59a2SDmitry Bezrukov ETH_ALEN, dev->net->dev_addr); 516*df2d59a2SDmitry Bezrukov 517f3aa095aSDmitry Bezrukov reg8 = 0xFF; 518f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 519f3aa095aSDmitry Bezrukov 520f3aa095aSDmitry Bezrukov reg8 = 0x0; 521f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 522f3aa095aSDmitry Bezrukov 523f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 524f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 525f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 526f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 527f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 528f3aa095aSDmitry Bezrukov 5297b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 5307b8b0654SDmitry Bezrukov 5317b8b0654SDmitry Bezrukov /* Phy advertise */ 5327b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 5337b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 5347b8b0654SDmitry Bezrukov 535f3aa095aSDmitry Bezrukov return 0; 536f3aa095aSDmitry Bezrukov } 537f3aa095aSDmitry Bezrukov 538f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 539f3aa095aSDmitry Bezrukov { 54033cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 541f3aa095aSDmitry Bezrukov u16 reg16 = 0; 542f3aa095aSDmitry Bezrukov 543f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 544f3aa095aSDmitry Bezrukov 2, ®16); 545f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 546f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 547f3aa095aSDmitry Bezrukov 2, ®16); 548f3aa095aSDmitry Bezrukov reg16 = 0; 549f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 550f3aa095aSDmitry Bezrukov 55133cd597fSDmitry Bezrukov /* Put PHY to low power*/ 55233cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 55333cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 55433cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 55533cd597fSDmitry Bezrukov 5567b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 5577b8b0654SDmitry Bezrukov 558f3aa095aSDmitry Bezrukov return 0; 5597cea2d40SDmitry Bezrukov } 5607cea2d40SDmitry Bezrukov 56117364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 56217364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 5637cea2d40SDmitry Bezrukov .bind = aqc111_bind, 5647cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 5657b8b0654SDmitry Bezrukov .status = aqc111_status, 5667b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 567f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 568f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 56917364b80SDmitry Bezrukov }; 57017364b80SDmitry Bezrukov 57117364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 57217364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 57317364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 57417364b80SDmitry Bezrukov }, \ 57517364b80SDmitry Bezrukov { \ 57617364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 57717364b80SDmitry Bezrukov USB_CLASS_COMM, \ 57817364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 57917364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 58017364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 58117364b80SDmitry Bezrukov 58217364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 58317364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 58417364b80SDmitry Bezrukov { },/* END */ 58517364b80SDmitry Bezrukov }; 58617364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 58717364b80SDmitry Bezrukov 58817364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 58917364b80SDmitry Bezrukov .name = "aqc111", 59017364b80SDmitry Bezrukov .id_table = products, 59117364b80SDmitry Bezrukov .probe = usbnet_probe, 59217364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 59317364b80SDmitry Bezrukov }; 59417364b80SDmitry Bezrukov 59517364b80SDmitry Bezrukov module_usb_driver(aq_driver); 59617364b80SDmitry Bezrukov 59717364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 59817364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 599