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> 12*027e6f78SDmitry Bezrukov #include <linux/ethtool.h> 1317364b80SDmitry Bezrukov #include <linux/mii.h> 1417364b80SDmitry Bezrukov #include <linux/usb.h> 1559b04eeaSDmitry Bezrukov #include <linux/crc32.h> 16df2d59a2SDmitry Bezrukov #include <linux/if_vlan.h> 1717364b80SDmitry Bezrukov #include <linux/usb/cdc.h> 1817364b80SDmitry Bezrukov #include <linux/usb/usbnet.h> 1917364b80SDmitry Bezrukov 20619fcb44SDmitry Bezrukov #include "aqc111.h" 21619fcb44SDmitry Bezrukov 22*027e6f78SDmitry Bezrukov #define DRIVER_NAME "aqc111" 23*027e6f78SDmitry Bezrukov 24619fcb44SDmitry Bezrukov static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 25619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 26619fcb44SDmitry Bezrukov { 27619fcb44SDmitry Bezrukov int ret; 28619fcb44SDmitry Bezrukov 29619fcb44SDmitry Bezrukov ret = usbnet_read_cmd_nopm(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 30619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 31619fcb44SDmitry Bezrukov 32619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 33619fcb44SDmitry Bezrukov netdev_warn(dev->net, 34619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 35619fcb44SDmitry Bezrukov cmd, index, ret); 36619fcb44SDmitry Bezrukov 37619fcb44SDmitry Bezrukov return ret; 38619fcb44SDmitry Bezrukov } 39619fcb44SDmitry Bezrukov 40619fcb44SDmitry Bezrukov static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value, 41619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 42619fcb44SDmitry Bezrukov { 43619fcb44SDmitry Bezrukov int ret; 44619fcb44SDmitry Bezrukov 45619fcb44SDmitry Bezrukov ret = usbnet_read_cmd(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 46619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 47619fcb44SDmitry Bezrukov 48619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 49619fcb44SDmitry Bezrukov netdev_warn(dev->net, 50619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 51619fcb44SDmitry Bezrukov cmd, index, ret); 52619fcb44SDmitry Bezrukov 53619fcb44SDmitry Bezrukov return ret; 54619fcb44SDmitry Bezrukov } 55619fcb44SDmitry Bezrukov 56f3aa095aSDmitry Bezrukov static int aqc111_read16_cmd(struct usbnet *dev, u8 cmd, u16 value, 57f3aa095aSDmitry Bezrukov u16 index, u16 *data) 58f3aa095aSDmitry Bezrukov { 59f3aa095aSDmitry Bezrukov int ret = 0; 60f3aa095aSDmitry Bezrukov 61f3aa095aSDmitry Bezrukov ret = aqc111_read_cmd(dev, cmd, value, index, sizeof(*data), data); 62f3aa095aSDmitry Bezrukov le16_to_cpus(data); 63f3aa095aSDmitry Bezrukov 64f3aa095aSDmitry Bezrukov return ret; 65f3aa095aSDmitry Bezrukov } 66f3aa095aSDmitry Bezrukov 67619fcb44SDmitry Bezrukov static int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 68619fcb44SDmitry Bezrukov u16 value, u16 index, u16 size, const void *data) 69619fcb44SDmitry Bezrukov { 70619fcb44SDmitry Bezrukov int err = -ENOMEM; 71619fcb44SDmitry Bezrukov void *buf = NULL; 72619fcb44SDmitry Bezrukov 73619fcb44SDmitry Bezrukov netdev_dbg(dev->net, 74619fcb44SDmitry Bezrukov "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n", 75619fcb44SDmitry Bezrukov __func__, cmd, reqtype, value, index, size); 76619fcb44SDmitry Bezrukov 77619fcb44SDmitry Bezrukov if (data) { 78619fcb44SDmitry Bezrukov buf = kmemdup(data, size, GFP_KERNEL); 79619fcb44SDmitry Bezrukov if (!buf) 80619fcb44SDmitry Bezrukov goto out; 81619fcb44SDmitry Bezrukov } 82619fcb44SDmitry Bezrukov 83619fcb44SDmitry Bezrukov err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 84619fcb44SDmitry Bezrukov cmd, reqtype, value, index, buf, size, 85619fcb44SDmitry Bezrukov (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT : 86619fcb44SDmitry Bezrukov AQ_USB_SET_TIMEOUT); 87619fcb44SDmitry Bezrukov 88619fcb44SDmitry Bezrukov if (unlikely(err < 0)) 89619fcb44SDmitry Bezrukov netdev_warn(dev->net, 90619fcb44SDmitry Bezrukov "Failed to write(0x%x) reg index 0x%04x: %d\n", 91619fcb44SDmitry Bezrukov cmd, index, err); 92619fcb44SDmitry Bezrukov kfree(buf); 93619fcb44SDmitry Bezrukov 94619fcb44SDmitry Bezrukov out: 95619fcb44SDmitry Bezrukov return err; 96619fcb44SDmitry Bezrukov } 97619fcb44SDmitry Bezrukov 98619fcb44SDmitry Bezrukov static int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 99619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 100619fcb44SDmitry Bezrukov { 101619fcb44SDmitry Bezrukov int ret; 102619fcb44SDmitry Bezrukov 103619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 104619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 105619fcb44SDmitry Bezrukov 106619fcb44SDmitry Bezrukov return ret; 107619fcb44SDmitry Bezrukov } 108619fcb44SDmitry Bezrukov 109619fcb44SDmitry Bezrukov static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 110619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 111619fcb44SDmitry Bezrukov { 112619fcb44SDmitry Bezrukov int ret; 113619fcb44SDmitry Bezrukov 114619fcb44SDmitry Bezrukov if (usb_autopm_get_interface(dev->intf) < 0) 115619fcb44SDmitry Bezrukov return -ENODEV; 116619fcb44SDmitry Bezrukov 117619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 118619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 119619fcb44SDmitry Bezrukov 120619fcb44SDmitry Bezrukov usb_autopm_put_interface(dev->intf); 121619fcb44SDmitry Bezrukov 122619fcb44SDmitry Bezrukov return ret; 123619fcb44SDmitry Bezrukov } 124619fcb44SDmitry Bezrukov 125f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 126f3aa095aSDmitry Bezrukov u16 index, u16 *data) 127f3aa095aSDmitry Bezrukov { 128f3aa095aSDmitry Bezrukov u16 tmp = *data; 129f3aa095aSDmitry Bezrukov 130f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 131f3aa095aSDmitry Bezrukov 132f3aa095aSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 133f3aa095aSDmitry Bezrukov } 134f3aa095aSDmitry Bezrukov 135f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value, 136f3aa095aSDmitry Bezrukov u16 index, u16 *data) 137f3aa095aSDmitry Bezrukov { 138f3aa095aSDmitry Bezrukov u16 tmp = *data; 139f3aa095aSDmitry Bezrukov 140f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 141f3aa095aSDmitry Bezrukov 142f3aa095aSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 143f3aa095aSDmitry Bezrukov } 144f3aa095aSDmitry Bezrukov 14533cd597fSDmitry Bezrukov static int aqc111_write32_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 14633cd597fSDmitry Bezrukov u16 index, u32 *data) 14733cd597fSDmitry Bezrukov { 14833cd597fSDmitry Bezrukov u32 tmp = *data; 14933cd597fSDmitry Bezrukov 15033cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 15133cd597fSDmitry Bezrukov 15233cd597fSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 15333cd597fSDmitry Bezrukov } 15433cd597fSDmitry Bezrukov 15533cd597fSDmitry Bezrukov static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value, 15633cd597fSDmitry Bezrukov u16 index, u32 *data) 15733cd597fSDmitry Bezrukov { 15833cd597fSDmitry Bezrukov u32 tmp = *data; 15933cd597fSDmitry Bezrukov 16033cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 16133cd597fSDmitry Bezrukov 16233cd597fSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 16333cd597fSDmitry Bezrukov } 16433cd597fSDmitry Bezrukov 16559b04eeaSDmitry Bezrukov static int aqc111_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, 16659b04eeaSDmitry Bezrukov u16 index, u16 size, void *data) 16759b04eeaSDmitry Bezrukov { 16859b04eeaSDmitry Bezrukov return usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 16959b04eeaSDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, 17059b04eeaSDmitry Bezrukov size); 17159b04eeaSDmitry Bezrukov } 17259b04eeaSDmitry Bezrukov 17359b04eeaSDmitry Bezrukov static int aqc111_write16_cmd_async(struct usbnet *dev, u8 cmd, u16 value, 17459b04eeaSDmitry Bezrukov u16 index, u16 *data) 17559b04eeaSDmitry Bezrukov { 17659b04eeaSDmitry Bezrukov u16 tmp = *data; 17759b04eeaSDmitry Bezrukov 17859b04eeaSDmitry Bezrukov cpu_to_le16s(&tmp); 17959b04eeaSDmitry Bezrukov 18059b04eeaSDmitry Bezrukov return aqc111_write_cmd_async(dev, cmd, value, index, 18159b04eeaSDmitry Bezrukov sizeof(tmp), &tmp); 18259b04eeaSDmitry Bezrukov } 18359b04eeaSDmitry Bezrukov 184*027e6f78SDmitry Bezrukov static void aqc111_get_drvinfo(struct net_device *net, 185*027e6f78SDmitry Bezrukov struct ethtool_drvinfo *info) 186*027e6f78SDmitry Bezrukov { 187*027e6f78SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 188*027e6f78SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 189*027e6f78SDmitry Bezrukov 190*027e6f78SDmitry Bezrukov /* Inherit standard device info */ 191*027e6f78SDmitry Bezrukov usbnet_get_drvinfo(net, info); 192*027e6f78SDmitry Bezrukov strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 193*027e6f78SDmitry Bezrukov snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u.%u", 194*027e6f78SDmitry Bezrukov aqc111_data->fw_ver.major, 195*027e6f78SDmitry Bezrukov aqc111_data->fw_ver.minor, 196*027e6f78SDmitry Bezrukov aqc111_data->fw_ver.rev); 197*027e6f78SDmitry Bezrukov info->eedump_len = 0x00; 198*027e6f78SDmitry Bezrukov info->regdump_len = 0x00; 199*027e6f78SDmitry Bezrukov } 200*027e6f78SDmitry Bezrukov 2017b8b0654SDmitry Bezrukov static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed) 2027b8b0654SDmitry Bezrukov { 2037b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 2047b8b0654SDmitry Bezrukov 2057b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 2067b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_PAUSE; 2077b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ASYM_PAUSE; 2087b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_DOWNSHIFT; 2097b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK; 2107b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= (3 << AQ_DSH_RETRIES_SHIFT) & 2117b8b0654SDmitry Bezrukov AQ_DSH_RETRIES_MASK; 2127b8b0654SDmitry Bezrukov 2137b8b0654SDmitry Bezrukov if (autoneg == AUTONEG_ENABLE) { 2147b8b0654SDmitry Bezrukov switch (speed) { 2157b8b0654SDmitry Bezrukov case SPEED_5000: 2167b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 2177b8b0654SDmitry Bezrukov /* fall-through */ 2187b8b0654SDmitry Bezrukov case SPEED_2500: 2197b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 2207b8b0654SDmitry Bezrukov /* fall-through */ 2217b8b0654SDmitry Bezrukov case SPEED_1000: 2227b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 2237b8b0654SDmitry Bezrukov /* fall-through */ 2247b8b0654SDmitry Bezrukov case SPEED_100: 2257b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 2267b8b0654SDmitry Bezrukov /* fall-through */ 2277b8b0654SDmitry Bezrukov } 2287b8b0654SDmitry Bezrukov } else { 2297b8b0654SDmitry Bezrukov switch (speed) { 2307b8b0654SDmitry Bezrukov case SPEED_5000: 2317b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_5G; 2327b8b0654SDmitry Bezrukov break; 2337b8b0654SDmitry Bezrukov case SPEED_2500: 2347b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_2G5; 2357b8b0654SDmitry Bezrukov break; 2367b8b0654SDmitry Bezrukov case SPEED_1000: 2377b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_1G; 2387b8b0654SDmitry Bezrukov break; 2397b8b0654SDmitry Bezrukov case SPEED_100: 2407b8b0654SDmitry Bezrukov aqc111_data->phy_cfg |= AQ_ADV_100M; 2417b8b0654SDmitry Bezrukov break; 2427b8b0654SDmitry Bezrukov } 2437b8b0654SDmitry Bezrukov } 2447b8b0654SDmitry Bezrukov 2457b8b0654SDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg); 2467b8b0654SDmitry Bezrukov } 2477b8b0654SDmitry Bezrukov 248*027e6f78SDmitry Bezrukov static const struct ethtool_ops aqc111_ethtool_ops = { 249*027e6f78SDmitry Bezrukov .get_drvinfo = aqc111_get_drvinfo, 250*027e6f78SDmitry Bezrukov .get_msglevel = usbnet_get_msglevel, 251*027e6f78SDmitry Bezrukov .set_msglevel = usbnet_set_msglevel, 252*027e6f78SDmitry Bezrukov .get_link = ethtool_op_get_link, 253*027e6f78SDmitry Bezrukov }; 254*027e6f78SDmitry Bezrukov 255a4017cc2SDmitry Bezrukov static int aqc111_change_mtu(struct net_device *net, int new_mtu) 256a4017cc2SDmitry Bezrukov { 257a4017cc2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 258a4017cc2SDmitry Bezrukov u16 reg16 = 0; 259a4017cc2SDmitry Bezrukov u8 buf[5]; 260a4017cc2SDmitry Bezrukov 261a4017cc2SDmitry Bezrukov net->mtu = new_mtu; 262a4017cc2SDmitry Bezrukov dev->hard_mtu = net->mtu + net->hard_header_len; 263a4017cc2SDmitry Bezrukov 264a4017cc2SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 265a4017cc2SDmitry Bezrukov 2, ®16); 266a4017cc2SDmitry Bezrukov if (net->mtu > 1500) 267a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 268a4017cc2SDmitry Bezrukov else 269a4017cc2SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_JUMBO_EN; 270a4017cc2SDmitry Bezrukov 271a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 272a4017cc2SDmitry Bezrukov 2, ®16); 273a4017cc2SDmitry Bezrukov 274a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) { 275a4017cc2SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[2], 5); 276a4017cc2SDmitry Bezrukov /* RX bulk configuration */ 277a4017cc2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 278a4017cc2SDmitry Bezrukov 5, 5, buf); 279a4017cc2SDmitry Bezrukov } 280a4017cc2SDmitry Bezrukov 281a4017cc2SDmitry Bezrukov /* Set high low water level */ 282a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 283a4017cc2SDmitry Bezrukov reg16 = 0x0810; 284a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 285a4017cc2SDmitry Bezrukov reg16 = 0x1020; 286a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 287a4017cc2SDmitry Bezrukov reg16 = 0x1420; 288a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 289a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 290a4017cc2SDmitry Bezrukov 291a4017cc2SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 292a4017cc2SDmitry Bezrukov 2, ®16); 293a4017cc2SDmitry Bezrukov 294a4017cc2SDmitry Bezrukov return 0; 295a4017cc2SDmitry Bezrukov } 296a4017cc2SDmitry Bezrukov 297df2d59a2SDmitry Bezrukov static int aqc111_set_mac_addr(struct net_device *net, void *p) 298df2d59a2SDmitry Bezrukov { 299df2d59a2SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 300df2d59a2SDmitry Bezrukov int ret = 0; 301df2d59a2SDmitry Bezrukov 302df2d59a2SDmitry Bezrukov ret = eth_mac_addr(net, p); 303df2d59a2SDmitry Bezrukov if (ret < 0) 304df2d59a2SDmitry Bezrukov return ret; 305df2d59a2SDmitry Bezrukov 306df2d59a2SDmitry Bezrukov /* Set the MAC address */ 307df2d59a2SDmitry Bezrukov return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 308df2d59a2SDmitry Bezrukov ETH_ALEN, net->dev_addr); 309df2d59a2SDmitry Bezrukov } 310df2d59a2SDmitry Bezrukov 3114189673aSDmitry Bezrukov static int aqc111_vlan_rx_kill_vid(struct net_device *net, 3124189673aSDmitry Bezrukov __be16 proto, u16 vid) 3134189673aSDmitry Bezrukov { 3144189673aSDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 3154189673aSDmitry Bezrukov u8 vlan_ctrl = 0; 3164189673aSDmitry Bezrukov u16 reg16 = 0; 3174189673aSDmitry Bezrukov u8 reg8 = 0; 3184189673aSDmitry Bezrukov 3194189673aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3204189673aSDmitry Bezrukov vlan_ctrl = reg8; 3214189673aSDmitry Bezrukov 3224189673aSDmitry Bezrukov /* Address */ 3234189673aSDmitry Bezrukov reg8 = (vid / 16); 3244189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8); 3254189673aSDmitry Bezrukov /* Data */ 3264189673aSDmitry Bezrukov reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD; 3274189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3284189673aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 3294189673aSDmitry Bezrukov reg16 &= ~(1 << (vid % 16)); 3304189673aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 3314189673aSDmitry Bezrukov reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE; 3324189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3334189673aSDmitry Bezrukov 3344189673aSDmitry Bezrukov return 0; 3354189673aSDmitry Bezrukov } 3364189673aSDmitry Bezrukov 3374189673aSDmitry Bezrukov static int aqc111_vlan_rx_add_vid(struct net_device *net, __be16 proto, u16 vid) 3384189673aSDmitry Bezrukov { 3394189673aSDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 3404189673aSDmitry Bezrukov u8 vlan_ctrl = 0; 3414189673aSDmitry Bezrukov u16 reg16 = 0; 3424189673aSDmitry Bezrukov u8 reg8 = 0; 3434189673aSDmitry Bezrukov 3444189673aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3454189673aSDmitry Bezrukov vlan_ctrl = reg8; 3464189673aSDmitry Bezrukov 3474189673aSDmitry Bezrukov /* Address */ 3484189673aSDmitry Bezrukov reg8 = (vid / 16); 3494189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8); 3504189673aSDmitry Bezrukov /* Data */ 3514189673aSDmitry Bezrukov reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD; 3524189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3534189673aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 3544189673aSDmitry Bezrukov reg16 |= (1 << (vid % 16)); 3554189673aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 3564189673aSDmitry Bezrukov reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE; 3574189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 3584189673aSDmitry Bezrukov 3594189673aSDmitry Bezrukov return 0; 3604189673aSDmitry Bezrukov } 3614189673aSDmitry Bezrukov 36259b04eeaSDmitry Bezrukov static void aqc111_set_rx_mode(struct net_device *net) 36359b04eeaSDmitry Bezrukov { 36459b04eeaSDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 36559b04eeaSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 36659b04eeaSDmitry Bezrukov int mc_count = 0; 36759b04eeaSDmitry Bezrukov 36859b04eeaSDmitry Bezrukov mc_count = netdev_mc_count(net); 36959b04eeaSDmitry Bezrukov 37059b04eeaSDmitry Bezrukov aqc111_data->rxctl &= ~(SFR_RX_CTL_PRO | SFR_RX_CTL_AMALL | 37159b04eeaSDmitry Bezrukov SFR_RX_CTL_AM); 37259b04eeaSDmitry Bezrukov 37359b04eeaSDmitry Bezrukov if (net->flags & IFF_PROMISC) { 37459b04eeaSDmitry Bezrukov aqc111_data->rxctl |= SFR_RX_CTL_PRO; 37559b04eeaSDmitry Bezrukov } else if ((net->flags & IFF_ALLMULTI) || mc_count > AQ_MAX_MCAST) { 37659b04eeaSDmitry Bezrukov aqc111_data->rxctl |= SFR_RX_CTL_AMALL; 37759b04eeaSDmitry Bezrukov } else if (!netdev_mc_empty(net)) { 37859b04eeaSDmitry Bezrukov u8 m_filter[AQ_MCAST_FILTER_SIZE] = { 0 }; 37959b04eeaSDmitry Bezrukov struct netdev_hw_addr *ha = NULL; 38059b04eeaSDmitry Bezrukov u32 crc_bits = 0; 38159b04eeaSDmitry Bezrukov 38259b04eeaSDmitry Bezrukov netdev_for_each_mc_addr(ha, net) { 38359b04eeaSDmitry Bezrukov crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 38459b04eeaSDmitry Bezrukov m_filter[crc_bits >> 3] |= BIT(crc_bits & 7); 38559b04eeaSDmitry Bezrukov } 38659b04eeaSDmitry Bezrukov 38759b04eeaSDmitry Bezrukov aqc111_write_cmd_async(dev, AQ_ACCESS_MAC, 38859b04eeaSDmitry Bezrukov SFR_MULTI_FILTER_ARRY, 38959b04eeaSDmitry Bezrukov AQ_MCAST_FILTER_SIZE, 39059b04eeaSDmitry Bezrukov AQ_MCAST_FILTER_SIZE, m_filter); 39159b04eeaSDmitry Bezrukov 39259b04eeaSDmitry Bezrukov aqc111_data->rxctl |= SFR_RX_CTL_AM; 39359b04eeaSDmitry Bezrukov } 39459b04eeaSDmitry Bezrukov 39559b04eeaSDmitry Bezrukov aqc111_write16_cmd_async(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 39659b04eeaSDmitry Bezrukov 2, &aqc111_data->rxctl); 39759b04eeaSDmitry Bezrukov } 39859b04eeaSDmitry Bezrukov 3996649d2a6SDmitry Bezrukov static int aqc111_set_features(struct net_device *net, 4006649d2a6SDmitry Bezrukov netdev_features_t features) 4016649d2a6SDmitry Bezrukov { 4026649d2a6SDmitry Bezrukov struct usbnet *dev = netdev_priv(net); 4036649d2a6SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 4046649d2a6SDmitry Bezrukov netdev_features_t changed = net->features ^ features; 4054189673aSDmitry Bezrukov u16 reg16 = 0; 4066649d2a6SDmitry Bezrukov u8 reg8 = 0; 4076649d2a6SDmitry Bezrukov 4086649d2a6SDmitry Bezrukov if (changed & NETIF_F_IP_CSUM) { 4096649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 4106649d2a6SDmitry Bezrukov reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP; 4116649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 4126649d2a6SDmitry Bezrukov 1, 1, ®8); 4136649d2a6SDmitry Bezrukov } 4146649d2a6SDmitry Bezrukov 4156649d2a6SDmitry Bezrukov if (changed & NETIF_F_IPV6_CSUM) { 4166649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 4176649d2a6SDmitry Bezrukov reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 4186649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 4196649d2a6SDmitry Bezrukov 1, 1, ®8); 4206649d2a6SDmitry Bezrukov } 4216649d2a6SDmitry Bezrukov 4226649d2a6SDmitry Bezrukov if (changed & NETIF_F_RXCSUM) { 4236649d2a6SDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 4246649d2a6SDmitry Bezrukov if (features & NETIF_F_RXCSUM) { 4256649d2a6SDmitry Bezrukov aqc111_data->rx_checksum = 1; 4266649d2a6SDmitry Bezrukov reg8 &= ~(SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 4276649d2a6SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6); 4286649d2a6SDmitry Bezrukov } else { 4296649d2a6SDmitry Bezrukov aqc111_data->rx_checksum = 0; 4306649d2a6SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 4316649d2a6SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 4326649d2a6SDmitry Bezrukov } 4336649d2a6SDmitry Bezrukov 4346649d2a6SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 4356649d2a6SDmitry Bezrukov 1, 1, ®8); 4366649d2a6SDmitry Bezrukov } 4374189673aSDmitry Bezrukov if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { 4384189673aSDmitry Bezrukov if (features & NETIF_F_HW_VLAN_CTAG_FILTER) { 4394189673aSDmitry Bezrukov u16 i = 0; 4404189673aSDmitry Bezrukov 4414189673aSDmitry Bezrukov for (i = 0; i < 256; i++) { 4424189673aSDmitry Bezrukov /* Address */ 4434189673aSDmitry Bezrukov reg8 = i; 4444189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, 4454189673aSDmitry Bezrukov SFR_VLAN_ID_ADDRESS, 4464189673aSDmitry Bezrukov 1, 1, ®8); 4474189673aSDmitry Bezrukov /* Data */ 4484189673aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, 4494189673aSDmitry Bezrukov SFR_VLAN_ID_DATA0, 4504189673aSDmitry Bezrukov 2, ®16); 4514189673aSDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_WE; 4524189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, 4534189673aSDmitry Bezrukov SFR_VLAN_ID_CONTROL, 4544189673aSDmitry Bezrukov 1, 1, ®8); 4554189673aSDmitry Bezrukov } 4564189673aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 4574189673aSDmitry Bezrukov 1, 1, ®8); 4584189673aSDmitry Bezrukov reg8 |= SFR_VLAN_CONTROL_VFE; 4594189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, 4604189673aSDmitry Bezrukov SFR_VLAN_ID_CONTROL, 1, 1, ®8); 4614189673aSDmitry Bezrukov } else { 4624189673aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 4634189673aSDmitry Bezrukov 1, 1, ®8); 4644189673aSDmitry Bezrukov reg8 &= ~SFR_VLAN_CONTROL_VFE; 4654189673aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, 4664189673aSDmitry Bezrukov SFR_VLAN_ID_CONTROL, 1, 1, ®8); 4674189673aSDmitry Bezrukov } 4684189673aSDmitry Bezrukov } 4694189673aSDmitry Bezrukov 4706649d2a6SDmitry Bezrukov return 0; 4716649d2a6SDmitry Bezrukov } 4726649d2a6SDmitry Bezrukov 4737cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 4747cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 4757cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 4764a3576d2SDmitry Bezrukov .ndo_start_xmit = usbnet_start_xmit, 4774a3576d2SDmitry Bezrukov .ndo_tx_timeout = usbnet_tx_timeout, 4784a3576d2SDmitry Bezrukov .ndo_get_stats64 = usbnet_get_stats64, 479a4017cc2SDmitry Bezrukov .ndo_change_mtu = aqc111_change_mtu, 480df2d59a2SDmitry Bezrukov .ndo_set_mac_address = aqc111_set_mac_addr, 481df2d59a2SDmitry Bezrukov .ndo_validate_addr = eth_validate_addr, 4824189673aSDmitry Bezrukov .ndo_vlan_rx_add_vid = aqc111_vlan_rx_add_vid, 4834189673aSDmitry Bezrukov .ndo_vlan_rx_kill_vid = aqc111_vlan_rx_kill_vid, 48459b04eeaSDmitry Bezrukov .ndo_set_rx_mode = aqc111_set_rx_mode, 4856649d2a6SDmitry Bezrukov .ndo_set_features = aqc111_set_features, 4867cea2d40SDmitry Bezrukov }; 4877cea2d40SDmitry Bezrukov 488df2d59a2SDmitry Bezrukov static int aqc111_read_perm_mac(struct usbnet *dev) 489df2d59a2SDmitry Bezrukov { 490df2d59a2SDmitry Bezrukov u8 buf[ETH_ALEN]; 491df2d59a2SDmitry Bezrukov int ret; 492df2d59a2SDmitry Bezrukov 493df2d59a2SDmitry Bezrukov ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 494df2d59a2SDmitry Bezrukov if (ret < 0) 495df2d59a2SDmitry Bezrukov goto out; 496df2d59a2SDmitry Bezrukov 497df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->perm_addr, buf); 498df2d59a2SDmitry Bezrukov 499df2d59a2SDmitry Bezrukov return 0; 500df2d59a2SDmitry Bezrukov out: 501df2d59a2SDmitry Bezrukov return ret; 502df2d59a2SDmitry Bezrukov } 503df2d59a2SDmitry Bezrukov 50433cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 50533cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 50633cd597fSDmitry Bezrukov { 50733cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 50833cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 50933cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 51033cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 51133cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 51233cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 51333cd597fSDmitry Bezrukov 51433cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 51533cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 51633cd597fSDmitry Bezrukov } 51733cd597fSDmitry Bezrukov 5187cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 5197cea2d40SDmitry Bezrukov { 5207cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 5217b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = udev->speed; 52233cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 5237cea2d40SDmitry Bezrukov int ret; 5247cea2d40SDmitry Bezrukov 5257cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 5267cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 5277cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 5287cea2d40SDmitry Bezrukov return -ENODEV; 5297cea2d40SDmitry Bezrukov } 5307cea2d40SDmitry Bezrukov 5317cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 5327cea2d40SDmitry Bezrukov 5337cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 5347cea2d40SDmitry Bezrukov if (ret < 0) { 5357cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 5367cea2d40SDmitry Bezrukov return ret; 5377cea2d40SDmitry Bezrukov } 5387cea2d40SDmitry Bezrukov 53933cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 54033cd597fSDmitry Bezrukov if (!aqc111_data) 54133cd597fSDmitry Bezrukov return -ENOMEM; 54233cd597fSDmitry Bezrukov 54333cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 54433cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 54533cd597fSDmitry Bezrukov 546df2d59a2SDmitry Bezrukov /* Init the MAC address */ 547df2d59a2SDmitry Bezrukov ret = aqc111_read_perm_mac(dev); 548df2d59a2SDmitry Bezrukov if (ret) 549df2d59a2SDmitry Bezrukov goto out; 550df2d59a2SDmitry Bezrukov 551df2d59a2SDmitry Bezrukov ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 5524a3576d2SDmitry Bezrukov 553361459cdSDmitry Bezrukov /* Set Rx urb size */ 554361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 555361459cdSDmitry Bezrukov 5564a3576d2SDmitry Bezrukov /* Set TX needed headroom & tailroom */ 5574a3576d2SDmitry Bezrukov dev->net->needed_headroom += sizeof(u64); 5584a3576d2SDmitry Bezrukov dev->net->needed_tailroom += sizeof(u64); 5594a3576d2SDmitry Bezrukov 560a4017cc2SDmitry Bezrukov dev->net->max_mtu = 16334; 561a4017cc2SDmitry Bezrukov 5627cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 563*027e6f78SDmitry Bezrukov dev->net->ethtool_ops = &aqc111_ethtool_ops; 5647cea2d40SDmitry Bezrukov 5654a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 5664a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 5674a3576d2SDmitry Bezrukov 5684a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 5694a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 5707afa6c98SDmitry Bezrukov dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE; 5714a3576d2SDmitry Bezrukov 572de074e7aSDmitry Bezrukov netif_set_gso_max_size(dev->net, 65535); 573de074e7aSDmitry Bezrukov 57433cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 5757b8b0654SDmitry Bezrukov aqc111_data->autoneg = AUTONEG_ENABLE; 5767b8b0654SDmitry Bezrukov aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 5777b8b0654SDmitry Bezrukov SPEED_5000 : SPEED_1000; 57833cd597fSDmitry Bezrukov 5797cea2d40SDmitry Bezrukov return 0; 580df2d59a2SDmitry Bezrukov 581df2d59a2SDmitry Bezrukov out: 582df2d59a2SDmitry Bezrukov kfree(aqc111_data); 583df2d59a2SDmitry Bezrukov return ret; 5847cea2d40SDmitry Bezrukov } 5857cea2d40SDmitry Bezrukov 5867cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 5877cea2d40SDmitry Bezrukov { 58833cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 589f3aa095aSDmitry Bezrukov u16 reg16; 590f3aa095aSDmitry Bezrukov 591f3aa095aSDmitry Bezrukov /* Force bz */ 592f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 593f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 594f3aa095aSDmitry Bezrukov 2, ®16); 595f3aa095aSDmitry Bezrukov reg16 = 0; 596f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 597f3aa095aSDmitry Bezrukov 2, ®16); 59833cd597fSDmitry Bezrukov 59933cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 6007b8b0654SDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 60133cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 60233cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 60333cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 60433cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 60533cd597fSDmitry Bezrukov 60633cd597fSDmitry Bezrukov kfree(aqc111_data); 607f3aa095aSDmitry Bezrukov } 608f3aa095aSDmitry Bezrukov 6097b8b0654SDmitry Bezrukov static void aqc111_status(struct usbnet *dev, struct urb *urb) 6107b8b0654SDmitry Bezrukov { 6117b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 6127b8b0654SDmitry Bezrukov u64 *event_data = NULL; 6137b8b0654SDmitry Bezrukov int link = 0; 6147b8b0654SDmitry Bezrukov 6157b8b0654SDmitry Bezrukov if (urb->actual_length < sizeof(*event_data)) 6167b8b0654SDmitry Bezrukov return; 6177b8b0654SDmitry Bezrukov 6187b8b0654SDmitry Bezrukov event_data = urb->transfer_buffer; 6197b8b0654SDmitry Bezrukov le64_to_cpus(event_data); 6207b8b0654SDmitry Bezrukov 6217b8b0654SDmitry Bezrukov if (*event_data & AQ_LS_MASK) 6227b8b0654SDmitry Bezrukov link = 1; 6237b8b0654SDmitry Bezrukov else 6247b8b0654SDmitry Bezrukov link = 0; 6257b8b0654SDmitry Bezrukov 6267b8b0654SDmitry Bezrukov aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 6277b8b0654SDmitry Bezrukov AQ_SPEED_SHIFT; 6287b8b0654SDmitry Bezrukov aqc111_data->link = link; 6297b8b0654SDmitry Bezrukov 6307b8b0654SDmitry Bezrukov if (netif_carrier_ok(dev->net) != link) 6317b8b0654SDmitry Bezrukov usbnet_defer_kevent(dev, EVENT_LINK_RESET); 6327b8b0654SDmitry Bezrukov } 6337b8b0654SDmitry Bezrukov 6347b8b0654SDmitry Bezrukov static void aqc111_configure_rx(struct usbnet *dev, 6357b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data) 6367b8b0654SDmitry Bezrukov { 6377b8b0654SDmitry Bezrukov enum usb_device_speed usb_speed = dev->udev->speed; 6387b8b0654SDmitry Bezrukov u16 link_speed = 0, usb_host = 0; 6397b8b0654SDmitry Bezrukov u8 buf[5] = { 0 }; 6407b8b0654SDmitry Bezrukov u8 queue_num = 0; 6417b8b0654SDmitry Bezrukov u16 reg16 = 0; 6427b8b0654SDmitry Bezrukov u8 reg8 = 0; 6437b8b0654SDmitry Bezrukov 6447b8b0654SDmitry Bezrukov buf[0] = 0x00; 6457b8b0654SDmitry Bezrukov buf[1] = 0xF8; 6467b8b0654SDmitry Bezrukov buf[2] = 0x07; 6477b8b0654SDmitry Bezrukov switch (aqc111_data->link_speed) { 6487b8b0654SDmitry Bezrukov case AQ_INT_SPEED_5G: 6497b8b0654SDmitry Bezrukov link_speed = 5000; 6507b8b0654SDmitry Bezrukov reg8 = 0x05; 6517b8b0654SDmitry Bezrukov reg16 = 0x001F; 6527b8b0654SDmitry Bezrukov break; 6537b8b0654SDmitry Bezrukov case AQ_INT_SPEED_2_5G: 6547b8b0654SDmitry Bezrukov link_speed = 2500; 6557b8b0654SDmitry Bezrukov reg16 = 0x003F; 6567b8b0654SDmitry Bezrukov break; 6577b8b0654SDmitry Bezrukov case AQ_INT_SPEED_1G: 6587b8b0654SDmitry Bezrukov link_speed = 1000; 6597b8b0654SDmitry Bezrukov reg16 = 0x009F; 6607b8b0654SDmitry Bezrukov break; 6617b8b0654SDmitry Bezrukov case AQ_INT_SPEED_100M: 6627b8b0654SDmitry Bezrukov link_speed = 100; 6637b8b0654SDmitry Bezrukov queue_num = 1; 6647b8b0654SDmitry Bezrukov reg16 = 0x063F; 6657b8b0654SDmitry Bezrukov buf[1] = 0xFB; 6667b8b0654SDmitry Bezrukov buf[2] = 0x4; 6677b8b0654SDmitry Bezrukov break; 6687b8b0654SDmitry Bezrukov } 6697b8b0654SDmitry Bezrukov 6707b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 6717b8b0654SDmitry Bezrukov 1, 1, ®8); 6727b8b0654SDmitry Bezrukov 6737b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 6747b8b0654SDmitry Bezrukov 6757b8b0654SDmitry Bezrukov switch (usb_speed) { 6767b8b0654SDmitry Bezrukov case USB_SPEED_SUPER: 6777b8b0654SDmitry Bezrukov usb_host = 3; 6787b8b0654SDmitry Bezrukov break; 6797b8b0654SDmitry Bezrukov case USB_SPEED_HIGH: 6807b8b0654SDmitry Bezrukov usb_host = 2; 6817b8b0654SDmitry Bezrukov break; 6827b8b0654SDmitry Bezrukov case USB_SPEED_FULL: 6837b8b0654SDmitry Bezrukov case USB_SPEED_LOW: 6847b8b0654SDmitry Bezrukov usb_host = 1; 6857b8b0654SDmitry Bezrukov queue_num = 0; 6867b8b0654SDmitry Bezrukov break; 6877b8b0654SDmitry Bezrukov default: 6887b8b0654SDmitry Bezrukov usb_host = 0; 6897b8b0654SDmitry Bezrukov break; 6907b8b0654SDmitry Bezrukov } 6917b8b0654SDmitry Bezrukov 692a4017cc2SDmitry Bezrukov if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) 693a4017cc2SDmitry Bezrukov queue_num = 2; /* For Jumbo packet 16KB */ 694a4017cc2SDmitry Bezrukov 6957b8b0654SDmitry Bezrukov memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 6967b8b0654SDmitry Bezrukov /* RX bulk configuration */ 6977b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 6987b8b0654SDmitry Bezrukov 6997b8b0654SDmitry Bezrukov /* Set high low water level */ 700a4017cc2SDmitry Bezrukov if (dev->net->mtu <= 4500) 7017b8b0654SDmitry Bezrukov reg16 = 0x0810; 702a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 9500) 703a4017cc2SDmitry Bezrukov reg16 = 0x1020; 704a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 12500) 705a4017cc2SDmitry Bezrukov reg16 = 0x1420; 706a4017cc2SDmitry Bezrukov else if (dev->net->mtu <= 16334) 707a4017cc2SDmitry Bezrukov reg16 = 0x1A20; 7087b8b0654SDmitry Bezrukov 7097b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 7107b8b0654SDmitry Bezrukov 2, ®16); 7117b8b0654SDmitry Bezrukov netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 7127b8b0654SDmitry Bezrukov } 7137b8b0654SDmitry Bezrukov 71402031466SDmitry Bezrukov static void aqc111_configure_csum_offload(struct usbnet *dev) 71502031466SDmitry Bezrukov { 71602031466SDmitry Bezrukov u8 reg8 = 0; 71702031466SDmitry Bezrukov 71802031466SDmitry Bezrukov if (dev->net->features & NETIF_F_RXCSUM) { 71902031466SDmitry Bezrukov reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 72002031466SDmitry Bezrukov SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 72102031466SDmitry Bezrukov } 72202031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 72302031466SDmitry Bezrukov 72402031466SDmitry Bezrukov reg8 = 0; 72502031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IP_CSUM) 72602031466SDmitry Bezrukov reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; 72702031466SDmitry Bezrukov 72802031466SDmitry Bezrukov if (dev->net->features & NETIF_F_IPV6_CSUM) 72902031466SDmitry Bezrukov reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 73002031466SDmitry Bezrukov 73102031466SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 73202031466SDmitry Bezrukov } 73302031466SDmitry Bezrukov 7347b8b0654SDmitry Bezrukov static int aqc111_link_reset(struct usbnet *dev) 7357b8b0654SDmitry Bezrukov { 7367b8b0654SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 7377b8b0654SDmitry Bezrukov u16 reg16 = 0; 7387b8b0654SDmitry Bezrukov u8 reg8 = 0; 7397b8b0654SDmitry Bezrukov 7407b8b0654SDmitry Bezrukov if (aqc111_data->link == 1) { /* Link up */ 7417b8b0654SDmitry Bezrukov aqc111_configure_rx(dev, aqc111_data); 7427b8b0654SDmitry Bezrukov 7437b8b0654SDmitry Bezrukov /* Vlan Tag Filter */ 7447b8b0654SDmitry Bezrukov reg8 = SFR_VLAN_CONTROL_VSO; 7454189673aSDmitry Bezrukov if (dev->net->features & NETIF_F_HW_VLAN_CTAG_FILTER) 7464189673aSDmitry Bezrukov reg8 |= SFR_VLAN_CONTROL_VFE; 7477b8b0654SDmitry Bezrukov 7487b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 7497b8b0654SDmitry Bezrukov 1, 1, ®8); 7507b8b0654SDmitry Bezrukov 7517b8b0654SDmitry Bezrukov reg8 = 0x0; 7527b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 7537b8b0654SDmitry Bezrukov 1, 1, ®8); 7547b8b0654SDmitry Bezrukov 7557b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 7567b8b0654SDmitry Bezrukov 1, 1, ®8); 7577b8b0654SDmitry Bezrukov 7587b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 7597b8b0654SDmitry Bezrukov 7607b8b0654SDmitry Bezrukov reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 76159b04eeaSDmitry Bezrukov aqc111_data->rxctl = reg16; 7627b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 7637b8b0654SDmitry Bezrukov 7647b8b0654SDmitry Bezrukov reg8 = SFR_RX_PATH_READY; 7657b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 7667b8b0654SDmitry Bezrukov 1, 1, ®8); 7677b8b0654SDmitry Bezrukov 7687b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 7697b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 7707b8b0654SDmitry Bezrukov 1, 1, ®8); 7717b8b0654SDmitry Bezrukov 7727b8b0654SDmitry Bezrukov reg16 = 0; 7737b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 7747b8b0654SDmitry Bezrukov 2, ®16); 7757b8b0654SDmitry Bezrukov 7767b8b0654SDmitry Bezrukov reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 7777b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 7787b8b0654SDmitry Bezrukov 2, ®16); 7797b8b0654SDmitry Bezrukov 78002031466SDmitry Bezrukov aqc111_configure_csum_offload(dev); 78102031466SDmitry Bezrukov 78259b04eeaSDmitry Bezrukov aqc111_set_rx_mode(dev->net); 78359b04eeaSDmitry Bezrukov 7847b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 7857b8b0654SDmitry Bezrukov 2, ®16); 7867b8b0654SDmitry Bezrukov 787a4017cc2SDmitry Bezrukov if (dev->net->mtu > 1500) 788a4017cc2SDmitry Bezrukov reg16 |= SFR_MEDIUM_JUMBO_EN; 789a4017cc2SDmitry Bezrukov 7907b8b0654SDmitry Bezrukov reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 7917b8b0654SDmitry Bezrukov SFR_MEDIUM_TXFLOW_CTRLEN; 7927b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 7937b8b0654SDmitry Bezrukov 2, ®16); 7947b8b0654SDmitry Bezrukov 79559b04eeaSDmitry Bezrukov aqc111_data->rxctl |= SFR_RX_CTL_START; 79659b04eeaSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 79759b04eeaSDmitry Bezrukov 2, &aqc111_data->rxctl); 7987b8b0654SDmitry Bezrukov 7997b8b0654SDmitry Bezrukov netif_carrier_on(dev->net); 8007b8b0654SDmitry Bezrukov } else { 8017b8b0654SDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 8027b8b0654SDmitry Bezrukov 2, ®16); 8037b8b0654SDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 8047b8b0654SDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 8057b8b0654SDmitry Bezrukov 2, ®16); 8067b8b0654SDmitry Bezrukov 80759b04eeaSDmitry Bezrukov aqc111_data->rxctl &= ~SFR_RX_CTL_START; 80859b04eeaSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 80959b04eeaSDmitry Bezrukov 2, &aqc111_data->rxctl); 8107b8b0654SDmitry Bezrukov 8117b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 8127b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 8137b8b0654SDmitry Bezrukov 1, 1, ®8); 8147b8b0654SDmitry Bezrukov reg8 = SFR_BULK_OUT_EFF_EN; 8157b8b0654SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 8167b8b0654SDmitry Bezrukov 1, 1, ®8); 8177b8b0654SDmitry Bezrukov 8187b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 8197b8b0654SDmitry Bezrukov } 8207b8b0654SDmitry Bezrukov return 0; 8217b8b0654SDmitry Bezrukov } 8227b8b0654SDmitry Bezrukov 823f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 824f3aa095aSDmitry Bezrukov { 82533cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 826f3aa095aSDmitry Bezrukov u8 reg8 = 0; 827f3aa095aSDmitry Bezrukov 828361459cdSDmitry Bezrukov dev->rx_urb_size = URB_SIZE; 829361459cdSDmitry Bezrukov 8304a3576d2SDmitry Bezrukov if (usb_device_no_sg_constraint(dev->udev)) 8314a3576d2SDmitry Bezrukov dev->can_dma_sg = 1; 8324a3576d2SDmitry Bezrukov 8334a3576d2SDmitry Bezrukov dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 8344a3576d2SDmitry Bezrukov dev->net->features |= AQ_SUPPORT_FEATURE; 8357afa6c98SDmitry Bezrukov dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE; 8364a3576d2SDmitry Bezrukov 83733cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 83833cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 83933cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 84033cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 84133cd597fSDmitry Bezrukov 842df2d59a2SDmitry Bezrukov /* Set the MAC address */ 843df2d59a2SDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 844df2d59a2SDmitry Bezrukov ETH_ALEN, dev->net->dev_addr); 845df2d59a2SDmitry Bezrukov 846f3aa095aSDmitry Bezrukov reg8 = 0xFF; 847f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 848f3aa095aSDmitry Bezrukov 849f3aa095aSDmitry Bezrukov reg8 = 0x0; 850f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 851f3aa095aSDmitry Bezrukov 852f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 853f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 854f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 855f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 856f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 857f3aa095aSDmitry Bezrukov 8587b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 8597b8b0654SDmitry Bezrukov 8607b8b0654SDmitry Bezrukov /* Phy advertise */ 8617b8b0654SDmitry Bezrukov aqc111_set_phy_speed(dev, aqc111_data->autoneg, 8627b8b0654SDmitry Bezrukov aqc111_data->advertised_speed); 8637b8b0654SDmitry Bezrukov 864f3aa095aSDmitry Bezrukov return 0; 865f3aa095aSDmitry Bezrukov } 866f3aa095aSDmitry Bezrukov 867f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 868f3aa095aSDmitry Bezrukov { 86933cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 870f3aa095aSDmitry Bezrukov u16 reg16 = 0; 871f3aa095aSDmitry Bezrukov 872f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 873f3aa095aSDmitry Bezrukov 2, ®16); 874f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 875f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 876f3aa095aSDmitry Bezrukov 2, ®16); 877f3aa095aSDmitry Bezrukov reg16 = 0; 878f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 879f3aa095aSDmitry Bezrukov 88033cd597fSDmitry Bezrukov /* Put PHY to low power*/ 88133cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 88233cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 88333cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 88433cd597fSDmitry Bezrukov 8857b8b0654SDmitry Bezrukov netif_carrier_off(dev->net); 8867b8b0654SDmitry Bezrukov 887f3aa095aSDmitry Bezrukov return 0; 8887cea2d40SDmitry Bezrukov } 8897cea2d40SDmitry Bezrukov 89002031466SDmitry Bezrukov static void aqc111_rx_checksum(struct sk_buff *skb, u64 pkt_desc) 89102031466SDmitry Bezrukov { 89202031466SDmitry Bezrukov u32 pkt_type = 0; 89302031466SDmitry Bezrukov 89402031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_NONE; 89502031466SDmitry Bezrukov /* checksum error bit is set */ 89602031466SDmitry Bezrukov if (pkt_desc & AQ_RX_PD_L4_ERR || pkt_desc & AQ_RX_PD_L3_ERR) 89702031466SDmitry Bezrukov return; 89802031466SDmitry Bezrukov 89902031466SDmitry Bezrukov pkt_type = pkt_desc & AQ_RX_PD_L4_TYPE_MASK; 90002031466SDmitry Bezrukov /* It must be a TCP or UDP packet with a valid checksum */ 90102031466SDmitry Bezrukov if (pkt_type == AQ_RX_PD_L4_TCP || pkt_type == AQ_RX_PD_L4_UDP) 90202031466SDmitry Bezrukov skb->ip_summed = CHECKSUM_UNNECESSARY; 90302031466SDmitry Bezrukov } 90402031466SDmitry Bezrukov 905361459cdSDmitry Bezrukov static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 906361459cdSDmitry Bezrukov { 9076649d2a6SDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 908361459cdSDmitry Bezrukov struct sk_buff *new_skb = NULL; 909361459cdSDmitry Bezrukov u32 pkt_total_offset = 0; 910361459cdSDmitry Bezrukov u64 *pkt_desc_ptr = NULL; 911361459cdSDmitry Bezrukov u32 start_of_descs = 0; 912361459cdSDmitry Bezrukov u32 desc_offset = 0; /*RX Header Offset*/ 913361459cdSDmitry Bezrukov u16 pkt_count = 0; 914361459cdSDmitry Bezrukov u64 desc_hdr = 0; 9157afa6c98SDmitry Bezrukov u16 vlan_tag = 0; 916361459cdSDmitry Bezrukov u32 skb_len = 0; 917361459cdSDmitry Bezrukov 918361459cdSDmitry Bezrukov if (!skb) 919361459cdSDmitry Bezrukov goto err; 920361459cdSDmitry Bezrukov 921361459cdSDmitry Bezrukov if (skb->len == 0) 922361459cdSDmitry Bezrukov goto err; 923361459cdSDmitry Bezrukov 924361459cdSDmitry Bezrukov skb_len = skb->len; 925361459cdSDmitry Bezrukov /* RX Descriptor Header */ 926361459cdSDmitry Bezrukov skb_trim(skb, skb->len - sizeof(desc_hdr)); 927361459cdSDmitry Bezrukov desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); 928361459cdSDmitry Bezrukov 929361459cdSDmitry Bezrukov /* Check these packets */ 930361459cdSDmitry Bezrukov desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >> 931361459cdSDmitry Bezrukov AQ_RX_DH_DESC_OFFSET_SHIFT; 932361459cdSDmitry Bezrukov pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK; 933361459cdSDmitry Bezrukov start_of_descs = skb_len - ((pkt_count + 1) * sizeof(desc_hdr)); 934361459cdSDmitry Bezrukov 935361459cdSDmitry Bezrukov /* self check descs position */ 936361459cdSDmitry Bezrukov if (start_of_descs != desc_offset) 937361459cdSDmitry Bezrukov goto err; 938361459cdSDmitry Bezrukov 939361459cdSDmitry Bezrukov /* self check desc_offset from header*/ 940361459cdSDmitry Bezrukov if (desc_offset >= skb_len) 941361459cdSDmitry Bezrukov goto err; 942361459cdSDmitry Bezrukov 943361459cdSDmitry Bezrukov if (pkt_count == 0) 944361459cdSDmitry Bezrukov goto err; 945361459cdSDmitry Bezrukov 946361459cdSDmitry Bezrukov /* Get the first RX packet descriptor */ 947361459cdSDmitry Bezrukov pkt_desc_ptr = (u64 *)(skb->data + desc_offset); 948361459cdSDmitry Bezrukov 949361459cdSDmitry Bezrukov while (pkt_count--) { 950361459cdSDmitry Bezrukov u64 pkt_desc = le64_to_cpup(pkt_desc_ptr); 951361459cdSDmitry Bezrukov u32 pkt_len_with_padd = 0; 952361459cdSDmitry Bezrukov u32 pkt_len = 0; 953361459cdSDmitry Bezrukov 954361459cdSDmitry Bezrukov pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >> 955361459cdSDmitry Bezrukov AQ_RX_PD_LEN_SHIFT); 956361459cdSDmitry Bezrukov pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); 957361459cdSDmitry Bezrukov 958361459cdSDmitry Bezrukov pkt_total_offset += pkt_len_with_padd; 959361459cdSDmitry Bezrukov if (pkt_total_offset > desc_offset || 960361459cdSDmitry Bezrukov (pkt_count == 0 && pkt_total_offset != desc_offset)) { 961361459cdSDmitry Bezrukov goto err; 962361459cdSDmitry Bezrukov } 963361459cdSDmitry Bezrukov 964361459cdSDmitry Bezrukov if (pkt_desc & AQ_RX_PD_DROP || 965361459cdSDmitry Bezrukov !(pkt_desc & AQ_RX_PD_RX_OK) || 966361459cdSDmitry Bezrukov pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { 967361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 968361459cdSDmitry Bezrukov /* Next RX Packet Descriptor */ 969361459cdSDmitry Bezrukov pkt_desc_ptr++; 970361459cdSDmitry Bezrukov continue; 971361459cdSDmitry Bezrukov } 972361459cdSDmitry Bezrukov 973361459cdSDmitry Bezrukov /* Clone SKB */ 974361459cdSDmitry Bezrukov new_skb = skb_clone(skb, GFP_ATOMIC); 975361459cdSDmitry Bezrukov 976361459cdSDmitry Bezrukov if (!new_skb) 977361459cdSDmitry Bezrukov goto err; 978361459cdSDmitry Bezrukov 979361459cdSDmitry Bezrukov new_skb->len = pkt_len; 980361459cdSDmitry Bezrukov skb_pull(new_skb, AQ_RX_HW_PAD); 981361459cdSDmitry Bezrukov skb_set_tail_pointer(new_skb, new_skb->len); 982361459cdSDmitry Bezrukov 983361459cdSDmitry Bezrukov new_skb->truesize = SKB_TRUESIZE(new_skb->len); 9846649d2a6SDmitry Bezrukov if (aqc111_data->rx_checksum) 98502031466SDmitry Bezrukov aqc111_rx_checksum(new_skb, pkt_desc); 986361459cdSDmitry Bezrukov 9877afa6c98SDmitry Bezrukov if (pkt_desc & AQ_RX_PD_VLAN) { 9887afa6c98SDmitry Bezrukov vlan_tag = pkt_desc >> AQ_RX_PD_VLAN_SHIFT; 9897afa6c98SDmitry Bezrukov __vlan_hwaccel_put_tag(new_skb, htons(ETH_P_8021Q), 9907afa6c98SDmitry Bezrukov vlan_tag & VLAN_VID_MASK); 9917afa6c98SDmitry Bezrukov } 9927afa6c98SDmitry Bezrukov 993361459cdSDmitry Bezrukov usbnet_skb_return(dev, new_skb); 994361459cdSDmitry Bezrukov if (pkt_count == 0) 995361459cdSDmitry Bezrukov break; 996361459cdSDmitry Bezrukov 997361459cdSDmitry Bezrukov skb_pull(skb, pkt_len_with_padd); 998361459cdSDmitry Bezrukov 999361459cdSDmitry Bezrukov /* Next RX Packet Header */ 1000361459cdSDmitry Bezrukov pkt_desc_ptr++; 1001361459cdSDmitry Bezrukov 1002361459cdSDmitry Bezrukov new_skb = NULL; 1003361459cdSDmitry Bezrukov } 1004361459cdSDmitry Bezrukov 1005361459cdSDmitry Bezrukov return 1; 1006361459cdSDmitry Bezrukov 1007361459cdSDmitry Bezrukov err: 1008361459cdSDmitry Bezrukov return 0; 1009361459cdSDmitry Bezrukov } 1010361459cdSDmitry Bezrukov 10114a3576d2SDmitry Bezrukov static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 10124a3576d2SDmitry Bezrukov gfp_t flags) 10134a3576d2SDmitry Bezrukov { 10144a3576d2SDmitry Bezrukov int frame_size = dev->maxpacket; 10154a3576d2SDmitry Bezrukov struct sk_buff *new_skb = NULL; 10164a3576d2SDmitry Bezrukov u64 *tx_desc_ptr = NULL; 10174a3576d2SDmitry Bezrukov int padding_size = 0; 10184a3576d2SDmitry Bezrukov int headroom = 0; 10194a3576d2SDmitry Bezrukov int tailroom = 0; 10204a3576d2SDmitry Bezrukov u64 tx_desc = 0; 10217afa6c98SDmitry Bezrukov u16 tci = 0; 10224a3576d2SDmitry Bezrukov 10234a3576d2SDmitry Bezrukov /*Length of actual data*/ 10244a3576d2SDmitry Bezrukov tx_desc |= skb->len & AQ_TX_DESC_LEN_MASK; 10254a3576d2SDmitry Bezrukov 1026de074e7aSDmitry Bezrukov /* TSO MSS */ 1027de074e7aSDmitry Bezrukov tx_desc |= ((u64)(skb_shinfo(skb)->gso_size & AQ_TX_DESC_MSS_MASK)) << 1028de074e7aSDmitry Bezrukov AQ_TX_DESC_MSS_SHIFT; 1029de074e7aSDmitry Bezrukov 10304a3576d2SDmitry Bezrukov headroom = (skb->len + sizeof(tx_desc)) % 8; 10314a3576d2SDmitry Bezrukov if (headroom != 0) 10324a3576d2SDmitry Bezrukov padding_size = 8 - headroom; 10334a3576d2SDmitry Bezrukov 10344a3576d2SDmitry Bezrukov if (((skb->len + sizeof(tx_desc) + padding_size) % frame_size) == 0) { 10354a3576d2SDmitry Bezrukov padding_size += 8; 10364a3576d2SDmitry Bezrukov tx_desc |= AQ_TX_DESC_DROP_PADD; 10374a3576d2SDmitry Bezrukov } 10384a3576d2SDmitry Bezrukov 10397afa6c98SDmitry Bezrukov /* Vlan Tag */ 10407afa6c98SDmitry Bezrukov if (vlan_get_tag(skb, &tci) >= 0) { 10417afa6c98SDmitry Bezrukov tx_desc |= AQ_TX_DESC_VLAN; 10427afa6c98SDmitry Bezrukov tx_desc |= ((u64)tci & AQ_TX_DESC_VLAN_MASK) << 10437afa6c98SDmitry Bezrukov AQ_TX_DESC_VLAN_SHIFT; 10447afa6c98SDmitry Bezrukov } 10457afa6c98SDmitry Bezrukov 10464a3576d2SDmitry Bezrukov if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) && 10474a3576d2SDmitry Bezrukov skb_linearize(skb)) 10484a3576d2SDmitry Bezrukov return NULL; 10494a3576d2SDmitry Bezrukov 10504a3576d2SDmitry Bezrukov headroom = skb_headroom(skb); 10514a3576d2SDmitry Bezrukov tailroom = skb_tailroom(skb); 10524a3576d2SDmitry Bezrukov 10534a3576d2SDmitry Bezrukov if (!(headroom >= sizeof(tx_desc) && tailroom >= padding_size)) { 10544a3576d2SDmitry Bezrukov new_skb = skb_copy_expand(skb, sizeof(tx_desc), 10554a3576d2SDmitry Bezrukov padding_size, flags); 10564a3576d2SDmitry Bezrukov dev_kfree_skb_any(skb); 10574a3576d2SDmitry Bezrukov skb = new_skb; 10584a3576d2SDmitry Bezrukov if (!skb) 10594a3576d2SDmitry Bezrukov return NULL; 10604a3576d2SDmitry Bezrukov } 10614a3576d2SDmitry Bezrukov if (padding_size != 0) 10624a3576d2SDmitry Bezrukov skb_put_zero(skb, padding_size); 10634a3576d2SDmitry Bezrukov /* Copy TX header */ 10644a3576d2SDmitry Bezrukov tx_desc_ptr = skb_push(skb, sizeof(tx_desc)); 10654a3576d2SDmitry Bezrukov *tx_desc_ptr = cpu_to_le64(tx_desc); 10664a3576d2SDmitry Bezrukov 10674a3576d2SDmitry Bezrukov usbnet_set_skb_tx_stats(skb, 1, 0); 10684a3576d2SDmitry Bezrukov 10694a3576d2SDmitry Bezrukov return skb; 10704a3576d2SDmitry Bezrukov } 10714a3576d2SDmitry Bezrukov 107217364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 107317364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 10747cea2d40SDmitry Bezrukov .bind = aqc111_bind, 10757cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 10767b8b0654SDmitry Bezrukov .status = aqc111_status, 10777b8b0654SDmitry Bezrukov .link_reset = aqc111_link_reset, 1078f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 1079f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 10804a3576d2SDmitry Bezrukov .flags = FLAG_ETHER | FLAG_FRAMING_AX | 10814a3576d2SDmitry Bezrukov FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 1082361459cdSDmitry Bezrukov .rx_fixup = aqc111_rx_fixup, 10834a3576d2SDmitry Bezrukov .tx_fixup = aqc111_tx_fixup, 108417364b80SDmitry Bezrukov }; 108517364b80SDmitry Bezrukov 108617364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 108717364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 108817364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 108917364b80SDmitry Bezrukov }, \ 109017364b80SDmitry Bezrukov { \ 109117364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 109217364b80SDmitry Bezrukov USB_CLASS_COMM, \ 109317364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 109417364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 109517364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 109617364b80SDmitry Bezrukov 109717364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 109817364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 109917364b80SDmitry Bezrukov { },/* END */ 110017364b80SDmitry Bezrukov }; 110117364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 110217364b80SDmitry Bezrukov 110317364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 110417364b80SDmitry Bezrukov .name = "aqc111", 110517364b80SDmitry Bezrukov .id_table = products, 110617364b80SDmitry Bezrukov .probe = usbnet_probe, 110717364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 110817364b80SDmitry Bezrukov }; 110917364b80SDmitry Bezrukov 111017364b80SDmitry Bezrukov module_usb_driver(aq_driver); 111117364b80SDmitry Bezrukov 111217364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 111317364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 1114