All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 net-next 00/21] Add support for Aquantia AQtion USB to 5/2.5GbE devices
@ 2018-11-13 14:44 Igor Russkikh
  2018-11-13 14:44   ` [v2,net-next,01/21] " Igor Russkikh
                   ` (20 more replies)
  0 siblings, 21 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

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

-- 
2.7.4

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 01/21] net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Initialize usb_driver structure skeleton

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 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

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 418b0904cecb..e5fb8ef2d815 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -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
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 27307a4ab003..99fd12be2111 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -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
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
new file mode 100644
index 000000000000..aaea2a4fcc9f
--- /dev/null
+++ b/drivers/net/usb/aqc111.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2002-2003 TiVo Inc.
+ * Copyright (C) 2017-2018 ASIX
+ * Copyright (C) 2018 Aquantia Corp.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+
+static const struct driver_info aqc111_info = {
+	.description	= "Aquantia AQtion USB to 5GbE Controller",
+};
+
+#define AQC111_USB_ETH_DEV(vid, pid, table) \
+	USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \
+	.driver_info = (unsigned long)&(table)
+
+static const struct usb_device_id products[] = {
+	{AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)},
+	{ },/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver aq_driver = {
+	.name		= "aqc111",
+	.id_table	= products,
+	.probe		= usbnet_probe,
+	.disconnect	= usbnet_disconnect,
+};
+
+module_usb_driver(aq_driver);
+
+MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers");
+MODULE_LICENSE("GPL");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,01/21] net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Initialize usb_driver structure skeleton

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 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

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 418b0904cecb..e5fb8ef2d815 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -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
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 27307a4ab003..99fd12be2111 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -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
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
new file mode 100644
index 000000000000..aaea2a4fcc9f
--- /dev/null
+++ b/drivers/net/usb/aqc111.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2002-2003 TiVo Inc.
+ * Copyright (C) 2017-2018 ASIX
+ * Copyright (C) 2018 Aquantia Corp.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+
+static const struct driver_info aqc111_info = {
+	.description	= "Aquantia AQtion USB to 5GbE Controller",
+};
+
+#define AQC111_USB_ETH_DEV(vid, pid, table) \
+	USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \
+	.driver_info = (unsigned long)&(table)
+
+static const struct usb_device_id products[] = {
+	{AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)},
+	{ },/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver aq_driver = {
+	.name		= "aqc111",
+	.id_table	= products,
+	.probe		= usbnet_probe,
+	.disconnect	= usbnet_disconnect,
+};
+
+module_usb_driver(aq_driver);
+
+MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers");
+MODULE_LICENSE("GPL");

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 02/21] net: usb: aqc111: Add bind and empty unbind callbacks
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Initialize net_device_ops structure

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index aaea2a4fcc9f..b54bb4a98ee3 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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) \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,02/21] net: usb: aqc111: Add bind and empty unbind callbacks
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Initialize net_device_ops structure

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index aaea2a4fcc9f..b54bb4a98ee3 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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) \

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 03/21] net: usb: aqc111: Add implementation of read and write commands
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Read/write command register defines and functions

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 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

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b54bb4a98ee3..34ed841b81dc 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
new file mode 100644
index 000000000000..f4302f7f0cc3
--- /dev/null
+++ b/drivers/net/usb/aqc111.h
@@ -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 <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * 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 */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,03/21] net: usb: aqc111: Add implementation of read and write commands
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Read/write command register defines and functions

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 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

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b54bb4a98ee3..34ed841b81dc 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
new file mode 100644
index 000000000000..f4302f7f0cc3
--- /dev/null
+++ b/drivers/net/usb/aqc111.h
@@ -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 <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * 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 */

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 04/21] net: usb: aqc111: Various callbacks implementation
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Reset, stop callbacks, driver unbind callback.
More register defines required for these callbacks.
Add helpers to read/write 16bit values

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c |  76 +++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 34ed841b81dc..b08af34a5417 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	reg16 = 0;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+				2, &reg16);
+}
+
+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, &reg8);
+
+	reg8 = 0x0;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, &reg8);
+
+	aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, &reg8);
+	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, &reg8);
+
+	return 0;
+}
+
+static int aqc111_stop(struct usbnet *dev)
+{
+	u16 reg16 = 0;
+
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+			  2, &reg16);
+	reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+			   2, &reg16);
+	reg16 = 0;
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+	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) \
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index f4302f7f0cc3..a252ccd78559 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -10,9 +10,110 @@
 #ifndef __LINUX_USBNET_AQC111_H
 #define __LINUX_USBNET_AQC111_H
 
+#define AQ_ACCESS_MAC			0x01
 #define AQ_PHY_POWER			0x31
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
 
+/* SFR Reg. ********************************************/
+
+#define SFR_GENERAL_STATUS		0x03
+#define SFR_CHIP_STATUS			0x05
+#define SFR_RX_CTL			0x0B
+	#define SFR_RX_CTL_TXPADCRC		0x0400
+	#define SFR_RX_CTL_IPE			0x0200
+	#define SFR_RX_CTL_DROPCRCERR		0x0100
+	#define SFR_RX_CTL_START		0x0080
+	#define SFR_RX_CTL_RF_WAK		0x0040
+	#define SFR_RX_CTL_AP			0x0020
+	#define SFR_RX_CTL_AM			0x0010
+	#define SFR_RX_CTL_AB			0x0008
+	#define SFR_RX_CTL_AMALL		0x0002
+	#define SFR_RX_CTL_PRO			0x0001
+	#define SFR_RX_CTL_STOP			0x0000
+#define SFR_INTER_PACKET_GAP_0		0x0D
+#define SFR_NODE_ID			0x10
+#define SFR_MULTI_FILTER_ARRY		0x16
+#define SFR_MEDIUM_STATUS_MODE		0x22
+	#define SFR_MEDIUM_XGMIIMODE		0x0001
+	#define SFR_MEDIUM_FULL_DUPLEX		0x0002
+	#define SFR_MEDIUM_RXFLOW_CTRLEN	0x0010
+	#define SFR_MEDIUM_TXFLOW_CTRLEN	0x0020
+	#define SFR_MEDIUM_JUMBO_EN		0x0040
+	#define SFR_MEDIUM_RECEIVE_EN		0x0100
+#define SFR_MONITOR_MODE		0x24
+	#define SFR_MONITOR_MODE_EPHYRW		0x01
+	#define SFR_MONITOR_MODE_RWLC		0x02
+	#define SFR_MONITOR_MODE_RWMP		0x04
+	#define SFR_MONITOR_MODE_RWWF		0x08
+	#define SFR_MONITOR_MODE_RW_FLAG	0x10
+	#define SFR_MONITOR_MODE_PMEPOL		0x20
+	#define SFR_MONITOR_MODE_PMETYPE	0x40
+#define SFR_PHYPWR_RSTCTL		0x26
+	#define SFR_PHYPWR_RSTCTL_BZ		0x0010
+	#define SFR_PHYPWR_RSTCTL_IPRL		0x0020
+#define SFR_VLAN_ID_ADDRESS		0x2A
+#define SFR_VLAN_ID_CONTROL		0x2B
+	#define SFR_VLAN_CONTROL_WE		0x0001
+	#define SFR_VLAN_CONTROL_RD		0x0002
+	#define SFR_VLAN_CONTROL_VSO		0x0010
+	#define SFR_VLAN_CONTROL_VFE		0x0020
+#define SFR_VLAN_ID_DATA0		0x2C
+#define SFR_VLAN_ID_DATA1		0x2D
+#define SFR_RX_BULKIN_QCTRL		0x2E
+	#define SFR_RX_BULKIN_QCTRL_TIME	0x01
+	#define SFR_RX_BULKIN_QCTRL_IFG		0x02
+	#define SFR_RX_BULKIN_QCTRL_SIZE	0x04
+#define SFR_RX_BULKIN_QTIMR_LOW		0x2F
+#define SFR_RX_BULKIN_QTIMR_HIGH	0x30
+#define SFR_RX_BULKIN_QSIZE		0x31
+#define SFR_RX_BULKIN_QIFG		0x32
+#define SFR_RXCOE_CTL			0x34
+	#define SFR_RXCOE_IP			0x01
+	#define SFR_RXCOE_TCP			0x02
+	#define SFR_RXCOE_UDP			0x04
+	#define SFR_RXCOE_ICMP			0x08
+	#define SFR_RXCOE_IGMP			0x10
+	#define SFR_RXCOE_TCPV6			0x20
+	#define SFR_RXCOE_UDPV6			0x40
+	#define SFR_RXCOE_ICMV6			0x80
+#define SFR_TXCOE_CTL			0x35
+	#define SFR_TXCOE_IP			0x01
+	#define SFR_TXCOE_TCP			0x02
+	#define SFR_TXCOE_UDP			0x04
+	#define SFR_TXCOE_ICMP			0x08
+	#define SFR_TXCOE_IGMP			0x10
+	#define SFR_TXCOE_TCPV6			0x20
+	#define SFR_TXCOE_UDPV6			0x40
+	#define SFR_TXCOE_ICMV6			0x80
+#define SFR_BM_INT_MASK			0x41
+#define SFR_BMRX_DMA_CONTROL		0x43
+	#define SFR_BMRX_DMA_EN			0x80
+#define SFR_BMTX_DMA_CONTROL		0x46
+#define SFR_PAUSE_WATERLVL_LOW		0x54
+#define SFR_PAUSE_WATERLVL_HIGH		0x55
+#define SFR_ARC_CTRL			0x9E
+#define SFR_SWP_CTRL			0xB1
+#define SFR_TX_PAUSE_RESEND_T		0xB2
+#define SFR_ETH_MAC_PATH		0xB7
+	#define SFR_RX_PATH_READY		0x01
+#define SFR_BULK_OUT_CTRL		0xB9
+	#define SFR_BULK_OUT_FLUSH_EN		0x01
+	#define SFR_BULK_OUT_EFF_EN		0x02
+
+static struct {
+	unsigned char ctrl;
+	unsigned char timer_l;
+	unsigned char timer_h;
+	unsigned char size;
+	unsigned char ifg;
+} AQC111_BULKIN_SIZE[] = {
+	/* xHCI & EHCI & OHCI */
+	{7, 0x00, 0x01, 0x1E, 0xFF},/* 10G, 5G, 2.5G, 1G */
+	{7, 0xA0, 0x00, 0x14, 0x00},/* 100M */
+	/* Jumbo packet */
+	{7, 0x00, 0x01, 0x18, 0xFF},
+};
+
 #endif /* __LINUX_USBNET_AQC111_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,04/21] net: usb: aqc111: Various callbacks implementation
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Reset, stop callbacks, driver unbind callback.
More register defines required for these callbacks.
Add helpers to read/write 16bit values

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c |  76 +++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 34ed841b81dc..b08af34a5417 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	reg16 = 0;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+				2, &reg16);
+}
+
+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, &reg8);
+
+	reg8 = 0x0;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, &reg8);
+
+	aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, &reg8);
+	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, &reg8);
+
+	return 0;
+}
+
+static int aqc111_stop(struct usbnet *dev)
+{
+	u16 reg16 = 0;
+
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+			  2, &reg16);
+	reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+			   2, &reg16);
+	reg16 = 0;
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+	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) \
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index f4302f7f0cc3..a252ccd78559 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -10,9 +10,110 @@
 #ifndef __LINUX_USBNET_AQC111_H
 #define __LINUX_USBNET_AQC111_H
 
+#define AQ_ACCESS_MAC			0x01
 #define AQ_PHY_POWER			0x31
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
 
+/* SFR Reg. ********************************************/
+
+#define SFR_GENERAL_STATUS		0x03
+#define SFR_CHIP_STATUS			0x05
+#define SFR_RX_CTL			0x0B
+	#define SFR_RX_CTL_TXPADCRC		0x0400
+	#define SFR_RX_CTL_IPE			0x0200
+	#define SFR_RX_CTL_DROPCRCERR		0x0100
+	#define SFR_RX_CTL_START		0x0080
+	#define SFR_RX_CTL_RF_WAK		0x0040
+	#define SFR_RX_CTL_AP			0x0020
+	#define SFR_RX_CTL_AM			0x0010
+	#define SFR_RX_CTL_AB			0x0008
+	#define SFR_RX_CTL_AMALL		0x0002
+	#define SFR_RX_CTL_PRO			0x0001
+	#define SFR_RX_CTL_STOP			0x0000
+#define SFR_INTER_PACKET_GAP_0		0x0D
+#define SFR_NODE_ID			0x10
+#define SFR_MULTI_FILTER_ARRY		0x16
+#define SFR_MEDIUM_STATUS_MODE		0x22
+	#define SFR_MEDIUM_XGMIIMODE		0x0001
+	#define SFR_MEDIUM_FULL_DUPLEX		0x0002
+	#define SFR_MEDIUM_RXFLOW_CTRLEN	0x0010
+	#define SFR_MEDIUM_TXFLOW_CTRLEN	0x0020
+	#define SFR_MEDIUM_JUMBO_EN		0x0040
+	#define SFR_MEDIUM_RECEIVE_EN		0x0100
+#define SFR_MONITOR_MODE		0x24
+	#define SFR_MONITOR_MODE_EPHYRW		0x01
+	#define SFR_MONITOR_MODE_RWLC		0x02
+	#define SFR_MONITOR_MODE_RWMP		0x04
+	#define SFR_MONITOR_MODE_RWWF		0x08
+	#define SFR_MONITOR_MODE_RW_FLAG	0x10
+	#define SFR_MONITOR_MODE_PMEPOL		0x20
+	#define SFR_MONITOR_MODE_PMETYPE	0x40
+#define SFR_PHYPWR_RSTCTL		0x26
+	#define SFR_PHYPWR_RSTCTL_BZ		0x0010
+	#define SFR_PHYPWR_RSTCTL_IPRL		0x0020
+#define SFR_VLAN_ID_ADDRESS		0x2A
+#define SFR_VLAN_ID_CONTROL		0x2B
+	#define SFR_VLAN_CONTROL_WE		0x0001
+	#define SFR_VLAN_CONTROL_RD		0x0002
+	#define SFR_VLAN_CONTROL_VSO		0x0010
+	#define SFR_VLAN_CONTROL_VFE		0x0020
+#define SFR_VLAN_ID_DATA0		0x2C
+#define SFR_VLAN_ID_DATA1		0x2D
+#define SFR_RX_BULKIN_QCTRL		0x2E
+	#define SFR_RX_BULKIN_QCTRL_TIME	0x01
+	#define SFR_RX_BULKIN_QCTRL_IFG		0x02
+	#define SFR_RX_BULKIN_QCTRL_SIZE	0x04
+#define SFR_RX_BULKIN_QTIMR_LOW		0x2F
+#define SFR_RX_BULKIN_QTIMR_HIGH	0x30
+#define SFR_RX_BULKIN_QSIZE		0x31
+#define SFR_RX_BULKIN_QIFG		0x32
+#define SFR_RXCOE_CTL			0x34
+	#define SFR_RXCOE_IP			0x01
+	#define SFR_RXCOE_TCP			0x02
+	#define SFR_RXCOE_UDP			0x04
+	#define SFR_RXCOE_ICMP			0x08
+	#define SFR_RXCOE_IGMP			0x10
+	#define SFR_RXCOE_TCPV6			0x20
+	#define SFR_RXCOE_UDPV6			0x40
+	#define SFR_RXCOE_ICMV6			0x80
+#define SFR_TXCOE_CTL			0x35
+	#define SFR_TXCOE_IP			0x01
+	#define SFR_TXCOE_TCP			0x02
+	#define SFR_TXCOE_UDP			0x04
+	#define SFR_TXCOE_ICMP			0x08
+	#define SFR_TXCOE_IGMP			0x10
+	#define SFR_TXCOE_TCPV6			0x20
+	#define SFR_TXCOE_UDPV6			0x40
+	#define SFR_TXCOE_ICMV6			0x80
+#define SFR_BM_INT_MASK			0x41
+#define SFR_BMRX_DMA_CONTROL		0x43
+	#define SFR_BMRX_DMA_EN			0x80
+#define SFR_BMTX_DMA_CONTROL		0x46
+#define SFR_PAUSE_WATERLVL_LOW		0x54
+#define SFR_PAUSE_WATERLVL_HIGH		0x55
+#define SFR_ARC_CTRL			0x9E
+#define SFR_SWP_CTRL			0xB1
+#define SFR_TX_PAUSE_RESEND_T		0xB2
+#define SFR_ETH_MAC_PATH		0xB7
+	#define SFR_RX_PATH_READY		0x01
+#define SFR_BULK_OUT_CTRL		0xB9
+	#define SFR_BULK_OUT_FLUSH_EN		0x01
+	#define SFR_BULK_OUT_EFF_EN		0x02
+
+static struct {
+	unsigned char ctrl;
+	unsigned char timer_l;
+	unsigned char timer_h;
+	unsigned char size;
+	unsigned char ifg;
+} AQC111_BULKIN_SIZE[] = {
+	/* xHCI & EHCI & OHCI */
+	{7, 0x00, 0x01, 0x1E, 0xFF},/* 10G, 5G, 2.5G, 1G */
+	{7, 0xA0, 0x00, 0x14, 0x00},/* 100M */
+	/* Jumbo packet */
+	{7, 0x00, 0x01, 0x18, 0xFF},
+};
+
 #endif /* __LINUX_USBNET_AQC111_H */

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 05/21] net: usb: aqc111: Introduce PHY access
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

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.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  44 +++++++++++++++++++
 2 files changed, 153 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b08af34a5417..c91acb7b7c4e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+
+	/* Power down ethernet PHY */
+	if (aqc111_data->dpa) {
+		reg8 = 0x00;
+		aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0,
+				      0, 1, &reg8);
+	} 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, &reg8);
+		if (reg8 == 0x00) {
+			reg8 = 0x02;
+			aqc111_write_cmd(dev, AQ_PHY_POWER, 0, 0, 1, &reg8);
+			msleep(200);
+		}
+
+		aqc111_mdio_read(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+				 &reg16);
+		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, &reg16);
+		}
+	} 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, &reg8);
 
@@ -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, &reg16);
 
+	/* 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,
+				  &reg16);
+	} else {
+		aqc111_data->phy_cfg |= AQ_LOW_POWER;
+		aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
+				   &aqc111_data->phy_cfg);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a252ccd78559..ac0bbeabf563 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -12,6 +12,17 @@
 
 #define AQ_ACCESS_MAC			0x01
 #define AQ_PHY_POWER			0x31
+#define AQ_PHY_CMD			0x32
+#define AQ_PHY_OPS			0x61
+
+#define AQC111_PHY_ID			0x00
+#define AQ_PHY_ADDR(mmd)		((AQC111_PHY_ID << 8) | mmd)
+
+#define AQ_PHY_GLOBAL_MMD		0x1E
+#define AQ_PHY_GLOBAL_ADDR		AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
+
+#define AQ_GLB_STD_CTRL_REG		0x0000
+	#define AQ_PHY_LOW_POWER_MODE		0x0800
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
@@ -102,6 +113,39 @@
 	#define SFR_BULK_OUT_FLUSH_EN		0x01
 	#define SFR_BULK_OUT_EFF_EN		0x02
 
+#define AQ_FW_VER_MAJOR			0xDA
+#define AQ_FW_VER_MINOR			0xDB
+#define AQ_FW_VER_REV			0xDC
+
+/*PHY_OPS**********************************************************************/
+
+#define AQ_ADV_100M	BIT(0)
+#define AQ_ADV_1G	BIT(1)
+#define AQ_ADV_2G5	BIT(2)
+#define AQ_ADV_5G	BIT(3)
+
+#define AQ_PAUSE	BIT(16)
+#define AQ_ASYM_PAUSE	BIT(17)
+#define AQ_LOW_POWER	BIT(18)
+#define AQ_PHY_POWER_EN	BIT(19)
+#define AQ_WOL		BIT(20)
+#define AQ_DOWNSHIFT	BIT(21)
+
+#define AQ_DSH_RETRIES_SHIFT	0x18
+#define AQ_DSH_RETRIES_MASK	0xF000000
+
+/******************************************************************************/
+
+struct aqc111_data {
+	struct {
+		u8 major;
+		u8 minor;
+		u8 rev;
+	} fw_ver;
+	u8 dpa; /*direct PHY access*/
+	u32 phy_cfg;
+};
+
 static struct {
 	unsigned char ctrl;
 	unsigned char timer_l;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,05/21] net: usb: aqc111: Introduce PHY access
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

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.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  44 +++++++++++++++++++
 2 files changed, 153 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b08af34a5417..c91acb7b7c4e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+
+	/* Power down ethernet PHY */
+	if (aqc111_data->dpa) {
+		reg8 = 0x00;
+		aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0,
+				      0, 1, &reg8);
+	} 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, &reg8);
+		if (reg8 == 0x00) {
+			reg8 = 0x02;
+			aqc111_write_cmd(dev, AQ_PHY_POWER, 0, 0, 1, &reg8);
+			msleep(200);
+		}
+
+		aqc111_mdio_read(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+				 &reg16);
+		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, &reg16);
+		}
+	} 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, &reg8);
 
@@ -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, &reg16);
 
+	/* 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,
+				  &reg16);
+	} else {
+		aqc111_data->phy_cfg |= AQ_LOW_POWER;
+		aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
+				   &aqc111_data->phy_cfg);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a252ccd78559..ac0bbeabf563 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -12,6 +12,17 @@
 
 #define AQ_ACCESS_MAC			0x01
 #define AQ_PHY_POWER			0x31
+#define AQ_PHY_CMD			0x32
+#define AQ_PHY_OPS			0x61
+
+#define AQC111_PHY_ID			0x00
+#define AQ_PHY_ADDR(mmd)		((AQC111_PHY_ID << 8) | mmd)
+
+#define AQ_PHY_GLOBAL_MMD		0x1E
+#define AQ_PHY_GLOBAL_ADDR		AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
+
+#define AQ_GLB_STD_CTRL_REG		0x0000
+	#define AQ_PHY_LOW_POWER_MODE		0x0800
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
@@ -102,6 +113,39 @@
 	#define SFR_BULK_OUT_FLUSH_EN		0x01
 	#define SFR_BULK_OUT_EFF_EN		0x02
 
+#define AQ_FW_VER_MAJOR			0xDA
+#define AQ_FW_VER_MINOR			0xDB
+#define AQ_FW_VER_REV			0xDC
+
+/*PHY_OPS**********************************************************************/
+
+#define AQ_ADV_100M	BIT(0)
+#define AQ_ADV_1G	BIT(1)
+#define AQ_ADV_2G5	BIT(2)
+#define AQ_ADV_5G	BIT(3)
+
+#define AQ_PAUSE	BIT(16)
+#define AQ_ASYM_PAUSE	BIT(17)
+#define AQ_LOW_POWER	BIT(18)
+#define AQ_PHY_POWER_EN	BIT(19)
+#define AQ_WOL		BIT(20)
+#define AQ_DOWNSHIFT	BIT(21)
+
+#define AQ_DSH_RETRIES_SHIFT	0x18
+#define AQ_DSH_RETRIES_MASK	0xF000000
+
+/******************************************************************************/
+
+struct aqc111_data {
+	struct {
+		u8 major;
+		u8 minor;
+		u8 rev;
+	} fw_ver;
+	u8 dpa; /*direct PHY access*/
+	u32 phy_cfg;
+};
+
 static struct {
 	unsigned char ctrl;
 	unsigned char timer_l;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Add full hardware initialization sequence and link configuration logic

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  45 +++++++
 2 files changed, 357 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index c91acb7b7c4e..2b78b5d7d29b 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
+			  &reg16_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, &reg16_1);
+	aqc111_mdio_write(dev, AQ_AUTONEG_10GT_CTRL_REG,
+			  AQ_PHY_AUTONEG_ADDR, &reg16_2);
+
+	aqc111_mdio_read(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+			 &reg16_1);
+	reg16_1 &= ~AQ_ANEG_ABILITY_MASK;
+	reg16_1 |= reg16_3;
+	aqc111_mdio_write(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+			  &reg16_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, &reg16_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, &reg8);
 	} 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, &reg16);
+		aqc111_mdio_write(dev, AQ_GLB_EGR_PAUSE_CTRL_REG,
+				  AQ_PHY_AUTONEG_ADDR, &reg16);
+	}
+
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0,
+			 1, 1, &reg8);
+
+	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, &reg16);
+	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, &reg8);
+
+		reg8 = 0x0;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+				 1, 1, &reg8);
+
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL,
+				 1, 1, &reg8);
+
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, &reg8);
+
+		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		reg8 = SFR_RX_PATH_READY;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+				 1, 1, &reg8);
+
+		reg8 = SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+
+		reg16 = 0;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				  2, &reg16);
+
+		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, &reg16);
+
+		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		netif_carrier_on(dev->net);
+	} else {
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				  2, &reg16);
+		reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		reg16 &= ~SFR_RX_CTL_START;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+		reg8 = SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+
+		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, &reg8);
 
+	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,
 };
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index ac0bbeabf563..fd49a43e6d93 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,12 +18,44 @@
 #define AQC111_PHY_ID			0x00
 #define AQ_PHY_ADDR(mmd)		((AQC111_PHY_ID << 8) | mmd)
 
+#define AQ_PHY_AUTONEG_MMD		0x07
+#define AQ_PHY_AUTONEG_ADDR		AQ_PHY_ADDR(AQ_PHY_AUTONEG_MMD)
+
+#define AQ_AUTONEG_STD_CTRL_REG		0x0000
+	#define AQ_ANEG_EX_PAGE_CTRL		0x2000
+	#define AQ_ANEG_EN_ANEG			0x1000
+	#define AQ_ANEG_RESTART_ANEG		0x0200
+
+#define AQ_AUTONEG_ADV_REG		0x0010
+	#define AQ_ANEG_100M			0x0100
+	#define AQ_ANEG_PAUSE			0x0400
+	#define AQ_ANEG_ASYM_PAUSE		0x0800
+	#define AQ_ANEG_ABILITY_MASK		0x0FE0
+
+#define AQ_AUTONEG_10GT_CTRL_REG	0x0020
+	#define AQ_ANEG_ADV_10G_T		0x1000
+	#define AQ_ANEG_ADV_5G_T		0x0100
+	#define AQ_ANEG_ADV_2G5_T		0x0080
+	#define AQ_ANEG_ADV_LT			0x0001
+
+#define AQ_AUTONEG_VEN_PROV1_REG	0xC400
+	#define AQ_ANEG_ADV_1G			0x8000
+	#define AQ_ANEG_ADV_AQRATE		0x1000
+	#define AQ_ANEG_ADV_5G_N		0x0800
+	#define AQ_ANEG_ADV_2G5_N		0x0400
+	#define AQ_ANEG_EX_PHY_ID		0x0040
+	#define AQ_ANEG_EN_DSH			0x0010
+	#define AQ_ANEG_DSH_RETRY		0x0003
+
 #define AQ_PHY_GLOBAL_MMD		0x1E
 #define AQ_PHY_GLOBAL_ADDR		AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
 
 #define AQ_GLB_STD_CTRL_REG		0x0000
 	#define AQ_PHY_LOW_POWER_MODE		0x0800
 
+#define AQ_GLB_ING_PAUSE_CTRL_REG	0x7148
+#define AQ_GLB_EGR_PAUSE_CTRL_REG	0x4148
+
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
 
@@ -123,6 +155,7 @@
 #define AQ_ADV_1G	BIT(1)
 #define AQ_ADV_2G5	BIT(2)
 #define AQ_ADV_5G	BIT(3)
+#define AQ_ADV_MASK	0x0F
 
 #define AQ_PAUSE	BIT(16)
 #define AQ_ASYM_PAUSE	BIT(17)
@@ -137,6 +170,10 @@
 /******************************************************************************/
 
 struct aqc111_data {
+	u8 link_speed;
+	u8 link;
+	u8 autoneg;
+	u32 advertised_speed;
 	struct {
 		u8 major;
 		u8 minor;
@@ -146,6 +183,14 @@ struct aqc111_data {
 	u32 phy_cfg;
 };
 
+#define AQ_LS_MASK		0x8000
+#define AQ_SPEED_MASK		0x7F00
+#define AQ_SPEED_SHIFT		0x0008
+#define AQ_INT_SPEED_5G		0x000F
+#define AQ_INT_SPEED_2_5G	0x0010
+#define AQ_INT_SPEED_1G		0x0011
+#define AQ_INT_SPEED_100M	0x0013
+
 static struct {
 	unsigned char ctrl;
 	unsigned char timer_l;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Add full hardware initialization sequence and link configuration logic

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  45 +++++++
 2 files changed, 357 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index c91acb7b7c4e..2b78b5d7d29b 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
+			  &reg16_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, &reg16_1);
+	aqc111_mdio_write(dev, AQ_AUTONEG_10GT_CTRL_REG,
+			  AQ_PHY_AUTONEG_ADDR, &reg16_2);
+
+	aqc111_mdio_read(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+			 &reg16_1);
+	reg16_1 &= ~AQ_ANEG_ABILITY_MASK;
+	reg16_1 |= reg16_3;
+	aqc111_mdio_write(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+			  &reg16_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, &reg16_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, &reg8);
 	} 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, &reg16);
+		aqc111_mdio_write(dev, AQ_GLB_EGR_PAUSE_CTRL_REG,
+				  AQ_PHY_AUTONEG_ADDR, &reg16);
+	}
+
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0,
+			 1, 1, &reg8);
+
+	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, &reg16);
+	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, &reg8);
+
+		reg8 = 0x0;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+				 1, 1, &reg8);
+
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL,
+				 1, 1, &reg8);
+
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, &reg8);
+
+		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		reg8 = SFR_RX_PATH_READY;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+				 1, 1, &reg8);
+
+		reg8 = SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+
+		reg16 = 0;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				  2, &reg16);
+
+		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, &reg16);
+
+		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		netif_carrier_on(dev->net);
+	} else {
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				  2, &reg16);
+		reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				   2, &reg16);
+
+		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		reg16 &= ~SFR_RX_CTL_START;
+		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+		reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+		reg8 = SFR_BULK_OUT_EFF_EN;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+				 1, 1, &reg8);
+
+		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, &reg8);
 
+	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,
 };
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index ac0bbeabf563..fd49a43e6d93 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,12 +18,44 @@
 #define AQC111_PHY_ID			0x00
 #define AQ_PHY_ADDR(mmd)		((AQC111_PHY_ID << 8) | mmd)
 
+#define AQ_PHY_AUTONEG_MMD		0x07
+#define AQ_PHY_AUTONEG_ADDR		AQ_PHY_ADDR(AQ_PHY_AUTONEG_MMD)
+
+#define AQ_AUTONEG_STD_CTRL_REG		0x0000
+	#define AQ_ANEG_EX_PAGE_CTRL		0x2000
+	#define AQ_ANEG_EN_ANEG			0x1000
+	#define AQ_ANEG_RESTART_ANEG		0x0200
+
+#define AQ_AUTONEG_ADV_REG		0x0010
+	#define AQ_ANEG_100M			0x0100
+	#define AQ_ANEG_PAUSE			0x0400
+	#define AQ_ANEG_ASYM_PAUSE		0x0800
+	#define AQ_ANEG_ABILITY_MASK		0x0FE0
+
+#define AQ_AUTONEG_10GT_CTRL_REG	0x0020
+	#define AQ_ANEG_ADV_10G_T		0x1000
+	#define AQ_ANEG_ADV_5G_T		0x0100
+	#define AQ_ANEG_ADV_2G5_T		0x0080
+	#define AQ_ANEG_ADV_LT			0x0001
+
+#define AQ_AUTONEG_VEN_PROV1_REG	0xC400
+	#define AQ_ANEG_ADV_1G			0x8000
+	#define AQ_ANEG_ADV_AQRATE		0x1000
+	#define AQ_ANEG_ADV_5G_N		0x0800
+	#define AQ_ANEG_ADV_2G5_N		0x0400
+	#define AQ_ANEG_EX_PHY_ID		0x0040
+	#define AQ_ANEG_EN_DSH			0x0010
+	#define AQ_ANEG_DSH_RETRY		0x0003
+
 #define AQ_PHY_GLOBAL_MMD		0x1E
 #define AQ_PHY_GLOBAL_ADDR		AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
 
 #define AQ_GLB_STD_CTRL_REG		0x0000
 	#define AQ_PHY_LOW_POWER_MODE		0x0800
 
+#define AQ_GLB_ING_PAUSE_CTRL_REG	0x7148
+#define AQ_GLB_EGR_PAUSE_CTRL_REG	0x4148
+
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
 
@@ -123,6 +155,7 @@
 #define AQ_ADV_1G	BIT(1)
 #define AQ_ADV_2G5	BIT(2)
 #define AQ_ADV_5G	BIT(3)
+#define AQ_ADV_MASK	0x0F
 
 #define AQ_PAUSE	BIT(16)
 #define AQ_ASYM_PAUSE	BIT(17)
@@ -137,6 +170,10 @@
 /******************************************************************************/
 
 struct aqc111_data {
+	u8 link_speed;
+	u8 link;
+	u8 autoneg;
+	u32 advertised_speed;
 	struct {
 		u8 major;
 		u8 minor;
@@ -146,6 +183,14 @@ struct aqc111_data {
 	u32 phy_cfg;
 };
 
+#define AQ_LS_MASK		0x8000
+#define AQ_SPEED_MASK		0x7F00
+#define AQ_SPEED_SHIFT		0x0008
+#define AQ_INT_SPEED_5G		0x000F
+#define AQ_INT_SPEED_2_5G	0x0010
+#define AQ_INT_SPEED_1G		0x0011
+#define AQ_INT_SPEED_100M	0x0013
+
 static struct {
 	unsigned char ctrl;
 	unsigned char timer_l;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 07/21] net: usb: aqc111: Add support for getting and setting of MAC address
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  1 +
 2 files changed, 48 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 2b78b5d7d29b..15b86dee7bca 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index fd49a43e6d93..a6359ff759cd 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,07/21] net: usb: aqc111: Add support for getting and setting of MAC address
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  1 +
 2 files changed, 48 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 2b78b5d7d29b..15b86dee7bca 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index fd49a43e6d93..a6359ff759cd 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 08/21] net: usb: aqc111: Implement TX data path
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  8 ++++++
 2 files changed, 80 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 15b86dee7bca..b630a8342ef2 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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) \
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a6359ff759cd..a3d9d7dde240 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,08/21] net: usb: aqc111: Implement TX data path
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  8 ++++++
 2 files changed, 80 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 15b86dee7bca..b630a8342ef2 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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) \
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a6359ff759cd..a3d9d7dde240 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 09/21] net: usb: aqc111: Implement RX data path
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  15 +++++++
 2 files changed, 118 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b630a8342ef2..ae101b44a109 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
 };
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a3d9d7dde240..aa0b37ebabae 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,09/21] net: usb: aqc111: Implement RX data path
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  15 +++++++
 2 files changed, 118 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b630a8342ef2..ae101b44a109 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
 };
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a3d9d7dde240..aa0b37ebabae 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 10/21] net: usb: aqc111: Add checksum offload support
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 38 ++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h | 16 ++++++++++++++--
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index ae101b44a109..90061157b7ac 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+
+	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, &reg8);
+}
+
 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, &reg16);
 
+		aqc111_configure_csum_offload(dev);
+
 		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				  2, &reg16);
 
@@ -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)
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index aa0b37ebabae..20637fd58be3 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,10/21] net: usb: aqc111: Add checksum offload support
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 38 ++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h | 16 ++++++++++++++--
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index ae101b44a109..90061157b7ac 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+
+	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, &reg8);
+}
+
 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, &reg16);
 
+		aqc111_configure_csum_offload(dev);
+
 		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				  2, &reg16);
 
@@ -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)
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index aa0b37ebabae..20637fd58be3 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 11/21] net: usb: aqc111: Add support for changing MTU
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 90061157b7ac..e197824f96f1 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	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, &reg16);
+
+	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, &reg16);
+
+	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, &reg16);
@@ -604,6 +659,9 @@ static int aqc111_link_reset(struct usbnet *dev)
 		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				  2, &reg16);
 
+		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,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,11/21] net: usb: aqc111: Add support for changing MTU
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 90061157b7ac..e197824f96f1 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	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, &reg16);
+
+	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, &reg16);
+
+	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, &reg16);
@@ -604,6 +659,9 @@ static int aqc111_link_reset(struct usbnet *dev)
 		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				  2, &reg16);
 
+		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,

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 12/21] net: usb: aqc111: Add support for enable/disable checksum offload
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/usb/aqc111.h |  1 +
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index e197824f96f1..891d6832b87c 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+		reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+				 1, 1, &reg8);
+	}
+
+	if (changed & NETIF_F_IPV6_CSUM) {
+		aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, &reg8);
+		reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+				 1, 1, &reg8);
+	}
+
+	if (changed & NETIF_F_RXCSUM) {
+		aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, &reg8);
+		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, &reg8);
+	}
+	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)
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 20637fd58be3..477815f8b7de 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -180,6 +180,7 @@
 /******************************************************************************/
 
 struct aqc111_data {
+	u8 rx_checksum;
 	u8 link_speed;
 	u8 link;
 	u8 autoneg;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,12/21] net: usb: aqc111: Add support for enable/disable checksum offload
@ 2018-11-13 14:44   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:44 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/usb/aqc111.h |  1 +
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index e197824f96f1..891d6832b87c 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+		reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+				 1, 1, &reg8);
+	}
+
+	if (changed & NETIF_F_IPV6_CSUM) {
+		aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, &reg8);
+		reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6;
+		aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+				 1, 1, &reg8);
+	}
+
+	if (changed & NETIF_F_RXCSUM) {
+		aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, &reg8);
+		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, &reg8);
+	}
+	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)
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 20637fd58be3..477815f8b7de 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -180,6 +180,7 @@
 /******************************************************************************/
 
 struct aqc111_data {
+	u8 rx_checksum;
 	u8 link_speed;
 	u8 link;
 	u8 autoneg;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 13/21] net: usb: aqc111: Add support for TSO
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 4 ++++
 drivers/net/usb/aqc111.h | 8 ++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 891d6832b87c..2cbdca3d8dfc 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 477815f8b7de..b27c4db22a51 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,13/21] net: usb: aqc111: Add support for TSO
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 4 ++++
 drivers/net/usb/aqc111.h | 8 ++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 891d6832b87c..2cbdca3d8dfc 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 477815f8b7de..b27c4db22a51 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
 

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 14/21] net: usb: aqc111: Implement set_rx_mode callback
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/net/usb/aqc111.h |  4 +++
 2 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 2cbdca3d8dfc..65f65fd043f2 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
 
 		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+		aqc111_data->rxctl = reg16;
 		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
 
 		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, &reg16);
 
@@ -708,8 +769,9 @@ static int aqc111_link_reset(struct usbnet *dev)
 		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				   2, &reg16);
 
-		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
-		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		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, &reg16);
 
-		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
-		reg16 &= ~SFR_RX_CTL_START;
-		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		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,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index b27c4db22a51..fdd7c1059fac 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,14/21] net: usb: aqc111: Implement set_rx_mode callback
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 72 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/net/usb/aqc111.h |  4 +++
 2 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 2cbdca3d8dfc..65f65fd043f2 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
 
 		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+		aqc111_data->rxctl = reg16;
 		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
 
 		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, &reg16);
 
@@ -708,8 +769,9 @@ static int aqc111_link_reset(struct usbnet *dev)
 		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
 				   2, &reg16);
 
-		reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
-		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		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, &reg16);
 
-		aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
-		reg16 &= ~SFR_RX_CTL_START;
-		aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+		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,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index b27c4db22a51..fdd7c1059fac 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 15/21] net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 17 +++++++++++++++++
 drivers/net/usb/aqc111.h | 12 +++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 65f65fd043f2..778d8199031e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index fdd7c1059fac..69113fb8d25f 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,15/21] net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 17 +++++++++++++++++
 drivers/net/usb/aqc111.h | 12 +++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 65f65fd043f2..778d8199031e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index fdd7c1059fac..69113fb8d25f 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 16/21] net: usb: aqc111: Add RX VLAN filtering support
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  2 +-
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 778d8199031e..34e09492fb0e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+	vlan_ctrl = reg8;
+
+	/* Address */
+	reg8 = (vid / 16);
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, &reg8);
+	/* Data */
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg16 &= ~(1 << (vid % 16));
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+
+	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, &reg8);
+	vlan_ctrl = reg8;
+
+	/* Address */
+	reg8 = (vid / 16);
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, &reg8);
+	/* Data */
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg16 |= (1 << (vid % 16));
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+
+	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, &reg8);
 	}
+	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, &reg8);
+				/* Data */
+				aqc111_write16_cmd(dev, AQ_ACCESS_MAC,
+						   SFR_VLAN_ID_DATA0,
+						   2, &reg16);
+				reg8 = SFR_VLAN_CONTROL_WE;
+				aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+						 SFR_VLAN_ID_CONTROL,
+						 1, 1, &reg8);
+			}
+			aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+					1, 1, &reg8);
+			reg8 |= SFR_VLAN_CONTROL_VFE;
+			aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+					 SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+		} else {
+			aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+					1, 1, &reg8);
+			reg8 &= ~SFR_VLAN_CONTROL_VFE;
+			aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+					 SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+		}
+	}
+
 	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, &reg8);
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 69113fb8d25f..6c951ca5d261 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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 |\
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,16/21] net: usb: aqc111: Add RX VLAN filtering support
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  2 +-
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 778d8199031e..34e09492fb0e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg8);
+	vlan_ctrl = reg8;
+
+	/* Address */
+	reg8 = (vid / 16);
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, &reg8);
+	/* Data */
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg16 &= ~(1 << (vid % 16));
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+
+	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, &reg8);
+	vlan_ctrl = reg8;
+
+	/* Address */
+	reg8 = (vid / 16);
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, &reg8);
+	/* Data */
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+	aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg16 |= (1 << (vid % 16));
+	aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, &reg16);
+	reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+
+	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, &reg8);
 	}
+	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, &reg8);
+				/* Data */
+				aqc111_write16_cmd(dev, AQ_ACCESS_MAC,
+						   SFR_VLAN_ID_DATA0,
+						   2, &reg16);
+				reg8 = SFR_VLAN_CONTROL_WE;
+				aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+						 SFR_VLAN_ID_CONTROL,
+						 1, 1, &reg8);
+			}
+			aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+					1, 1, &reg8);
+			reg8 |= SFR_VLAN_CONTROL_VFE;
+			aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+					 SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+		} else {
+			aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+					1, 1, &reg8);
+			reg8 &= ~SFR_VLAN_CONTROL_VFE;
+			aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+					 SFR_VLAN_ID_CONTROL, 1, 1, &reg8);
+		}
+	}
+
 	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, &reg8);
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 69113fb8d25f..6c951ca5d261 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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 |\

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 17/21] net: usb: aqc111: Initialize ethtool_ops structure
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Implement get_drvinfo, set/get_msglevel, get_link callbacks

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 34e09492fb0e..b3160b0320eb 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,17/21] net: usb: aqc111: Initialize ethtool_ops structure
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Implement get_drvinfo, set/get_msglevel, get_link callbacks

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 34e09492fb0e..b3160b0320eb 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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;

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b3160b0320eb..80fedf2ab2dd 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index b3160b0320eb..80fedf2ab2dd 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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)

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  12 +++
 2 files changed, 227 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 80fedf2ab2dd..16d1934cc815 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	temp_rx_ctrl = reg16;
+	/* Stop RX operations*/
+	reg16 &= ~SFR_RX_CTL_START;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+	/* Force bz */
+	aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+			       2, &reg16);
+	reg16 |= SFR_PHYPWR_RSTCTL_BZ;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+				2, &reg16);
+
+	reg8 = SFR_BULK_OUT_EFF_EN;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+			      1, 1, &reg8);
+
+	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, &reg8);
+
+	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, &reg8);
+		} 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, &reg8);
+		reg8 = SFR_BMRX_DMA_EN;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+				      1, 1, &reg8);
+		reg8 = SFR_RX_PATH_READY;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+				      1, 1, &reg8);
+		reg8 = 0x07;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL,
+				      1, 1, &reg8);
+		reg8 = 0x00;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+				      SFR_RX_BULKIN_QTIMR_LOW, 1, 1, &reg8);
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+				      SFR_RX_BULKIN_QTIMR_HIGH, 1, 1, &reg8);
+		reg8 = 0xFF;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QSIZE,
+				      1, 1, &reg8);
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QIFG,
+				      1, 1, &reg8);
+
+		aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
+				       SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+		reg16 |= SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
+					SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+
+		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, &reg16);
+		}
+
+		/* Disable RX path */
+		aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
+				       SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+		reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
+					SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+	}
+
+	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, &reg8);
+		if (reg8 == 0x00) {
+			reg8 = 0x02;
+			aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0, 0,
+					      1, &reg8);
+			msleep(200);
+		}
+
+		aqc111_mdio_read(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+				 &reg16);
+		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, &reg16);
+		}
+	}
+
+	reg8 = 0xFF;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK,
+			      1, 1, &reg8);
+	/* 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, &reg16);
+
+	reg16 |= SFR_RX_CTL_START;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+	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, &reg16);
+	reg16 |= SFR_MEDIUM_RECEIVE_EN;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				2, &reg16);
+	reg8 = SFR_RX_PATH_READY;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+			      1, 1, &reg8);
+	reg8 = 0x0;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 1, 1, &reg8);
+
+	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,
 };
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 6c951ca5d261..b62ef420bb68 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  12 +++
 2 files changed, 227 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 80fedf2ab2dd..16d1934cc815 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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, &reg16);
+	temp_rx_ctrl = reg16;
+	/* Stop RX operations*/
+	reg16 &= ~SFR_RX_CTL_START;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+	/* Force bz */
+	aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+			       2, &reg16);
+	reg16 |= SFR_PHYPWR_RSTCTL_BZ;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+				2, &reg16);
+
+	reg8 = SFR_BULK_OUT_EFF_EN;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+			      1, 1, &reg8);
+
+	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, &reg8);
+
+	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, &reg8);
+		} 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, &reg8);
+		reg8 = SFR_BMRX_DMA_EN;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+				      1, 1, &reg8);
+		reg8 = SFR_RX_PATH_READY;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+				      1, 1, &reg8);
+		reg8 = 0x07;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL,
+				      1, 1, &reg8);
+		reg8 = 0x00;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+				      SFR_RX_BULKIN_QTIMR_LOW, 1, 1, &reg8);
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+				      SFR_RX_BULKIN_QTIMR_HIGH, 1, 1, &reg8);
+		reg8 = 0xFF;
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QSIZE,
+				      1, 1, &reg8);
+		aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QIFG,
+				      1, 1, &reg8);
+
+		aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
+				       SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+		reg16 |= SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
+					SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+
+		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, &reg16);
+		}
+
+		/* Disable RX path */
+		aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
+				       SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+		reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+		aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
+					SFR_MEDIUM_STATUS_MODE, 2, &reg16);
+	}
+
+	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, &reg8);
+		if (reg8 == 0x00) {
+			reg8 = 0x02;
+			aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0, 0,
+					      1, &reg8);
+			msleep(200);
+		}
+
+		aqc111_mdio_read(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+				 &reg16);
+		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, &reg16);
+		}
+	}
+
+	reg8 = 0xFF;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK,
+			      1, 1, &reg8);
+	/* 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, &reg16);
+
+	reg16 |= SFR_RX_CTL_START;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, &reg16);
+
+	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, &reg16);
+	reg16 |= SFR_MEDIUM_RECEIVE_EN;
+	aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+				2, &reg16);
+	reg8 = SFR_RX_PATH_READY;
+	aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+			      1, 1, &reg8);
+	reg8 = 0x0;
+	aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 1, 1, &reg8);
+
+	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,
 };
 
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 6c951ca5d261..b62ef420bb68 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -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

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 20/21] net: usb: aqc111: Add ASIX's HW ids
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

It enables driver for ASIX products which are also based on aqc111/112U chips.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 16d1934cc815..3ae1dcc1178e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,20/21] net: usb: aqc111: Add ASIX's HW ids
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

It enables driver for ASIX products which are also based on aqc111/112U chips.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/aqc111.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 16d1934cc815..3ae1dcc1178e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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);

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v2 net-next 21/21] net: usb: aqc111: Extend cdc_ether blacklist
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Added Aquantia and ASIX device IDs to prevent loading cdc_ether for
these devices. Our firmware reports CDC configuration simultaneously
with vendor specific.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/cdc_ether.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 5c42cf81a08b..22527baa8467 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -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		0x0b95
 
 static 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.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [v2,net-next,21/21] net: usb: aqc111: Extend cdc_ether blacklist
@ 2018-11-13 14:45   ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-13 14:45 UTC (permalink / raw)
  To: David S . Miller; +Cc: linux-usb, netdev, Dmitry Bezrukov, Igor Russkikh

From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>

Added Aquantia and ASIX device IDs to prevent loading cdc_ether for
these devices. Our firmware reports CDC configuration simultaneously
with vendor specific.

Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
 drivers/net/usb/cdc_ether.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 5c42cf81a08b..22527baa8467 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -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		0x0b95
 
 static 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.

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-13 20:50     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 20:50 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On Tue, Nov 13, 2018 at 02:45:13PM +0000, Igor Russkikh wrote:
> +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);
> +	}

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.

> +	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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-13 20:50     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 20:50 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On Tue, Nov 13, 2018 at 02:45:13PM +0000, Igor Russkikh wrote:
> +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);
> +	}

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.

> +	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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 20:58     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 20:58 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On Tue, Nov 13, 2018 at 02:44:45PM +0000, Igor Russkikh wrote:
> From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
> 
> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-13 20:58     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 20:58 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On Tue, Nov 13, 2018 at 02:44:45PM +0000, Igor Russkikh wrote:
> From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
> 
> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-13 21:02     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 21:02 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> +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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-13 21:02     ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-13 21:02 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> +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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14  7:44       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:44 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

>>
>> 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.

Hi Andrew,

I'm actually still in doubt as well on this matter.
Of course thats quite possible.

Here was my original comment:

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14  7:44       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:44 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

>>
>> 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.

Hi Andrew,

I'm actually still in doubt as well on this matter.
Of course thats quite possible.

Here was my original comment:

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-14  7:46       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:46 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov


>> +	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.

Right, I've explained that to you but forgot to add a comment here.

>> +	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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
@ 2018-11-14  7:46       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:46 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

>> +	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.

Right, I've explained that to you but forgot to add a comment here.

>> +	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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-14  7:56       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:56 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov


>> +
>> +		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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-14  7:56       ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-14  7:56 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

>> +
>> +		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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 21:16         ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-14 21:16 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> > 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 21:16         ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-14 21:16 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> > 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-14 21:30         ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-14 21:30 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
@ 2018-11-14 21:30         ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-14 21:30 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 22:53           ` Florian Fainelli
  0 siblings, 0 replies; 65+ messages in thread
From: Florian Fainelli @ 2018-11-14 22:53 UTC (permalink / raw)
  To: Andrew Lunn, Igor Russkikh
  Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On 11/14/18 1:16 PM, Andrew Lunn wrote:
>>> 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.

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.
-- 
Florian

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-14 22:53           ` Florian Fainelli
  0 siblings, 0 replies; 65+ messages in thread
From: Florian Fainelli @ 2018-11-14 22:53 UTC (permalink / raw)
  To: Andrew Lunn, Igor Russkikh
  Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

On 11/14/18 1:16 PM, Andrew Lunn wrote:
>>> 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.

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.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16  9:53             ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-16  9:53 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn
  Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov


Hi Andrew, Florian,

>>>
>>> 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.
> 
> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16  9:53             ` Igor Russkikh
  0 siblings, 0 replies; 65+ messages in thread
From: Igor Russkikh @ 2018-11-16  9:53 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn
  Cc: David S . Miller, linux-usb, netdev, Dmitry Bezrukov

Hi Andrew, Florian,

>>>
>>> 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.
> 
> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16 18:33               ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-16 18:33 UTC (permalink / raw)
  To: Igor Russkikh
  Cc: Florian Fainelli, David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [v2,net-next,06/21] net: usb: aqc111: Introduce link management
@ 2018-11-16 18:33               ` Andrew Lunn
  0 siblings, 0 replies; 65+ messages in thread
From: Andrew Lunn @ 2018-11-16 18:33 UTC (permalink / raw)
  To: Igor Russkikh
  Cc: Florian Fainelli, David S . Miller, linux-usb, netdev, Dmitry Bezrukov

> 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

^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2018-11-17  4:47 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-13 14:44 [PATCH v2 net-next 00/21] Add support for Aquantia AQtion USB to 5/2.5GbE devices Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 01/21] net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,01/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 02/21] net: usb: aqc111: Add bind and empty unbind callbacks Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,02/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 03/21] net: usb: aqc111: Add implementation of read and write commands Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,03/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 04/21] net: usb: aqc111: Various callbacks implementation Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,04/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 05/21] net: usb: aqc111: Introduce PHY access Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,05/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 06/21] net: usb: aqc111: Introduce link management Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,06/21] " Igor Russkikh
2018-11-13 20:58   ` [PATCH v2 net-next 06/21] " Andrew Lunn
2018-11-13 20:58     ` [v2,net-next,06/21] " Andrew Lunn
2018-11-14  7:44     ` [PATCH v2 net-next 06/21] " Igor Russkikh
2018-11-14  7:44       ` [v2,net-next,06/21] " Igor Russkikh
2018-11-14 21:16       ` [PATCH v2 net-next 06/21] " Andrew Lunn
2018-11-14 21:16         ` [v2,net-next,06/21] " Andrew Lunn
2018-11-14 22:53         ` [PATCH v2 net-next 06/21] " Florian Fainelli
2018-11-14 22:53           ` [v2,net-next,06/21] " Florian Fainelli
2018-11-16  9:53           ` [PATCH v2 net-next 06/21] " Igor Russkikh
2018-11-16  9:53             ` [v2,net-next,06/21] " Igor Russkikh
2018-11-16 18:33             ` [PATCH v2 net-next 06/21] " Andrew Lunn
2018-11-16 18:33               ` [v2,net-next,06/21] " Andrew Lunn
2018-11-13 14:44 ` [PATCH v2 net-next 07/21] net: usb: aqc111: Add support for getting and setting of MAC address Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,07/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 08/21] net: usb: aqc111: Implement TX data path Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,08/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 09/21] net: usb: aqc111: Implement RX " Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,09/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 10/21] net: usb: aqc111: Add checksum offload support Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,10/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 11/21] net: usb: aqc111: Add support for changing MTU Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,11/21] " Igor Russkikh
2018-11-13 14:44 ` [PATCH v2 net-next 12/21] net: usb: aqc111: Add support for enable/disable checksum offload Igor Russkikh
2018-11-13 14:44   ` [v2,net-next,12/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 13/21] net: usb: aqc111: Add support for TSO Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,13/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 14/21] net: usb: aqc111: Implement set_rx_mode callback Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,14/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 15/21] net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,15/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 16/21] net: usb: aqc111: Add RX VLAN filtering support Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,16/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 17/21] net: usb: aqc111: Initialize ethtool_ops structure Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,17/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,18/21] " Igor Russkikh
2018-11-13 20:50   ` [PATCH v2 net-next 18/21] " Andrew Lunn
2018-11-13 20:50     ` [v2,net-next,18/21] " Andrew Lunn
2018-11-14  7:46     ` [PATCH v2 net-next 18/21] " Igor Russkikh
2018-11-14  7:46       ` [v2,net-next,18/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,19/21] " Igor Russkikh
2018-11-13 21:02   ` [PATCH v2 net-next 19/21] " Andrew Lunn
2018-11-13 21:02     ` [v2,net-next,19/21] " Andrew Lunn
2018-11-14  7:56     ` [PATCH v2 net-next 19/21] " Igor Russkikh
2018-11-14  7:56       ` [v2,net-next,19/21] " Igor Russkikh
2018-11-14 21:30       ` [PATCH v2 net-next 19/21] " Andrew Lunn
2018-11-14 21:30         ` [v2,net-next,19/21] " Andrew Lunn
2018-11-13 14:45 ` [PATCH v2 net-next 20/21] net: usb: aqc111: Add ASIX's HW ids Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,20/21] " Igor Russkikh
2018-11-13 14:45 ` [PATCH v2 net-next 21/21] net: usb: aqc111: Extend cdc_ether blacklist Igor Russkikh
2018-11-13 14:45   ` [v2,net-next,21/21] " Igor Russkikh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.