Netdev List
 help / color / mirror / Atom feed
* [PATCH v3 net-next 17/21] net: usb: aqc111: Initialize ethtool_ops structure
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 89b7ee1fad22..2028db453df9 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)
 {
@@ -178,6 +181,23 @@ static int aqc111_write16_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
 				      sizeof(tmp), &tmp);
 }
 
+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(struct usbnet *dev, u8 autoneg, u16 speed)
 {
 	struct aqc111_data *aqc111_data = dev->driver_priv;
@@ -225,6 +245,13 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
 }
 
+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);
@@ -533,6 +560,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 18/21] net: usb: aqc111: Implement get/set_link_ksettings callbacks
From: Igor Russkikh @ 2018-11-21 10:14 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 2028db453df9..d96f8d4fb7a0 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -16,6 +16,7 @@
 #include <linux/if_vlan.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/usbnet.h>
+#include <linux/linkmode.h>
 
 #include "aqc111.h"
 
@@ -198,6 +199,84 @@ 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)
+		linkmode_copy(elk->link_modes.advertising,
+			      elk->link_modes.supported);
+	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(struct usbnet *dev, u8 autoneg, u16 speed)
 {
 	struct aqc111_data *aqc111_data = dev->driver_priv;
@@ -245,11 +324,56 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
 }
 
+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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 19/21] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
From: Igor Russkikh @ 2018-11-21 10:14 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 | 180 +++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  12 +++
 2 files changed, 192 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index d96f8d4fb7a0..03f9b5a20e6c 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -54,6 +54,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)
 {
@@ -199,6 +210,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)
 {
@@ -369,6 +409,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,
@@ -1206,6 +1248,142 @@ 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;
+		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);
+
+		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;
+		aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
+				   &aqc111_data->phy_cfg);
+
+		/* 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;
+
+	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) \
@@ -1227,6 +1405,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 0ce23a741211..4d68b3a6067c 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,6 +18,7 @@
 #define AQ_ACCESS_MAC			0x01
 #define AQ_FLASH_PARAMETERS		0x20
 #define AQ_PHY_POWER			0x31
+#define AQ_WOL_CFG			0x60
 #define AQ_PHY_OPS			0x61
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
@@ -145,8 +146,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;
@@ -160,6 +171,7 @@ struct aqc111_data {
 		u8 rev;
 	} fw_ver;
 	u32 phy_cfg;
+	u8 wol_flags;
 };
 
 #define AQ_LS_MASK		0x8000
-- 
2.17.1

^ permalink raw reply related

* [PATCH v3 net-next 20/21] net: usb: aqc111: Add ASIX's HW ids
From: Igor Russkikh @ 2018-11-21 10:14 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 03f9b5a20e6c..782925d77ef6 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -1248,6 +1248,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);
@@ -1397,6 +1435,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 21/21] net: usb: aqc111: Extend cdc_ether blacklist
From: Igor Russkikh @ 2018-11-21 10:14 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 5c42cf81a08b..b3b3c05903a1 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,30 @@ 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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 04/21] net: usb: aqc111: Various callbacks implementation
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 fbd48b8a6944..75849714abfa 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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 06/21] net: usb: aqc111: Introduce link management
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 | 235 +++++++++++++++++++++++++++++++++++++++
 drivers/net/usb/aqc111.h |  13 +++
 2 files changed, 248 insertions(+)

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index e277209df616..e33be16b506c 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -157,6 +157,53 @@ static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value,
 	return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp);
 }
 
+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;
+		}
+	}
+
+	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
+}
+
 static const struct net_device_ops aqc111_netdev_ops = {
 	.ndo_open		= usbnet_open,
 	.ndo_stop		= usbnet_stop,
@@ -179,6 +226,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;
 
@@ -206,6 +254,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;
 }
@@ -224,6 +275,7 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
 				2, &reg16);
 
 	/* Power down ethernet PHY */
+	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,
@@ -232,6 +284,179 @@ 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;
+	}
+
+	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;
@@ -254,6 +479,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;
 }
 
@@ -275,6 +506,8 @@ static int aqc111_stop(struct usbnet *dev)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
 			   &aqc111_data->phy_cfg);
 
+	netif_carrier_off(dev->net);
+
 	return 0;
 }
 
@@ -282,6 +515,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 a93d34af76b9..f3b45d8ca4e3 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -113,6 +113,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)
@@ -127,6 +128,10 @@
 /******************************************************************************/
 
 struct aqc111_data {
+	u8 link_speed;
+	u8 link;
+	u8 autoneg;
+	u32 advertised_speed;
 	struct {
 		u8 major;
 		u8 minor;
@@ -135,6 +140,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 07/21] net: usb: aqc111: Add support for getting and setting of MAC address
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 e33be16b506c..390ed6cbc3fd 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>
 
@@ -204,11 +205,43 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
 }
 
+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)
 {
@@ -251,6 +284,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);
@@ -259,6 +298,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)
@@ -467,6 +510,10 @@ static int aqc111_reset(struct usbnet *dev)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
 			   &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 f3b45d8ca4e3..0c8e1ee29893 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_OPS			0x61
 
-- 
2.17.1

^ permalink raw reply related

* [PATCH v3 net-next 08/21] net: usb: aqc111: Implement TX data path
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 390ed6cbc3fd..dc9f0996afaf 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -222,6 +222,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,
 };
@@ -290,8 +293,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) ?
@@ -505,6 +519,12 @@ static int aqc111_reset(struct usbnet *dev)
 	struct aqc111_data *aqc111_data = dev->driver_priv;
 	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;
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
@@ -558,6 +578,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,
@@ -566,6 +635,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 0c8e1ee29893..c09f188b9f3d 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,6 +18,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
@@ -149,6 +153,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 09/21] net: usb: aqc111: Implement RX data path
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 dc9f0996afaf..2ad8b3100e2e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -294,6 +294,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);
@@ -519,6 +522,8 @@ static int aqc111_reset(struct usbnet *dev)
 	struct aqc111_data *aqc111_data = dev->driver_priv;
 	u8 reg8 = 0;
 
+	dev->rx_urb_size = URB_SIZE;
+
 	if (usb_device_no_sg_constraint(dev->udev))
 		dev->can_dma_sg = 1;
 
@@ -578,6 +583,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)
 {
@@ -637,6 +739,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 c09f188b9f3d..c5785f890022 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
@@ -157,6 +159,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 10/21] net: usb: aqc111: Add checksum offload support
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 2ad8b3100e2e..2a322391896c 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -439,6 +439,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;
@@ -482,6 +502,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);
 
@@ -583,6 +605,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;
@@ -661,6 +698,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 c5785f890022..ff43443bfd72 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -21,8 +21,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. ********************************************/
 
@@ -162,6 +165,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 11/21] net: usb: aqc111: Add support for changing MTU
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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 2a322391896c..5cd0e7f9ef47 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -205,6 +205,48 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
 	aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, &aqc111_data->phy_cfg);
 }
 
+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);
@@ -225,6 +267,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,
 };
@@ -301,6 +344,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))
@@ -427,12 +472,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);
@@ -507,6 +562,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.17.1

^ permalink raw reply related

* [PATCH v3 net-next 05/21] net: usb: aqc111: Introduce PHY access
From: Igor Russkikh @ 2018-11-21 10:13 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org, davem@davemloft.net,
	netdev@vger.kernel.org
  Cc: andrew@lunn.ch, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1542794577.git.igor.russkikh@aquantia.com>

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

Add helpers to write 32bit values.
Implement PHY power up/down sequences.
AQC111, PHY is being controlled via vendor command interface.

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

diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 75849714abfa..e277209df616 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -137,14 +137,49 @@ 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 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;
+}
+
 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,13 +196,23 @@ 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;
 
 	/* Force bz */
@@ -177,12 +222,26 @@ 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 */
+	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;
 	u8 reg8 = 0;
 
+	/* Power up ethernet PHY */
+	aqc111_data->phy_cfg = AQ_PHY_POWER_EN;
+	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 +259,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 +270,11 @@ 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*/
+	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..a93d34af76b9 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -12,6 +12,7 @@
 
 #define AQ_ACCESS_MAC			0x01
 #define AQ_PHY_POWER			0x31
+#define AQ_PHY_OPS			0x61
 
 #define AQ_USB_PHY_SET_TIMEOUT		10000
 #define AQ_USB_SET_TIMEOUT		4000
@@ -102,6 +103,38 @@
 	#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;
+	u32 phy_cfg;
+};
+
 static struct {
 	unsigned char ctrl;
 	unsigned char timer_l;
-- 
2.17.1

^ permalink raw reply related

* Re: Issue with RTL8111 NIC after upgrade to kernel 4.19
From: Heiner Kallweit @ 2018-11-21 20:49 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Norbert Jurkeit, nic_swsd, Florian Fainelli, davem, netdev,
	linux-kernel, michael.wiktowy, jcline, marc.c.dionne
In-Reply-To: <eda84d0b-2d9f-07ae-34a1-767bc5200964@gmail.com>

On 21.11.2018 21:32, Heiner Kallweit wrote:
> On 21.11.2018 21:20, Andrew Lunn wrote:
>>> request_module() is supposed to be synchronous, however after some
>>> reading this may not be 100% guaranteed. Maybe the module init
>>> function on some systems isn't finished yet when request_module()
>>> returns. As a result the genphy driver may be used instead of
>>> the PHY version-specific driver.
>>
>> Hi Heiner
>>
>> That would be true for all PHYs i think. We would of noticed this
>> problem with other systems using other PHY drivers.
>>
>> 	Andrew
>>
> It could be a timing issue affecting certain systems only. At least
> for now I don't have a good explanation why loading the module via
> request_module() and loading it upfront manually makes a difference.
> 
> One affected user just reported the PHY to be a RTL8211B. This is
> what I expected, because this PHY crashes when writing to the MMD
> registers (the MMD registers are used otherwise by this PHY).
> See also commit 0231b1a074c6 ("net: phy: realtek: Use the dummy
> stubs for MMD register access for rtl8211b").
> 
> Let's see whether the other affected systems use the same PHY
> version.
> 
Next report is also about a RTL8211B and as I assumed:
- W/o manually loading the realtek module the genphy driver is used
  and network fails.
- W/ manually loading the realtek module the proper RTL8211B PHY
  driver is used and network works.

So it seems that even after request_module() the PHY driver isn't
yet available when device and driver are matched.

If further reports support this (pre-)analysis, then indeed it
seems to be a timing issue and a proper fix most likely is
difficult. As a workaround I could imagine to add a delay loop
after request_module() checking for a Realtek PHY driver via
driver_find(). When adding one small delay after this we should
be sufficiently sure that all Realtek PHY drivers are registered.

> Heiner
> 

^ permalink raw reply

* Re: Issue with RTL8111 NIC after upgrade to kernel 4.19
From: Heiner Kallweit @ 2018-11-21 20:52 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Norbert Jurkeit, nic_swsd, Florian Fainelli, davem, netdev,
	linux-kernel, michael.wiktowy, jcline, marc.c.dionne
In-Reply-To: <6aeba3d6-2292-1221-9be7-1c0bb7cbc203@gmail.com>

On 21.11.2018 21:49, Heiner Kallweit wrote:
> On 21.11.2018 21:32, Heiner Kallweit wrote:
>> On 21.11.2018 21:20, Andrew Lunn wrote:
>>>> request_module() is supposed to be synchronous, however after some
>>>> reading this may not be 100% guaranteed. Maybe the module init
>>>> function on some systems isn't finished yet when request_module()
>>>> returns. As a result the genphy driver may be used instead of
>>>> the PHY version-specific driver.
>>>
>>> Hi Heiner
>>>
>>> That would be true for all PHYs i think. We would of noticed this
>>> problem with other systems using other PHY drivers.
>>>
>>> 	Andrew
>>>
>> It could be a timing issue affecting certain systems only. At least
>> for now I don't have a good explanation why loading the module via
>> request_module() and loading it upfront manually makes a difference.
>>
>> One affected user just reported the PHY to be a RTL8211B. This is
>> what I expected, because this PHY crashes when writing to the MMD
>> registers (the MMD registers are used otherwise by this PHY).
>> See also commit 0231b1a074c6 ("net: phy: realtek: Use the dummy
>> stubs for MMD register access for rtl8211b").
>>
>> Let's see whether the other affected systems use the same PHY
>> version.
>>
> Next report is also about a RTL8211B and as I assumed:
> - W/o manually loading the realtek module the genphy driver is used
>   and network fails.
> - W/ manually loading the realtek module the proper RTL8211B PHY
>   driver is used and network works.
> 
> So it seems that even after request_module() the PHY driver isn't
> yet available when device and driver are matched.
> 
> If further reports support this (pre-)analysis, then indeed it
> seems to be a timing issue and a proper fix most likely is
> difficult. As a workaround I could imagine to add a delay loop
> after request_module() checking for a Realtek PHY driver via
> driver_find(). When adding one small delay after this we should
> be sufficiently sure that all Realtek PHY drivers are registered.
> 
Uups, no. We talk about phylib here, not about the r8169 driver.
So we need a different solution.

>> Heiner
>>
> 

^ permalink raw reply

* Re: [PATCH net] net/ibmnvic: Fix deadlock problem in reset
From: Abdul Haleem @ 2018-11-21 10:40 UTC (permalink / raw)
  To: Juliet Kim; +Cc: netdev, linuxppc-dev, mwb, tlfalcon, tyreld
In-Reply-To: <20181119215727.22197.97260.stgit@ltcalpine2-lp22.aus.stglabs.ibm.com>

On Mon, 2018-11-19 at 15:59 -0600, Juliet Kim wrote:
> This patch changes to use rtnl_lock only during a reset to avoid
> deadlock that could occur when a thread operating close is holding
> rtnl_lock and waiting for reset_lock acquired by another thread,
> which is waiting for rtnl_lock in order to set the number of tx/rx
> queues during a reset.
> 
> Also, we now setting the number of tx/rx queues during a soft reset
> for failover or LPM events.
> 
> Signed-off-by: Juliet Kim <julietk@linux.vnet.ibm.com>
> ---
>  drivers/net/ethernet/ibm/ibmvnic.c |   59 +++++++++++++-----------------------
>  drivers/net/ethernet/ibm/ibmvnic.h |    2 +
>  2 files changed, 22 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
> index 7893bef..4a5de59 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.c
> +++ b/drivers/net/ethernet/ibm/ibmvnic.c
> @@ -1103,20 +1103,15 @@ static int ibmvnic_open(struct net_device *netdev)
>  		return 0;
>  	}
> 
> -	mutex_lock(&adapter->reset_lock);
> -
>  	if (adapter->state != VNIC_CLOSED) {
>  		rc = ibmvnic_login(netdev);
> -		if (rc) {
> -			mutex_unlock(&adapter->reset_lock);
> +		if (rc)
>  			return rc;
> -		}
> 
>  		rc = init_resources(adapter);
>  		if (rc) {
>  			netdev_err(netdev, "failed to initialize resources\n");
>  			release_resources(adapter);
> -			mutex_unlock(&adapter->reset_lock);
>  			return rc;
>  		}
>  	}
> @@ -1124,8 +1119,6 @@ static int ibmvnic_open(struct net_device *netdev)
>  	rc = __ibmvnic_open(netdev);
>  	netif_carrier_on(netdev);
> 
> -	mutex_unlock(&adapter->reset_lock);
> -
>  	return rc;
>  }
> 
> @@ -1269,10 +1262,8 @@ static int ibmvnic_close(struct net_device *netdev)
>  		return 0;
>  	}
> 
> -	mutex_lock(&adapter->reset_lock);
>  	rc = __ibmvnic_close(netdev);
>  	ibmvnic_cleanup(netdev);
> -	mutex_unlock(&adapter->reset_lock);
> 
>  	return rc;
>  }
> @@ -1820,20 +1811,15 @@ static int do_reset(struct ibmvnic_adapter *adapter,
>  				return rc;
>  		} else if (adapter->req_rx_queues != old_num_rx_queues ||
>  			   adapter->req_tx_queues != old_num_tx_queues) {
> -			adapter->map_id = 1;
>  			release_rx_pools(adapter);
>  			release_tx_pools(adapter);
> -			rc = init_rx_pools(netdev);
> -			if (rc)
> -				return rc;
> -			rc = init_tx_pools(netdev);
> -			if (rc)
> -				return rc;
> -
>  			release_napi(adapter);
> -			rc = init_napi(adapter);
> +			release_vpd_data(adapter);
> +
> +			rc = init_resources(adapter);
>  			if (rc)
>  				return rc;
> +
>  		} else {
>  			rc = reset_tx_pools(adapter);
>  			if (rc)
> @@ -1917,17 +1903,8 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
>  		adapter->state = VNIC_PROBED;
>  		return 0;
>  	}
> -	/* netif_set_real_num_xx_queues needs to take rtnl lock here
> -	 * unless wait_for_reset is set, in which case the rtnl lock
> -	 * has already been taken before initializing the reset
> -	 */
> -	if (!adapter->wait_for_reset) {
> -		rtnl_lock();
> -		rc = init_resources(adapter);
> -		rtnl_unlock();
> -	} else {
> -		rc = init_resources(adapter);
> -	}
> +
> +	rc = init_resources(adapter);
>  	if (rc)
>  		return rc;
> 
> @@ -1986,13 +1963,21 @@ static void __ibmvnic_reset(struct work_struct *work)
>  	struct ibmvnic_rwi *rwi;
>  	struct ibmvnic_adapter *adapter;
>  	struct net_device *netdev;
> +	bool we_lock_rtnl = false;
>  	u32 reset_state;
>  	int rc = 0;
> 
>  	adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
>  	netdev = adapter->netdev;
> 
> -	mutex_lock(&adapter->reset_lock);
> +	/* netif_set_real_num_xx_queues needs to take rtnl lock here
> +	 * unless wait_for_reset is set, in which case the rtnl lock
> +	 * has already been taken before initializing the reset
> +	 */
> +	if (!adapter->wait_for_reset) {
> +		rtnl_lock();
> +		we_lock_rtnl = true;
> +	}
>  	reset_state = adapter->state;
> 
>  	rwi = get_next_rwi(adapter);
> @@ -2020,12 +2005,11 @@ static void __ibmvnic_reset(struct work_struct *work)
>  	if (rc) {
>  		netdev_dbg(adapter->netdev, "Reset failed\n");
>  		free_all_rwi(adapter);
> -		mutex_unlock(&adapter->reset_lock);
> -		return;
>  	}
> 
>  	adapter->resetting = false;
> -	mutex_unlock(&adapter->reset_lock);
> +	if (we_lock_rtnl)
> +		rtnl_unlock();
>  }
> 
>  static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
> @@ -4768,7 +4752,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
> 
>  	INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
>  	INIT_LIST_HEAD(&adapter->rwi_list);
> -	mutex_init(&adapter->reset_lock);
>  	mutex_init(&adapter->rwi_lock);
>  	adapter->resetting = false;
> 
> @@ -4840,8 +4823,8 @@ static int ibmvnic_remove(struct vio_dev *dev)
>  	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
> 
>  	adapter->state = VNIC_REMOVING;
> -	unregister_netdev(netdev);
> -	mutex_lock(&adapter->reset_lock);
> +	rtnl_lock();
> +	unregister_netdevice(netdev);
> 
>  	release_resources(adapter);
>  	release_sub_crqs(adapter, 1);
> @@ -4852,7 +4835,7 @@ static int ibmvnic_remove(struct vio_dev *dev)
> 
>  	adapter->state = VNIC_REMOVED;
> 
> -	mutex_unlock(&adapter->reset_lock);
> +	rtnl_unlock();
>  	device_remove_file(&dev->dev, &dev_attr_failover);
>  	free_netdev(netdev);
>  	dev_set_drvdata(&dev->dev, NULL);
> diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
> index 18103b8..99c4f8d 100644
> --- a/drivers/net/ethernet/ibm/ibmvnic.h
> +++ b/drivers/net/ethernet/ibm/ibmvnic.h
> @@ -1075,7 +1075,7 @@ struct ibmvnic_adapter {
>  	struct tasklet_struct tasklet;
>  	enum vnic_state state;
>  	enum ibmvnic_reset_reason reset_reason;
> -	struct mutex reset_lock, rwi_lock;
> +	struct mutex rwi_lock;
>  	struct list_head rwi_list;
>  	struct work_struct ibmvnic_reset;
>  	bool resetting;
> 

Thanks for the fix, Please add Reported-and-tested-by: Abdul Haleem <abdhalee@linux.vnet.ibm.com>

-- 
Regard's

Abdul Haleem
IBM Linux Technology Centre

^ permalink raw reply

* Re: [PATCH v1 2/2] netfilter: Add PSID mode to MASQUERADE
From: kbuild test robot @ 2018-11-21 10:41 UTC (permalink / raw)
  To: Felix Jia
  Cc: kbuild-all, David S . Miller, Pablo Neira Ayuso, Blair Steven,
	netdev, Anthony Lineham, Scott Parlane, Felix Jia
In-Reply-To: <20181120013114.22020-2-felix.jia@alliedtelesis.co.nz>

[-- Attachment #1: Type: text/plain, Size: 2544 bytes --]

Hi Blair,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on nf-next/master]
[also build test ERROR on v4.20-rc3 next-20181121]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Felix-Jia/ip6_tunnel-Adding-support-of-mapping-rules-for-MAP-E-tunnel/20181120-173346
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=8.1.0 make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

>> net/ipv6/netfilter/nf_nat_proto_icmpv6.c:85:15: error: initialization of 'bool (*)(const struct nf_conntrack_tuple *, enum nf_nat_manip_type,  const struct nf_nat_range2 *)' {aka '_Bool (*)(const struct nf_conntrack_tuple *, enum nf_nat_manip_type,  const struct nf_nat_range2 *)'} from incompatible pointer type 'bool (*)(const struct nf_conntrack_tuple *, enum nf_nat_manip_type,  const union nf_conntrack_man_proto *, const union nf_conntrack_man_proto *)' {aka '_Bool (*)(const struct nf_conntrack_tuple *, enum nf_nat_manip_type,  const union nf_conntrack_man_proto *, const union nf_conntrack_man_proto *)'} [-Werror=incompatible-pointer-types]
     .in_range  = icmpv6_in_range,
                  ^~~~~~~~~~~~~~~
   net/ipv6/netfilter/nf_nat_proto_icmpv6.c:85:15: note: (near initialization for 'nf_nat_l4proto_icmpv6.in_range')
   cc1: some warnings being treated as errors

vim +85 net/ipv6/netfilter/nf_nat_proto_icmpv6.c

58a317f1 Patrick McHardy 2012-08-26  81  
58a317f1 Patrick McHardy 2012-08-26  82  const struct nf_nat_l4proto nf_nat_l4proto_icmpv6 = {
58a317f1 Patrick McHardy 2012-08-26  83  	.l4proto		= IPPROTO_ICMPV6,
58a317f1 Patrick McHardy 2012-08-26  84  	.manip_pkt		= icmpv6_manip_pkt,
58a317f1 Patrick McHardy 2012-08-26 @85  	.in_range		= icmpv6_in_range,

:::::: The code at line 85 was first introduced by commit
:::::: 58a317f1061c894d2344c0b6a18ab4a64b69b815 netfilter: ipv6: add IPv6 NAT support

:::::: TO: Patrick McHardy <kaber@trash.net>
:::::: CC: Pablo Neira Ayuso <pablo@netfilter.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52297 bytes --]

^ permalink raw reply

* [PATCH net-next 0/4] Ease to interpret net-nsid
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev


The goal of this series is to ease the interpretation of nsid received in
netlink messages from other netns (when the user uses
NETLINK_F_LISTEN_ALL_NSID).

After this series, with a patched iproute2:

$ ip netns add foo
$ ip netns add bar
$ touch /var/run/netns/init_net
$ mount --bind /proc/1/ns/net /var/run/netns/init_net
$ ip netns set init_net 11
$ ip netns set foo 12
$ ip netns set bar 13
$ ip netns
init_net (id: 11)
bar (id: 13)
foo (id: 12)
$ ip -n foo netns set init_net 21
$ ip -n foo netns set foo 22
$ ip -n foo netns set bar 23
$ ip -n foo netns
init_net (id: 21)
bar (id: 23)
foo (id: 22)
$ ip -n bar netns set init_net 31
$ ip -n bar netns set foo 32
$ ip -n bar netns set bar 33
$ ip -n bar netns
init_net (id: 31)
bar (id: 33)
foo (id: 32)
$ ip netns list-id target-nsid 12
nsid 21 current-nsid 11 (iproute2 netns name: init_net)
nsid 22 current-nsid 12 (iproute2 netns name: foo)
nsid 23 current-nsid 13 (iproute2 netns name: bar)
$ ip -n bar netns list-id target-nsid 32 nsid 31
nsid 21 current-nsid 31 (iproute2 netns name: init_net)

 include/uapi/linux/net_namespace.h |   2 +
 net/core/net_namespace.c           | 132 ++++++++++++++++++++++++++++++-------
 2 files changed, 110 insertions(+), 24 deletions(-)

Comments are welcomed,
Regards,
Nicolas

^ permalink raw reply

* [PATCH net-next 3/4] netns: enable to specify a nsid for a get request
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel
In-Reply-To: <20181121110124.5501-1-nicolas.dichtel@6wind.com>

Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
netns to a nsid of another netns.
This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
user to interpret a nsid received from an other netns.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3d02a742155f..92730905886c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -783,6 +783,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	} else if (tb[NETNSA_FD]) {
 		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
 		nla = tb[NETNSA_FD];
+	} else if (tb[NETNSA_NSID]) {
+		peer = get_net_ns_by_id(net, nla_get_u32(tb[NETNSA_NSID]));
+		if (!peer)
+			peer = ERR_PTR(-ENOENT);
+		nla = tb[NETNSA_NSID];
 	} else {
 		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
 		return -EINVAL;
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill()
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel
In-Reply-To: <20181121110124.5501-1-nicolas.dichtel@6wind.com>

This argument is not used anymore.

Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index fefe72774aeb..3e6af99bbe53 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -739,7 +739,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, struct net *net, int nsid)
+			 int cmd, int nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -801,7 +801,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(net, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, net, id);
+			    RTM_NEWNSID, id);
 	if (err < 0)
 		goto err_out;
 
@@ -833,7 +833,7 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, net_cb->net, id);
+			    RTM_NEWNSID, id);
 	if (ret < 0)
 		return ret;
 
@@ -876,7 +876,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next 4/4] netns: enable to dump full nsid translation table
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel
In-Reply-To: <20181121110124.5501-1-nicolas.dichtel@6wind.com>

Like the previous patch, the goal is to ease to convert nsids from one
netns to another netns.
A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 30 ++++++++++++++++++++++++------
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0ed9dd61d32a..9f9956809565 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -17,6 +17,7 @@ enum {
 	NETNSA_PID,
 	NETNSA_FD,
 	NETNSA_TARGET_NSID,
+	NETNSA_CURRENT_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 92730905886c..fc568cd0b560 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -740,7 +740,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, int nsid)
+			 int cmd, int nsid, bool add_ref, int ref_nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -755,6 +755,9 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
 	if (nla_put_s32(skb, NETNSA_NSID, nsid))
 		goto nla_put_failure;
 
+	if (add_ref && nla_put_s32(skb, NETNSA_CURRENT_NSID, ref_nsid))
+		goto nla_put_failure;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
@@ -769,9 +772,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
 	struct net *peer, *target = net;
+	bool add_ref = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	int err, id;
+	int err, id, ref_id;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
 			  rtnl_net_policy, extack);
@@ -809,6 +813,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 			err = PTR_ERR(target);
 			goto put_peer;
 		}
+		ref_id = peernet2id(net, peer);
+		add_ref = true;
 	} else {
 		get_net(target);
 	}
@@ -821,7 +827,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, id);
+			    RTM_NEWNSID, id, add_ref, ref_id);
 	if (err < 0)
 		goto free_nlmsg;
 
@@ -849,14 +855,17 @@ struct rtnl_net_dump_cb {
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 {
 	struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
-	int ret;
+	int ref_id = 0, ret;
 
 	if (net_cb->idx < net_cb->s_idx)
 		goto cont;
 
+	if (net_cb->ref_net)
+		ref_id = __peernet2id(net_cb->ref_net, peer);
+
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, id);
+			    RTM_NEWNSID, id, net_cb->ref_net, ref_id);
 	if (ret < 0)
 		return ret;
 
@@ -923,7 +932,16 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	}
 
 	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	if (net_cb.ref_net &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
+	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
+		err = -EAGAIN;
+		goto end;
+	}
 	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	if (net_cb.ref_net &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
+		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
 	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
@@ -942,7 +960,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id, false, 0);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel
In-Reply-To: <20181121110124.5501-1-nicolas.dichtel@6wind.com>

Like it was done for link and address, add the ability to perform get/dump
in another netns by specifying a target nsid attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 97 ++++++++++++++++++++++++------
 2 files changed, 80 insertions(+), 18 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0187c74d8889..0ed9dd61d32a 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
 	NETNSA_NSID,
 	NETNSA_PID,
 	NETNSA_FD,
+	NETNSA_TARGET_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3e6af99bbe53..3d02a742155f 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
 	[NETNSA_NSID]		= { .type = NLA_S32 },
 	[NETNSA_PID]		= { .type = NLA_U32 },
 	[NETNSA_FD]		= { .type = NLA_U32 },
+	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
 };
 
 static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -767,9 +768,9 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
+	struct net *peer, *target = net;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	struct net *peer;
 	int err, id;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -793,30 +794,47 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return PTR_ERR(peer);
 	}
 
+	if (tb[NETNSA_TARGET_NSID]) {
+		id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
+		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
+		if (IS_ERR(target)) {
+			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
+			NL_SET_ERR_MSG(extack,
+				       "Target netns reference is invalid");
+			err = PTR_ERR(target);
+			goto put_peer;
+		}
+	} else {
+		get_net(target);
+	}
+
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
 	if (!msg) {
 		err = -ENOMEM;
-		goto out;
+		goto put_target;
 	}
 
-	id = peernet2id(net, peer);
+	id = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
 			    RTM_NEWNSID, id);
 	if (err < 0)
-		goto err_out;
+		goto free_nlmsg;
 
 	err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid);
-	goto out;
+	goto put_target;
 
-err_out:
+free_nlmsg:
 	nlmsg_free(msg);
-out:
+put_target:
+	put_net(target);
+put_peer:
 	put_net(peer);
 	return err;
 }
 
 struct rtnl_net_dump_cb {
-	struct net *net;
+	struct net *tgt_net;
+	struct net *ref_net;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 	int idx;
@@ -842,29 +860,72 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	return 0;
 }
 
+static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
+				   struct rtnl_net_dump_cb *net_cb,
+				   struct netlink_callback *cb)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	struct nlattr *tb[NETNSA_MAX + 1];
+	int err, i;
+
+	err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
+				 rtnl_net_policy, extack);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i <= NETNSA_MAX; i++) {
+		if (!tb[i])
+			continue;
+
+		if (i == NETNSA_TARGET_NSID) {
+			struct net *net;
+
+			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
+			if (IS_ERR(net)) {
+				NL_SET_BAD_ATTR(extack, tb[i]);
+				NL_SET_ERR_MSG(extack,
+					       "Invalid target network namespace id");
+				return PTR_ERR(net);
+			}
+			net_cb->ref_net = net_cb->tgt_net;
+			net_cb->tgt_net = net;
+		} else {
+			NL_SET_BAD_ATTR(extack, tb[i]);
+			NL_SET_ERR_MSG(extack,
+				       "Unsupported attribute in dump request");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
-		.net = net,
+		.tgt_net = sock_net(skb->sk),
 		.skb = skb,
 		.cb = cb,
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
+	int err = 0;
 
-	if (cb->strict_check &&
-	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
-			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
-			return -EINVAL;
+	if (cb->strict_check) {
+		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
+		if (err < 0)
+			goto end;
 	}
 
-	spin_lock_bh(&net->nsid_lock);
-	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-	spin_unlock_bh(&net->nsid_lock);
+	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
-	return skb->len;
+end:
+	if (net_cb.ref_net)
+		put_net(net_cb.tgt_net);
+	return err < 0 ? err : skb->len;
 }
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
-- 
2.18.0

^ permalink raw reply related

* Re: Issue with RTL8111 NIC after upgrade to kernel 4.19
From: Marc Dionne @ 2018-11-21 21:53 UTC (permalink / raw)
  To: hkallweit1
  Cc: andrew, norbert.jurkeit, nic_swsd, Florian Fainelli, David Miller,
	netdev, Linux Kernel Mailing List, michael.wiktowy, jcline
In-Reply-To: <7d6362e1-e197-d338-d6b0-9036c3802e2c@gmail.com>

On Wed, Nov 21, 2018 at 4:52 PM Heiner Kallweit <hkallweit1@gmail.com> wrote:
>
> On 21.11.2018 21:49, Heiner Kallweit wrote:
> > On 21.11.2018 21:32, Heiner Kallweit wrote:
> >> On 21.11.2018 21:20, Andrew Lunn wrote:
> >>>> request_module() is supposed to be synchronous, however after some
> >>>> reading this may not be 100% guaranteed. Maybe the module init
> >>>> function on some systems isn't finished yet when request_module()
> >>>> returns. As a result the genphy driver may be used instead of
> >>>> the PHY version-specific driver.
> >>>
> >>> Hi Heiner
> >>>
> >>> That would be true for all PHYs i think. We would of noticed this
> >>> problem with other systems using other PHY drivers.
> >>>
> >>>     Andrew
> >>>
> >> It could be a timing issue affecting certain systems only. At least
> >> for now I don't have a good explanation why loading the module via
> >> request_module() and loading it upfront manually makes a difference.
> >>
> >> One affected user just reported the PHY to be a RTL8211B. This is
> >> what I expected, because this PHY crashes when writing to the MMD
> >> registers (the MMD registers are used otherwise by this PHY).
> >> See also commit 0231b1a074c6 ("net: phy: realtek: Use the dummy
> >> stubs for MMD register access for rtl8211b").
> >>
> >> Let's see whether the other affected systems use the same PHY
> >> version.
> >>
> > Next report is also about a RTL8211B and as I assumed:
> > - W/o manually loading the realtek module the genphy driver is used
> >   and network fails.
> > - W/ manually loading the realtek module the proper RTL8211B PHY
> >   driver is used and network works.
> >
> > So it seems that even after request_module() the PHY driver isn't
> > yet available when device and driver are matched.
> >
> > If further reports support this (pre-)analysis, then indeed it
> > seems to be a timing issue and a proper fix most likely is
> > difficult. As a workaround I could imagine to add a delay loop
> > after request_module() checking for a Realtek PHY driver via
> > driver_find(). When adding one small delay after this we should
> > be sufficiently sure that all Realtek PHY drivers are registered.
> >
> Uups, no. We talk about phylib here, not about the r8169 driver.
> So we need a different solution.
>
> >> Heiner

Thanks for the explanation, better than my crude attempt at
understanding what was going on.

If you have any proposed fixes or diagnostic patches based on current
mainline I can quickly compile and test them here on an affected
system.  It doesn't fail consistently for me (as others have
reported), but that could be because it depends on the timing.

Marc

^ permalink raw reply

* [PATCH v3 00/02] ravb: Duplex handling update V3
From: Magnus Damm @ 2018-11-21 11:21 UTC (permalink / raw)
  To: netdev; +Cc: linux-renesas-soc, Magnus Damm, davem, sergei.shtylyov

ravb: Duplex handling update V3

[PATCH v3 01/02] ravb: Do not announce HDX as supported
[PATCH v3 02/02] ravb: Clean up duplex handling

This series is V3 of duplex handling improvements for the Ethernet-AVB driver.

Previous versions of this series have been posted to linux-renesas-soc as RFC
so V3 is the first actual version to make it to netdev.

Based on the latest data sheet for R-Car Gen3 [1] and R-Car Gen2 [2]
the following information is part of the EthernetAVB-IF overview page:

Transfer speed: Supports transfer at 100 and 1000 Mbps
Mode: Full-duplex mode

It seems that the driver implementation is not matching the information
provided in the friendly data sheet, and on top of this during run-time
when changing PHY configuration of the link partner the Ethernet-AVB PHY
seems to want to announce unsupported modes.

[1] R-Car Series, 3rd Generation Rev.1.00 (Apr 2018)
[2] R-Car Series, 2nd Generation Rev.2.00 (Feb 2016)

Changes since V2:
- Updated patch 1/2 to make use of phy_remove_link_mode()
- Added Reviewed-by from Sergei - thanks!

Changes since V1:
- Updated patches to reflect input from Sergei and Geert - thanks!

Fixes: c156633f1353 ("Renesas Ethernet AVB driver proper")
Signed-off-by: Magnus Damm <damm+renesas@opensource.se>
Reviewed-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
---

 Applies on top of next-20181121

 drivers/net/ethernet/renesas/ravb.h      |    1 -
 drivers/net/ethernet/renesas/ravb_main.c |   23 +++++------------------
 2 files changed, 5 insertions(+), 19 deletions(-)

^ permalink raw reply

* [PATCH v3 01/02] ravb: Do not announce HDX as supported
From: Magnus Damm @ 2018-11-21 11:21 UTC (permalink / raw)
  To: netdev; +Cc: linux-renesas-soc, Magnus Damm, davem, sergei.shtylyov
In-Reply-To: <154279926877.10272.700833429936129422.sendpatchset@octo>

From: Magnus Damm <damm+renesas@opensource.se>

According to the data sheet the Ethernet-AVB hardware in R-Car Gen3
and R-Car Gen2 SoCs do not support half duplex operation. So update
the driver to mark 100Mbit and 1Gbps HDX as unsupported.

Fixes: c156633f1353 ("Renesas Ethernet AVB driver proper")
Signed-off-by: Magnus Damm <damm+renesas@opensource.se>
Reviewed-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
---

 Slightly reworked since V2 to make use of phy_remove_link_mode().
 In case Sergei wants to opt-out from the Reviewed-by tag for V2 let us know.
 
 Applies on top of next-20181121

 drivers/net/ethernet/renesas/ravb_main.c |    4 ++++
 1 file changed, 4 insertions(+)

--- 0001/drivers/net/ethernet/renesas/ravb_main.c
+++ work/drivers/net/ethernet/renesas/ravb_main.c	2018-11-21 19:47:58.165498803 +0900
@@ -1088,6 +1088,10 @@ static int ravb_phy_init(struct net_devi
 	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Pause_BIT);
 	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
 
+	/* Half Duplex is not supported */
+	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+	phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+
 	phy_attached_info(phydev);
 
 	return 0;

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox