Add support for Aquantia AQtion USB to 5/2.5GbE devices
Subsystems (5)
v2 cover Add support for Aquantia AQtion USB to 5/2.5GbE devices
This patchset introduces support for new multigig ethernet to USB dongle, developed jointly by Aquantia (Phy) and ASIX (USB MAC).
The driver has similar structure with other ASIX MAC drivers (AX88179), but with a number of important differences:
- Driver supports both direct Phy and custom firmware interface for Phy programming. This is due to different firmware modules available with this product.
- Driver handles new 2.5G/5G link speed configuration and reporting.
- Device support all speeds from 100M up to 5G.
- Device supports MTU up to 16K.
Device supports various standard networking features, like checksum offloads, vlan tagging/filtering, TSO.
The code of this driver is based on original ASIX sources and was extended by Aquantia for 5G multigig support.
Patchset v2 includes following changes:
- Function variables declarions fixed to reverse xmass tree
- Improve patch layout structure
- Remove unnecessary curly braces in switch/case statements
- Use 'packed' attribute for HW structures only
- Use eth_mac_addr function in set_mac_addr callback
- Remove unnecessary 'memset' calls.
- Read MAC address from EEPROM function has now better name
- Use driver_priv field to store context. It avoids ugly cast.
- Set max_mtu field. Remove check for MTU size
- Rewrite read/write functions. Add helpers for read/write 16/32 bit values
- Use mask and shifts instead of bitfields to support BE platforms.
- Use stack allocated buffer for configuring mcast filters
- Use AUTONEG_ENABLE when go to suspend state
- Pad out wol_cfg field from context structure. Use stack allocated instead
- Remove driver version
- Check field 'duplex' in set_link_ksetting callback as well
- Use already created defines in usb matching macro
- Rename phy_ops struct to phy_cfg
- Use ether_addr_copy for copying mac address
- Add fall-through comment in switch/case for avoid checkpatch warning
- Remove match for CDC ether device
- Add ASIX's HW id-s to match this driver
- Add all HW id-s with which driver can work to blacklist of cdc_ether driver
Dmitry Bezrukov (21):
net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
net: usb: aqc111: Add bind and empty unbind callbacks
net: usb: aqc111: Add implementation of read and write commands
net: usb: aqc111: Various callbacks implementation
net: usb: aqc111: Introduce PHY access
net: usb: aqc111: Introduce link management
net: usb: aqc111: Add support for getting and setting of MAC address
net: usb: aqc111: Implement TX data path
net: usb: aqc111: Implement RX data path
net: usb: aqc111: Add checksum offload support
net: usb: aqc111: Add support for changing MTU
net: usb: aqc111: Add support for enable/disable checksum offload
net: usb: aqc111: Add support for TSO
net: usb: aqc111: Implement set_rx_mode callback
net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
net: usb: aqc111: Add RX VLAN filtering support
net: usb: aqc111: Initialize ethtool_ops structure
net: usb: aqc111: Implement get/set_link_ksettings callbacks
net: usb: aqc111: Add support for wake on LAN by MAGIC packet
net: usb: aqc111: Add ASIX's HW ids
net: usb: aqc111: Extend cdc_ether blacklist
drivers/net/usb/Kconfig | 12 + drivers/net/usb/Makefile | 1 + drivers/net/usb/aqc111.c | 1605 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 275 ++++++++ drivers/net/usb/cdc_ether.c | 23 + 5 files changed, 1916 insertions(+) create mode 100644 drivers/net/usb/aqc111.c create mode 100644 drivers/net/usb/aqc111.h
Signature · 1 line
2.7.4
PATCH v2 1/21 net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
From: Dmitry Bezrukov <[email protected]>
Initialize usb_driver structure skeleton
--- drivers/net/usb/Kconfig | 12 ++++++++++++ drivers/net/usb/Makefile | 1 + drivers/net/usb/aqc111.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 drivers/net/usb/aqc111.c
drivers/net/usb/Kconfig +12 -0
@@ -613,4 +613,16 @@ config USB_NET_CH9200 To compile this driver as a module, choose M here: the module will be called ch9200. +config USB_NET_AQC111 + tristate "Aquantia AQtion USB to 5/2.5GbE Controllers support" + depends on USB_USBNET + select CRC32 + default y + help + This option adds support for Aquantia AQtion USB + Ethernet adapters based on AQC111U/AQC112 chips. + + This driver should work with at least the following devices: + * Aquantia AQtion USB to 5GbE + endif # USB_NET_DRIVERS
drivers/net/usb/Makefile +1 -0
@@ -40,3 +40,4 @@ obj-$(CONFIG_USB_VL600) += lg-vl600.o obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o obj-$(CONFIG_USB_NET_CH9200) += ch9200.o +obj-$(CONFIG_USB_NET_AQC111) += aqc111.o
drivers/net/usb/aqc111.c new file +41 -0
41 lines not on this page · raw message
PATCH v2 2/21 net: usb: aqc111: Add bind and empty unbind callbacks
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Initialize net_device_ops structure
--- drivers/net/usb/aqc111.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
drivers/net/usb/aqc111.c +35 -0
@@ -14,8 +14,43 @@#include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> +static const struct net_device_ops aqc111_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, +}; + +static int aqc111_bind (struct usbnet *dev,struct usb_interface *intf) +{ +struct usb_device *udev =interface_to_usbdev (intf); +int ret; + +/* Check if vendor configuration */ +if (udev->actconfig->desc.bConfigurationValue !=1 ) { +usb_driver_set_configuration (udev,1 ); +return -ENODEV ; + } + +usb_reset_configuration (dev->udev); + + ret =usbnet_get_endpoints (dev, intf); +if (ret <0 ) { +netdev_dbg (dev->net,"usbnet_get_endpoints failed" ); +return ret; + } + + dev->net->netdev_ops = &aqc111_netdev_ops; + +return 0 ; +} + +static void aqc111_unbind (struct usbnet *dev,struct usb_interface *intf) +{ +} +static const struct driver_info aqc111_info = { .description ="Aquantia AQtion USB to 5GbE Controller" , + .bind = aqc111_bind, + .unbind = aqc111_unbind, };#define AQC111_USB_ETH_DEV (vid, pid, table) \
PATCH v2 3/21 net: usb: aqc111: Add implementation of read and write commands
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Read/write command register defines and functions
--- drivers/net/usb/aqc111.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 18 ++++++++++ 2 files changed, 110 insertions(+) create mode 100644 drivers/net/usb/aqc111.h
drivers/net/usb/aqc111.c +92 -0
@@ -14,6 +14,98 @@#include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> +#include "aqc111.h" + +static int aqc111_read_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 size,void *data) +{ +int ret; + + ret =usbnet_read_cmd_nopm (dev, cmd,USB_DIR_IN |USB_TYPE_VENDOR | +USB_RECIP_DEVICE , value, index, data, size); + +if (unlikely (ret <0 )) +netdev_warn (dev->net, +"Failed to read(0x%x) reg index 0x%04x: %d\n" , + cmd, index, ret); + +return ret; +} + +static int aqc111_read_cmd (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 size,void *data) +{ +int ret; + + ret =usbnet_read_cmd (dev, cmd,USB_DIR_IN |USB_TYPE_VENDOR | +USB_RECIP_DEVICE , value, index, data, size); + +if (unlikely (ret <0 )) +netdev_warn (dev->net, +"Failed to read(0x%x) reg index 0x%04x: %d\n" , + cmd, index, ret); + +return ret; +} + +static int __aqc111_write_cmd (struct usbnet *dev,u8 cmd,u8 reqtype, +u16 value,u16 index,u16 size,const void *data) +{ +int err = -ENOMEM ; +void *buf =NULL ; + +netdev_dbg (dev->net, +"%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n" , + __func__, cmd, reqtype, value, index, size); + +if (data) { + buf =kmemdup (data, size,GFP_KERNEL ); +if (!buf) + goto out; + } + + err =usb_control_msg (dev->udev,usb_sndctrlpipe (dev->udev,0 ), + cmd, reqtype, value, index, buf, size, + (cmd ==AQ_PHY_POWER ) ?AQ_USB_PHY_SET_TIMEOUT : +AQ_USB_SET_TIMEOUT ); + +if (unlikely (err <0 )) +netdev_warn (dev->net, +"Failed to write(0x%x) reg index 0x%04x: %d\n" , + cmd, index, err); +kfree (buf); + +out: +return err; +} + +static int aqc111_write_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 size,void *data) +{ +int ret; + + ret =__aqc111_write_cmd (dev, cmd,USB_DIR_OUT |USB_TYPE_VENDOR | +USB_RECIP_DEVICE , value, index, size, data); + +return ret; +} + +static int aqc111_write_cmd (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 size,void *data) +{ +int ret; + +if (usb_autopm_get_interface (dev->intf) <0 ) +return -ENODEV ; + + ret =__aqc111_write_cmd (dev, cmd,USB_DIR_OUT |USB_TYPE_VENDOR | +USB_RECIP_DEVICE , value, index, size, data); + +usb_autopm_put_interface (dev->intf); + +return ret; +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop,
drivers/net/usb/aqc111.h new file +18 -0
@@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later +* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller +* Copyright (C) 2003-2005 David Hollis <[email protected]> +* Copyright (C) 2005 Phil Chang <[email protected]> +* Copyright (C) 2002-2003 TiVo Inc. +* Copyright (C) 2017-2018 ASIX +* Copyright (C) 2018 Aquantia Corp. +*/ + +#ifndef __LINUX_USBNET_AQC111_H +#define __LINUX_USBNET_AQC111_H + +#define AQ_PHY_POWER 0x31 + +#define AQ_USB_PHY_SET_TIMEOUT 10000 +#define AQ_USB_SET_TIMEOUT 4000 + +#endif /* __LINUX_USBNET_AQC111_H */
PATCH v2 4/21 net: usb: aqc111: Various callbacks implementation
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Reset, stop callbacks, driver unbind callback. More register defines required for these callbacks. Add helpers to read/write 16bit values
--- drivers/net/usb/aqc111.c | 76 +++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+)
drivers/net/usb/aqc111.c +76 -0
@@ -48,6 +48,17 @@ static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,return ret; } +static int aqc111_read16_cmd (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 *data) +{ +int ret =0 ; + + ret =aqc111_read_cmd (dev, cmd, value, index,sizeof (*data), data); +le16_to_cpus (data); + +return ret; +} +static int __aqc111_write_cmd (struct usbnet *dev,u8 cmd,u8 reqtype,u16 value,u16 index,u16 size,const void *data) {
@@ -106,6 +117,26 @@ static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value,return ret; } +static int aqc111_write16_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 *data) +{ +u16 tmp = *data; + +cpu_to_le16s (&tmp); + +return aqc111_write_cmd_nopm (dev, cmd, value, index,sizeof (tmp), &tmp); +} + +static int aqc111_write16_cmd (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 *data) +{ +u16 tmp = *data; + +cpu_to_le16s (&tmp); + +return aqc111_write_cmd (dev, cmd, value, index,sizeof (tmp), &tmp); +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop,
@@ -137,12 +168,57 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)static void aqc111_unbind (struct usbnet *dev,struct usb_interface *intf) { +u16 reg16; + +/* Force bz */ + reg16 =SFR_PHYPWR_RSTCTL_BZ ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_PHYPWR_RSTCTL , +2 , ®16); + reg16 =0 ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_PHYPWR_RSTCTL , +2 , ®16); +} + +static int aqc111_reset (struct usbnet *dev) +{ +u8 reg8 =0 ; + + reg8 =0xFF ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BM_INT_MASK ,1 ,1 , ®8); + + reg8 =0x0 ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_SWP_CTRL ,1 ,1 , ®8); + +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_MONITOR_MODE ,1 ,1 , ®8); + reg8 &= ~(SFR_MONITOR_MODE_EPHYRW |SFR_MONITOR_MODE_RWLC | +SFR_MONITOR_MODE_RWMP |SFR_MONITOR_MODE_RWWF | +SFR_MONITOR_MODE_RW_FLAG ); +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_MONITOR_MODE ,1 ,1 , ®8); + +return 0 ; +} + +static int aqc111_stop (struct usbnet *dev) +{ +u16 reg16 =0 ; + +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + reg16 &= ~SFR_MEDIUM_RECEIVE_EN ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + reg16 =0 ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + +return 0 ; }static const struct driver_info aqc111_info = { .description ="Aquantia AQtion USB to 5GbE Controller" , .bind = aqc111_bind, .unbind = aqc111_unbind, + .reset = aqc111_reset, + .stop = aqc111_stop, };#define AQC111_USB_ETH_DEV (vid, pid, table) \
drivers/net/usb/aqc111.h +101 -0
110 lines not on this page · raw message
PATCH v2 5/21 net: usb: aqc111: Introduce PHY access
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Add helpers to write 32bit values.
Implement PHY power up/down sequences.
AQC111, depending on FW used, may has PHY being controlled either directly (dpa = 1) or via vendor command interface (dpa = 0). Drivers supports both themes.
We determine this from firmware versioning agreement.
--- drivers/net/usb/aqc111.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 44 +++++++++++++++++++ 2 files changed, 153 insertions(+)
drivers/net/usb/aqc111.c +109 -0
@@ -137,14 +137,62 @@ static int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value,return aqc111_write_cmd (dev, cmd, value, index,sizeof (tmp), &tmp); } +static int aqc111_write32_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u32 *data) +{ +u32 tmp = *data; + +cpu_to_le32s (&tmp); + +return aqc111_write_cmd_nopm (dev, cmd, value, index,sizeof (tmp), &tmp); +} + +static int aqc111_write32_cmd (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u32 *data) +{ +u32 tmp = *data; + +cpu_to_le32s (&tmp); + +return aqc111_write_cmd (dev, cmd, value, index,sizeof (tmp), &tmp); +} + +static int aqc111_mdio_read (struct usbnet *dev,u16 value,u16 index,u16 *data) +{ +return aqc111_read16_cmd (dev,AQ_PHY_CMD , value, index, data); +} + +static int aqc111_mdio_write (struct usbnet *dev,u16 value, +u16 index,u16 *data) +{ +return aqc111_write16_cmd (dev,AQ_PHY_CMD , value, index, data); +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, }; +static void aqc111_read_fw_version (struct usbnet *dev, +struct aqc111_data *aqc111_data) +{ +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,AQ_FW_VER_MAJOR , +1 ,1 , &aqc111_data->fw_ver.major); +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,AQ_FW_VER_MINOR , +1 ,1 , &aqc111_data->fw_ver.minor); +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,AQ_FW_VER_REV , +1 ,1 , &aqc111_data->fw_ver.rev); + +if (aqc111_data->fw_ver.major &0x80 ) + aqc111_data->fw_ver.major &= ~0x80 ; +else + aqc111_data->dpa =1 ; +} +static int aqc111_bind (struct usbnet *dev,struct usb_interface *intf) {struct usb_device *udev =interface_to_usbdev (intf); +struct aqc111_data *aqc111_data;int ret;/* Check if vendor configuration */
@@ -161,14 +209,25 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)return ret; } + aqc111_data =kzalloc (sizeof (*aqc111_data),GFP_KERNEL ); +if (!aqc111_data) +return -ENOMEM ; + +/* store aqc111_data pointer in device data field */ + dev->driver_priv = aqc111_data; + dev->net->netdev_ops = &aqc111_netdev_ops; +aqc111_read_fw_version (dev, aqc111_data); +return 0 ; }static void aqc111_unbind (struct usbnet *dev,struct usb_interface *intf) { +struct aqc111_data *aqc111_data = dev->driver_priv;u16 reg16; +u8 reg8;/* Force bz */ reg16 =SFR_PHYPWR_RSTCTL_BZ ;
@@ -177,12 +236,50 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) reg16 =0 ;aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_PHYPWR_RSTCTL ,2 , ®16); + +/* Power down ethernet PHY */ +if (aqc111_data->dpa) { + reg8 =0x00 ; +aqc111_write_cmd_nopm (dev,AQ_PHY_POWER ,0 , +0 ,1 , ®8); + }else { + aqc111_data->phy_cfg |=AQ_LOW_POWER ; + aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN ; +aqc111_write32_cmd_nopm (dev,AQ_PHY_OPS ,0 ,0 , + &aqc111_data->phy_cfg); + } + +kfree (aqc111_data); }static int aqc111_reset (struct usbnet *dev) { +struct aqc111_data *aqc111_data = dev->driver_priv; +u16 reg16 =0 ;u8 reg8 =0 ; +/* Power up ethernet PHY */ + aqc111_data->phy_cfg =AQ_PHY_POWER_EN ; +if (aqc111_data->dpa) { +aqc111_read_cmd (dev,AQ_PHY_POWER ,0 ,0 ,1 , ®8); +if (reg8 ==0x00 ) { + reg8 =0x02 ; +aqc111_write_cmd (dev,AQ_PHY_POWER ,0 ,0 ,1 , ®8); +msleep (200 ); + } + +aqc111_mdio_read (dev,AQ_GLB_STD_CTRL_REG ,AQ_PHY_GLOBAL_ADDR , + ®16); +if (reg16 &AQ_PHY_LOW_POWER_MODE ) { + reg16 &= ~AQ_PHY_LOW_POWER_MODE ; +aqc111_mdio_write (dev,AQ_GLB_STD_CTRL_REG , +AQ_PHY_GLOBAL_ADDR , ®16); + } + }else { +aqc111_write32_cmd (dev,AQ_PHY_OPS ,0 ,0 , + &aqc111_data->phy_cfg); + } + reg8 =0xFF ;aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BM_INT_MASK ,1 ,1 , ®8);
@@ -200,6 +297,7 @@ static int aqc111_reset(struct usbnet *dev)static int aqc111_stop (struct usbnet *dev) { +struct aqc111_data *aqc111_data = dev->driver_priv;u16 reg16 =0 ; aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
@@ -210,6 +308,17 @@ static int aqc111_stop(struct usbnet *dev) reg16 =0 ;aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); +/* Put PHY to low power*/ +if (aqc111_data->dpa) { + reg16 =AQ_PHY_LOW_POWER_MODE ; +aqc111_mdio_write (dev,AQ_GLB_STD_CTRL_REG ,AQ_PHY_GLOBAL_ADDR , + ®16); + }else { + aqc111_data->phy_cfg |=AQ_LOW_POWER ; +aqc111_write32_cmd (dev,AQ_PHY_OPS ,0 ,0 , + &aqc111_data->phy_cfg); + } +return 0 ; }
drivers/net/usb/aqc111.h +44 -0
56 lines not on this page · raw message
PATCH v2 6/21 net: usb: aqc111: Introduce link management
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Add full hardware initialization sequence and link configuration logic
--- drivers/net/usb/aqc111.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 45 +++++++ 2 files changed, 357 insertions(+)
drivers/net/usb/aqc111.c +312 -0
@@ -168,6 +168,122 @@ static int aqc111_mdio_write(struct usbnet *dev, u16 value,return aqc111_write16_cmd (dev,AQ_PHY_CMD , value, index, data); } +static void aqc111_set_phy_speed_fw_iface (struct usbnet *dev, +struct aqc111_data *aqc111_data) +{ +aqc111_write32_cmd (dev,AQ_PHY_OPS ,0 ,0 , &aqc111_data->phy_cfg); +} + +static void aqc111_set_phy_speed_direct (struct usbnet *dev, +struct aqc111_data *aqc111_data) +{ +u16 reg16_1 =0 ; +u16 reg16_2 =0 ; +u16 reg16_3 =0 ; + +/* Disable auto-negotiation */ + reg16_1 =AQ_ANEG_EX_PAGE_CTRL ; +aqc111_mdio_write (dev,AQ_AUTONEG_STD_CTRL_REG ,AQ_PHY_AUTONEG_ADDR , + ®16_1); + + reg16_1 =AQ_ANEG_EX_PHY_ID |AQ_ANEG_ADV_AQRATE ; +if (aqc111_data->phy_cfg &AQ_DOWNSHIFT ) { + reg16_1 |=AQ_ANEG_EN_DSH ; + reg16_1 |= (aqc111_data->phy_cfg &AQ_DSH_RETRIES_MASK ) >> +AQ_DSH_RETRIES_SHIFT ; + } + + reg16_2 =AQ_ANEG_ADV_LT ; +if (aqc111_data->phy_cfg &AQ_PAUSE ) + reg16_3 |=AQ_ANEG_PAUSE ; + +if (aqc111_data->phy_cfg &AQ_ASYM_PAUSE ) + reg16_3 |=AQ_ANEG_ASYM_PAUSE ; + +if (aqc111_data->phy_cfg &AQ_ADV_5G ) { + reg16_1 |=AQ_ANEG_ADV_5G_N ; + reg16_2 |=AQ_ANEG_ADV_5G_T ; + } +if (aqc111_data->phy_cfg &AQ_ADV_2G5 ) { + reg16_1 |=AQ_ANEG_ADV_2G5_N ; + reg16_2 |=AQ_ANEG_ADV_2G5_T ; + } +if (aqc111_data->phy_cfg &AQ_ADV_1G ) + reg16_1 |=AQ_ANEG_ADV_1G ; + +if (aqc111_data->phy_cfg &AQ_ADV_100M ) + reg16_3 |=AQ_ANEG_100M ; + +aqc111_mdio_write (dev,AQ_AUTONEG_VEN_PROV1_REG , +AQ_PHY_AUTONEG_ADDR , ®16_1); +aqc111_mdio_write (dev,AQ_AUTONEG_10GT_CTRL_REG , +AQ_PHY_AUTONEG_ADDR , ®16_2); + +aqc111_mdio_read (dev,AQ_AUTONEG_ADV_REG ,AQ_PHY_AUTONEG_ADDR , + ®16_1); + reg16_1 &= ~AQ_ANEG_ABILITY_MASK ; + reg16_1 |= reg16_3; +aqc111_mdio_write (dev,AQ_AUTONEG_ADV_REG ,AQ_PHY_AUTONEG_ADDR , + ®16_1); + +/* Restart auto-negotiation */ + reg16_1 =AQ_ANEG_EX_PAGE_CTRL |AQ_ANEG_EN_ANEG | +AQ_ANEG_RESTART_ANEG ; + +aqc111_mdio_write (dev,AQ_AUTONEG_STD_CTRL_REG , +AQ_PHY_AUTONEG_ADDR , ®16_1); +} + +static void aqc111_set_phy_speed (struct usbnet *dev,u8 autoneg,u16 speed) +{ +struct aqc111_data *aqc111_data = dev->driver_priv; + + aqc111_data->phy_cfg &= ~AQ_ADV_MASK ; + aqc111_data->phy_cfg |=AQ_PAUSE ; + aqc111_data->phy_cfg |=AQ_ASYM_PAUSE ; + aqc111_data->phy_cfg |=AQ_DOWNSHIFT ; + aqc111_data->phy_cfg &= ~AQ_DSH_RETRIES_MASK ; + aqc111_data->phy_cfg |= (3 <<AQ_DSH_RETRIES_SHIFT ) & +AQ_DSH_RETRIES_MASK ; + +if (autoneg ==AUTONEG_ENABLE ) { +switch (speed) { +case SPEED_5000 : + aqc111_data->phy_cfg |=AQ_ADV_5G ; +/* fall-through */ +case SPEED_2500 : + aqc111_data->phy_cfg |=AQ_ADV_2G5 ; +/* fall-through */ +case SPEED_1000 : + aqc111_data->phy_cfg |=AQ_ADV_1G ; +/* fall-through */ +case SPEED_100 : + aqc111_data->phy_cfg |=AQ_ADV_100M ; +/* fall-through */ + } + }else { +switch (speed) { +case SPEED_5000 : + aqc111_data->phy_cfg |=AQ_ADV_5G ; +break ; +case SPEED_2500 : + aqc111_data->phy_cfg |=AQ_ADV_2G5 ; +break ; +case SPEED_1000 : + aqc111_data->phy_cfg |=AQ_ADV_1G ; +break ; +case SPEED_100 : + aqc111_data->phy_cfg |=AQ_ADV_100M ; +break ; + } + } + +if (aqc111_data->dpa) +aqc111_set_phy_speed_direct (dev, aqc111_data); +else +aqc111_set_phy_speed_fw_iface (dev, aqc111_data); +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop,
@@ -192,6 +308,7 @@ static void aqc111_read_fw_version(struct usbnet *dev,static int aqc111_bind (struct usbnet *dev,struct usb_interface *intf) {struct usb_device *udev =interface_to_usbdev (intf); +enum usb_device_speed usb_speed = udev->speed;struct aqc111_data *aqc111_data;int ret;
@@ -219,6 +336,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &aqc111_netdev_ops;aqc111_read_fw_version (dev, aqc111_data); + aqc111_data->autoneg =AUTONEG_ENABLE ; + aqc111_data->advertised_speed = (usb_speed ==USB_SPEED_SUPER ) ? +SPEED_5000 :SPEED_1000 ;return 0 ; }
@@ -243,6 +363,7 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)aqc111_write_cmd_nopm (dev,AQ_PHY_POWER ,0 ,0 ,1 , ®8); }else { + aqc111_data->phy_cfg &= ~AQ_ADV_MASK ; aqc111_data->phy_cfg |=AQ_LOW_POWER ; aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN ; aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
@@ -252,6 +373,187 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)kfree (aqc111_data); } +static void aqc111_status (struct usbnet *dev,struct urb *urb) +{ +struct aqc111_data *aqc111_data = dev->driver_priv; +u64 *event_data =NULL ; +int link =0 ; + +if (urb->actual_length <sizeof (*event_data)) +return ; + + event_data = urb->transfer_buffer; +le64_to_cpus (event_data); + +if (*event_data &AQ_LS_MASK ) + link =1 ; +else + link =0 ; + + aqc111_data->link_speed = (*event_data &AQ_SPEED_MASK ) >> +AQ_SPEED_SHIFT ; + aqc111_data->link = link; + +if (netif_carrier_ok (dev->net) != link) +usbnet_defer_kevent (dev,EVENT_LINK_RESET ); +} + +static void aqc111_configure_rx (struct usbnet *dev, +struct aqc111_data *aqc111_data) +{ +enum usb_device_speed usb_speed = dev->udev->speed; +u16 link_speed =0 , usb_host =0 ; +u8 buf[5 ] = {0 }; +u8 queue_num =0 ; +u16 reg16 =0 ; +u8 reg8 =0 ; + + buf[0 ] =0x00 ; + buf[1 ] =0xF8 ; + buf[2 ] =0x07 ; +switch (aqc111_data->link_speed) { +case AQ_INT_SPEED_5G : + link_speed =5000 ; + reg8 =0x05 ; + reg16 =0x001F ; +break ; +case AQ_INT_SPEED_2_5G : + link_speed =2500 ; + reg16 =0x003F ; +break ; +case AQ_INT_SPEED_1G : + link_speed =1000 ; + reg16 =0x009F ; +break ; +case AQ_INT_SPEED_100M : + link_speed =100 ; + queue_num =1 ; + reg16 =0x063F ; + buf[1 ] =0xFB ; + buf[2 ] =0x4 ; +break ; + } + +if (aqc111_data->dpa) { +/* Set Phy Flow control */ +aqc111_mdio_write (dev,AQ_GLB_ING_PAUSE_CTRL_REG , +AQ_PHY_AUTONEG_ADDR , ®16); +aqc111_mdio_write (dev,AQ_GLB_EGR_PAUSE_CTRL_REG , +AQ_PHY_AUTONEG_ADDR , ®16); + } + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_INTER_PACKET_GAP_0 , +1 ,1 , ®8); + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_TX_PAUSE_RESEND_T ,3 ,3 , buf); + +switch (usb_speed) { +case USB_SPEED_SUPER : + usb_host =3 ; +break ; +case USB_SPEED_HIGH : + usb_host =2 ; +break ; +case USB_SPEED_FULL : +case USB_SPEED_LOW : + usb_host =1 ; + queue_num =0 ; +break ; +default : + usb_host =0 ; +break ; + } + +memcpy (buf, &AQC111_BULKIN_SIZE [queue_num],5 ); +/* RX bulk configuration */ +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QCTRL ,5 ,5 , buf); + +/* Set high low water level */ + reg16 =0x0810 ; + +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_PAUSE_WATERLVL_LOW , +2 , ®16); +netdev_info (dev->net,"Link Speed %d, USB %d" , link_speed, usb_host); +} + +static int aqc111_link_reset (struct usbnet *dev) +{ +struct aqc111_data *aqc111_data = dev->driver_priv; +u16 reg16 =0 ; +u8 reg8 =0 ; + +if (aqc111_data->link ==1 ) {/* Link up */ +aqc111_configure_rx (dev, aqc111_data); + +/* Vlan Tag Filter */ + reg8 =SFR_VLAN_CONTROL_VSO ; + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL , +1 ,1 , ®8); + + reg8 =0x0 ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BMRX_DMA_CONTROL , +1 ,1 , ®8); + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BMTX_DMA_CONTROL , +1 ,1 , ®8); + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_ARC_CTRL ,1 ,1 , ®8); + + reg16 =SFR_RX_CTL_IPE |SFR_RX_CTL_AB ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + + reg8 =SFR_RX_PATH_READY ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_ETH_MAC_PATH , +1 ,1 , ®8); + + reg8 =SFR_BULK_OUT_EFF_EN ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BULK_OUT_CTRL , +1 ,1 , ®8); + + reg16 =0 ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + + reg16 =SFR_MEDIUM_XGMIIMODE |SFR_MEDIUM_FULL_DUPLEX ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + + reg16 |=SFR_MEDIUM_RECEIVE_EN |SFR_MEDIUM_RXFLOW_CTRLEN | +SFR_MEDIUM_TXFLOW_CTRLEN ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + + reg16 =SFR_RX_CTL_IPE |SFR_RX_CTL_AB |SFR_RX_CTL_START ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + +netif_carrier_on (dev->net); + }else { +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + reg16 &= ~SFR_MEDIUM_RECEIVE_EN ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + reg16 &= ~SFR_RX_CTL_START ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + + reg8 =SFR_BULK_OUT_FLUSH_EN |SFR_BULK_OUT_EFF_EN ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BULK_OUT_CTRL , +1 ,1 , ®8); + reg8 =SFR_BULK_OUT_EFF_EN ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BULK_OUT_CTRL , +1 ,1 , ®8); + +netif_carrier_off (dev->net); + } +return 0 ; +} +static int aqc111_reset (struct usbnet *dev) {struct aqc111_data *aqc111_data = dev->driver_priv;
@@ -292,6 +594,12 @@ static int aqc111_reset(struct usbnet *dev) SFR_MONITOR_MODE_RW_FLAG);aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_MONITOR_MODE ,1 ,1 , ®8); +netif_carrier_off (dev->net); + +/* Phy advertise */ +aqc111_set_phy_speed (dev, aqc111_data->autoneg, + aqc111_data->advertised_speed); +return 0 ; }
@@ -319,6 +627,8 @@ static int aqc111_stop(struct usbnet *dev) &aqc111_data->phy_cfg); } +netif_carrier_off (dev->net); +return 0 ; }
@@ -326,6 +636,8 @@ static const struct driver_info aqc111_info = { .description = "Aquantia AQtion USB to 5GbE Controller", .bind = aqc111_bind, .unbind = aqc111_unbind, + .status = aqc111_status, + .link_reset = aqc111_link_reset, .reset = aqc111_reset, .stop = aqc111_stop, };
drivers/net/usb/aqc111.h +45 -0
75 lines not on this page · raw message
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Quoted 3 lines · Igor Russkikh
From: Dmitry Bezrukov <[email protected]>
Add full hardware initialization sequence and link configuration logic
Hi Igor
I'm still not convinced the PHY driver should be embedded in the MAC driver, rather than using phylink.
If i remember correctly, it was because the MAC is involved in determining if the link is up? That is nothing new. phylink expects this. The MAC driver should call phylink_mac_change() when the MACs SERDES goes up/down.
Andrew
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Quoted 5 lines
Quoted 2 lines
Add full hardware initialization sequence and link configuration logic
Hi Igor
Quoted 7 lines
I'm still not convinced the PHY driver should be embedded in the MAC driver, rather than using phylink.
If i remember correctly, it was because the MAC is involved in determining if the link is up? That is nothing new. phylink expects this. The MAC driver should call
phylink_mac_change()when the MACs SERDES goes up/down.
Hi Andrew,
I'm actually still in doubt as well on this matter. Of course thats quite possible.
Here was my original comment:
Quoted 6 lines
Thats again because of this product has tightly integrated MAC+Phy. MAC FW controls system interface and reports/alters link state as a joint state on copper and SIF (even in dpa direct phy mode).
We can't extract phy api into a standalone fully functional phylib therefore. Also as far as I know this particular phy is not available in the wild.
So the point is that MAC firmware is managing SERDES and system interface link. Even if we cut out phy stuff into a separate phylink driver - that driver will never be functional in standalone mode, without aqc111 mac driver.
It only may make sense from software decomposition perspective - to separate pieces of phy code.
We'll discuss and reconsider this internally and will give you more comments,
Thanks,
Igor
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Quoted 8 lines
Quoted 6 lines
Thats again because of this product has tightly integrated MAC+Phy. MAC FW controls system interface and reports/alters link state as a joint state on copper and SIF (even in dpa direct phy mode).
We can't extract phy api into a standalone fully functional phylib therefore. Also as far as I know this particular phy is not available in the wild.
So the point is that MAC firmware is managing SERDES and system interface link.
Linux can manage that SERDES link between the MAC and the PHY. There are two ways this can go:
1) You use phylib. When the PHY reports link, the adjust_link callback in the MAC is called. The phydev structure contains information about how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It works, but it is not so nice.
2) phylink gives you a much nicer API to do the same. Again, the PHY reports the link is up. phylink will then tell the MAC how to configure its end of the SERDES. The problem with phylink is that it expects a DT building. You don't have that, since this is a USB device. But you also don't need a lot of the features of phylink like SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard to make this work without device tree.
By using core linux code, we avoid bugs in firmware which nobody can fix. The Linux core code should be well tested and supported, but phylink is rather new, so might still have some corner cases.
I also cannot imaging parts of the PHY driver will not be re-usable for other Aquantia PHYs. I have a board with an AQCS109 under my desk waiting for me to do something with it. I really would like a better PHY driver for it than the kernel currently has. Hopefully there is some code reuse possibilities here.
Andrew
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Quoted 29 lines · Andrew Lunn
Quoted 8 lines
Quoted 6 lines
Thats again because of this product has tightly integrated MAC+Phy. MAC FW controls system interface and reports/alters link state as a joint state on copper and SIF (even in dpa direct phy mode).
We can't extract phy api into a standalone fully functional phylib therefore. Also as far as I know this particular phy is not available in the wild.
So the point is that MAC firmware is managing SERDES and system interface link.
Linux can manage that SERDES link between the MAC and the PHY. There are two ways this can go:
1) You use phylib. When the PHY reports link, the
adjust_linkcallback in the MAC is called. The phydev structure contains information about how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It works, but it is not so nice.2) phylink gives you a much nicer API to do the same. Again, the PHY reports the link is up. phylink will then tell the MAC how to configure its end of the SERDES. The problem with phylink is that it expects a DT building. You don't have that, since this is a USB device. But you also don't need a lot of the features of phylink like SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard to make this work without device tree.
By using core linux code, we avoid bugs in firmware which nobody can fix. The Linux core code should be well tested and supported, but phylink is rather new, so might still have some corner cases.
Quoted 5 lines
I also cannot imaging parts of the PHY driver will not be re-usable for other Aquantia PHYs. I have a board with an AQCS109 under my desk waiting for me to do something with it. I really would like a better PHY driver for it than the kernel currently has. Hopefully there is some code reuse possibilities here.
Even if the firmware is helping, there is still value in using PHYLINK to report things to Linux as Andrew is saying in that you get a lot of things for free: auto-negotiation results, link_ksetttings_{get,set} etc.
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Hi Andrew, Florian,
Quoted 29 lines
Quoted 23 lines
Quoted 2 lines
So the point is that MAC firmware is managing SERDES and system interface link.
Linux can manage that SERDES link between the MAC and the PHY. There are two ways this can go:
1) You use phylib. When the PHY reports link, the
adjust_linkcallback in the MAC is called. The phydev structure contains information about how you should configure the SERDES, SGMII, 2500Base-X, 5000Base-X. It works, but it is not so nice.2) phylink gives you a much nicer API to do the same. Again, the PHY reports the link is up. phylink will then tell the MAC how to configure its end of the SERDES. The problem with phylink is that it expects a DT building. You don't have that, since this is a USB device. But you also don't need a lot of the features of phylink like SFPs, the i2c bus for the SFPs, GPIOs etc. So it should not be to hard to make this work without device tree.
By using core linux code, we avoid bugs in firmware which nobody can fix. The Linux core code should be well tested and supported, but phylink is rather new, so might still have some corner cases.
Quoted 5 lines
I also cannot imaging parts of the PHY driver will not be re-usable for other Aquantia PHYs. I have a board with an AQCS109 under my desk waiting for me to do something with it. I really would like a better PHY driver for it than the kernel currently has. Hopefully there is some code reuse possibilities here.
Quoted 3 lines
Even if the firmware is helping, there is still value in using PHYLINK to report things to Linux as Andrew is saying in that you get a lot of things for free: auto-negotiation results, link_ksetttings_{get,set} etc.
Thanks for the detailed explanation, I agree separating phy logic would really improve things.
But just in time we've got a new updates from HW management/system teams, It looks like they are deprecating direct phy access firmware mode, so the only thing we have to support in this driver is FW based interface for the link management.
Production dongles will always have firmware fully controlling all the phy. Thus, I think in next series we'll just cut off all the direct phy access code.
I agree with Andrew we eventually need a better generic Aquantia PHYs support in linux, hope to look into this matter soon.
Regards,
Igor
Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
Quoted 3 lines
Production dongles will always have firmware fully controlling all the phy. Thus, I think in next series we'll just cut off all the direct phy access code.
O.K, but that is also a shame. The PHY i have has all sorts of nice things, MACSEC, temperature sensors, PTP, cable tests logic, etc. Without having a proper PHY driver which can access the registers, a lot of that is going to be very hard to use.
Andrew
PATCH v2 7/21 net: usb: aqc111: Add support for getting and setting of MAC address
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 1 + 2 files changed, 48 insertions(+)
drivers/net/usb/aqc111.c +47 -0
@@ -11,6 +11,7 @@#include <linux/netdevice.h> #include <linux/mii.h> #include <linux/usb.h> +#include <linux/if_vlan.h> #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h>
@@ -284,11 +285,43 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)aqc111_set_phy_speed_fw_iface (dev, aqc111_data); } +static int aqc111_set_mac_addr (struct net_device *net,void *p) +{ +struct usbnet *dev =netdev_priv (net); +int ret =0 ; + + ret =eth_mac_addr (net, p); +if (ret <0 ) +return ret; + +/* Set the MAC address */ +return aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_NODE_ID ,ETH_ALEN , +ETH_ALEN , net->dev_addr); +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, + .ndo_set_mac_address = aqc111_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; +static int aqc111_read_perm_mac (struct usbnet *dev) +{ +u8 buf[ETH_ALEN ]; +int ret; + + ret =aqc111_read_cmd (dev,AQ_FLASH_PARAMETERS ,0 ,0 ,ETH_ALEN , buf); +if (ret <0 ) + goto out; + +ether_addr_copy (dev->net->perm_addr, buf); + +return 0 ; +out: +return ret; +} +static void aqc111_read_fw_version (struct usbnet *dev,struct aqc111_data *aqc111_data) {
@@ -333,6 +366,12 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)/* store aqc111_data pointer in device data field */ dev->driver_priv = aqc111_data; +/* Init the MAC address */ + ret =aqc111_read_perm_mac (dev); +if (ret) + goto out; + +ether_addr_copy (dev->net->dev_addr, dev->net->perm_addr); dev->net->netdev_ops = &aqc111_netdev_ops;aqc111_read_fw_version (dev, aqc111_data);
@@ -341,6 +380,10 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) SPEED_5000 :SPEED_1000 ;return 0 ; + +out: +kfree (aqc111_data); +return ret; }static void aqc111_unbind (struct usbnet *dev,struct usb_interface *intf)
@@ -582,6 +625,10 @@ static int aqc111_reset(struct usbnet *dev) &aqc111_data->phy_cfg); } +/* Set the MAC address */ +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_NODE_ID ,ETH_ALEN , +ETH_ALEN , dev->net->dev_addr); + reg8 =0xFF ;aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BM_INT_MASK ,1 ,1 , ®8);
drivers/net/usb/aqc111.h +1 -0
@@ -11,6 +11,7 @@#define __LINUX_USBNET_AQC111_H#define AQ_ACCESS_MAC 0x01 +#define AQ_FLASH_PARAMETERS 0x20#define AQ_PHY_POWER 0x31#define AQ_PHY_CMD 0x32#define AQ_PHY_OPS 0x61
PATCH v2 8/21 net: usb: aqc111: Implement TX data path
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 8 ++++++ 2 files changed, 80 insertions(+)
drivers/net/usb/aqc111.c +72 -0
@@ -302,6 +302,9 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p)static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_get_stats64 = usbnet_get_stats64, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, };
@@ -372,8 +375,19 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) goto out;ether_addr_copy (dev->net->dev_addr, dev->net->perm_addr); + +/* Set TX needed headroom & tailroom */ + dev->net->needed_headroom +=sizeof (u64); + dev->net->needed_tailroom +=sizeof (u64); + dev->net->netdev_ops = &aqc111_netdev_ops; +if (usb_device_no_sg_constraint (dev->udev)) + dev->can_dma_sg =1 ; + + dev->net->hw_features |=AQ_SUPPORT_HW_FEATURE ; + dev->net->features |=AQ_SUPPORT_FEATURE ; +aqc111_read_fw_version (dev, aqc111_data); aqc111_data->autoneg =AUTONEG_ENABLE ; aqc111_data->advertised_speed = (usb_speed == USB_SPEED_SUPER) ?
@@ -603,6 +617,12 @@ static int aqc111_reset(struct usbnet *dev)u16 reg16 =0 ;u8 reg8 =0 ; +if (usb_device_no_sg_constraint (dev->udev)) + dev->can_dma_sg =1 ; + + dev->net->hw_features |=AQ_SUPPORT_HW_FEATURE ; + dev->net->features |=AQ_SUPPORT_FEATURE ; +/* Power up ethernet PHY */ aqc111_data->phy_cfg =AQ_PHY_POWER_EN ;if (aqc111_data->dpa) {
@@ -679,6 +699,55 @@ static int aqc111_stop(struct usbnet *dev)return 0 ; } +static struct sk_buff *aqc111_tx_fixup (struct usbnet *dev,struct sk_buff *skb, +gfp_t flags) +{ +int frame_size = dev->maxpacket; +struct sk_buff *new_skb =NULL ; +int padding_size =0 ; +int headroom =0 ; +int tailroom =0 ; +u64 tx_desc =0 ; + +/*Length of actual data*/ + tx_desc |= skb->len &AQ_TX_DESC_LEN_MASK ; + + headroom = (skb->len +sizeof (tx_desc)) %8 ; +if (headroom !=0 ) + padding_size =8 - headroom; + +if (((skb->len +sizeof (tx_desc) + padding_size) % frame_size) ==0 ) { + padding_size +=8 ; + tx_desc |=AQ_TX_DESC_DROP_PADD ; + } + +if (!dev->can_dma_sg && (dev->net->features &NETIF_F_SG ) && +skb_linearize (skb)) +return NULL ; + + headroom =skb_headroom (skb); + tailroom =skb_tailroom (skb); + +if (!(headroom >=sizeof (tx_desc) && tailroom >= padding_size)) { + new_skb =skb_copy_expand (skb,sizeof (tx_desc), + padding_size, flags); +dev_kfree_skb_any (skb); + skb = new_skb; +if (!skb) +return NULL ; + } +if (padding_size !=0 ) +skb_put (skb, padding_size); +/* Copy TX header */ +skb_push (skb,sizeof (tx_desc)); +cpu_to_le64s (&tx_desc); +skb_copy_to_linear_data (skb, &tx_desc,sizeof (tx_desc)); + +usbnet_set_skb_tx_stats (skb,1 ,0 ); + +return skb; +} +static const struct driver_info aqc111_info = { .description ="Aquantia AQtion USB to 5GbE Controller" , .bind = aqc111_bind,
@@ -687,6 +756,9 @@ static const struct driver_info aqc111_info = { .link_reset = aqc111_link_reset, .reset = aqc111_reset, .stop = aqc111_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | + FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, + .tx_fixup = aqc111_tx_fixup, };#define AQC111_USB_ETH_DEV (vid, pid, table) \
drivers/net/usb/aqc111.h +8 -0
@@ -60,6 +60,10 @@#define AQ_USB_PHY_SET_TIMEOUT 10000#define AQ_USB_SET_TIMEOUT 4000 +/* Feature. ********************************************/ +#define AQ_SUPPORT_FEATURE (NETIF_F_SG) +#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG) +/* SFR Reg. ********************************************/ #define SFR_GENERAL_STATUS 0x03
@@ -192,6 +196,10 @@ struct aqc111_data {#define AQ_INT_SPEED_1G 0x0011#define AQ_INT_SPEED_100M 0x0013 +/* TX Descriptor */ +#define AQ_TX_DESC_LEN_MASK 0x1FFFFF +#define AQ_TX_DESC_DROP_PADD BIT(28) + static struct { unsigned char ctrl; unsigned char timer_l;
PATCH v2 9/21 net: usb: aqc111: Implement RX data path
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 15 +++++++ 2 files changed, 118 insertions(+)
drivers/net/usb/aqc111.c +103 -0
@@ -376,6 +376,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)ether_addr_copy (dev->net->dev_addr, dev->net->perm_addr); +/* Set Rx urb size */ + dev->rx_urb_size =URB_SIZE ; +/* Set TX needed headroom & tailroom */ dev->net->needed_headroom +=sizeof (u64); dev->net->needed_tailroom +=sizeof (u64);
@@ -617,6 +620,8 @@ static int aqc111_reset(struct usbnet *dev)u16 reg16 =0 ;u8 reg8 =0 ; + dev->rx_urb_size =URB_SIZE ; +if (usb_device_no_sg_constraint (dev->udev)) dev->can_dma_sg =1 ;
@@ -699,6 +704,103 @@ static int aqc111_stop(struct usbnet *dev)return 0 ; } +static int aqc111_rx_fixup (struct usbnet *dev,struct sk_buff *skb) +{ +struct sk_buff *new_skb =NULL ; +u32 pkt_total_offset =0 ; +u32 start_of_descs =0 ; +u64 *pkt_desc =NULL ; +u32 desc_offset =0 ;/*RX Header Offset*/ +u16 pkt_count =0 ; +u64 desc_hdr =0 ; +u32 skb_len =0 ; + +if (!skb) + goto err; + +if (skb->len ==0 ) + goto err; + + skb_len = skb->len; +/* RX Descriptor Header */ +skb_trim (skb, skb->len -sizeof (desc_hdr)); + desc_hdr = *(u64 *)skb_tail_pointer (skb); +le64_to_cpus (&desc_hdr); + +/* Check these packets */ + desc_offset = (desc_hdr &AQ_RX_DH_DESC_OFFSET_MASK ) >> +AQ_RX_DH_DESC_OFFSET_SHIFT ; + pkt_count = desc_hdr &AQ_RX_DH_PKT_CNT_MASK ; + start_of_descs = skb_len - ((pkt_count +1 ) *sizeof (desc_hdr)); + +/* self check descs position */ +if (start_of_descs != desc_offset) + goto err; + +/* self check desc_offset from header*/ +if (desc_offset >= skb_len) + goto err; + +if (pkt_count ==0 ) + goto err; + +/* Get the first RX packet descriptor */ + pkt_desc = (u64 *)(skb->data + desc_offset); + +while (pkt_count--) { +u32 pkt_len =0 ; +u32 pkt_len_with_padd =0 ; + +le64_to_cpus (pkt_desc); + pkt_len = (u32)((*pkt_desc &AQ_RX_PD_LEN_MASK ) >> +AQ_RX_PD_LEN_SHIFT ); + pkt_len_with_padd = ((pkt_len +7 ) &0x7FFF8 ); + + pkt_total_offset += pkt_len_with_padd; +if (pkt_total_offset > desc_offset || + (pkt_count ==0 && pkt_total_offset != desc_offset)) { + goto err; + } + +if (*pkt_desc &AQ_RX_PD_DROP || + !(*pkt_desc &AQ_RX_PD_RX_OK ) || + pkt_len > (dev->hard_mtu +AQ_RX_HW_PAD )) { +skb_pull (skb, pkt_len_with_padd); +/* Next RX Packet Descriptor */ + pkt_desc++; +continue ; + } + +/* Clone SKB */ + new_skb =skb_clone (skb,GFP_ATOMIC ); + +if (!new_skb) + goto err; + + new_skb->len = pkt_len; +skb_pull (new_skb,AQ_RX_HW_PAD ); +skb_set_tail_pointer (new_skb, new_skb->len); + + new_skb->truesize = new_skb->len +sizeof (struct sk_buff ); + +usbnet_skb_return (dev, new_skb); +if (pkt_count ==0 ) +break ; + +skb_pull (skb, pkt_len_with_padd); + +/* Next RX Packet Header */ + pkt_desc++; + + new_skb =NULL ; + } + +return 1 ; + +err: +return 0 ; +} +static struct sk_buff *aqc111_tx_fixup (struct usbnet *dev,struct sk_buff *skb,gfp_t flags) {
@@ -758,6 +860,7 @@ static const struct driver_info aqc111_info = { .stop = aqc111_stop, .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, + .rx_fixup = aqc111_rx_fixup, .tx_fixup = aqc111_tx_fixup, };
drivers/net/usb/aqc111.h +15 -0
@@ -10,6 +10,8 @@#ifndef __LINUX_USBNET_AQC111_H#define __LINUX_USBNET_AQC111_H +#define URB_SIZE (1024 * 62) +#define AQ_ACCESS_MAC 0x01#define AQ_FLASH_PARAMETERS 0x20#define AQ_PHY_POWER 0x31
@@ -200,6 +202,19 @@ struct aqc111_data {#define AQ_TX_DESC_LEN_MASK 0x1FFFFF#define AQ_TX_DESC_DROP_PADD BIT(28) +#define AQ_RX_HW_PAD 0x02 + +/* RX Packet Descriptor */ +#define AQ_RX_PD_RX_OK BIT(11) +#define AQ_RX_PD_DROP BIT(31) +#define AQ_RX_PD_LEN_MASK 0x7FFF0000 +#define AQ_RX_PD_LEN_SHIFT 0x10 + +/* RX Descriptor header */ +#define AQ_RX_DH_PKT_CNT_MASK 0x1FFF +#define AQ_RX_DH_DESC_OFFSET_MASK 0xFFFFE000 +#define AQ_RX_DH_DESC_OFFSET_SHIFT 0x0D + static struct { unsigned char ctrl; unsigned char timer_l;
PATCH v2 10/21 net: usb: aqc111: Add checksum offload support
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 16 ++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-)
drivers/net/usb/aqc111.c +38 -0
@@ -536,6 +536,26 @@ static void aqc111_configure_rx(struct usbnet *dev,netdev_info (dev->net,"Link Speed %d, USB %d" , link_speed, usb_host); } +static void aqc111_configure_csum_offload (struct usbnet *dev) +{ +u8 reg8 =0 ; + +if (dev->net->features &NETIF_F_RXCSUM ) { + reg8 |=SFR_RXCOE_IP |SFR_RXCOE_TCP |SFR_RXCOE_UDP | +SFR_RXCOE_TCPV6 |SFR_RXCOE_UDPV6 ; + } +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RXCOE_CTL ,1 ,1 , ®8); + + reg8 =0 ; +if (dev->net->features &NETIF_F_IP_CSUM ) + reg8 |=SFR_TXCOE_IP |SFR_TXCOE_TCP |SFR_TXCOE_UDP ; + +if (dev->net->features &NETIF_F_IPV6_CSUM ) + reg8 |=SFR_TXCOE_TCPV6 |SFR_TXCOE_UDPV6 ; + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_TXCOE_CTL ,1 ,1 , ®8); +} +static int aqc111_link_reset (struct usbnet *dev) {struct aqc111_data *aqc111_data = dev->driver_priv;
@@ -579,6 +599,8 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16); +aqc111_configure_csum_offload (dev); +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16);
@@ -704,6 +726,21 @@ static int aqc111_stop(struct usbnet *dev)return 0 ; } +static void aqc111_rx_checksum (struct sk_buff *skb,u64 *pkt_desc) +{ +u32 pkt_type =0 ; + + skb->ip_summed =CHECKSUM_NONE ; +/* checksum error bit is set */ +if (*pkt_desc &AQ_RX_PD_L4_ERR || *pkt_desc &AQ_RX_PD_L3_ERR ) +return ; + + pkt_type = *pkt_desc &AQ_RX_PD_L4_TYPE_MASK ; +/* It must be a TCP or UDP packet with a valid checksum */ +if (pkt_type ==AQ_RX_PD_L4_TCP || pkt_type ==AQ_RX_PD_L4_UDP ) + skb->ip_summed =CHECKSUM_UNNECESSARY ; +} +static int aqc111_rx_fixup (struct usbnet *dev,struct sk_buff *skb) {struct sk_buff *new_skb =NULL ;
@@ -782,6 +819,7 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)skb_set_tail_pointer (new_skb, new_skb->len); new_skb->truesize = new_skb->len +sizeof (struct sk_buff ); +aqc111_rx_checksum (new_skb, pkt_desc);usbnet_skb_return (dev, new_skb);if (pkt_count ==0 )
drivers/net/usb/aqc111.h +14 -2
@@ -63,8 +63,11 @@#define AQ_USB_SET_TIMEOUT 4000/* Feature. ********************************************/ -#define AQ_SUPPORT_FEATURE (NETIF_F_SG) -#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG) +#define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) + +#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)/* SFR Reg. ********************************************/
@@ -205,6 +208,15 @@ struct aqc111_data {#define AQ_RX_HW_PAD 0x02/* RX Packet Descriptor */ +#define AQ_RX_PD_L4_ERR BIT(0) +#define AQ_RX_PD_L3_ERR BIT(1) +#define AQ_RX_PD_L4_TYPE_MASK 0x1C +#define AQ_RX_PD_L4_UDP 0x04 +#define AQ_RX_PD_L4_TCP 0x10 +#define AQ_RX_PD_L3_TYPE_MASK 0x60 +#define AQ_RX_PD_L3_IP 0x20 +#define AQ_RX_PD_L3_IP6 0x40 +#define AQ_RX_PD_RX_OK BIT(11)#define AQ_RX_PD_DROP BIT(31)#define AQ_RX_PD_LEN_MASK 0x7FFF0000
PATCH v2 11/21 net: usb: aqc111: Add support for changing MTU
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-)
drivers/net/usb/aqc111.c +59 -1
@@ -285,6 +285,48 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)aqc111_set_phy_speed_fw_iface (dev, aqc111_data); } +static int aqc111_change_mtu (struct net_device *net,int new_mtu) +{ +struct usbnet *dev =netdev_priv (net); +u16 reg16 =0 ; +u8 buf[5 ]; + + net->mtu = new_mtu; + dev->hard_mtu = net->mtu + net->hard_header_len; + +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); +if (net->mtu >1500 ) + reg16 |=SFR_MEDIUM_JUMBO_EN ; +else + reg16 &= ~SFR_MEDIUM_JUMBO_EN ; + +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + +if (dev->net->mtu >12500 && dev->net->mtu <=16334 ) { +memcpy (buf, &AQC111_BULKIN_SIZE [2 ],5 ); +/* RX bulk configuration */ +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QCTRL , +5 ,5 , buf); + } + +/* Set high low water level */ +if (dev->net->mtu <=4500 ) + reg16 =0x0810 ; +else if (dev->net->mtu <=9500 ) + reg16 =0x1020 ; +else if (dev->net->mtu <=12500 ) + reg16 =0x1420 ; +else if (dev->net->mtu <=16334 ) + reg16 =0x1A20 ; + +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_PAUSE_WATERLVL_LOW , +2 , ®16); + +return 0 ; +} +static int aqc111_set_mac_addr (struct net_device *net,void *p) {struct usbnet *dev =netdev_priv (net);
@@ -305,6 +347,7 @@ static const struct net_device_ops aqc111_netdev_ops = { .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_get_stats64 = usbnet_get_stats64, + .ndo_change_mtu = aqc111_change_mtu, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, };
@@ -383,6 +426,8 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->needed_headroom +=sizeof (u64); dev->net->needed_tailroom +=sizeof (u64); + dev->net->max_mtu =16334 ; + dev->net->netdev_ops = &aqc111_netdev_ops;if (usb_device_no_sg_constraint (dev->udev))
@@ -524,12 +569,22 @@ static void aqc111_configure_rx(struct usbnet *dev,break ; } +if (dev->net->mtu >12500 && dev->net->mtu <=16334 ) + queue_num =2 ;/* For Jumbo packet 16KB */ +memcpy (buf, &AQC111_BULKIN_SIZE [queue_num],5 );/* RX bulk configuration */ aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QCTRL ,5 ,5 , buf);/* Set high low water level */ - reg16 =0x0810 ; +if (dev->net->mtu <=4500 ) + reg16 =0x0810 ; +else if (dev->net->mtu <=9500 ) + reg16 =0x1020 ; +else if (dev->net->mtu <=12500 ) + reg16 =0x1420 ; +else if (dev->net->mtu <=16334 ) + reg16 =0x1A20 ;aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_PAUSE_WATERLVL_LOW ,2 , ®16);
@@ -604,6 +659,9 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16); +if (dev->net->mtu >1500 ) + reg16 |=SFR_MEDIUM_JUMBO_EN ; + reg16 |=SFR_MEDIUM_RECEIVE_EN |SFR_MEDIUM_RXFLOW_CTRLEN |SFR_MEDIUM_TXFLOW_CTRLEN ; aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
PATCH v2 12/21 net: usb: aqc111: Add support for enable/disable checksum offload
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- drivers/net/usb/aqc111.h | 1 + 2 files changed, 45 insertions(+), 1 deletion(-)
drivers/net/usb/aqc111.c +44 -1
@@ -341,6 +341,46 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p) ETH_ALEN, net->dev_addr); } +static int aqc111_set_features (struct net_device *net, +netdev_features_t features) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; +netdev_features_t changed = net->features ^ features; +u8 reg8 =0 ; + +if (changed &NETIF_F_IP_CSUM ) { +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_TXCOE_CTL ,1 ,1 , ®8); + reg8 ^=SFR_TXCOE_TCP |SFR_TXCOE_UDP ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_TXCOE_CTL , +1 ,1 , ®8); + } + +if (changed &NETIF_F_IPV6_CSUM ) { +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_TXCOE_CTL ,1 ,1 , ®8); + reg8 ^=SFR_TXCOE_TCPV6 |SFR_TXCOE_UDPV6 ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_TXCOE_CTL , +1 ,1 , ®8); + } + +if (changed &NETIF_F_RXCSUM ) { +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_RXCOE_CTL ,1 ,1 , ®8); +if (features &NETIF_F_RXCSUM ) { + aqc111_data->rx_checksum =1 ; + reg8 &= ~(SFR_RXCOE_IP |SFR_RXCOE_TCP |SFR_RXCOE_UDP | +SFR_RXCOE_TCPV6 |SFR_RXCOE_UDPV6 ); + }else { + aqc111_data->rx_checksum =0 ; + reg8 |=SFR_RXCOE_IP |SFR_RXCOE_TCP |SFR_RXCOE_UDP | +SFR_RXCOE_TCPV6 |SFR_RXCOE_UDPV6 ; + } + +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RXCOE_CTL , +1 ,1 , ®8); + } +return 0 ; +} +static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop,
@@ -350,6 +390,7 @@ static const struct net_device_ops aqc111_netdev_ops = { .ndo_change_mtu = aqc111_change_mtu, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_set_features = aqc111_set_features, };static int aqc111_read_perm_mac (struct usbnet *dev)
@@ -801,6 +842,7 @@ static void aqc111_rx_checksum(struct sk_buff *skb, u64 *pkt_desc)static int aqc111_rx_fixup (struct usbnet *dev,struct sk_buff *skb) { +struct aqc111_data *aqc111_data = dev->driver_priv;struct sk_buff *new_skb =NULL ;u32 pkt_total_offset =0 ;u32 start_of_descs =0 ;
@@ -877,7 +919,8 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)skb_set_tail_pointer (new_skb, new_skb->len); new_skb->truesize = new_skb->len +sizeof (struct sk_buff ); -aqc111_rx_checksum (new_skb, pkt_desc); +if (aqc111_data->rx_checksum) +aqc111_rx_checksum (new_skb, pkt_desc);usbnet_skb_return (dev, new_skb);if (pkt_count ==0 )
drivers/net/usb/aqc111.h +1 -0
@@ -180,6 +180,7 @@/******************************************************************************/ struct aqc111_data { +u8 rx_checksum;u8 link_speed;u8 link;u8 autoneg;
PATCH v2 13/21 net: usb: aqc111: Add support for TSO
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 4 ++++ drivers/net/usb/aqc111.h | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/net/usb/aqc111.c +4 -0
@@ -953,6 +953,10 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,/*Length of actual data*/ tx_desc |= skb->len &AQ_TX_DESC_LEN_MASK ; +/* TSO MSS */ + tx_desc |= ((u64)(skb_shinfo (skb)->gso_size &AQ_TX_DESC_MSS_MASK )) << +AQ_TX_DESC_MSS_SHIFT ; + headroom = (skb->len +sizeof (tx_desc)) %8 ;if (headroom !=0 ) padding_size =8 - headroom;
drivers/net/usb/aqc111.h +6 -2
@@ -64,10 +64,12 @@/* Feature. ********************************************/ #define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ - NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ + NETIF_F_TSO)#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ - NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ + NETIF_F_TSO)/* SFR Reg. ********************************************/
@@ -205,6 +207,8 @@ struct aqc111_data {/* TX Descriptor */ #define AQ_TX_DESC_LEN_MASK 0x1FFFFF#define AQ_TX_DESC_DROP_PADD BIT(28) +#define AQ_TX_DESC_MSS_MASK 0x7FFF +#define AQ_TX_DESC_MSS_SHIFT 0x20#define AQ_RX_HW_PAD 0x02
PATCH v2 14/21 net: usb: aqc111: Implement set_rx_mode callback
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/net/usb/aqc111.h | 4 +++ 2 files changed, 71 insertions(+), 5 deletions(-)
drivers/net/usb/aqc111.c +67 -5
@@ -11,6 +11,7 @@#include <linux/netdevice.h> #include <linux/mii.h> #include <linux/usb.h> +#include <linux/crc32.h> #include <linux/if_vlan.h> #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h>
@@ -158,6 +159,25 @@ static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value,return aqc111_write_cmd (dev, cmd, value, index,sizeof (tmp), &tmp); } +static int aqc111_write_cmd_async (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 size,void *data) +{ +return usbnet_write_cmd_async (dev, cmd,USB_DIR_OUT |USB_TYPE_VENDOR | +USB_RECIP_DEVICE , value, index, data, + size); +} + +static int aqc111_write16_cmd_async (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 *data) +{ +u16 tmp = *data; + +cpu_to_le16s (&tmp); + +return aqc111_write_cmd_async (dev, cmd, value, index, +sizeof (tmp), &tmp); +} +static int aqc111_mdio_read (struct usbnet *dev,u16 value,u16 index,u16 *data) {return aqc111_read16_cmd (dev,AQ_PHY_CMD , value, index, data);
@@ -341,6 +361,43 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p) ETH_ALEN, net->dev_addr); } +static void aqc111_set_rx_mode (struct net_device *net) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; +int mc_count =0 ; + + mc_count =netdev_mc_count (net); + + aqc111_data->rxctl &= ~(SFR_RX_CTL_PRO |SFR_RX_CTL_AMALL | +SFR_RX_CTL_AM ); + +if (net->flags &IFF_PROMISC ) { + aqc111_data->rxctl |=SFR_RX_CTL_PRO ; + }else if ((net->flags &IFF_ALLMULTI ) || mc_count >AQ_MAX_MCAST ) { + aqc111_data->rxctl |=SFR_RX_CTL_AMALL ; + }else if (!netdev_mc_empty (net)) { +u8 m_filter[AQ_MCAST_FILTER_SIZE ] = {0 }; +struct netdev_hw_addr *ha =NULL ; +u32 crc_bits =0 ; + +netdev_for_each_mc_addr (ha, net) { + crc_bits =ether_crc (ETH_ALEN , ha->addr) >>26 ; + m_filter[crc_bits >>3 ] |=BIT (crc_bits &7 ); + } + +aqc111_write_cmd_async (dev,AQ_ACCESS_MAC , +SFR_MULTI_FILTER_ARRY , +AQ_MCAST_FILTER_SIZE , +AQ_MCAST_FILTER_SIZE , m_filter); + + aqc111_data->rxctl |=SFR_RX_CTL_AM ; + } + +aqc111_write16_cmd_async (dev,AQ_ACCESS_MAC ,SFR_RX_CTL , +2 , &aqc111_data->rxctl); +} +static int aqc111_set_features (struct net_device *net,netdev_features_t features) {
@@ -390,6 +447,7 @@ static const struct net_device_ops aqc111_netdev_ops = { .ndo_change_mtu = aqc111_change_mtu, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = aqc111_set_rx_mode, .ndo_set_features = aqc111_set_features, };
@@ -677,6 +735,7 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_ARC_CTRL ,1 ,1 , ®8); reg16 =SFR_RX_CTL_IPE |SFR_RX_CTL_AB ; + aqc111_data->rxctl = reg16;aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); reg8 =SFR_RX_PATH_READY ;
@@ -697,6 +756,8 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_configure_csum_offload (dev); +aqc111_set_rx_mode (dev->net); +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16);
@@ -708,8 +769,9 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16); - reg16 =SFR_RX_CTL_IPE |SFR_RX_CTL_AB |SFR_RX_CTL_START ; -aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + aqc111_data->rxctl |=SFR_RX_CTL_START ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL , +2 , &aqc111_data->rxctl);netif_carrier_on (dev->net); }else {
@@ -719,9 +781,9 @@ static int aqc111_link_reset(struct usbnet *dev)aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE ,2 , ®16); -aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); - reg16 &= ~SFR_RX_CTL_START ; -aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + aqc111_data->rxctl &= ~SFR_RX_CTL_START ; +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_RX_CTL , +2 , &aqc111_data->rxctl); reg8 =SFR_BULK_OUT_FLUSH_EN |SFR_BULK_OUT_EFF_EN ; aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
drivers/net/usb/aqc111.h +4 -0
@@ -12,6 +12,9 @@#define URB_SIZE (1024 * 62) +#define AQ_MCAST_FILTER_SIZE 8 +#define AQ_MAX_MCAST 64 +#define AQ_ACCESS_MAC 0x01#define AQ_FLASH_PARAMETERS 0x20#define AQ_PHY_POWER 0x31
@@ -182,6 +185,7 @@/******************************************************************************/ struct aqc111_data { +u16 rxctl;u8 rx_checksum;u8 link_speed;u8 link;
PATCH v2 15/21 net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 17 +++++++++++++++++ drivers/net/usb/aqc111.h | 12 +++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-)
drivers/net/usb/aqc111.c +17 -0
@@ -534,6 +534,7 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->hw_features |=AQ_SUPPORT_HW_FEATURE ; dev->net->features |=AQ_SUPPORT_FEATURE ; + dev->net->vlan_features |=AQ_SUPPORT_VLAN_FEATURE ;aqc111_read_fw_version (dev, aqc111_data); aqc111_data->autoneg =AUTONEG_ENABLE ;
@@ -810,6 +811,7 @@ static int aqc111_reset(struct usbnet *dev) dev->net->hw_features |=AQ_SUPPORT_HW_FEATURE ; dev->net->features |=AQ_SUPPORT_FEATURE ; + dev->net->vlan_features |=AQ_SUPPORT_VLAN_FEATURE ;/* Power up ethernet PHY */ aqc111_data->phy_cfg =AQ_PHY_POWER_EN ;
@@ -912,6 +914,7 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)u32 desc_offset =0 ;/*RX Header Offset*/ u16 pkt_count =0 ;u64 desc_hdr =0 ; +u16 vlan_tag =0 ;u32 skb_len =0 ;if (!skb)
@@ -984,6 +987,12 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)if (aqc111_data->rx_checksum)aqc111_rx_checksum (new_skb, pkt_desc); +if (*pkt_desc &AQ_RX_PD_VLAN ) { + vlan_tag = *pkt_desc >>AQ_RX_PD_VLAN_SHIFT ; +__vlan_hwaccel_put_tag (new_skb,htons (ETH_P_8021Q ), + vlan_tag &VLAN_VID_MASK ); + } +usbnet_skb_return (dev, new_skb);if (pkt_count ==0 )break ;
@@ -1011,6 +1020,7 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,int headroom =0 ;int tailroom =0 ;u64 tx_desc =0 ; +u16 tci =0 ;/*Length of actual data*/ tx_desc |= skb->len &AQ_TX_DESC_LEN_MASK ;
@@ -1028,6 +1038,13 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, tx_desc |=AQ_TX_DESC_DROP_PADD ; } +/* Vlan Tag */ +if (vlan_get_tag (skb, &tci) >=0 ) { + tx_desc |=AQ_TX_DESC_VLAN ; + tx_desc |= ((u64 )tci &AQ_TX_DESC_VLAN_MASK ) << +AQ_TX_DESC_VLAN_SHIFT ; + } +if (!dev->can_dma_sg && (dev->net->features &NETIF_F_SG ) &&skb_linearize (skb))return NULL ;
drivers/net/usb/aqc111.h +11 -1
@@ -68,12 +68,17 @@/* Feature. ********************************************/ #define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ - NETIF_F_TSO) + NETIF_F_TSO | NETIF_F_HW_VLAN_CTAG_TX |\ + NETIF_F_HW_VLAN_CTAG_RX)#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ NETIF_F_TSO) +#define AQ_SUPPORT_VLAN_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ + NETIF_F_TSO) +/* SFR Reg. ********************************************/ #define SFR_GENERAL_STATUS 0x03
@@ -211,8 +216,11 @@ struct aqc111_data {/* TX Descriptor */ #define AQ_TX_DESC_LEN_MASK 0x1FFFFF#define AQ_TX_DESC_DROP_PADD BIT(28) +#define AQ_TX_DESC_VLAN BIT(29)#define AQ_TX_DESC_MSS_MASK 0x7FFF#define AQ_TX_DESC_MSS_SHIFT 0x20 +#define AQ_TX_DESC_VLAN_MASK 0xFFFF +#define AQ_TX_DESC_VLAN_SHIFT 0x30#define AQ_RX_HW_PAD 0x02
@@ -226,10 +234,12 @@ struct aqc111_data {#define AQ_RX_PD_L3_IP 0x20#define AQ_RX_PD_L3_IP6 0x40 +#define AQ_RX_PD_VLAN BIT(10)#define AQ_RX_PD_RX_OK BIT(11)#define AQ_RX_PD_DROP BIT(31)#define AQ_RX_PD_LEN_MASK 0x7FFF0000#define AQ_RX_PD_LEN_SHIFT 0x10 +#define AQ_RX_PD_VLAN_SHIFT 0x20/* RX Descriptor header */ #define AQ_RX_DH_PKT_CNT_MASK 0x1FFF
PATCH v2 16/21 net: usb: aqc111: Add RX VLAN filtering support
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-)
drivers/net/usb/aqc111.c +89 -0
@@ -361,6 +361,57 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p) ETH_ALEN, net->dev_addr); } +static int aqc111_vlan_rx_kill_vid (struct net_device *net, +__be16 proto,u16 vid) +{ +struct usbnet *dev =netdev_priv (net); +u8 vlan_ctrl =0 ; +u16 reg16 =0 ; +u8 reg8 =0 ; + +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + vlan_ctrl = reg8; + +/* Address */ + reg8 = (vid /16 ); +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_ADDRESS ,1 ,1 , ®8); +/* Data */ + reg8 = vlan_ctrl |SFR_VLAN_CONTROL_RD ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_DATA0 ,2 , ®16); + reg16 &= ~(1 << (vid %16 )); +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_DATA0 ,2 , ®16); + reg8 = vlan_ctrl |SFR_VLAN_CONTROL_WE ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + +return 0 ; +} + +static int aqc111_vlan_rx_add_vid (struct net_device *net,__be16 proto,u16 vid) +{ +struct usbnet *dev =netdev_priv (net); +u8 vlan_ctrl =0 ; +u16 reg16 =0 ; +u8 reg8 =0 ; + +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + vlan_ctrl = reg8; + +/* Address */ + reg8 = (vid /16 ); +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_ADDRESS ,1 ,1 , ®8); +/* Data */ + reg8 = vlan_ctrl |SFR_VLAN_CONTROL_RD ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); +aqc111_read16_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_DATA0 ,2 , ®16); + reg16 |= (1 << (vid %16 )); +aqc111_write16_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_DATA0 ,2 , ®16); + reg8 = vlan_ctrl |SFR_VLAN_CONTROL_WE ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + +return 0 ; +} +static void aqc111_set_rx_mode (struct net_device *net) {struct usbnet *dev =netdev_priv (net);
@@ -404,6 +455,7 @@ static int aqc111_set_features(struct net_device *net,struct usbnet *dev =netdev_priv (net);struct aqc111_data *aqc111_data = dev->driver_priv;netdev_features_t changed = net->features ^ features; +u16 reg16 =0 ;u8 reg8 =0 ;if (changed &NETIF_F_IP_CSUM ) {
@@ -435,6 +487,39 @@ static int aqc111_set_features(struct net_device *net,aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_RXCOE_CTL ,1 ,1 , ®8); } +if (changed &NETIF_F_HW_VLAN_CTAG_FILTER ) { +if (features &NETIF_F_HW_VLAN_CTAG_FILTER ) { +u16 i =0 ; + +for (i =0 ; i <256 ; i++) { +/* Address */ + reg8 = i; +aqc111_write_cmd (dev,AQ_ACCESS_MAC , +SFR_VLAN_ID_ADDRESS , +1 ,1 , ®8); +/* Data */ +aqc111_write16_cmd (dev,AQ_ACCESS_MAC , +SFR_VLAN_ID_DATA0 , +2 , ®16); + reg8 =SFR_VLAN_CONTROL_WE ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC , +SFR_VLAN_ID_CONTROL , +1 ,1 , ®8); + } +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL , +1 ,1 , ®8); + reg8 |=SFR_VLAN_CONTROL_VFE ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC , +SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + }else { +aqc111_read_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL , +1 ,1 , ®8); + reg8 &= ~SFR_VLAN_CONTROL_VFE ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC , +SFR_VLAN_ID_CONTROL ,1 ,1 , ®8); + } + } +return 0 ; }
@@ -447,6 +532,8 @@ static const struct net_device_ops aqc111_netdev_ops = { .ndo_change_mtu = aqc111_change_mtu, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_add_vid = aqc111_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = aqc111_vlan_rx_kill_vid, .ndo_set_rx_mode = aqc111_set_rx_mode, .ndo_set_features = aqc111_set_features, };
@@ -722,6 +809,8 @@ static int aqc111_link_reset(struct usbnet *dev)/* Vlan Tag Filter */ reg8 =SFR_VLAN_CONTROL_VSO ; +if (dev->net->features &NETIF_F_HW_VLAN_CTAG_FILTER ) + reg8 |=SFR_VLAN_CONTROL_VFE ;aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_VLAN_ID_CONTROL ,1 ,1 , ®8);
drivers/net/usb/aqc111.h +1 -1
@@ -73,7 +73,7 @@#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\ - NETIF_F_TSO) + NETIF_F_TSO | NETIF_F_HW_VLAN_CTAG_FILTER)#define AQ_SUPPORT_VLAN_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
PATCH v2 17/21 net: usb: aqc111: Initialize ethtool_ops structure
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Implement get_drvinfo, set/get_msglevel, get_link callbacks
--- drivers/net/usb/aqc111.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/net/usb/aqc111.c +28 -0
@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/netdevice.h> +#include <linux/ethtool.h> #include <linux/mii.h> #include <linux/usb.h> #include <linux/crc32.h>
@@ -18,6 +19,8 @@#include "aqc111.h" +#define DRIVER_NAME "aqc111" +static int aqc111_read_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value,u16 index,u16 size,void *data) {
@@ -189,6 +192,23 @@ static int aqc111_mdio_write(struct usbnet *dev, u16 value,return aqc111_write16_cmd (dev,AQ_PHY_CMD , value, index, data); } +static void aqc111_get_drvinfo (struct net_device *net, +struct ethtool_drvinfo *info) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; + +/* Inherit standard device info */ +usbnet_get_drvinfo (net, info); +strlcpy (info->driver,DRIVER_NAME ,sizeof (info->driver)); +snprintf (info->fw_version,sizeof (info->fw_version),"%u.%u.%u" , + aqc111_data->fw_ver.major, + aqc111_data->fw_ver.minor, + aqc111_data->fw_ver.rev); + info->eedump_len =0x00 ; + info->regdump_len =0x00 ; +} +static void aqc111_set_phy_speed_fw_iface (struct usbnet *dev,struct aqc111_data *aqc111_data) {
@@ -305,6 +325,13 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)aqc111_set_phy_speed_fw_iface (dev, aqc111_data); } +static const struct ethtool_ops aqc111_ethtool_ops = { + .get_drvinfo = aqc111_get_drvinfo, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_link = ethtool_op_get_link, +}; +static int aqc111_change_mtu (struct net_device *net,int new_mtu) {struct usbnet *dev =netdev_priv (net);
@@ -615,6 +642,7 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->max_mtu =16334 ; dev->net->netdev_ops = &aqc111_netdev_ops; + dev->net->ethtool_ops = &aqc111_ethtool_ops;if (usb_device_no_sg_constraint (dev->udev)) dev->can_dma_sg =1 ;
PATCH v2 18/21 net: usb: aqc111: Implement get/set_link_ksettings callbacks
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+)
drivers/net/usb/aqc111.c +124 -0
@@ -209,6 +209,85 @@ static void aqc111_get_drvinfo(struct net_device *net, info->regdump_len =0x00 ; } +static void aqc111_speed_to_link_mode (u32 speed, +struct ethtool_link_ksettings *elk) +{ +switch (speed) { +case SPEED_5000 : +ethtool_link_ksettings_add_link_mode (elk, advertising, + 5000baseT_Full); +break ; +case SPEED_2500 : +ethtool_link_ksettings_add_link_mode (elk, advertising, + 2500baseT_Full); +break ; +case SPEED_1000 : +ethtool_link_ksettings_add_link_mode (elk, advertising, + 1000baseT_Full); +break ; +case SPEED_100 : +ethtool_link_ksettings_add_link_mode (elk, advertising, + 100baseT_Full); +break ; + } +} + +static int aqc111_get_link_ksettings (struct net_device *net, +struct ethtool_link_ksettings *elk) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; +enum usb_device_speed usb_speed = dev->udev->speed; +u32 speed =SPEED_UNKNOWN ; + +ethtool_link_ksettings_zero_link_mode (elk, supported); +ethtool_link_ksettings_add_link_mode (elk, supported, + 100baseT_Full); +ethtool_link_ksettings_add_link_mode (elk, supported, + 1000baseT_Full); +if (usb_speed ==USB_SPEED_SUPER ) { +ethtool_link_ksettings_add_link_mode (elk, supported, + 2500baseT_Full); +ethtool_link_ksettings_add_link_mode (elk, supported, + 5000baseT_Full); + } +ethtool_link_ksettings_add_link_mode (elk, supported,TP ); +ethtool_link_ksettings_add_link_mode (elk, supported, Autoneg); + + elk->base.port =PORT_TP ; + elk->base.transceiver =XCVR_INTERNAL ; + + elk->base.mdio_support =0x00 ;/*Not supported*/ + +if (aqc111_data->autoneg) +bitmap_copy (elk->link_modes.advertising, + elk->link_modes.supported, + __ETHTOOL_LINK_MODE_MASK_NBITS); +else +aqc111_speed_to_link_mode (aqc111_data->advertised_speed, elk); + + elk->base.autoneg = aqc111_data->autoneg; + +switch (aqc111_data->link_speed) { +case AQ_INT_SPEED_5G : + speed =SPEED_5000 ; +break ; +case AQ_INT_SPEED_2_5G : + speed =SPEED_2500 ; +break ; +case AQ_INT_SPEED_1G : + speed =SPEED_1000 ; +break ; +case AQ_INT_SPEED_100M : + speed =SPEED_100 ; +break ; + } + elk->base.duplex =DUPLEX_FULL ; + elk->base.speed = speed; + +return 0 ; +} +static void aqc111_set_phy_speed_fw_iface (struct usbnet *dev,struct aqc111_data *aqc111_data) {
@@ -325,11 +404,56 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)aqc111_set_phy_speed_fw_iface (dev, aqc111_data); } +static int aqc111_set_link_ksettings (struct net_device *net, +const struct ethtool_link_ksettings *elk) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; +enum usb_device_speed usb_speed = dev->udev->speed; +u8 autoneg = elk->base.autoneg; +u32 speed = elk->base.speed; + +if (autoneg ==AUTONEG_ENABLE ) { +if (aqc111_data->autoneg !=AUTONEG_ENABLE ) { + aqc111_data->autoneg =AUTONEG_ENABLE ; + aqc111_data->advertised_speed = + (usb_speed ==USB_SPEED_SUPER ) ? +SPEED_5000 :SPEED_1000 ; +aqc111_set_phy_speed (dev, aqc111_data->autoneg, + aqc111_data->advertised_speed); + } + }else { +if (speed !=SPEED_100 && + speed !=SPEED_1000 && + speed !=SPEED_2500 && + speed !=SPEED_5000 && + speed !=SPEED_UNKNOWN ) +return -EINVAL ; + +if (elk->base.duplex !=DUPLEX_FULL ) +return -EINVAL ; + +if (usb_speed !=USB_SPEED_SUPER && speed >SPEED_1000 ) +return -EINVAL ; + + aqc111_data->autoneg =AUTONEG_DISABLE ; +if (speed !=SPEED_UNKNOWN ) + aqc111_data->advertised_speed = speed; + +aqc111_set_phy_speed (dev, aqc111_data->autoneg, + aqc111_data->advertised_speed); + } + +return 0 ; +} +static const struct ethtool_ops aqc111_ethtool_ops = { .get_drvinfo = aqc111_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_link = ethtool_op_get_link, + .get_link_ksettings = aqc111_get_link_ksettings, + .set_link_ksettings = aqc111_set_link_ksettings };static int aqc111_change_mtu (struct net_device *net,int new_mtu)
Re: [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
Quoted 9 lines · Igor Russkikh
drivers/net/usb/aqc111.c +9
-0+static int aqc111_get_link_ksettings (struct net_device *net, +struct ethtool_link_ksettings *elk) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; +enum usb_device_speed usb_speed = dev->udev->speed; +u32 speed =SPEED_UNKNOWN ; + +ethtool_link_ksettings_zero_link_mode (elk, supported);
drivers/net/usb/aqc111.c static void aqc111_get_drvinfo(struct net_device *net, · line 253
Quoted 10 lines
drivers/net/usb/aqc111.c +10
-0+ethtool_link_ksettings_add_link_mode (elk, supported, + 100baseT_Full); +ethtool_link_ksettings_add_link_mode (elk, supported, + 1000baseT_Full); +if (usb_speed ==USB_SPEED_SUPER ) { +ethtool_link_ksettings_add_link_mode (elk, supported, + 2500baseT_Full); +ethtool_link_ksettings_add_link_mode (elk, supported, + 5000baseT_Full); + }
Hi Igor
We discussed this with the first version of the patches. I think you should add a comment explaining why 2.5G and 5G is disabled unless Super speed is available.
drivers/net/usb/aqc111.c static void aqc111_get_drvinfo(struct net_device *net, · line 265
Quoted 4 lines
drivers/net/usb/aqc111.c +4
-0+if (aqc111_data->autoneg) +bitmap_copy (elk->link_modes.advertising, + elk->link_modes.supported, + __ETHTOOL_LINK_MODE_MASK_NBITS);
linkmode_copy(). It is quite new, so you probably don't know about it.
Andrew
Re: [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
Quoted 9 lines
drivers/net/usb/aqc111.c static void aqc111_get_drvinfo(struct net_device *net, · line 253
Quoted 6 lines
drivers/net/usb/aqc111.c +6
-0+if (usb_speed ==USB_SPEED_SUPER ) { +ethtool_link_ksettings_add_link_mode (elk, supported, + 2500baseT_Full); +ethtool_link_ksettings_add_link_mode (elk, supported, + 5000baseT_Full); + }Hi Igor
Quoted 3 lines
We discussed this with the first version of the patches. I think you should add a comment explaining why 2.5G and 5G is disabled unless Super speed is available.
Right, I've explained that to you but forgot to add a comment here.
Quoted 6 lines
drivers/net/usb/aqc111.c static void aqc111_get_drvinfo(struct net_device *net, · line 265
Quoted 4 lines
drivers/net/usb/aqc111.c +4
-0+if (aqc111_data->autoneg) +bitmap_copy (elk->link_modes.advertising, + elk->link_modes.supported, + __ETHTOOL_LINK_MODE_MASK_NBITS);
linkmode_copy(). It is quite new, so you probably don't know about it.
Ok,
Regards,
Igor
PATCH v2 19/21 net: usb: aqc111: Add support for wake on LAN by MAGIC packet
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
--- drivers/net/usb/aqc111.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 12 +++ 2 files changed, 227 insertions(+)
drivers/net/usb/aqc111.c +215 -0
@@ -53,6 +53,17 @@ static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,return ret; } +static int aqc111_read16_cmd_nopm (struct usbnet *dev,u8 cmd,u16 value, +u16 index,u16 *data) +{ +int ret =0 ; + + ret =aqc111_read_cmd_nopm (dev, cmd, value, index,sizeof (*data), data); +le16_to_cpus (data); + +return ret; +} +static int aqc111_read16_cmd (struct usbnet *dev,u8 cmd,u16 value,u16 index,u16 *data) {
@@ -209,6 +220,35 @@ static void aqc111_get_drvinfo(struct net_device *net, info->regdump_len =0x00 ; } +static void aqc111_get_wol (struct net_device *net, +struct ethtool_wolinfo *wolinfo) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; + + wolinfo->supported =WAKE_MAGIC ; + wolinfo->wolopts =0 ; + +if (aqc111_data->wol_flags &AQ_WOL_FLAG_MP ) + wolinfo->wolopts |=WAKE_MAGIC ; +} + +static int aqc111_set_wol (struct net_device *net, +struct ethtool_wolinfo *wolinfo) +{ +struct usbnet *dev =netdev_priv (net); +struct aqc111_data *aqc111_data = dev->driver_priv; + +if (wolinfo->wolopts & ~WAKE_MAGIC ) +return -EINVAL ; + + aqc111_data->wol_flags =0 ; +if (wolinfo->wolopts &WAKE_MAGIC ) + aqc111_data->wol_flags |=AQ_WOL_FLAG_MP ; + +return 0 ; +} +static void aqc111_speed_to_link_mode (u32 speed,struct ethtool_link_ksettings *elk) {
@@ -449,6 +489,8 @@ static int aqc111_set_link_ksettings(struct net_device *net,static const struct ethtool_ops aqc111_ethtool_ops = { .get_drvinfo = aqc111_get_drvinfo, + .get_wol = aqc111_get_wol, + .set_wol = aqc111_set_wol, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_link = ethtool_op_get_link,
@@ -1327,6 +1369,177 @@ static const struct driver_info aqc111_info = { .tx_fixup = aqc111_tx_fixup, }; +static int aqc111_suspend (struct usb_interface *intf,pm_message_t message) +{ +struct usbnet *dev =usb_get_intfdata (intf); +struct aqc111_data *aqc111_data = dev->driver_priv; +u16 temp_rx_ctrl =0x00 ; +u16 reg16; +u8 reg8; + +usbnet_suspend (intf, message); + +aqc111_read16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + temp_rx_ctrl = reg16; +/* Stop RX operations*/ + reg16 &= ~SFR_RX_CTL_START ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); +/* Force bz */ +aqc111_read16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_PHYPWR_RSTCTL , +2 , ®16); + reg16 |=SFR_PHYPWR_RSTCTL_BZ ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_PHYPWR_RSTCTL , +2 , ®16); + + reg8 =SFR_BULK_OUT_EFF_EN ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_BULK_OUT_CTRL , +1 ,1 , ®8); + + temp_rx_ctrl &= ~(SFR_RX_CTL_START |SFR_RX_CTL_RF_WAK | +SFR_RX_CTL_AP |SFR_RX_CTL_AM ); +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL , +2 , &temp_rx_ctrl); + + reg8 =0x00 ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_ETH_MAC_PATH , +1 ,1 , ®8); + +if (aqc111_data->wol_flags) { +struct aqc111_wol_cfg wol_cfg = {0 }; + + aqc111_data->phy_cfg |=AQ_WOL ; +if (aqc111_data->dpa) { + reg8 =0 ; +if (aqc111_data->wol_flags &AQ_WOL_FLAG_MP ) + reg8 |=SFR_MONITOR_MODE_RWMP ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_MONITOR_MODE ,1 ,1 , ®8); + }else { +ether_addr_copy (wol_cfg.hw_addr, dev->net->dev_addr); + wol_cfg.flags = aqc111_data->wol_flags; + } + + temp_rx_ctrl |= (SFR_RX_CTL_AB |SFR_RX_CTL_START ); +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL , +2 , &temp_rx_ctrl); + reg8 =0x00 ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_BM_INT_MASK , +1 ,1 , ®8); + reg8 =SFR_BMRX_DMA_EN ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_BMRX_DMA_CONTROL , +1 ,1 , ®8); + reg8 =SFR_RX_PATH_READY ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_ETH_MAC_PATH , +1 ,1 , ®8); + reg8 =0x07 ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QCTRL , +1 ,1 , ®8); + reg8 =0x00 ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_RX_BULKIN_QTIMR_LOW ,1 ,1 , ®8); +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_RX_BULKIN_QTIMR_HIGH ,1 ,1 , ®8); + reg8 =0xFF ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QSIZE , +1 ,1 , ®8); +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_BULKIN_QIFG , +1 ,1 , ®8); + +aqc111_read16_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_MEDIUM_STATUS_MODE ,2 , ®16); + reg16 |=SFR_MEDIUM_RECEIVE_EN ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_MEDIUM_STATUS_MODE ,2 , ®16); + +if (aqc111_data->dpa) { +aqc111_set_phy_speed (dev,AUTONEG_ENABLE ,SPEED_100 ); + }else { +aqc111_write_cmd (dev,AQ_WOL_CFG ,0 ,0 , +WOL_CFG_SIZE , &wol_cfg); +aqc111_write32_cmd (dev,AQ_PHY_OPS ,0 ,0 , + &aqc111_data->phy_cfg); + } + }else { + aqc111_data->phy_cfg |=AQ_LOW_POWER ; +if (!aqc111_data->dpa) { +aqc111_write32_cmd (dev,AQ_PHY_OPS ,0 ,0 , + &aqc111_data->phy_cfg); + }else { + reg16 =AQ_PHY_LOW_POWER_MODE ; +aqc111_mdio_write (dev,AQ_GLB_STD_CTRL_REG , +AQ_PHY_GLOBAL_ADDR , ®16); + } + +/* Disable RX path */ +aqc111_read16_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_MEDIUM_STATUS_MODE ,2 , ®16); + reg16 &= ~SFR_MEDIUM_RECEIVE_EN ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC , +SFR_MEDIUM_STATUS_MODE ,2 , ®16); + } + +return 0 ; +} + +static int aqc111_resume (struct usb_interface *intf) +{ +struct usbnet *dev =usb_get_intfdata (intf); +struct aqc111_data *aqc111_data = dev->driver_priv; +u16 reg16; +u8 reg8; + +netif_carrier_off (dev->net); + +/* Power up ethernet PHY */ + aqc111_data->phy_cfg |=AQ_PHY_POWER_EN ; + aqc111_data->phy_cfg &= ~AQ_LOW_POWER ; + aqc111_data->phy_cfg &= ~AQ_WOL ; +if (aqc111_data->dpa) { +aqc111_read_cmd_nopm (dev,AQ_PHY_POWER ,0 ,0 ,1 , ®8); +if (reg8 ==0x00 ) { + reg8 =0x02 ; +aqc111_write_cmd_nopm (dev,AQ_PHY_POWER ,0 ,0 , +1 , ®8); +msleep (200 ); + } + +aqc111_mdio_read (dev,AQ_GLB_STD_CTRL_REG ,AQ_PHY_GLOBAL_ADDR , + ®16); +if (reg16 &AQ_PHY_LOW_POWER_MODE ) { + reg16 &= ~AQ_PHY_LOW_POWER_MODE ; +aqc111_mdio_write (dev,AQ_GLB_STD_CTRL_REG , +AQ_PHY_GLOBAL_ADDR , ®16); + } + } + + reg8 =0xFF ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_BM_INT_MASK , +1 ,1 , ®8); +/* Configure RX control register => start operation */ + reg16 = aqc111_data->rxctl; + reg16 &= ~SFR_RX_CTL_START ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + + reg16 |=SFR_RX_CTL_START ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_RX_CTL ,2 , ®16); + +aqc111_set_phy_speed (dev, aqc111_data->autoneg, + aqc111_data->advertised_speed); + +aqc111_read16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + reg16 |=SFR_MEDIUM_RECEIVE_EN ; +aqc111_write16_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_MEDIUM_STATUS_MODE , +2 , ®16); + reg8 =SFR_RX_PATH_READY ; +aqc111_write_cmd_nopm (dev,AQ_ACCESS_MAC ,SFR_ETH_MAC_PATH , +1 ,1 , ®8); + reg8 =0x0 ; +aqc111_write_cmd (dev,AQ_ACCESS_MAC ,SFR_BMRX_DMA_CONTROL ,1 ,1 , ®8); + +return usbnet_resume (intf); +} +#define AQC111_USB_ETH_DEV (vid, pid, table) \ USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ .driver_info = (unsigned long)&(table)
@@ -1341,6 +1554,8 @@ static struct usb_driver aq_driver = { .name = "aqc111", .id_table = products, .probe = usbnet_probe, + .suspend = aqc111_suspend, + .resume = aqc111_resume, .disconnect = usbnet_disconnect, };
drivers/net/usb/aqc111.h +12 -0
@@ -19,6 +19,7 @@#define AQ_FLASH_PARAMETERS 0x20#define AQ_PHY_POWER 0x31#define AQ_PHY_CMD 0x32 +#define AQ_WOL_CFG 0x60#define AQ_PHY_OPS 0x61#define AQC111_PHY_ID 0x00
@@ -187,8 +188,18 @@#define AQ_DSH_RETRIES_SHIFT 0x18#define AQ_DSH_RETRIES_MASK 0xF000000 +#define AQ_WOL_FLAG_MP 0x2 +/******************************************************************************/ +struct aqc111_wol_cfg { +u8 hw_addr[6 ]; +u8 flags; +u8 rsvd[283 ]; +} __packed; + +#define WOL_CFG_SIZE sizeof(struct aqc111_wol_cfg) +struct aqc111_data {u16 rxctl;u8 rx_checksum;
@@ -203,6 +214,7 @@ struct aqc111_data { } fw_ver;u8 dpa;/*direct PHY access*/ u32 phy_cfg; +u8 wol_flags; };#define AQ_LS_MASK 0x8000
Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
drivers/net/usb/aqc111.c static const struct driver_info aqc111_info = { · line 1455
Quoted 6 lines
drivers/net/usb/aqc111.c +5
-0+static int aqc111_suspend (struct usb_interface *intf,pm_message_t message) +{ + +if (aqc111_data->dpa) { +aqc111_set_phy_speed (dev,AUTONEG_ENABLE ,SPEED_100 );
So this is better, you leave auto-neg enabled. But you really should be taking the link partners capabilities into account.
Andrew
Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
Quoted 6 lines
drivers/net/usb/aqc111.c static const struct driver_info aqc111_info = { · line 1455
Quoted 3 lines
drivers/net/usb/aqc111.c +3
-0+ +if (aqc111_data->dpa) { +aqc111_set_phy_speed (dev,AUTONEG_ENABLE ,SPEED_100 );So this is better, you leave auto-neg enabled. But you really should be taking the link partners capabilities into account.
We've considered that, but then thought about the following case:
After such a sleep state where partner's capabilities were considered, user may move with the unit and replug it into different link partner with other, incompatible speed mask. That will anyway lead to wol link failure.
In that sense it may be better to just select the most widely available 100M low power speed and don't do any intelligence here?
Regards,
Igor
Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
Quoted 5 lines
We've considered that, but then thought about the following case:
After such a sleep state where partner's capabilities were considered, user may move with the unit and replug it into different link partner with other, incompatible speed mask. That will anyway lead to wol link failure.
WOL for a nomadic device? Is that even a real use case?
Anyway, looking at the link partner capabilities is just really a corner case, that the LP only supports 1G. Do such devices exist?
So skipping this is fine. But if you use phylib, you pretty much get it for free if you want it.
Andrew
PATCH v2 20/21 net: usb: aqc111: Add ASIX's HW ids
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
It enables driver for ASIX products which are also based on aqc111/112U chips.
--- drivers/net/usb/aqc111.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
drivers/net/usb/aqc111.c +40 -0
@@ -1369,6 +1369,44 @@ static const struct driver_info aqc111_info = { .tx_fixup = aqc111_tx_fixup, }; +#define ASIX111_DESC \ +"ASIX USB 3.1 Gen1 to 5G Multi-Gigabit Ethernet Adapter" + +static const struct driver_info asix111_info = { + .description =ASIX111_DESC , + .bind = aqc111_bind, + .unbind = aqc111_unbind, + .status = aqc111_status, + .link_reset = aqc111_link_reset, + .reset = aqc111_reset, + .stop = aqc111_stop, + .flags =FLAG_ETHER |FLAG_FRAMING_AX | +FLAG_AVOID_UNLINK_URBS |FLAG_MULTI_PACKET , + .rx_fixup = aqc111_rx_fixup, + .tx_fixup = aqc111_tx_fixup, +}; + +#undef ASIX111_DESC + +#define ASIX112_DESC \ +"ASIX USB 3.1 Gen1 to 2.5G Multi-Gigabit Ethernet Adapter" + +static const struct driver_info asix112_info = { + .description =ASIX112_DESC , + .bind = aqc111_bind, + .unbind = aqc111_unbind, + .status = aqc111_status, + .link_reset = aqc111_link_reset, + .reset = aqc111_reset, + .stop = aqc111_stop, + .flags =FLAG_ETHER |FLAG_FRAMING_AX | +FLAG_AVOID_UNLINK_URBS |FLAG_MULTI_PACKET , + .rx_fixup = aqc111_rx_fixup, + .tx_fixup = aqc111_tx_fixup, +}; + +#undef ASIX112_DESC +static int aqc111_suspend (struct usb_interface *intf,pm_message_t message) {struct usbnet *dev =usb_get_intfdata (intf);
@@ -1546,6 +1584,8 @@ static int aqc111_resume(struct usb_interface *intf)static const struct usb_device_id products[] = { {AQC111_USB_ETH_DEV (0x2eca ,0xc101 , aqc111_info)}, + {AQC111_USB_ETH_DEV (0x0b95 ,0x2790 , asix111_info)}, + {AQC111_USB_ETH_DEV (0x0b95 ,0x2791 , asix112_info)}, { },/* END */ };MODULE_DEVICE_TABLE (usb, products);
PATCH v2 21/21 net: usb: aqc111: Extend cdc_ether blacklist
In reply to Igor RusskikhFrom: Dmitry Bezrukov <[email protected]>
Added Aquantia and ASIX device IDs to prevent loading cdc_ether for these devices. Our firmware reports CDC configuration simultaneously with vendor specific.
--- drivers/net/usb/cdc_ether.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
drivers/net/usb/cdc_ether.c +23 -0
@@ -562,6 +562,8 @@ static const struct driver_info wwan_info = {#define MICROSOFT_VENDOR_ID 0x045e#define UBLOX_VENDOR_ID 0x1546#define TPLINK_VENDOR_ID 0x2357 +#define AQUANTIA_VENDOR_ID 0x2eca +#define ASIX_VENDOR_ID 0x0b95static const struct usb_device_id products[] = {/* BLACKLIST !!
@@ -821,6 +823,27 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* Aquantia AQtion USB to 5GbE Controller (based on AQC111U) */ +{ +USB_DEVICE_AND_INTERFACE_INFO (AQUANTIA_VENDOR_ID ,0xc101 ,USB_CLASS_COMM , + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info =0 , +}, + +/* ASIX USB 3.1 Gen1 to 5G Multi-Gigabit Ethernet Adapter (based on AQC111U) */ +{ +USB_DEVICE_AND_INTERFACE_INFO (ASIX_VENDOR_ID ,0x2790 ,USB_CLASS_COMM , +USB_CDC_SUBCLASS_ETHERNET ,USB_CDC_PROTO_NONE ), + .driver_info = 0, +}, + +/* ASIX USB 3.1 Gen1 to 2.5G Multi-Gigabit Ethernet Adapter (based on AQC112U) */ +{ +USB_DEVICE_AND_INTERFACE_INFO (ASIX_VENDOR_ID ,0x2791 ,USB_CLASS_COMM , +USB_CDC_SUBCLASS_ETHERNET ,USB_CDC_PROTO_NONE ), + .driver_info = 0, +}, +/* WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive.