18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller 38c2ecf20Sopenharmony_ci * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 58c2ecf20Sopenharmony_ci * Copyright (C) 2002-2003 TiVo Inc. 68c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 ASIX 78c2ecf20Sopenharmony_ci * Copyright (C) 2018 Aquantia Corp. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 128c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 138c2ecf20Sopenharmony_ci#include <linux/mii.h> 148c2ecf20Sopenharmony_ci#include <linux/usb.h> 158c2ecf20Sopenharmony_ci#include <linux/crc32.h> 168c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 178c2ecf20Sopenharmony_ci#include <linux/usb/cdc.h> 188c2ecf20Sopenharmony_ci#include <linux/usb/usbnet.h> 198c2ecf20Sopenharmony_ci#include <linux/linkmode.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "aqc111.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRIVER_NAME "aqc111" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 268c2ecf20Sopenharmony_ci u16 index, u16 size, void *data) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int ret; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci ret = usbnet_read_cmd_nopm(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 318c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, data, size); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 348c2ecf20Sopenharmony_ci netdev_warn(dev->net, 358c2ecf20Sopenharmony_ci "Failed to read(0x%x) reg index 0x%04x: %d\n", 368c2ecf20Sopenharmony_ci cmd, index, ret); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return ret; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value, 428c2ecf20Sopenharmony_ci u16 index, u16 size, void *data) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret = usbnet_read_cmd(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 478c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, data, size); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 508c2ecf20Sopenharmony_ci netdev_warn(dev->net, 518c2ecf20Sopenharmony_ci "Failed to read(0x%x) reg index 0x%04x: %d\n", 528c2ecf20Sopenharmony_ci cmd, index, ret); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return ret; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int aqc111_read16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 588c2ecf20Sopenharmony_ci u16 index, u16 *data) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int ret = 0; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci ret = aqc111_read_cmd_nopm(dev, cmd, value, index, sizeof(*data), data); 638c2ecf20Sopenharmony_ci le16_to_cpus(data); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return ret; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int aqc111_read16_cmd(struct usbnet *dev, u8 cmd, u16 value, 698c2ecf20Sopenharmony_ci u16 index, u16 *data) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int ret = 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ret = aqc111_read_cmd(dev, cmd, value, index, sizeof(*data), data); 748c2ecf20Sopenharmony_ci le16_to_cpus(data); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return ret; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 808c2ecf20Sopenharmony_ci u16 value, u16 index, u16 size, const void *data) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int err = -ENOMEM; 838c2ecf20Sopenharmony_ci void *buf = NULL; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci netdev_dbg(dev->net, 868c2ecf20Sopenharmony_ci "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n", 878c2ecf20Sopenharmony_ci __func__, cmd, reqtype, value, index, size); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (data) { 908c2ecf20Sopenharmony_ci buf = kmemdup(data, size, GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!buf) 928c2ecf20Sopenharmony_ci goto out; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 968c2ecf20Sopenharmony_ci cmd, reqtype, value, index, buf, size, 978c2ecf20Sopenharmony_ci (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT : 988c2ecf20Sopenharmony_ci AQ_USB_SET_TIMEOUT); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 1018c2ecf20Sopenharmony_ci netdev_warn(dev->net, 1028c2ecf20Sopenharmony_ci "Failed to write(0x%x) reg index 0x%04x: %d\n", 1038c2ecf20Sopenharmony_ci cmd, index, err); 1048c2ecf20Sopenharmony_ci kfree(buf); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciout: 1078c2ecf20Sopenharmony_ci return err; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 1118c2ecf20Sopenharmony_ci u16 index, u16 size, void *data) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci int ret; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 1168c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, size, data); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 1228c2ecf20Sopenharmony_ci u16 index, u16 size, void *data) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int ret; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (usb_autopm_get_interface(dev->intf) < 0) 1278c2ecf20Sopenharmony_ci return -ENODEV; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 1308c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, size, data); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci usb_autopm_put_interface(dev->intf); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int aqc111_write16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 1388c2ecf20Sopenharmony_ci u16 index, u16 *data) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u16 tmp = *data; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci cpu_to_le16s(&tmp); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value, 1488c2ecf20Sopenharmony_ci u16 index, u16 *data) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci u16 tmp = *data; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci cpu_to_le16s(&tmp); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int aqc111_write32_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 1588c2ecf20Sopenharmony_ci u16 index, u32 *data) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci u32 tmp = *data; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci cpu_to_le32s(&tmp); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value, 1688c2ecf20Sopenharmony_ci u16 index, u32 *data) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci u32 tmp = *data; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci cpu_to_le32s(&tmp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int aqc111_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, 1788c2ecf20Sopenharmony_ci u16 index, u16 size, void *data) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 1818c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, data, 1828c2ecf20Sopenharmony_ci size); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int aqc111_write16_cmd_async(struct usbnet *dev, u8 cmd, u16 value, 1868c2ecf20Sopenharmony_ci u16 index, u16 *data) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u16 tmp = *data; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci cpu_to_le16s(&tmp); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return aqc111_write_cmd_async(dev, cmd, value, index, 1938c2ecf20Sopenharmony_ci sizeof(tmp), &tmp); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void aqc111_get_drvinfo(struct net_device *net, 1978c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 2008c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Inherit standard device info */ 2038c2ecf20Sopenharmony_ci usbnet_get_drvinfo(net, info); 2048c2ecf20Sopenharmony_ci strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 2058c2ecf20Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u.%u", 2068c2ecf20Sopenharmony_ci aqc111_data->fw_ver.major, 2078c2ecf20Sopenharmony_ci aqc111_data->fw_ver.minor, 2088c2ecf20Sopenharmony_ci aqc111_data->fw_ver.rev); 2098c2ecf20Sopenharmony_ci info->eedump_len = 0x00; 2108c2ecf20Sopenharmony_ci info->regdump_len = 0x00; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void aqc111_get_wol(struct net_device *net, 2148c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wolinfo) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 2178c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci wolinfo->supported = WAKE_MAGIC; 2208c2ecf20Sopenharmony_ci wolinfo->wolopts = 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (aqc111_data->wol_flags & AQ_WOL_FLAG_MP) 2238c2ecf20Sopenharmony_ci wolinfo->wolopts |= WAKE_MAGIC; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int aqc111_set_wol(struct net_device *net, 2278c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wolinfo) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 2308c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (wolinfo->wolopts & ~WAKE_MAGIC) 2338c2ecf20Sopenharmony_ci return -EINVAL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci aqc111_data->wol_flags = 0; 2368c2ecf20Sopenharmony_ci if (wolinfo->wolopts & WAKE_MAGIC) 2378c2ecf20Sopenharmony_ci aqc111_data->wol_flags |= AQ_WOL_FLAG_MP; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void aqc111_speed_to_link_mode(u32 speed, 2438c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *elk) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci switch (speed) { 2468c2ecf20Sopenharmony_ci case SPEED_5000: 2478c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, advertising, 2488c2ecf20Sopenharmony_ci 5000baseT_Full); 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case SPEED_2500: 2518c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, advertising, 2528c2ecf20Sopenharmony_ci 2500baseT_Full); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case SPEED_1000: 2558c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, advertising, 2568c2ecf20Sopenharmony_ci 1000baseT_Full); 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci case SPEED_100: 2598c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, advertising, 2608c2ecf20Sopenharmony_ci 100baseT_Full); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int aqc111_get_link_ksettings(struct net_device *net, 2668c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *elk) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 2698c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 2708c2ecf20Sopenharmony_ci enum usb_device_speed usb_speed = dev->udev->speed; 2718c2ecf20Sopenharmony_ci u32 speed = SPEED_UNKNOWN; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(elk, supported); 2748c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, 2758c2ecf20Sopenharmony_ci 100baseT_Full); 2768c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, 2778c2ecf20Sopenharmony_ci 1000baseT_Full); 2788c2ecf20Sopenharmony_ci if (usb_speed == USB_SPEED_SUPER) { 2798c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, 2808c2ecf20Sopenharmony_ci 2500baseT_Full); 2818c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, 2828c2ecf20Sopenharmony_ci 5000baseT_Full); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, TP); 2858c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(elk, supported, Autoneg); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci elk->base.port = PORT_TP; 2888c2ecf20Sopenharmony_ci elk->base.transceiver = XCVR_INTERNAL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci elk->base.mdio_support = 0x00; /*Not supported*/ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (aqc111_data->autoneg) 2938c2ecf20Sopenharmony_ci linkmode_copy(elk->link_modes.advertising, 2948c2ecf20Sopenharmony_ci elk->link_modes.supported); 2958c2ecf20Sopenharmony_ci else 2968c2ecf20Sopenharmony_ci aqc111_speed_to_link_mode(aqc111_data->advertised_speed, elk); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci elk->base.autoneg = aqc111_data->autoneg; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci switch (aqc111_data->link_speed) { 3018c2ecf20Sopenharmony_ci case AQ_INT_SPEED_5G: 3028c2ecf20Sopenharmony_ci speed = SPEED_5000; 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci case AQ_INT_SPEED_2_5G: 3058c2ecf20Sopenharmony_ci speed = SPEED_2500; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case AQ_INT_SPEED_1G: 3088c2ecf20Sopenharmony_ci speed = SPEED_1000; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case AQ_INT_SPEED_100M: 3118c2ecf20Sopenharmony_ci speed = SPEED_100; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci elk->base.duplex = DUPLEX_FULL; 3158c2ecf20Sopenharmony_ci elk->base.speed = speed; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 3258c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_PAUSE; 3268c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ASYM_PAUSE; 3278c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_DOWNSHIFT; 3288c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK; 3298c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= (3 << AQ_DSH_RETRIES_SHIFT) & 3308c2ecf20Sopenharmony_ci AQ_DSH_RETRIES_MASK; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_ENABLE) { 3338c2ecf20Sopenharmony_ci switch (speed) { 3348c2ecf20Sopenharmony_ci case SPEED_5000: 3358c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_5G; 3368c2ecf20Sopenharmony_ci fallthrough; 3378c2ecf20Sopenharmony_ci case SPEED_2500: 3388c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_2G5; 3398c2ecf20Sopenharmony_ci fallthrough; 3408c2ecf20Sopenharmony_ci case SPEED_1000: 3418c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_1G; 3428c2ecf20Sopenharmony_ci fallthrough; 3438c2ecf20Sopenharmony_ci case SPEED_100: 3448c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_100M; 3458c2ecf20Sopenharmony_ci /* fall-through */ 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci switch (speed) { 3498c2ecf20Sopenharmony_ci case SPEED_5000: 3508c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_5G; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case SPEED_2500: 3538c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_2G5; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case SPEED_1000: 3568c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_1G; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case SPEED_100: 3598c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_ADV_100M; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int aqc111_set_link_ksettings(struct net_device *net, 3688c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *elk) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 3718c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 3728c2ecf20Sopenharmony_ci enum usb_device_speed usb_speed = dev->udev->speed; 3738c2ecf20Sopenharmony_ci u8 autoneg = elk->base.autoneg; 3748c2ecf20Sopenharmony_ci u32 speed = elk->base.speed; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (autoneg == AUTONEG_ENABLE) { 3778c2ecf20Sopenharmony_ci if (aqc111_data->autoneg != AUTONEG_ENABLE) { 3788c2ecf20Sopenharmony_ci aqc111_data->autoneg = AUTONEG_ENABLE; 3798c2ecf20Sopenharmony_ci aqc111_data->advertised_speed = 3808c2ecf20Sopenharmony_ci (usb_speed == USB_SPEED_SUPER) ? 3818c2ecf20Sopenharmony_ci SPEED_5000 : SPEED_1000; 3828c2ecf20Sopenharmony_ci aqc111_set_phy_speed(dev, aqc111_data->autoneg, 3838c2ecf20Sopenharmony_ci aqc111_data->advertised_speed); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci if (speed != SPEED_100 && 3878c2ecf20Sopenharmony_ci speed != SPEED_1000 && 3888c2ecf20Sopenharmony_ci speed != SPEED_2500 && 3898c2ecf20Sopenharmony_ci speed != SPEED_5000 && 3908c2ecf20Sopenharmony_ci speed != SPEED_UNKNOWN) 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (elk->base.duplex != DUPLEX_FULL) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (usb_speed != USB_SPEED_SUPER && speed > SPEED_1000) 3978c2ecf20Sopenharmony_ci return -EINVAL; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci aqc111_data->autoneg = AUTONEG_DISABLE; 4008c2ecf20Sopenharmony_ci if (speed != SPEED_UNKNOWN) 4018c2ecf20Sopenharmony_ci aqc111_data->advertised_speed = speed; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci aqc111_set_phy_speed(dev, aqc111_data->autoneg, 4048c2ecf20Sopenharmony_ci aqc111_data->advertised_speed); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic const struct ethtool_ops aqc111_ethtool_ops = { 4118c2ecf20Sopenharmony_ci .get_drvinfo = aqc111_get_drvinfo, 4128c2ecf20Sopenharmony_ci .get_wol = aqc111_get_wol, 4138c2ecf20Sopenharmony_ci .set_wol = aqc111_set_wol, 4148c2ecf20Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 4158c2ecf20Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 4168c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 4178c2ecf20Sopenharmony_ci .get_link_ksettings = aqc111_get_link_ksettings, 4188c2ecf20Sopenharmony_ci .set_link_ksettings = aqc111_set_link_ksettings 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int aqc111_change_mtu(struct net_device *net, int new_mtu) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 4248c2ecf20Sopenharmony_ci u16 reg16 = 0; 4258c2ecf20Sopenharmony_ci u8 buf[5]; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci net->mtu = new_mtu; 4288c2ecf20Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4318c2ecf20Sopenharmony_ci 2, ®16); 4328c2ecf20Sopenharmony_ci if (net->mtu > 1500) 4338c2ecf20Sopenharmony_ci reg16 |= SFR_MEDIUM_JUMBO_EN; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci reg16 &= ~SFR_MEDIUM_JUMBO_EN; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 4388c2ecf20Sopenharmony_ci 2, ®16); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (dev->net->mtu > 12500) { 4418c2ecf20Sopenharmony_ci memcpy(buf, &AQC111_BULKIN_SIZE[2], 5); 4428c2ecf20Sopenharmony_ci /* RX bulk configuration */ 4438c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 4448c2ecf20Sopenharmony_ci 5, 5, buf); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Set high low water level */ 4488c2ecf20Sopenharmony_ci if (dev->net->mtu <= 4500) 4498c2ecf20Sopenharmony_ci reg16 = 0x0810; 4508c2ecf20Sopenharmony_ci else if (dev->net->mtu <= 9500) 4518c2ecf20Sopenharmony_ci reg16 = 0x1020; 4528c2ecf20Sopenharmony_ci else if (dev->net->mtu <= 12500) 4538c2ecf20Sopenharmony_ci reg16 = 0x1420; 4548c2ecf20Sopenharmony_ci else 4558c2ecf20Sopenharmony_ci reg16 = 0x1A20; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 4588c2ecf20Sopenharmony_ci 2, ®16); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int aqc111_set_mac_addr(struct net_device *net, void *p) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 4668c2ecf20Sopenharmony_ci int ret = 0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ret = eth_mac_addr(net, p); 4698c2ecf20Sopenharmony_ci if (ret < 0) 4708c2ecf20Sopenharmony_ci return ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Set the MAC address */ 4738c2ecf20Sopenharmony_ci return aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 4748c2ecf20Sopenharmony_ci ETH_ALEN, net->dev_addr); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int aqc111_vlan_rx_kill_vid(struct net_device *net, 4788c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 4818c2ecf20Sopenharmony_ci u8 vlan_ctrl = 0; 4828c2ecf20Sopenharmony_ci u16 reg16 = 0; 4838c2ecf20Sopenharmony_ci u8 reg8 = 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 4868c2ecf20Sopenharmony_ci vlan_ctrl = reg8; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* Address */ 4898c2ecf20Sopenharmony_ci reg8 = (vid / 16); 4908c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8); 4918c2ecf20Sopenharmony_ci /* Data */ 4928c2ecf20Sopenharmony_ci reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD; 4938c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 4948c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 4958c2ecf20Sopenharmony_ci reg16 &= ~(1 << (vid % 16)); 4968c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 4978c2ecf20Sopenharmony_ci reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE; 4988c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int aqc111_vlan_rx_add_vid(struct net_device *net, __be16 proto, u16 vid) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 5068c2ecf20Sopenharmony_ci u8 vlan_ctrl = 0; 5078c2ecf20Sopenharmony_ci u16 reg16 = 0; 5088c2ecf20Sopenharmony_ci u8 reg8 = 0; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 5118c2ecf20Sopenharmony_ci vlan_ctrl = reg8; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Address */ 5148c2ecf20Sopenharmony_ci reg8 = (vid / 16); 5158c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8); 5168c2ecf20Sopenharmony_ci /* Data */ 5178c2ecf20Sopenharmony_ci reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD; 5188c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 5198c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 5208c2ecf20Sopenharmony_ci reg16 |= (1 << (vid % 16)); 5218c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, ®16); 5228c2ecf20Sopenharmony_ci reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE; 5238c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void aqc111_set_rx_mode(struct net_device *net) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 5318c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 5328c2ecf20Sopenharmony_ci int mc_count = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci mc_count = netdev_mc_count(net); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci aqc111_data->rxctl &= ~(SFR_RX_CTL_PRO | SFR_RX_CTL_AMALL | 5378c2ecf20Sopenharmony_ci SFR_RX_CTL_AM); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (net->flags & IFF_PROMISC) { 5408c2ecf20Sopenharmony_ci aqc111_data->rxctl |= SFR_RX_CTL_PRO; 5418c2ecf20Sopenharmony_ci } else if ((net->flags & IFF_ALLMULTI) || mc_count > AQ_MAX_MCAST) { 5428c2ecf20Sopenharmony_ci aqc111_data->rxctl |= SFR_RX_CTL_AMALL; 5438c2ecf20Sopenharmony_ci } else if (!netdev_mc_empty(net)) { 5448c2ecf20Sopenharmony_ci u8 m_filter[AQ_MCAST_FILTER_SIZE] = { 0 }; 5458c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha = NULL; 5468c2ecf20Sopenharmony_ci u32 crc_bits = 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, net) { 5498c2ecf20Sopenharmony_ci crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 5508c2ecf20Sopenharmony_ci m_filter[crc_bits >> 3] |= BIT(crc_bits & 7); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci aqc111_write_cmd_async(dev, AQ_ACCESS_MAC, 5548c2ecf20Sopenharmony_ci SFR_MULTI_FILTER_ARRY, 5558c2ecf20Sopenharmony_ci AQ_MCAST_FILTER_SIZE, 5568c2ecf20Sopenharmony_ci AQ_MCAST_FILTER_SIZE, m_filter); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci aqc111_data->rxctl |= SFR_RX_CTL_AM; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci aqc111_write16_cmd_async(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 5628c2ecf20Sopenharmony_ci 2, &aqc111_data->rxctl); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int aqc111_set_features(struct net_device *net, 5668c2ecf20Sopenharmony_ci netdev_features_t features) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 5698c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 5708c2ecf20Sopenharmony_ci netdev_features_t changed = net->features ^ features; 5718c2ecf20Sopenharmony_ci u16 reg16 = 0; 5728c2ecf20Sopenharmony_ci u8 reg8 = 0; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (changed & NETIF_F_IP_CSUM) { 5758c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 5768c2ecf20Sopenharmony_ci reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP; 5778c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 5788c2ecf20Sopenharmony_ci 1, 1, ®8); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (changed & NETIF_F_IPV6_CSUM) { 5828c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 5838c2ecf20Sopenharmony_ci reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 5848c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 5858c2ecf20Sopenharmony_ci 1, 1, ®8); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (changed & NETIF_F_RXCSUM) { 5898c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 5908c2ecf20Sopenharmony_ci if (features & NETIF_F_RXCSUM) { 5918c2ecf20Sopenharmony_ci aqc111_data->rx_checksum = 1; 5928c2ecf20Sopenharmony_ci reg8 &= ~(SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 5938c2ecf20Sopenharmony_ci SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6); 5948c2ecf20Sopenharmony_ci } else { 5958c2ecf20Sopenharmony_ci aqc111_data->rx_checksum = 0; 5968c2ecf20Sopenharmony_ci reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 5978c2ecf20Sopenharmony_ci SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 6018c2ecf20Sopenharmony_ci 1, 1, ®8); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { 6048c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_FILTER) { 6058c2ecf20Sopenharmony_ci u16 i = 0; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 6088c2ecf20Sopenharmony_ci /* Address */ 6098c2ecf20Sopenharmony_ci reg8 = i; 6108c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, 6118c2ecf20Sopenharmony_ci SFR_VLAN_ID_ADDRESS, 6128c2ecf20Sopenharmony_ci 1, 1, ®8); 6138c2ecf20Sopenharmony_ci /* Data */ 6148c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, 6158c2ecf20Sopenharmony_ci SFR_VLAN_ID_DATA0, 6168c2ecf20Sopenharmony_ci 2, ®16); 6178c2ecf20Sopenharmony_ci reg8 = SFR_VLAN_CONTROL_WE; 6188c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, 6198c2ecf20Sopenharmony_ci SFR_VLAN_ID_CONTROL, 6208c2ecf20Sopenharmony_ci 1, 1, ®8); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 6238c2ecf20Sopenharmony_ci 1, 1, ®8); 6248c2ecf20Sopenharmony_ci reg8 |= SFR_VLAN_CONTROL_VFE; 6258c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, 6268c2ecf20Sopenharmony_ci SFR_VLAN_ID_CONTROL, 1, 1, ®8); 6278c2ecf20Sopenharmony_ci } else { 6288c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 6298c2ecf20Sopenharmony_ci 1, 1, ®8); 6308c2ecf20Sopenharmony_ci reg8 &= ~SFR_VLAN_CONTROL_VFE; 6318c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, 6328c2ecf20Sopenharmony_ci SFR_VLAN_ID_CONTROL, 1, 1, ®8); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return 0; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct net_device_ops aqc111_netdev_ops = { 6408c2ecf20Sopenharmony_ci .ndo_open = usbnet_open, 6418c2ecf20Sopenharmony_ci .ndo_stop = usbnet_stop, 6428c2ecf20Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 6438c2ecf20Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 6448c2ecf20Sopenharmony_ci .ndo_get_stats64 = usbnet_get_stats64, 6458c2ecf20Sopenharmony_ci .ndo_change_mtu = aqc111_change_mtu, 6468c2ecf20Sopenharmony_ci .ndo_set_mac_address = aqc111_set_mac_addr, 6478c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 6488c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = aqc111_vlan_rx_add_vid, 6498c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = aqc111_vlan_rx_kill_vid, 6508c2ecf20Sopenharmony_ci .ndo_set_rx_mode = aqc111_set_rx_mode, 6518c2ecf20Sopenharmony_ci .ndo_set_features = aqc111_set_features, 6528c2ecf20Sopenharmony_ci}; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int aqc111_read_perm_mac(struct usbnet *dev) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci u8 buf[ETH_ALEN]; 6578c2ecf20Sopenharmony_ci int ret; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, ETH_ALEN, buf); 6608c2ecf20Sopenharmony_ci if (ret < 0) 6618c2ecf20Sopenharmony_ci goto out; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci ether_addr_copy(dev->net->perm_addr, buf); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return 0; 6668c2ecf20Sopenharmony_ciout: 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic void aqc111_read_fw_version(struct usbnet *dev, 6718c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 6748c2ecf20Sopenharmony_ci 1, 1, &aqc111_data->fw_ver.major); 6758c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 6768c2ecf20Sopenharmony_ci 1, 1, &aqc111_data->fw_ver.minor); 6778c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 6788c2ecf20Sopenharmony_ci 1, 1, &aqc111_data->fw_ver.rev); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (aqc111_data->fw_ver.major & 0x80) 6818c2ecf20Sopenharmony_ci aqc111_data->fw_ver.major &= ~0x80; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 6878c2ecf20Sopenharmony_ci enum usb_device_speed usb_speed = udev->speed; 6888c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data; 6898c2ecf20Sopenharmony_ci int ret; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Check if vendor configuration */ 6928c2ecf20Sopenharmony_ci if (udev->actconfig->desc.bConfigurationValue != 1) { 6938c2ecf20Sopenharmony_ci usb_driver_set_configuration(udev, 1); 6948c2ecf20Sopenharmony_ci return -ENODEV; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci usb_reset_configuration(dev->udev); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ret = usbnet_get_endpoints(dev, intf); 7008c2ecf20Sopenharmony_ci if (ret < 0) { 7018c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 7068c2ecf20Sopenharmony_ci if (!aqc111_data) 7078c2ecf20Sopenharmony_ci return -ENOMEM; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* store aqc111_data pointer in device data field */ 7108c2ecf20Sopenharmony_ci dev->driver_priv = aqc111_data; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* Init the MAC address */ 7138c2ecf20Sopenharmony_ci ret = aqc111_read_perm_mac(dev); 7148c2ecf20Sopenharmony_ci if (ret) 7158c2ecf20Sopenharmony_ci goto out; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Set Rx urb size */ 7208c2ecf20Sopenharmony_ci dev->rx_urb_size = URB_SIZE; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Set TX needed headroom & tailroom */ 7238c2ecf20Sopenharmony_ci dev->net->needed_headroom += sizeof(u64); 7248c2ecf20Sopenharmony_ci dev->net->needed_tailroom += sizeof(u64); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci dev->net->max_mtu = 16334; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci dev->net->netdev_ops = &aqc111_netdev_ops; 7298c2ecf20Sopenharmony_ci dev->net->ethtool_ops = &aqc111_ethtool_ops; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (usb_device_no_sg_constraint(dev->udev)) 7328c2ecf20Sopenharmony_ci dev->can_dma_sg = 1; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 7358c2ecf20Sopenharmony_ci dev->net->features |= AQ_SUPPORT_FEATURE; 7368c2ecf20Sopenharmony_ci dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci netif_set_gso_max_size(dev->net, 65535); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci aqc111_read_fw_version(dev, aqc111_data); 7418c2ecf20Sopenharmony_ci aqc111_data->autoneg = AUTONEG_ENABLE; 7428c2ecf20Sopenharmony_ci aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ? 7438c2ecf20Sopenharmony_ci SPEED_5000 : SPEED_1000; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ciout: 7488c2ecf20Sopenharmony_ci kfree(aqc111_data); 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 7558c2ecf20Sopenharmony_ci u16 reg16; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* Force bz */ 7588c2ecf20Sopenharmony_ci reg16 = SFR_PHYPWR_RSTCTL_BZ; 7598c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 7608c2ecf20Sopenharmony_ci 2, ®16); 7618c2ecf20Sopenharmony_ci reg16 = 0; 7628c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 7638c2ecf20Sopenharmony_ci 2, ®16); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Power down ethernet PHY */ 7668c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_ADV_MASK; 7678c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_LOW_POWER; 7688c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 7698c2ecf20Sopenharmony_ci aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 7708c2ecf20Sopenharmony_ci &aqc111_data->phy_cfg); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci kfree(aqc111_data); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic void aqc111_status(struct usbnet *dev, struct urb *urb) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 7788c2ecf20Sopenharmony_ci u64 *event_data = NULL; 7798c2ecf20Sopenharmony_ci int link = 0; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (urb->actual_length < sizeof(*event_data)) 7828c2ecf20Sopenharmony_ci return; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci event_data = urb->transfer_buffer; 7858c2ecf20Sopenharmony_ci le64_to_cpus(event_data); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (*event_data & AQ_LS_MASK) 7888c2ecf20Sopenharmony_ci link = 1; 7898c2ecf20Sopenharmony_ci else 7908c2ecf20Sopenharmony_ci link = 0; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci aqc111_data->link_speed = (*event_data & AQ_SPEED_MASK) >> 7938c2ecf20Sopenharmony_ci AQ_SPEED_SHIFT; 7948c2ecf20Sopenharmony_ci aqc111_data->link = link; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev->net) != link) 7978c2ecf20Sopenharmony_ci usbnet_defer_kevent(dev, EVENT_LINK_RESET); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic void aqc111_configure_rx(struct usbnet *dev, 8018c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci enum usb_device_speed usb_speed = dev->udev->speed; 8048c2ecf20Sopenharmony_ci u16 link_speed = 0, usb_host = 0; 8058c2ecf20Sopenharmony_ci u8 buf[5] = { 0 }; 8068c2ecf20Sopenharmony_ci u8 queue_num = 0; 8078c2ecf20Sopenharmony_ci u16 reg16 = 0; 8088c2ecf20Sopenharmony_ci u8 reg8 = 0; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci buf[0] = 0x00; 8118c2ecf20Sopenharmony_ci buf[1] = 0xF8; 8128c2ecf20Sopenharmony_ci buf[2] = 0x07; 8138c2ecf20Sopenharmony_ci switch (aqc111_data->link_speed) { 8148c2ecf20Sopenharmony_ci case AQ_INT_SPEED_5G: 8158c2ecf20Sopenharmony_ci link_speed = 5000; 8168c2ecf20Sopenharmony_ci reg8 = 0x05; 8178c2ecf20Sopenharmony_ci reg16 = 0x001F; 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci case AQ_INT_SPEED_2_5G: 8208c2ecf20Sopenharmony_ci link_speed = 2500; 8218c2ecf20Sopenharmony_ci reg16 = 0x003F; 8228c2ecf20Sopenharmony_ci break; 8238c2ecf20Sopenharmony_ci case AQ_INT_SPEED_1G: 8248c2ecf20Sopenharmony_ci link_speed = 1000; 8258c2ecf20Sopenharmony_ci reg16 = 0x009F; 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci case AQ_INT_SPEED_100M: 8288c2ecf20Sopenharmony_ci link_speed = 100; 8298c2ecf20Sopenharmony_ci queue_num = 1; 8308c2ecf20Sopenharmony_ci reg16 = 0x063F; 8318c2ecf20Sopenharmony_ci buf[1] = 0xFB; 8328c2ecf20Sopenharmony_ci buf[2] = 0x4; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0, 8378c2ecf20Sopenharmony_ci 1, 1, ®8); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci switch (usb_speed) { 8428c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 8438c2ecf20Sopenharmony_ci usb_host = 3; 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 8468c2ecf20Sopenharmony_ci usb_host = 2; 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 8498c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 8508c2ecf20Sopenharmony_ci usb_host = 1; 8518c2ecf20Sopenharmony_ci queue_num = 0; 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci default: 8548c2ecf20Sopenharmony_ci usb_host = 0; 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (dev->net->mtu > 12500 && dev->net->mtu <= 16334) 8598c2ecf20Sopenharmony_ci queue_num = 2; /* For Jumbo packet 16KB */ 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5); 8628c2ecf20Sopenharmony_ci /* RX bulk configuration */ 8638c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* Set high low water level */ 8668c2ecf20Sopenharmony_ci if (dev->net->mtu <= 4500) 8678c2ecf20Sopenharmony_ci reg16 = 0x0810; 8688c2ecf20Sopenharmony_ci else if (dev->net->mtu <= 9500) 8698c2ecf20Sopenharmony_ci reg16 = 0x1020; 8708c2ecf20Sopenharmony_ci else if (dev->net->mtu <= 12500) 8718c2ecf20Sopenharmony_ci reg16 = 0x1420; 8728c2ecf20Sopenharmony_ci else if (dev->net->mtu <= 16334) 8738c2ecf20Sopenharmony_ci reg16 = 0x1A20; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW, 8768c2ecf20Sopenharmony_ci 2, ®16); 8778c2ecf20Sopenharmony_ci netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic void aqc111_configure_csum_offload(struct usbnet *dev) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci u8 reg8 = 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (dev->net->features & NETIF_F_RXCSUM) { 8858c2ecf20Sopenharmony_ci reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | 8868c2ecf20Sopenharmony_ci SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci reg8 = 0; 8918c2ecf20Sopenharmony_ci if (dev->net->features & NETIF_F_IP_CSUM) 8928c2ecf20Sopenharmony_ci reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (dev->net->features & NETIF_F_IPV6_CSUM) 8958c2ecf20Sopenharmony_ci reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic int aqc111_link_reset(struct usbnet *dev) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 9038c2ecf20Sopenharmony_ci u16 reg16 = 0; 9048c2ecf20Sopenharmony_ci u8 reg8 = 0; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (aqc111_data->link == 1) { /* Link up */ 9078c2ecf20Sopenharmony_ci aqc111_configure_rx(dev, aqc111_data); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Vlan Tag Filter */ 9108c2ecf20Sopenharmony_ci reg8 = SFR_VLAN_CONTROL_VSO; 9118c2ecf20Sopenharmony_ci if (dev->net->features & NETIF_F_HW_VLAN_CTAG_FILTER) 9128c2ecf20Sopenharmony_ci reg8 |= SFR_VLAN_CONTROL_VFE; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 9158c2ecf20Sopenharmony_ci 1, 1, ®8); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci reg8 = 0x0; 9188c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 9198c2ecf20Sopenharmony_ci 1, 1, ®8); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL, 9228c2ecf20Sopenharmony_ci 1, 1, ®8); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB; 9278c2ecf20Sopenharmony_ci aqc111_data->rxctl = reg16; 9288c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci reg8 = SFR_RX_PATH_READY; 9318c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 9328c2ecf20Sopenharmony_ci 1, 1, ®8); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci reg8 = SFR_BULK_OUT_EFF_EN; 9358c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 9368c2ecf20Sopenharmony_ci 1, 1, ®8); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci reg16 = 0; 9398c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9408c2ecf20Sopenharmony_ci 2, ®16); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX; 9438c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9448c2ecf20Sopenharmony_ci 2, ®16); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci aqc111_configure_csum_offload(dev); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci aqc111_set_rx_mode(dev->net); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9518c2ecf20Sopenharmony_ci 2, ®16); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (dev->net->mtu > 1500) 9548c2ecf20Sopenharmony_ci reg16 |= SFR_MEDIUM_JUMBO_EN; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN | 9578c2ecf20Sopenharmony_ci SFR_MEDIUM_TXFLOW_CTRLEN; 9588c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9598c2ecf20Sopenharmony_ci 2, ®16); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci aqc111_data->rxctl |= SFR_RX_CTL_START; 9628c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 9638c2ecf20Sopenharmony_ci 2, &aqc111_data->rxctl); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci netif_carrier_on(dev->net); 9668c2ecf20Sopenharmony_ci } else { 9678c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9688c2ecf20Sopenharmony_ci 2, ®16); 9698c2ecf20Sopenharmony_ci reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 9708c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 9718c2ecf20Sopenharmony_ci 2, ®16); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci aqc111_data->rxctl &= ~SFR_RX_CTL_START; 9748c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 9758c2ecf20Sopenharmony_ci 2, &aqc111_data->rxctl); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN; 9788c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 9798c2ecf20Sopenharmony_ci 1, 1, ®8); 9808c2ecf20Sopenharmony_ci reg8 = SFR_BULK_OUT_EFF_EN; 9818c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 9828c2ecf20Sopenharmony_ci 1, 1, ®8); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci netif_carrier_off(dev->net); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci return 0; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic int aqc111_reset(struct usbnet *dev) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 9928c2ecf20Sopenharmony_ci u8 reg8 = 0; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci dev->rx_urb_size = URB_SIZE; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (usb_device_no_sg_constraint(dev->udev)) 9978c2ecf20Sopenharmony_ci dev->can_dma_sg = 1; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE; 10008c2ecf20Sopenharmony_ci dev->net->features |= AQ_SUPPORT_FEATURE; 10018c2ecf20Sopenharmony_ci dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* Power up ethernet PHY */ 10048c2ecf20Sopenharmony_ci aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 10058c2ecf20Sopenharmony_ci aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 10068c2ecf20Sopenharmony_ci &aqc111_data->phy_cfg); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* Set the MAC address */ 10098c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN, 10108c2ecf20Sopenharmony_ci ETH_ALEN, dev->net->dev_addr); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci reg8 = 0xFF; 10138c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci reg8 = 0x0; 10168c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 10198c2ecf20Sopenharmony_ci reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 10208c2ecf20Sopenharmony_ci SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 10218c2ecf20Sopenharmony_ci SFR_MONITOR_MODE_RW_FLAG); 10228c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci netif_carrier_off(dev->net); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* Phy advertise */ 10278c2ecf20Sopenharmony_ci aqc111_set_phy_speed(dev, aqc111_data->autoneg, 10288c2ecf20Sopenharmony_ci aqc111_data->advertised_speed); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic int aqc111_stop(struct usbnet *dev) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 10368c2ecf20Sopenharmony_ci u16 reg16 = 0; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 10398c2ecf20Sopenharmony_ci 2, ®16); 10408c2ecf20Sopenharmony_ci reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 10418c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 10428c2ecf20Sopenharmony_ci 2, ®16); 10438c2ecf20Sopenharmony_ci reg16 = 0; 10448c2ecf20Sopenharmony_ci aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Put PHY to low power*/ 10478c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_LOW_POWER; 10488c2ecf20Sopenharmony_ci aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 10498c2ecf20Sopenharmony_ci &aqc111_data->phy_cfg); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci netif_carrier_off(dev->net); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return 0; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void aqc111_rx_checksum(struct sk_buff *skb, u64 pkt_desc) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci u32 pkt_type = 0; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 10618c2ecf20Sopenharmony_ci /* checksum error bit is set */ 10628c2ecf20Sopenharmony_ci if (pkt_desc & AQ_RX_PD_L4_ERR || pkt_desc & AQ_RX_PD_L3_ERR) 10638c2ecf20Sopenharmony_ci return; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci pkt_type = pkt_desc & AQ_RX_PD_L4_TYPE_MASK; 10668c2ecf20Sopenharmony_ci /* It must be a TCP or UDP packet with a valid checksum */ 10678c2ecf20Sopenharmony_ci if (pkt_type == AQ_RX_PD_L4_TCP || pkt_type == AQ_RX_PD_L4_UDP) 10688c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 10748c2ecf20Sopenharmony_ci struct sk_buff *new_skb = NULL; 10758c2ecf20Sopenharmony_ci u32 pkt_total_offset = 0; 10768c2ecf20Sopenharmony_ci u64 *pkt_desc_ptr = NULL; 10778c2ecf20Sopenharmony_ci u32 start_of_descs = 0; 10788c2ecf20Sopenharmony_ci u32 desc_offset = 0; /*RX Header Offset*/ 10798c2ecf20Sopenharmony_ci u16 pkt_count = 0; 10808c2ecf20Sopenharmony_ci u64 desc_hdr = 0; 10818c2ecf20Sopenharmony_ci u16 vlan_tag = 0; 10828c2ecf20Sopenharmony_ci u32 skb_len; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (!skb) 10858c2ecf20Sopenharmony_ci goto err; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci skb_len = skb->len; 10888c2ecf20Sopenharmony_ci if (skb_len < sizeof(desc_hdr)) 10898c2ecf20Sopenharmony_ci goto err; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* RX Descriptor Header */ 10928c2ecf20Sopenharmony_ci skb_trim(skb, skb_len - sizeof(desc_hdr)); 10938c2ecf20Sopenharmony_ci desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb)); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Check these packets */ 10968c2ecf20Sopenharmony_ci desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >> 10978c2ecf20Sopenharmony_ci AQ_RX_DH_DESC_OFFSET_SHIFT; 10988c2ecf20Sopenharmony_ci pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK; 10998c2ecf20Sopenharmony_ci start_of_descs = skb_len - ((pkt_count + 1) * sizeof(desc_hdr)); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* self check descs position */ 11028c2ecf20Sopenharmony_ci if (start_of_descs != desc_offset) 11038c2ecf20Sopenharmony_ci goto err; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* self check desc_offset from header and make sure that the 11068c2ecf20Sopenharmony_ci * bounds of the metadata array are inside the SKB 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_ci if (pkt_count * 2 + desc_offset >= skb_len) 11098c2ecf20Sopenharmony_ci goto err; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Packets must not overlap the metadata array */ 11128c2ecf20Sopenharmony_ci skb_trim(skb, desc_offset); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (pkt_count == 0) 11158c2ecf20Sopenharmony_ci goto err; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Get the first RX packet descriptor */ 11188c2ecf20Sopenharmony_ci pkt_desc_ptr = (u64 *)(skb->data + desc_offset); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci while (pkt_count--) { 11218c2ecf20Sopenharmony_ci u64 pkt_desc = le64_to_cpup(pkt_desc_ptr); 11228c2ecf20Sopenharmony_ci u32 pkt_len_with_padd = 0; 11238c2ecf20Sopenharmony_ci u32 pkt_len = 0; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >> 11268c2ecf20Sopenharmony_ci AQ_RX_PD_LEN_SHIFT); 11278c2ecf20Sopenharmony_ci pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci pkt_total_offset += pkt_len_with_padd; 11308c2ecf20Sopenharmony_ci if (pkt_total_offset > desc_offset || 11318c2ecf20Sopenharmony_ci (pkt_count == 0 && pkt_total_offset != desc_offset)) { 11328c2ecf20Sopenharmony_ci goto err; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (pkt_desc & AQ_RX_PD_DROP || 11368c2ecf20Sopenharmony_ci !(pkt_desc & AQ_RX_PD_RX_OK) || 11378c2ecf20Sopenharmony_ci pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { 11388c2ecf20Sopenharmony_ci skb_pull(skb, pkt_len_with_padd); 11398c2ecf20Sopenharmony_ci /* Next RX Packet Descriptor */ 11408c2ecf20Sopenharmony_ci pkt_desc_ptr++; 11418c2ecf20Sopenharmony_ci continue; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* Clone SKB */ 11458c2ecf20Sopenharmony_ci new_skb = skb_clone(skb, GFP_ATOMIC); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (!new_skb) 11488c2ecf20Sopenharmony_ci goto err; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci new_skb->len = pkt_len; 11518c2ecf20Sopenharmony_ci skb_pull(new_skb, AQ_RX_HW_PAD); 11528c2ecf20Sopenharmony_ci skb_set_tail_pointer(new_skb, new_skb->len); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci new_skb->truesize = SKB_TRUESIZE(new_skb->len); 11558c2ecf20Sopenharmony_ci if (aqc111_data->rx_checksum) 11568c2ecf20Sopenharmony_ci aqc111_rx_checksum(new_skb, pkt_desc); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (pkt_desc & AQ_RX_PD_VLAN) { 11598c2ecf20Sopenharmony_ci vlan_tag = pkt_desc >> AQ_RX_PD_VLAN_SHIFT; 11608c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(new_skb, htons(ETH_P_8021Q), 11618c2ecf20Sopenharmony_ci vlan_tag & VLAN_VID_MASK); 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci usbnet_skb_return(dev, new_skb); 11658c2ecf20Sopenharmony_ci if (pkt_count == 0) 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci skb_pull(skb, pkt_len_with_padd); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* Next RX Packet Header */ 11718c2ecf20Sopenharmony_ci pkt_desc_ptr++; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci new_skb = NULL; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return 1; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cierr: 11798c2ecf20Sopenharmony_ci return 0; 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 11838c2ecf20Sopenharmony_ci gfp_t flags) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci int frame_size = dev->maxpacket; 11868c2ecf20Sopenharmony_ci struct sk_buff *new_skb = NULL; 11878c2ecf20Sopenharmony_ci u64 *tx_desc_ptr = NULL; 11888c2ecf20Sopenharmony_ci int padding_size = 0; 11898c2ecf20Sopenharmony_ci int headroom = 0; 11908c2ecf20Sopenharmony_ci int tailroom = 0; 11918c2ecf20Sopenharmony_ci u64 tx_desc = 0; 11928c2ecf20Sopenharmony_ci u16 tci = 0; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /*Length of actual data*/ 11958c2ecf20Sopenharmony_ci tx_desc |= skb->len & AQ_TX_DESC_LEN_MASK; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* TSO MSS */ 11988c2ecf20Sopenharmony_ci tx_desc |= ((u64)(skb_shinfo(skb)->gso_size & AQ_TX_DESC_MSS_MASK)) << 11998c2ecf20Sopenharmony_ci AQ_TX_DESC_MSS_SHIFT; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci headroom = (skb->len + sizeof(tx_desc)) % 8; 12028c2ecf20Sopenharmony_ci if (headroom != 0) 12038c2ecf20Sopenharmony_ci padding_size = 8 - headroom; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (((skb->len + sizeof(tx_desc) + padding_size) % frame_size) == 0) { 12068c2ecf20Sopenharmony_ci padding_size += 8; 12078c2ecf20Sopenharmony_ci tx_desc |= AQ_TX_DESC_DROP_PADD; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* Vlan Tag */ 12118c2ecf20Sopenharmony_ci if (vlan_get_tag(skb, &tci) >= 0) { 12128c2ecf20Sopenharmony_ci tx_desc |= AQ_TX_DESC_VLAN; 12138c2ecf20Sopenharmony_ci tx_desc |= ((u64)tci & AQ_TX_DESC_VLAN_MASK) << 12148c2ecf20Sopenharmony_ci AQ_TX_DESC_VLAN_SHIFT; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) && 12188c2ecf20Sopenharmony_ci skb_linearize(skb)) 12198c2ecf20Sopenharmony_ci return NULL; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci headroom = skb_headroom(skb); 12228c2ecf20Sopenharmony_ci tailroom = skb_tailroom(skb); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (!(headroom >= sizeof(tx_desc) && tailroom >= padding_size)) { 12258c2ecf20Sopenharmony_ci new_skb = skb_copy_expand(skb, sizeof(tx_desc), 12268c2ecf20Sopenharmony_ci padding_size, flags); 12278c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12288c2ecf20Sopenharmony_ci skb = new_skb; 12298c2ecf20Sopenharmony_ci if (!skb) 12308c2ecf20Sopenharmony_ci return NULL; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci if (padding_size != 0) 12338c2ecf20Sopenharmony_ci skb_put_zero(skb, padding_size); 12348c2ecf20Sopenharmony_ci /* Copy TX header */ 12358c2ecf20Sopenharmony_ci tx_desc_ptr = skb_push(skb, sizeof(tx_desc)); 12368c2ecf20Sopenharmony_ci *tx_desc_ptr = cpu_to_le64(tx_desc); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci usbnet_set_skb_tx_stats(skb, 1, 0); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci return skb; 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic const struct driver_info aqc111_info = { 12448c2ecf20Sopenharmony_ci .description = "Aquantia AQtion USB to 5GbE Controller", 12458c2ecf20Sopenharmony_ci .bind = aqc111_bind, 12468c2ecf20Sopenharmony_ci .unbind = aqc111_unbind, 12478c2ecf20Sopenharmony_ci .status = aqc111_status, 12488c2ecf20Sopenharmony_ci .link_reset = aqc111_link_reset, 12498c2ecf20Sopenharmony_ci .reset = aqc111_reset, 12508c2ecf20Sopenharmony_ci .stop = aqc111_stop, 12518c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | 12528c2ecf20Sopenharmony_ci FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 12538c2ecf20Sopenharmony_ci .rx_fixup = aqc111_rx_fixup, 12548c2ecf20Sopenharmony_ci .tx_fixup = aqc111_tx_fixup, 12558c2ecf20Sopenharmony_ci}; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci#define ASIX111_DESC \ 12588c2ecf20Sopenharmony_ci"ASIX USB 3.1 Gen1 to 5G Multi-Gigabit Ethernet Adapter" 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic const struct driver_info asix111_info = { 12618c2ecf20Sopenharmony_ci .description = ASIX111_DESC, 12628c2ecf20Sopenharmony_ci .bind = aqc111_bind, 12638c2ecf20Sopenharmony_ci .unbind = aqc111_unbind, 12648c2ecf20Sopenharmony_ci .status = aqc111_status, 12658c2ecf20Sopenharmony_ci .link_reset = aqc111_link_reset, 12668c2ecf20Sopenharmony_ci .reset = aqc111_reset, 12678c2ecf20Sopenharmony_ci .stop = aqc111_stop, 12688c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | 12698c2ecf20Sopenharmony_ci FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 12708c2ecf20Sopenharmony_ci .rx_fixup = aqc111_rx_fixup, 12718c2ecf20Sopenharmony_ci .tx_fixup = aqc111_tx_fixup, 12728c2ecf20Sopenharmony_ci}; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci#undef ASIX111_DESC 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci#define ASIX112_DESC \ 12778c2ecf20Sopenharmony_ci"ASIX USB 3.1 Gen1 to 2.5G Multi-Gigabit Ethernet Adapter" 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic const struct driver_info asix112_info = { 12808c2ecf20Sopenharmony_ci .description = ASIX112_DESC, 12818c2ecf20Sopenharmony_ci .bind = aqc111_bind, 12828c2ecf20Sopenharmony_ci .unbind = aqc111_unbind, 12838c2ecf20Sopenharmony_ci .status = aqc111_status, 12848c2ecf20Sopenharmony_ci .link_reset = aqc111_link_reset, 12858c2ecf20Sopenharmony_ci .reset = aqc111_reset, 12868c2ecf20Sopenharmony_ci .stop = aqc111_stop, 12878c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | 12888c2ecf20Sopenharmony_ci FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 12898c2ecf20Sopenharmony_ci .rx_fixup = aqc111_rx_fixup, 12908c2ecf20Sopenharmony_ci .tx_fixup = aqc111_tx_fixup, 12918c2ecf20Sopenharmony_ci}; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci#undef ASIX112_DESC 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic const struct driver_info trendnet_info = { 12968c2ecf20Sopenharmony_ci .description = "USB-C 3.1 to 5GBASE-T Ethernet Adapter", 12978c2ecf20Sopenharmony_ci .bind = aqc111_bind, 12988c2ecf20Sopenharmony_ci .unbind = aqc111_unbind, 12998c2ecf20Sopenharmony_ci .status = aqc111_status, 13008c2ecf20Sopenharmony_ci .link_reset = aqc111_link_reset, 13018c2ecf20Sopenharmony_ci .reset = aqc111_reset, 13028c2ecf20Sopenharmony_ci .stop = aqc111_stop, 13038c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | 13048c2ecf20Sopenharmony_ci FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 13058c2ecf20Sopenharmony_ci .rx_fixup = aqc111_rx_fixup, 13068c2ecf20Sopenharmony_ci .tx_fixup = aqc111_tx_fixup, 13078c2ecf20Sopenharmony_ci}; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic const struct driver_info qnap_info = { 13108c2ecf20Sopenharmony_ci .description = "QNAP QNA-UC5G1T USB to 5GbE Adapter", 13118c2ecf20Sopenharmony_ci .bind = aqc111_bind, 13128c2ecf20Sopenharmony_ci .unbind = aqc111_unbind, 13138c2ecf20Sopenharmony_ci .status = aqc111_status, 13148c2ecf20Sopenharmony_ci .link_reset = aqc111_link_reset, 13158c2ecf20Sopenharmony_ci .reset = aqc111_reset, 13168c2ecf20Sopenharmony_ci .stop = aqc111_stop, 13178c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | 13188c2ecf20Sopenharmony_ci FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, 13198c2ecf20Sopenharmony_ci .rx_fixup = aqc111_rx_fixup, 13208c2ecf20Sopenharmony_ci .tx_fixup = aqc111_tx_fixup, 13218c2ecf20Sopenharmony_ci}; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int aqc111_suspend(struct usb_interface *intf, pm_message_t message) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 13268c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 13278c2ecf20Sopenharmony_ci u16 temp_rx_ctrl = 0x00; 13288c2ecf20Sopenharmony_ci u16 reg16; 13298c2ecf20Sopenharmony_ci u8 reg8; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci usbnet_suspend(intf, message); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 13348c2ecf20Sopenharmony_ci temp_rx_ctrl = reg16; 13358c2ecf20Sopenharmony_ci /* Stop RX operations*/ 13368c2ecf20Sopenharmony_ci reg16 &= ~SFR_RX_CTL_START; 13378c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 13388c2ecf20Sopenharmony_ci /* Force bz */ 13398c2ecf20Sopenharmony_ci aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 13408c2ecf20Sopenharmony_ci 2, ®16); 13418c2ecf20Sopenharmony_ci reg16 |= SFR_PHYPWR_RSTCTL_BZ; 13428c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 13438c2ecf20Sopenharmony_ci 2, ®16); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci reg8 = SFR_BULK_OUT_EFF_EN; 13468c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL, 13478c2ecf20Sopenharmony_ci 1, 1, ®8); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci temp_rx_ctrl &= ~(SFR_RX_CTL_START | SFR_RX_CTL_RF_WAK | 13508c2ecf20Sopenharmony_ci SFR_RX_CTL_AP | SFR_RX_CTL_AM); 13518c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 13528c2ecf20Sopenharmony_ci 2, &temp_rx_ctrl); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci reg8 = 0x00; 13558c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 13568c2ecf20Sopenharmony_ci 1, 1, ®8); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (aqc111_data->wol_flags) { 13598c2ecf20Sopenharmony_ci struct aqc111_wol_cfg wol_cfg; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci memset(&wol_cfg, 0, sizeof(struct aqc111_wol_cfg)); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_WOL; 13648c2ecf20Sopenharmony_ci ether_addr_copy(wol_cfg.hw_addr, dev->net->dev_addr); 13658c2ecf20Sopenharmony_ci wol_cfg.flags = aqc111_data->wol_flags; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci temp_rx_ctrl |= (SFR_RX_CTL_AB | SFR_RX_CTL_START); 13688c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 13698c2ecf20Sopenharmony_ci 2, &temp_rx_ctrl); 13708c2ecf20Sopenharmony_ci reg8 = 0x00; 13718c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 13728c2ecf20Sopenharmony_ci 1, 1, ®8); 13738c2ecf20Sopenharmony_ci reg8 = SFR_BMRX_DMA_EN; 13748c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 13758c2ecf20Sopenharmony_ci 1, 1, ®8); 13768c2ecf20Sopenharmony_ci reg8 = SFR_RX_PATH_READY; 13778c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 13788c2ecf20Sopenharmony_ci 1, 1, ®8); 13798c2ecf20Sopenharmony_ci reg8 = 0x07; 13808c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 13818c2ecf20Sopenharmony_ci 1, 1, ®8); 13828c2ecf20Sopenharmony_ci reg8 = 0x00; 13838c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, 13848c2ecf20Sopenharmony_ci SFR_RX_BULKIN_QTIMR_LOW, 1, 1, ®8); 13858c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, 13868c2ecf20Sopenharmony_ci SFR_RX_BULKIN_QTIMR_HIGH, 1, 1, ®8); 13878c2ecf20Sopenharmony_ci reg8 = 0xFF; 13888c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QSIZE, 13898c2ecf20Sopenharmony_ci 1, 1, ®8); 13908c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QIFG, 13918c2ecf20Sopenharmony_ci 1, 1, ®8); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, 13948c2ecf20Sopenharmony_ci SFR_MEDIUM_STATUS_MODE, 2, ®16); 13958c2ecf20Sopenharmony_ci reg16 |= SFR_MEDIUM_RECEIVE_EN; 13968c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, 13978c2ecf20Sopenharmony_ci SFR_MEDIUM_STATUS_MODE, 2, ®16); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0, 14008c2ecf20Sopenharmony_ci WOL_CFG_SIZE, &wol_cfg); 14018c2ecf20Sopenharmony_ci aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 14028c2ecf20Sopenharmony_ci &aqc111_data->phy_cfg); 14038c2ecf20Sopenharmony_ci } else { 14048c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_LOW_POWER; 14058c2ecf20Sopenharmony_ci aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 14068c2ecf20Sopenharmony_ci &aqc111_data->phy_cfg); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Disable RX path */ 14098c2ecf20Sopenharmony_ci aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, 14108c2ecf20Sopenharmony_ci SFR_MEDIUM_STATUS_MODE, 2, ®16); 14118c2ecf20Sopenharmony_ci reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 14128c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, 14138c2ecf20Sopenharmony_ci SFR_MEDIUM_STATUS_MODE, 2, ®16); 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci return 0; 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic int aqc111_resume(struct usb_interface *intf) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 14228c2ecf20Sopenharmony_ci struct aqc111_data *aqc111_data = dev->driver_priv; 14238c2ecf20Sopenharmony_ci u16 reg16; 14248c2ecf20Sopenharmony_ci u8 reg8; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci netif_carrier_off(dev->net); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* Power up ethernet PHY */ 14298c2ecf20Sopenharmony_ci aqc111_data->phy_cfg |= AQ_PHY_POWER_EN; 14308c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_LOW_POWER; 14318c2ecf20Sopenharmony_ci aqc111_data->phy_cfg &= ~AQ_WOL; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci reg8 = 0xFF; 14348c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 14358c2ecf20Sopenharmony_ci 1, 1, ®8); 14368c2ecf20Sopenharmony_ci /* Configure RX control register => start operation */ 14378c2ecf20Sopenharmony_ci reg16 = aqc111_data->rxctl; 14388c2ecf20Sopenharmony_ci reg16 &= ~SFR_RX_CTL_START; 14398c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci reg16 |= SFR_RX_CTL_START; 14428c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci aqc111_set_phy_speed(dev, aqc111_data->autoneg, 14458c2ecf20Sopenharmony_ci aqc111_data->advertised_speed); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 14488c2ecf20Sopenharmony_ci 2, ®16); 14498c2ecf20Sopenharmony_ci reg16 |= SFR_MEDIUM_RECEIVE_EN; 14508c2ecf20Sopenharmony_ci aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 14518c2ecf20Sopenharmony_ci 2, ®16); 14528c2ecf20Sopenharmony_ci reg8 = SFR_RX_PATH_READY; 14538c2ecf20Sopenharmony_ci aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH, 14548c2ecf20Sopenharmony_ci 1, 1, ®8); 14558c2ecf20Sopenharmony_ci reg8 = 0x0; 14568c2ecf20Sopenharmony_ci aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 1, 1, ®8); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci return usbnet_resume(intf); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci#define AQC111_USB_ETH_DEV(vid, pid, table) \ 14628c2ecf20Sopenharmony_ci USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 14638c2ecf20Sopenharmony_ci .driver_info = (unsigned long)&(table) \ 14648c2ecf20Sopenharmony_ci}, \ 14658c2ecf20Sopenharmony_ci{ \ 14668c2ecf20Sopenharmony_ci USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 14678c2ecf20Sopenharmony_ci USB_CLASS_COMM, \ 14688c2ecf20Sopenharmony_ci USB_CDC_SUBCLASS_ETHERNET, \ 14698c2ecf20Sopenharmony_ci USB_CDC_PROTO_NONE), \ 14708c2ecf20Sopenharmony_ci .driver_info = (unsigned long)&(table), 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic const struct usb_device_id products[] = { 14738c2ecf20Sopenharmony_ci {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 14748c2ecf20Sopenharmony_ci {AQC111_USB_ETH_DEV(0x0b95, 0x2790, asix111_info)}, 14758c2ecf20Sopenharmony_ci {AQC111_USB_ETH_DEV(0x0b95, 0x2791, asix112_info)}, 14768c2ecf20Sopenharmony_ci {AQC111_USB_ETH_DEV(0x20f4, 0xe05a, trendnet_info)}, 14778c2ecf20Sopenharmony_ci {AQC111_USB_ETH_DEV(0x1c04, 0x0015, qnap_info)}, 14788c2ecf20Sopenharmony_ci { },/* END */ 14798c2ecf20Sopenharmony_ci}; 14808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, products); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic struct usb_driver aq_driver = { 14838c2ecf20Sopenharmony_ci .name = "aqc111", 14848c2ecf20Sopenharmony_ci .id_table = products, 14858c2ecf20Sopenharmony_ci .probe = usbnet_probe, 14868c2ecf20Sopenharmony_ci .suspend = aqc111_suspend, 14878c2ecf20Sopenharmony_ci .resume = aqc111_resume, 14888c2ecf20Sopenharmony_ci .disconnect = usbnet_disconnect, 14898c2ecf20Sopenharmony_ci}; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cimodule_usb_driver(aq_driver); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 14948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1495