* [PATCH net-next 16/19] net: usb: aqc111: Add RX VLAN filtering support
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 2 +-
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index a9051dd7c5bd..9908b0a04da6 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -351,6 +351,57 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p)
ETH_ALEN, net->dev_addr);
}
+static int aqc111_vlan_rx_kill_vid(struct net_device *net,
+ __be16 proto, u16 vid)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 reg8 = 0;
+ u16 reg16 = 0;
+ u8 vlan_ctrl = 0;
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ vlan_ctrl = reg8;
+
+ /* Address */
+ reg8 = (vid / 16);
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8);
+ /* Data */
+ reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, 2, ®16);
+ reg16 &= ~(1 << (vid % 16));
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, 2, ®16);
+ reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+
+ return 0;
+}
+
+static int aqc111_vlan_rx_add_vid(struct net_device *net, __be16 proto, u16 vid)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 reg8 = 0;
+ u16 reg16 = 0;
+ u8 vlan_ctrl = 0;
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ vlan_ctrl = reg8;
+
+ /* Address */
+ reg8 = (vid / 16);
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_ADDRESS, 1, 1, ®8);
+ /* Data */
+ reg8 = vlan_ctrl | SFR_VLAN_CONTROL_RD;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, 2, ®16);
+ reg16 |= (1 << (vid % 16));
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_DATA0, 2, 2, ®16);
+ reg8 = vlan_ctrl | SFR_VLAN_CONTROL_WE;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+
+ return 0;
+}
+
static void aqc111_set_rx_mode(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
@@ -393,6 +444,7 @@ static int aqc111_set_features(struct net_device *net,
netdev_features_t features)
{
u8 reg8 = 0;
+ u16 reg16 = 0;
struct usbnet *dev = netdev_priv(net);
struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
netdev_features_t changed = net->features ^ features;
@@ -426,6 +478,39 @@ static int aqc111_set_features(struct net_device *net,
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL,
1, 1, ®8);
}
+ if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
+ if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
+ u16 i = 0;
+
+ for (i = 0; i < 256; i++) {
+ /* Address */
+ reg8 = i;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+ SFR_VLAN_ID_ADDRESS,
+ 1, 1, ®8);
+ /* Data */
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+ SFR_VLAN_ID_DATA0,
+ 2, 2, ®16);
+ reg8 = SFR_VLAN_CONTROL_WE;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+ SFR_VLAN_ID_CONTROL,
+ 1, 1, ®8);
+ }
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+ 1, 1, ®8);
+ reg8 |= SFR_VLAN_CONTROL_VFE;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+ SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ } else {
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+ 1, 1, ®8);
+ reg8 &= ~SFR_VLAN_CONTROL_VFE;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC,
+ SFR_VLAN_ID_CONTROL, 1, 1, ®8);
+ }
+ }
+
return 0;
}
@@ -438,6 +523,8 @@ static const struct net_device_ops aqc111_netdev_ops = {
.ndo_change_mtu = aqc111_change_mtu,
.ndo_set_mac_address = aqc111_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_vlan_rx_add_vid = aqc111_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = aqc111_vlan_rx_kill_vid,
.ndo_set_rx_mode = aqc111_set_rx_mode,
.ndo_set_features = aqc111_set_features,
};
@@ -726,6 +813,8 @@ static int aqc111_link_reset(struct usbnet *dev)
/* Vlan Tag Filter */
reg8 = SFR_VLAN_CONTROL_VSO;
+ if (dev->net->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ reg8 |= SFR_VLAN_CONTROL_VFE;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
1, 1, ®8);
@@ -994,6 +1083,7 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
new_skb->truesize = new_skb->len + sizeof(struct sk_buff);
if (aqc111_data->rx_checksum)
aqc111_rx_checksum(new_skb, &pkt_desc);
+
if (pkt_desc->vlan_ind)
__vlan_hwaccel_put_tag(new_skb,
htons(ETH_P_8021Q),
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index e33459d90ddd..a7ccee225e93 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -73,7 +73,7 @@
#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
- NETIF_F_TSO)
+ NETIF_F_TSO | NETIF_F_HW_VLAN_CTAG_FILTER)
#define AQ_SUPPORT_VLAN_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 17/19] net: usb: aqc111: Initialize ethtool_ops structure
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 9908b0a04da6..ade2b60b4811 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,9 @@
#include "aqc111.h"
+#define DRIVER_VERSION "1.0.0.0"
+#define DRIVER_NAME "Aquantia AQtion USB to 5GbE"
+
static int __aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,
u16 index, u16 size, void *data, int nopm)
{
@@ -170,6 +174,24 @@ static int aq_mdio_write_cmd(struct usbnet *dev, u16 value, u16 index,
return aqc111_write_cmd(dev, AQ_PHY_CMD, value, index, size, data);
}
+static void aqc111_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u.%u",
+ aqc111_data->fw_ver.major,
+ aqc111_data->fw_ver.minor,
+ aqc111_data->fw_ver.rev);
+ info->eedump_len = 0x00;
+ info->regdump_len = 0x00;
+}
+
static void aqc111_set_phy_speed_fw_iface(struct usbnet *dev,
struct aqc111_data *aqc111_data)
{
@@ -286,6 +308,13 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
}
+static const struct ethtool_ops aqc111_ethtool_ops = {
+ .get_drvinfo = aqc111_get_drvinfo,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_link = ethtool_op_get_link,
+};
+
static int aqc111_change_mtu(struct net_device *net, int new_mtu)
{
struct usbnet *dev = netdev_priv(net);
@@ -605,6 +634,7 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->needed_tailroom += AQ_TX_HEADER_SIZE;
dev->net->netdev_ops = &aqc111_netdev_ops;
+ dev->net->ethtool_ops = &aqc111_ethtool_ops;
if (usb_device_no_sg_constraint(dev->udev))
dev->can_dma_sg = 1;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 15/19] net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 14 ++++++++++++++
drivers/net/usb/aqc111.h | 7 ++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index cc23c39beab3..a9051dd7c5bd 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -524,6 +524,7 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE;
dev->net->features |= AQ_SUPPORT_FEATURE;
+ dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE;
aqc111_read_fw_version(dev, aqc111_data);
aqc111_data->autoneg = AUTONEG_ENABLE;
@@ -817,6 +818,7 @@ static int aqc111_reset(struct usbnet *dev)
dev->net->hw_features |= AQ_SUPPORT_HW_FEATURE;
dev->net->features |= AQ_SUPPORT_FEATURE;
+ dev->net->vlan_features |= AQ_SUPPORT_VLAN_FEATURE;
/* Power up ethernet PHY */
aqc111_data->phy_ops.advertising = 0;
@@ -992,6 +994,11 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
new_skb->truesize = new_skb->len + sizeof(struct sk_buff);
if (aqc111_data->rx_checksum)
aqc111_rx_checksum(new_skb, &pkt_desc);
+ if (pkt_desc->vlan_ind)
+ __vlan_hwaccel_put_tag(new_skb,
+ htons(ETH_P_8021Q),
+ pkt_desc->vlan_tag &
+ VLAN_VID_MASK);
usbnet_skb_return(dev, new_skb);
if (pkt_count == 0)
@@ -1020,6 +1027,7 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
int tailroom = 0;
int padding_size = 0;
struct sk_buff *new_skb = NULL;
+ u16 tci = 0;
memset(&tx_hdr, 0x00, sizeof(tx_hdr));
@@ -1038,6 +1046,12 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
tx_hdr.drop_padding = 1;
}
+ /* Vlan Tag */
+ if (vlan_get_tag(skb, &tci) >= 0) {
+ tx_hdr.vlan_tag = 1;
+ tx_hdr.vlan_info = tci;
+ }
+
if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) &&
skb_linearize(skb))
return NULL;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 2f324ec66a65..e33459d90ddd 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -68,12 +68,17 @@
/* Feature. ********************************************/
#define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
- NETIF_F_TSO)
+ NETIF_F_TSO | NETIF_F_HW_VLAN_CTAG_TX |\
+ NETIF_F_HW_VLAN_CTAG_RX)
#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
NETIF_F_TSO)
+#define AQ_SUPPORT_VLAN_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
+ NETIF_F_TSO)
+
/* SFR Reg. ********************************************/
#define SFR_GENERAL_STATUS 0x03
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 14/19] net: usb: aqc111: Implement set_rx_mode callback
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 4 +++
2 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index f61fa7446b72..cc23c39beab3 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/mii.h>
#include <linux/usb.h>
+#include <linux/crc32.h>
#include <linux/if_vlan.h>
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
@@ -139,6 +140,24 @@ static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value,
return __aqc111_write_cmd(dev, cmd, value, index, size, data, 0);
}
+static void aqc111_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data)
+{
+ if (size == 2) {
+ u16 buf;
+
+ buf = *((u16 *)data);
+ cpu_to_le16s(&buf);
+ usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, value, index, &buf,
+ size);
+ } else {
+ usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, value, index, data,
+ size);
+ }
+}
+
static int aq_mdio_read_cmd(struct usbnet *dev, u16 value, u16 index,
u16 size, void *data)
{
@@ -332,6 +351,44 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p)
ETH_ALEN, net->dev_addr);
}
+static void aqc111_set_rx_mode(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ u8 *m_filter = ((u8 *)dev->data) + 12;
+ int mc_count = 0;
+
+ mc_count = netdev_mc_count(net);
+
+ aqc111_data->rxctl &= ~(SFR_RX_CTL_PRO | SFR_RX_CTL_AMALL |
+ SFR_RX_CTL_AM);
+
+ if (net->flags & IFF_PROMISC) {
+ aqc111_data->rxctl |= SFR_RX_CTL_PRO;
+ } else if ((net->flags & IFF_ALLMULTI) || mc_count > AQ_MAX_MCAST) {
+ aqc111_data->rxctl |= SFR_RX_CTL_AMALL;
+ } else if (!netdev_mc_empty(net)) {
+ u32 crc_bits = 0;
+ struct netdev_hw_addr *ha = NULL;
+
+ memset(m_filter, 0, AQ_MCAST_FILTER_SIZE);
+ netdev_for_each_mc_addr(ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ m_filter[crc_bits >> 3] |= BIT(crc_bits & 7);
+ }
+
+ aqc111_write_cmd_async(dev, AQ_ACCESS_MAC,
+ SFR_MULTI_FILTER_ARRY,
+ AQ_MCAST_FILTER_SIZE,
+ AQ_MCAST_FILTER_SIZE, m_filter);
+
+ aqc111_data->rxctl |= SFR_RX_CTL_AM;
+ }
+
+ aqc111_write_cmd_async(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, &aqc111_data->rxctl);
+}
+
static int aqc111_set_features(struct net_device *net,
netdev_features_t features)
{
@@ -381,6 +438,7 @@ static const struct net_device_ops aqc111_netdev_ops = {
.ndo_change_mtu = aqc111_change_mtu,
.ndo_set_mac_address = aqc111_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = aqc111_set_rx_mode,
.ndo_set_features = aqc111_set_features,
};
@@ -681,6 +739,7 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8);
reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+ aqc111_data->rxctl = reg16;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
reg8 = SFR_RX_PATH_READY;
@@ -701,6 +760,8 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_configure_csum_offload(dev);
+ aqc111_set_rx_mode(dev->net);
+
aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
@@ -712,8 +773,9 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
- reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
- aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+ aqc111_data->rxctl |= SFR_RX_CTL_START;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, &aqc111_data->rxctl);
netif_carrier_on(dev->net);
} else {
@@ -723,9 +785,9 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
- aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
- reg16 &= ~SFR_RX_CTL_START;
- aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+ aqc111_data->rxctl &= ~SFR_RX_CTL_START;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, &aqc111_data->rxctl);
reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 9cf357777df9..2f324ec66a65 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -12,6 +12,9 @@
#define URB_SIZE (1024 * 62)
+#define AQ_MCAST_FILTER_SIZE 8
+#define AQ_MAX_MCAST 64
+
#define AQ_ACCESS_MAC 0x01
#define AQ_FLASH_PARAMETERS 0x20
#define AQ_PHY_POWER 0x31
@@ -207,6 +210,7 @@ struct aqc111_phy_options {
};
struct aqc111_data {
+ u16 rxctl;
u8 rx_checksum;
u8 link_speed;
u8 link;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 13/19] net: usb: aqc111: Add support for TSO
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 3 +++
drivers/net/usb/aqc111.h | 6 ++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 6efd9a9ad44e..f61fa7446b72 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -964,6 +964,9 @@ static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
/*Length of actual data*/
tx_hdr.length = (skb->len & 0x1FFFFF);
+ /* TSO MSS */
+ tx_hdr.max_seg_size = skb_shinfo(skb)->gso_size;
+
headroom = (skb->len + AQ_TX_HEADER_SIZE) % 8;
if (headroom != 0)
padding_size = 8 - headroom;
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 0be2e4cbb00a..9cf357777df9 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -64,10 +64,12 @@
/* Feature. ********************************************/
#define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
- NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
+ NETIF_F_TSO)
#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
- NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |\
+ NETIF_F_TSO)
/* SFR Reg. ********************************************/
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 12/19] net: usb: aqc111: Add support for enable/disable checksum offload
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 45 ++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/usb/aqc111.h | 1 +
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 134cfc632584..6efd9a9ad44e 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -332,6 +332,46 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p)
ETH_ALEN, net->dev_addr);
}
+static int aqc111_set_features(struct net_device *net,
+ netdev_features_t features)
+{
+ u8 reg8 = 0;
+ struct usbnet *dev = netdev_priv(net);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ netdev_features_t changed = net->features ^ features;
+
+ if (changed & NETIF_F_IP_CSUM) {
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8);
+ reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+ 1, 1, ®8);
+ }
+
+ if (changed & NETIF_F_IPV6_CSUM) {
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8);
+ reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL,
+ 1, 1, ®8);
+ }
+
+ if (changed & NETIF_F_RXCSUM) {
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8);
+ if (features & NETIF_F_RXCSUM) {
+ aqc111_data->rx_checksum = 1;
+ reg8 &= ~(SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP |
+ SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6);
+ } else {
+ aqc111_data->rx_checksum = 0;
+ reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP |
+ SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6;
+ }
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL,
+ 1, 1, ®8);
+ }
+ return 0;
+}
+
static const struct net_device_ops aqc111_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
@@ -341,6 +381,7 @@ static const struct net_device_ops aqc111_netdev_ops = {
.ndo_change_mtu = aqc111_change_mtu,
.ndo_set_mac_address = aqc111_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_features = aqc111_set_features,
};
static int aqc111_get_mac(struct usbnet *dev, u8 *buf)
@@ -814,6 +855,7 @@ static void aqc111_rx_checksum(struct sk_buff *skb, void *pkt_hdr)
static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct sk_buff *new_skb = NULL;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
u32 skb_len = 0;
u32 desc_offset = 0; /*RX Header Offset*/
u32 start_of_descs = 0;
@@ -886,7 +928,8 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
skb_set_tail_pointer(new_skb, new_skb->len);
new_skb->truesize = new_skb->len + sizeof(struct sk_buff);
- aqc111_rx_checksum(new_skb, &pkt_desc);
+ if (aqc111_data->rx_checksum)
+ aqc111_rx_checksum(new_skb, &pkt_desc);
usbnet_skb_return(dev, new_skb);
if (pkt_count == 0)
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 1632e78ebe9b..0be2e4cbb00a 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -205,6 +205,7 @@ struct aqc111_phy_options {
};
struct aqc111_data {
+ u8 rx_checksum;
u8 link_speed;
u8 link;
u8 autoneg;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 03/19] net: usb: aqc111: Add implementation of read and write commands
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Read/write command register defines and functions
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/aqc111.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 19 ++++++++
2 files changed, 143 insertions(+)
create mode 100644 drivers/net/usb/aqc111.h
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index c914e19387f2..7f3e5a615750 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -14,6 +14,130 @@
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
+#include "aqc111.h"
+
+static int __aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data, int nopm)
+{
+ int ret;
+ int (*fn)(struct usbnet *dev, u8 cmd, u8 reqtype, u16 value,
+ u16 index, void *data, u16 size);
+
+ if (nopm)
+ fn = usbnet_read_cmd_nopm;
+ else
+ fn = usbnet_read_cmd;
+
+ ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, data, size);
+ if (size == 2)
+ le16_to_cpus(data);
+
+ if (unlikely(ret < 0))
+ netdev_warn(dev->net,
+ "Failed to read(0x%x) reg index 0x%04x: %d\n",
+ cmd, index, ret);
+ return ret;
+}
+
+static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data)
+{
+ return __aqc111_read_cmd(dev, cmd, value, index, size, data, 1);
+}
+
+static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data)
+{
+ return __aqc111_read_cmd(dev, cmd, value, index, size, data, 0);
+}
+
+static int __aq_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
+ u16 value, u16 index, const void *data, u16 size)
+{
+ void *buf = NULL;
+ int err = -ENOMEM;
+
+ netdev_dbg(dev->net,
+ "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n",
+ __func__, cmd, reqtype, value, index, size);
+
+ if (data) {
+ buf = kmemdup(data, size, GFP_KERNEL);
+ if (!buf)
+ goto out;
+ }
+
+ if (size == 2)
+ cpu_to_le16s(buf);
+ else if (size == 4)
+ cpu_to_le32s(buf);
+
+ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ cmd, reqtype, value, index, buf, size,
+ (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT :
+ AQ_USB_SET_TIMEOUT);
+
+ kfree(buf);
+
+out:
+ return err;
+}
+
+static int aq_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype,
+ u16 value, u16 index, const void *data, u16 size)
+{
+ return __aq_write_cmd(dev, cmd, reqtype, value, index,
+ data, size);
+}
+
+static int aq_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
+ u16 value, u16 index, const void *data, u16 size)
+{
+ int ret;
+
+ if (usb_autopm_get_interface(dev->intf) < 0)
+ return -ENODEV;
+ ret = __aq_write_cmd(dev, cmd, reqtype, value, index, data, size);
+ usb_autopm_put_interface(dev->intf);
+ return ret;
+}
+
+static int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data, int nopm)
+{
+ int ret;
+ int (*fn)(struct usbnet *dev, u8 cmd, u8 reqtype, u16 value,
+ u16 index, const void *data, u16 size);
+
+ if (nopm)
+ fn = aq_write_cmd_nopm;
+ else
+ fn = aq_write_cmd;
+
+ ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, data, size);
+
+ if (unlikely(ret < 0))
+ netdev_warn(dev->net,
+ "Failed to write(0x%x) reg 0x%04x: %d\n",
+ cmd, value, ret);
+
+ return ret;
+}
+
+static int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data)
+{
+ return __aqc111_write_cmd(dev, cmd, value, index, size, data, 1);
+}
+
+static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value,
+ u16 index, u16 size, void *data)
+{
+ return __aqc111_write_cmd(dev, cmd, value, index, size, data, 0);
+}
+
static const struct net_device_ops aqc111_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
new file mode 100644
index 000000000000..1698a6a104fe
--- /dev/null
+++ b/drivers/net/usb/aqc111.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Aquantia Corp. Aquantia AQtion USB to 5GbE Controller
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2002-2003 TiVo Inc.
+ * Copyright (C) 2017-2018 ASIX
+ * Copyright (C) 2018 Aquantia Corp.
+ */
+
+#ifndef __LINUX_USBNET_AQC111_H
+#define __LINUX_USBNET_AQC111_H
+
+#define AQ_PHY_POWER 0x31
+
+#define AQ_USB_PHY_SET_TIMEOUT 10000
+#define AQ_USB_SET_TIMEOUT 4000
+
+#endif /* __LINUX_USBNET_AQC111_H */
+
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 11/19] net: usb: aqc111: Add support for changing MTU
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 63 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 5967f7adeab4..134cfc632584 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -267,6 +267,54 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
}
+static int aqc111_change_mtu(struct net_device *net, int new_mtu)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u16 reg16 = 0;
+ u8 buf[5];
+
+ if (new_mtu <= 0 || new_mtu > 16334) {
+ netdev_info(net, "Invalid MTU %d requested, hw max 16334",
+ new_mtu);
+ return -EINVAL;
+ }
+
+ net->mtu = new_mtu;
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+ if (net->mtu > 1500)
+ reg16 |= SFR_MEDIUM_JUMBO_EN;
+ else
+ reg16 &= ~SFR_MEDIUM_JUMBO_EN;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ if (dev->net->mtu > 12500 && dev->net->mtu < 16384) {
+ 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 < 16384)
+ reg16 = 0x1A20;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW,
+ 2, 2, ®16);
+
+ return 0;
+}
+
static int aqc111_set_mac_addr(struct net_device *net, void *p)
{
struct usbnet *dev = netdev_priv(net);
@@ -290,6 +338,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,
};
@@ -524,13 +573,22 @@ static void aqc111_configure_rx(struct usbnet *dev,
break;
}
}
+ if (dev->net->mtu > 12500 && dev->net->mtu < 16384)
+ 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 < 16384)
+ reg16 = 0x1A20;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW,
2, 2, ®16);
@@ -605,6 +663,9 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
+ if (dev->net->mtu > 1500)
+ reg16 |= SFR_MEDIUM_JUMBO_EN;
+
reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN |
SFR_MEDIUM_TXFLOW_CTRLEN;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 06/19] net: usb: aqc111: Introduce link management
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 330 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 51 ++++++++
2 files changed, 381 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 30219bb6ddfd..1d366f4a1c51 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -150,6 +150,122 @@ static int aq_mdio_write_cmd(struct usbnet *dev, u16 value, u16 index,
return aqc111_write_cmd(dev, AQ_PHY_CMD, value, index, size, data);
}
+static void aqc111_set_phy_speed_fw_iface(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ aqc111_write_cmd(dev, AQ_PHY_OPS, 0, 0, 4, &aqc111_data->phy_ops);
+}
+
+static void aqc111_set_phy_speed_direct(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ u16 reg16_1 = 0;
+ u16 reg16_2 = 0;
+ u16 reg16_3 = 0;
+
+ /* Disable auto-negotiation */
+ reg16_1 = AQ_ANEG_EX_PAGE_CTRL;
+ aq_mdio_write_cmd(dev, AQ_AUTONEG_STD_CTRL_REG, AQ_PHY_AUTONEG_ADDR,
+ 2, ®16_1);
+
+ reg16_1 = AQ_ANEG_EX_PHY_ID | AQ_ANEG_ADV_AQRATE;
+ if (aqc111_data->phy_ops.downshift) {
+ reg16_1 |= AQ_ANEG_EN_DSH;
+ reg16_1 |= aqc111_data->phy_ops.dsh_ret_cnt & 0x0F;
+ }
+
+ reg16_2 = AQ_ANEG_ADV_LT;
+ if (aqc111_data->phy_ops.pause)
+ reg16_3 |= AQ_ANEG_PAUSE;
+
+ if (aqc111_data->phy_ops.asym_pause)
+ reg16_3 |= AQ_ANEG_ASYM_PAUSE;
+
+ if (aqc111_data->phy_ops.adv_5G) {
+ reg16_1 |= AQ_ANEG_ADV_5G_N;
+ reg16_2 |= AQ_ANEG_ADV_5G_T;
+ }
+ if (aqc111_data->phy_ops.adv_2G5) {
+ reg16_1 |= AQ_ANEG_ADV_2G5_N;
+ reg16_2 |= AQ_ANEG_ADV_2G5_T;
+ }
+ if (aqc111_data->phy_ops.adv_1G)
+ reg16_1 |= AQ_ANEG_ADV_1G;
+
+ if (aqc111_data->phy_ops.adv_5G)
+ reg16_3 |= AQ_ANEG_100M;
+
+ aq_mdio_write_cmd(dev, AQ_AUTONEG_VEN_PROV1_REG,
+ AQ_PHY_AUTONEG_ADDR, 2, ®16_1);
+ aq_mdio_write_cmd(dev, AQ_AUTONEG_10GT_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, 2, ®16_2);
+
+ aq_mdio_read_cmd(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+ 2, ®16_1);
+ reg16_1 &= ~AQ_ANEG_ABILITY_MASK;
+ reg16_1 |= reg16_3;
+ aq_mdio_write_cmd(dev, AQ_AUTONEG_ADV_REG, AQ_PHY_AUTONEG_ADDR,
+ 2, ®16_1);
+
+ /* Restart auto-negotiation */
+ reg16_1 = AQ_ANEG_EX_PAGE_CTRL | AQ_ANEG_EN_ANEG |
+ AQ_ANEG_RESTART_ANEG;
+
+ aq_mdio_write_cmd(dev, AQ_AUTONEG_STD_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, 2, ®16_1);
+}
+
+static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
+{
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ aqc111_data->phy_ops.advertising = 0;
+ aqc111_data->phy_ops.pause = 1;
+ aqc111_data->phy_ops.asym_pause = 1;
+ aqc111_data->phy_ops.downshift = 1;
+ aqc111_data->phy_ops.dsh_ret_cnt = 3;
+ if (autoneg == AUTONEG_ENABLE) {
+ switch (speed) {
+ case SPEED_5000:
+ aqc111_data->phy_ops.adv_5G = 1;
+ case SPEED_2500:
+ aqc111_data->phy_ops.adv_2G5 = 1;
+ case SPEED_1000:
+ aqc111_data->phy_ops.adv_1G = 1;
+ case SPEED_100:
+ aqc111_data->phy_ops.adv_100M = 1;
+ }
+ } else {
+ switch (speed) {
+ case SPEED_5000:
+ {
+ aqc111_data->phy_ops.adv_5G = 1;
+ break;
+ }
+ case SPEED_2500:
+ {
+ aqc111_data->phy_ops.adv_2G5 = 1;
+ break;
+ }
+ case SPEED_1000:
+ {
+ aqc111_data->phy_ops.adv_1G = 1;
+ break;
+ }
+ case SPEED_100:
+ {
+ aqc111_data->phy_ops.adv_100M = 1;
+ break;
+ }
+ }
+ }
+
+ if (aqc111_data->dpa)
+ aqc111_set_phy_speed_direct(dev, aqc111_data);
+ else
+ aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
+}
+
static const struct net_device_ops aqc111_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
@@ -176,6 +292,7 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
int ret;
struct usb_device *udev = interface_to_usbdev(intf);
struct aqc111_data *aqc111_data;
+ enum usb_device_speed usb_speed = dev->udev->speed;
/* Check if vendor configuration */
if (udev->actconfig->desc.bConfigurationValue != 1) {
@@ -202,6 +319,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;
}
@@ -227,6 +347,7 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0,
0, 1, ®8);
} else {
+ aqc111_data->phy_ops.advertising = 0;
aqc111_data->phy_ops.low_power = 1;
aqc111_data->phy_ops.phy_power = 0;
aqc111_write_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
@@ -236,13 +357,212 @@ 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_int_data *event = NULL;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ int link = 0;
+
+ if (urb->actual_length < 8)
+ return;
+
+ event = urb->transfer_buffer;
+
+ if (event->link_status)
+ link = 1;
+ else
+ link = 0;
+
+ aqc111_data->link_speed = event->link_speed;
+ 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)
+{
+ u8 reg8 = 0;
+ u8 queue_num = 0;
+ u16 reg16 = 0;
+ u16 link_speed = 0, usb_host = 0;
+ u8 buf[5] = { 0 };
+ enum usb_device_speed usb_speed = dev->udev->speed;
+
+ buf[0] = 0x00;
+ buf[1] = 0xF8;
+ buf[2] = 0x07;
+ switch (aqc111_data->link_speed) {
+ case AQ_INT_SPEED_5G:
+ {
+ link_speed = 5000;
+ reg8 = 0x05;
+ reg16 = 0x001F;
+ break;
+ }
+ case AQ_INT_SPEED_2_5G:
+ {
+ link_speed = 2500;
+ reg16 = 0x003F;
+ break;
+ }
+ case AQ_INT_SPEED_1G:
+ {
+ link_speed = 1000;
+ reg16 = 0x009F;
+ break;
+ }
+ case AQ_INT_SPEED_100M:
+ {
+ link_speed = 100;
+ queue_num = 1;
+ reg16 = 0x063F;
+ buf[1] = 0xFB;
+ buf[2] = 0x4;
+ break;
+ }
+ }
+
+ if (aqc111_data->dpa) {
+ /* Set Phy Flow control */
+ aq_mdio_write_cmd(dev, AQ_GLB_ING_PAUSE_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, 2, ®16);
+ aq_mdio_write_cmd(dev, AQ_GLB_EGR_PAUSE_CTRL_REG,
+ AQ_PHY_AUTONEG_ADDR, 2, ®16);
+ }
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_INTER_PACKET_GAP_0,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TX_PAUSE_RESEND_T, 3, 3, buf);
+
+ switch (usb_speed) {
+ case USB_SPEED_SUPER:
+ {
+ usb_host = 3;
+ break;
+ }
+ case USB_SPEED_HIGH:
+ {
+ usb_host = 2;
+ break;
+ }
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ {
+ usb_host = 1;
+ queue_num = 0;
+ break;
+ }
+ default:
+ {
+ usb_host = 0;
+ break;
+ }
+ }
+
+ memcpy(buf, &AQC111_BULKIN_SIZE[queue_num], 5);
+ /* RX bulk configuration */
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL, 5, 5, buf);
+
+ /* Set high low water level */
+ reg16 = 0x0810;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_PAUSE_WATERLVL_LOW,
+ 2, 2, ®16);
+ netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host);
+}
+
+static int aqc111_link_reset(struct usbnet *dev)
+{
+ u8 reg8 = 0;
+ u16 reg16 = 0;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ if (aqc111_data->link == 1) { /* Link up */
+ aqc111_configure_rx(dev, aqc111_data);
+
+ /* Vlan Tag Filter */
+ reg8 = SFR_VLAN_CONTROL_VSO;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_VLAN_ID_CONTROL,
+ 1, 1, ®8);
+
+ reg8 = 0x0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMTX_DMA_CONTROL,
+ 1, 1, ®8);
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ARC_CTRL, 1, 1, ®8);
+
+ reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+
+ reg8 = SFR_RX_PATH_READY;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+ 1, 1, ®8);
+
+ reg8 = SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+
+ reg16 = 0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ reg16 = SFR_MEDIUM_XGMIIMODE | SFR_MEDIUM_FULL_DUPLEX;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ reg16 |= SFR_MEDIUM_RECEIVE_EN | SFR_MEDIUM_RXFLOW_CTRLEN |
+ SFR_MEDIUM_TXFLOW_CTRLEN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ reg16 = SFR_RX_CTL_IPE | SFR_RX_CTL_AB | SFR_RX_CTL_START;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+
+ netif_carrier_on(dev->net);
+ } else {
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+ reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+ reg16 &= ~SFR_RX_CTL_START;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+
+ reg8 = SFR_BULK_OUT_FLUSH_EN | SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+ reg8 = SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+
+ netif_carrier_off(dev->net);
+ }
+ return 0;
+}
+
static int aqc111_reset(struct usbnet *dev)
{
u8 reg8 = 0;
u16 reg16 = 0;
+ enum usb_device_speed usb_speed;
struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ usb_speed = dev->udev->speed;
+
/* Power up ethernet PHY */
+ aqc111_data->phy_ops.advertising = 0;
aqc111_data->phy_ops.phy_ctrl1 = 0;
aqc111_data->phy_ops.phy_ctrl2 = 0;
@@ -279,6 +599,12 @@ static int aqc111_reset(struct usbnet *dev)
SFR_MONITOR_MODE_RW_FLAG);
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8);
+ netif_carrier_off(dev->net);
+
+ /* Phy advertise */
+ aqc111_set_phy_speed(dev, aqc111_data->autoneg,
+ aqc111_data->advertised_speed);
+
return 0;
}
@@ -307,6 +633,8 @@ static int aqc111_stop(struct usbnet *dev)
4, &aqc111_data->phy_ops);
}
+ netif_carrier_off(dev->net);
+
return 0;
}
@@ -314,6 +642,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 8738d2c4ae90..5c5602e6d236 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -18,12 +18,44 @@
#define AQC111_PHY_ID 0x00
#define AQ_PHY_ADDR(mmd) ((AQC111_PHY_ID << 8) | mmd)
+#define AQ_PHY_AUTONEG_MMD 0x07
+#define AQ_PHY_AUTONEG_ADDR AQ_PHY_ADDR(AQ_PHY_AUTONEG_MMD)
+
+#define AQ_AUTONEG_STD_CTRL_REG 0x0000
+ #define AQ_ANEG_EX_PAGE_CTRL 0x2000
+ #define AQ_ANEG_EN_ANEG 0x1000
+ #define AQ_ANEG_RESTART_ANEG 0x0200
+
+#define AQ_AUTONEG_ADV_REG 0x0010
+ #define AQ_ANEG_100M 0x0100
+ #define AQ_ANEG_PAUSE 0x0400
+ #define AQ_ANEG_ASYM_PAUSE 0x0800
+ #define AQ_ANEG_ABILITY_MASK 0x0FE0
+
+#define AQ_AUTONEG_10GT_CTRL_REG 0x0020
+ #define AQ_ANEG_ADV_10G_T 0x1000
+ #define AQ_ANEG_ADV_5G_T 0x0100
+ #define AQ_ANEG_ADV_2G5_T 0x0080
+ #define AQ_ANEG_ADV_LT 0x0001
+
+#define AQ_AUTONEG_VEN_PROV1_REG 0xC400
+ #define AQ_ANEG_ADV_1G 0x8000
+ #define AQ_ANEG_ADV_AQRATE 0x1000
+ #define AQ_ANEG_ADV_5G_N 0x0800
+ #define AQ_ANEG_ADV_2G5_N 0x0400
+ #define AQ_ANEG_EX_PHY_ID 0x0040
+ #define AQ_ANEG_EN_DSH 0x0010
+ #define AQ_ANEG_DSH_RETRY 0x0003
+
#define AQ_PHY_GLOBAL_MMD 0x1E
#define AQ_PHY_GLOBAL_ADDR AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
#define AQ_GLB_STD_CTRL_REG 0x0000
#define AQ_PHY_LOW_POWER_MODE 0x0800
+#define AQ_GLB_ING_PAUSE_CTRL_REG 0x7148
+#define AQ_GLB_EGR_PAUSE_CTRL_REG 0x4148
+
#define AQ_USB_PHY_SET_TIMEOUT 10000
#define AQ_USB_SET_TIMEOUT 4000
@@ -163,6 +195,10 @@ struct aqc111_phy_options {
};
struct aqc111_data {
+ u8 link_speed;
+ u8 link;
+ u8 autoneg;
+ u32 advertised_speed;
struct {
u8 major;
u8 minor;
@@ -172,6 +208,21 @@ struct aqc111_data {
struct aqc111_phy_options phy_ops;
} __packed;
+struct aqc111_int_data {
+ u8 res1;
+ u8 link_speed: 7;
+ u8 link_status: 1;
+ __le16 res2;
+ __le16 res3;
+ __le16 res4;
+} __packed;
+
+#define AQ_INT_SPEED_10G 0x0E
+#define AQ_INT_SPEED_5G 0x0F
+#define AQ_INT_SPEED_2_5G 0x10
+#define AQ_INT_SPEED_1G 0x11
+#define AQ_INT_SPEED_100M 0x13
+
static struct {
unsigned char ctrl;
unsigned char timer_l;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 05/19] net: usb: aqc111: Introduce PHY access
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Implement PHY power up/down sequences.
AQC111, depending on FW used, may has PHY being controlled either
directly (dpa = 1) or via vendor command interface (dpa = 0).
Drivers supports both themes.
We determine this from firmware versioning agreement.
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/aqc111.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 70 ++++++++++++++++++++++++++++++++++++
2 files changed, 163 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 22bb259d71fb..30219bb6ddfd 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -138,15 +138,44 @@ static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value,
return __aqc111_write_cmd(dev, cmd, value, index, size, data, 0);
}
+static int aq_mdio_read_cmd(struct usbnet *dev, u16 value, u16 index,
+ u16 size, void *data)
+{
+ return aqc111_read_cmd(dev, AQ_PHY_CMD, value, index, size, data);
+}
+
+static int aq_mdio_write_cmd(struct usbnet *dev, u16 value, u16 index,
+ u16 size, void *data)
+{
+ return aqc111_write_cmd(dev, AQ_PHY_CMD, value, index, size, data);
+}
+
static const struct net_device_ops aqc111_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
};
+static void aqc111_read_fw_version(struct usbnet *dev,
+ struct aqc111_data *aqc111_data)
+{
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR,
+ 1, 1, &aqc111_data->fw_ver.major);
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR,
+ 1, 1, &aqc111_data->fw_ver.minor);
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV,
+ 1, 1, &aqc111_data->fw_ver.rev);
+
+ if (aqc111_data->fw_ver.major & 0x80)
+ aqc111_data->fw_ver.major &= ~0x80;
+ else
+ aqc111_data->dpa = 1;
+}
+
static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
struct usb_device *udev = interface_to_usbdev(intf);
+ struct aqc111_data *aqc111_data;
/* Check if vendor configuration */
if (udev->actconfig->desc.bConfigurationValue != 1) {
@@ -162,8 +191,18 @@ 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->data[0] = (unsigned long)aqc111_data;
+ memset(aqc111_data, 0, sizeof(*aqc111_data));
+
dev->net->netdev_ops = &aqc111_netdev_ops;
+ aqc111_read_fw_version(dev, aqc111_data);
+
return 0;
}
@@ -172,6 +211,8 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
u8 reg8;
u16 reg16;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
/* Force bz */
reg16 = SFR_PHYPWR_RSTCTL_BZ;
aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
@@ -179,12 +220,52 @@ static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
reg16 = 0;
aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
2, 2, ®16);
+
+ /* Power down ethernet PHY */
+ if (aqc111_data->dpa) {
+ reg8 = 0x00;
+ aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0,
+ 0, 1, ®8);
+ } else {
+ aqc111_data->phy_ops.low_power = 1;
+ aqc111_data->phy_ops.phy_power = 0;
+ aqc111_write_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ 4, &aqc111_data->phy_ops);
+ }
+
+ kfree(aqc111_data);
}
static int aqc111_reset(struct usbnet *dev)
{
u8 reg8 = 0;
u16 reg16 = 0;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ /* Power up ethernet PHY */
+ aqc111_data->phy_ops.phy_ctrl1 = 0;
+ aqc111_data->phy_ops.phy_ctrl2 = 0;
+
+ aqc111_data->phy_ops.phy_power = 1;
+ if (aqc111_data->dpa) {
+ aqc111_read_cmd(dev, AQ_PHY_POWER, 0, 0, 1, ®8);
+ if (reg8 == 0x00) {
+ reg8 = 0x02;
+ aqc111_write_cmd(dev, AQ_PHY_POWER, 0, 0, 1, ®8);
+ msleep(200);
+ }
+
+ aq_mdio_read_cmd(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+ 2, ®16);
+ if (reg16 & AQ_PHY_LOW_POWER_MODE) {
+ reg16 &= ~AQ_PHY_LOW_POWER_MODE;
+ aq_mdio_write_cmd(dev, AQ_GLB_STD_CTRL_REG,
+ AQ_PHY_GLOBAL_ADDR, 2, ®16);
+ }
+ } else {
+ aqc111_write_cmd(dev, AQ_PHY_OPS, 0, 0,
+ 4, &aqc111_data->phy_ops);
+ }
reg8 = 0xFF;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8);
@@ -204,6 +285,7 @@ static int aqc111_reset(struct usbnet *dev)
static int aqc111_stop(struct usbnet *dev)
{
u16 reg16 = 0;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
@@ -214,6 +296,17 @@ static int aqc111_stop(struct usbnet *dev)
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
2, 2, ®16);
+ /* Put PHY to low power*/
+ if (aqc111_data->dpa) {
+ reg16 = AQ_PHY_LOW_POWER_MODE;
+ aq_mdio_write_cmd(dev, AQ_GLB_STD_CTRL_REG, AQ_PHY_GLOBAL_ADDR,
+ 2, ®16);
+ } else {
+ aqc111_data->phy_ops.low_power = 1;
+ aqc111_write_cmd(dev, AQ_PHY_OPS, 0, 0,
+ 4, &aqc111_data->phy_ops);
+ }
+
return 0;
}
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 6b34202fa22b..8738d2c4ae90 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -12,6 +12,17 @@
#define AQ_ACCESS_MAC 0x01
#define AQ_PHY_POWER 0x31
+#define AQ_PHY_CMD 0x32
+#define AQ_PHY_OPS 0x61
+
+#define AQC111_PHY_ID 0x00
+#define AQ_PHY_ADDR(mmd) ((AQC111_PHY_ID << 8) | mmd)
+
+#define AQ_PHY_GLOBAL_MMD 0x1E
+#define AQ_PHY_GLOBAL_ADDR AQ_PHY_ADDR(AQ_PHY_GLOBAL_MMD)
+
+#define AQ_GLB_STD_CTRL_REG 0x0000
+ #define AQ_PHY_LOW_POWER_MODE 0x0800
#define AQ_USB_PHY_SET_TIMEOUT 10000
#define AQ_USB_SET_TIMEOUT 4000
@@ -102,6 +113,65 @@
#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
+
+/******************************************************************************/
+
+struct aqc111_phy_options {
+ union {
+ struct {
+ u8 adv_100M: 1;
+ u8 adv_1G: 1;
+ u8 adv_2G5: 1;
+ u8 adv_5G: 1;
+ u8 rsvd1: 4;
+ };
+ u8 advertising;
+ };
+ union {
+ struct {
+ u8 eee_100M: 1;
+ u8 eee_1G: 1;
+ u8 eee_2G5: 1;
+ u8 eee_5G: 1;
+ u8 rsvd2: 4;
+ };
+ u8 eee;
+ };
+ union {
+ struct {
+ u8 pause: 1;
+ u8 asym_pause: 1;
+ u8 low_power: 1;
+ u8 phy_power: 1;
+ u8 wol: 1;
+ u8 downshift: 1;
+ u8 rsvd4: 2;
+ };
+ u8 phy_ctrl1;
+ };
+ union {
+ struct {
+ u8 dsh_ret_cnt: 4;
+ u8 magic_packet:1;
+ u8 rsvd5: 3;
+ };
+ u8 phy_ctrl2;
+ };
+};
+
+struct aqc111_data {
+ struct {
+ u8 major;
+ u8 minor;
+ u8 rev;
+ } fw_ver;
+ u8 dpa; /*direct PHY access*/
+ struct aqc111_phy_options phy_ops;
+} __packed;
+
static struct {
unsigned char ctrl;
unsigned char timer_l;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 04/19] net: usb: aqc111: Various callbacks implementation
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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.
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/aqc111.c | 48 ++++++++++++++++++++++
drivers/net/usb/aqc111.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 149 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 7f3e5a615750..22bb259d71fb 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -169,12 +169,60 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
{
+ u8 reg8;
+ u16 reg16;
+
+ /* Force bz */
+ reg16 = SFR_PHYPWR_RSTCTL_BZ;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+ 2, 2, ®16);
+ reg16 = 0;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+ 2, 2, ®16);
+}
+
+static int aqc111_reset(struct usbnet *dev)
+{
+ u8 reg8 = 0;
+ u16 reg16 = 0;
+
+ reg8 = 0xFF;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8);
+
+ reg8 = 0x0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8);
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8);
+ reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC |
+ SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF |
+ SFR_MONITOR_MODE_RW_FLAG);
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8);
+
+ return 0;
+}
+
+static int aqc111_stop(struct usbnet *dev)
+{
+ u16 reg16 = 0;
+
+ aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+ reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+ reg16 = 0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, ®16);
+
+ return 0;
}
static const struct driver_info aqc111_info = {
.description = "Aquantia AQtion USB to 5GbE Controller",
.bind = aqc111_bind,
.unbind = aqc111_unbind,
+ .reset = aqc111_reset,
+ .stop = aqc111_stop,
};
#define AQC111_USB_ETH_DEV(vid, pid, table) \
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 1698a6a104fe..6b34202fa22b 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -10,10 +10,111 @@
#ifndef __LINUX_USBNET_AQC111_H
#define __LINUX_USBNET_AQC111_H
+#define AQ_ACCESS_MAC 0x01
#define AQ_PHY_POWER 0x31
#define AQ_USB_PHY_SET_TIMEOUT 10000
#define AQ_USB_SET_TIMEOUT 4000
+/* SFR Reg. ********************************************/
+
+#define SFR_GENERAL_STATUS 0x03
+#define SFR_CHIP_STATUS 0x05
+#define SFR_RX_CTL 0x0B
+ #define SFR_RX_CTL_TXPADCRC 0x0400
+ #define SFR_RX_CTL_IPE 0x0200
+ #define SFR_RX_CTL_DROPCRCERR 0x0100
+ #define SFR_RX_CTL_START 0x0080
+ #define SFR_RX_CTL_RF_WAK 0x0040
+ #define SFR_RX_CTL_AP 0x0020
+ #define SFR_RX_CTL_AM 0x0010
+ #define SFR_RX_CTL_AB 0x0008
+ #define SFR_RX_CTL_AMALL 0x0002
+ #define SFR_RX_CTL_PRO 0x0001
+ #define SFR_RX_CTL_STOP 0x0000
+#define SFR_INTER_PACKET_GAP_0 0x0D
+#define SFR_NODE_ID 0x10
+#define SFR_MULTI_FILTER_ARRY 0x16
+#define SFR_MEDIUM_STATUS_MODE 0x22
+ #define SFR_MEDIUM_XGMIIMODE 0x0001
+ #define SFR_MEDIUM_FULL_DUPLEX 0x0002
+ #define SFR_MEDIUM_RXFLOW_CTRLEN 0x0010
+ #define SFR_MEDIUM_TXFLOW_CTRLEN 0x0020
+ #define SFR_MEDIUM_JUMBO_EN 0x0040
+ #define SFR_MEDIUM_RECEIVE_EN 0x0100
+#define SFR_MONITOR_MODE 0x24
+ #define SFR_MONITOR_MODE_EPHYRW 0x01
+ #define SFR_MONITOR_MODE_RWLC 0x02
+ #define SFR_MONITOR_MODE_RWMP 0x04
+ #define SFR_MONITOR_MODE_RWWF 0x08
+ #define SFR_MONITOR_MODE_RW_FLAG 0x10
+ #define SFR_MONITOR_MODE_PMEPOL 0x20
+ #define SFR_MONITOR_MODE_PMETYPE 0x40
+#define SFR_PHYPWR_RSTCTL 0x26
+ #define SFR_PHYPWR_RSTCTL_BZ 0x0010
+ #define SFR_PHYPWR_RSTCTL_IPRL 0x0020
+#define SFR_VLAN_ID_ADDRESS 0x2A
+#define SFR_VLAN_ID_CONTROL 0x2B
+ #define SFR_VLAN_CONTROL_WE 0x0001
+ #define SFR_VLAN_CONTROL_RD 0x0002
+ #define SFR_VLAN_CONTROL_VSO 0x0010
+ #define SFR_VLAN_CONTROL_VFE 0x0020
+#define SFR_VLAN_ID_DATA0 0x2C
+#define SFR_VLAN_ID_DATA1 0x2D
+#define SFR_RX_BULKIN_QCTRL 0x2E
+ #define SFR_RX_BULKIN_QCTRL_TIME 0x01
+ #define SFR_RX_BULKIN_QCTRL_IFG 0x02
+ #define SFR_RX_BULKIN_QCTRL_SIZE 0x04
+#define SFR_RX_BULKIN_QTIMR_LOW 0x2F
+#define SFR_RX_BULKIN_QTIMR_HIGH 0x30
+#define SFR_RX_BULKIN_QSIZE 0x31
+#define SFR_RX_BULKIN_QIFG 0x32
+#define SFR_RXCOE_CTL 0x34
+ #define SFR_RXCOE_IP 0x01
+ #define SFR_RXCOE_TCP 0x02
+ #define SFR_RXCOE_UDP 0x04
+ #define SFR_RXCOE_ICMP 0x08
+ #define SFR_RXCOE_IGMP 0x10
+ #define SFR_RXCOE_TCPV6 0x20
+ #define SFR_RXCOE_UDPV6 0x40
+ #define SFR_RXCOE_ICMV6 0x80
+#define SFR_TXCOE_CTL 0x35
+ #define SFR_TXCOE_IP 0x01
+ #define SFR_TXCOE_TCP 0x02
+ #define SFR_TXCOE_UDP 0x04
+ #define SFR_TXCOE_ICMP 0x08
+ #define SFR_TXCOE_IGMP 0x10
+ #define SFR_TXCOE_TCPV6 0x20
+ #define SFR_TXCOE_UDPV6 0x40
+ #define SFR_TXCOE_ICMV6 0x80
+#define SFR_BM_INT_MASK 0x41
+#define SFR_BMRX_DMA_CONTROL 0x43
+ #define SFR_BMRX_DMA_EN 0x80
+#define SFR_BMTX_DMA_CONTROL 0x46
+#define SFR_PAUSE_WATERLVL_LOW 0x54
+#define SFR_PAUSE_WATERLVL_HIGH 0x55
+#define SFR_ARC_CTRL 0x9E
+#define SFR_SWP_CTRL 0xB1
+#define SFR_TX_PAUSE_RESEND_T 0xB2
+#define SFR_ETH_MAC_PATH 0xB7
+ #define SFR_RX_PATH_READY 0x01
+#define SFR_BULK_OUT_CTRL 0xB9
+ #define SFR_BULK_OUT_FLUSH_EN 0x01
+ #define SFR_BULK_OUT_EFF_EN 0x02
+
+static struct {
+ unsigned char ctrl;
+ unsigned char timer_l;
+ unsigned char timer_h;
+ unsigned char size;
+ unsigned char ifg;
+} AQC111_BULKIN_SIZE[] = {
+ /* xHCI & EHCI & OHCI */
+ {7, 0x00, 0x01, 0x1E, 0xFF},/* 10G, 5G, 2.5G, 1G */
+ {7, 0xA0, 0x00, 0x14, 0x00},/* 100M */
+ /* Jumbo packet */
+ {7, 0x00, 0x01, 0x18, 0xFF},
+};
+
#endif /* __LINUX_USBNET_AQC111_H */
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 10/19] net: usb: aqc111: Add checksum offload support
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 23 +++++++++++++++++++++--
2 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index fc068e731335..5967f7adeab4 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -537,6 +537,26 @@ static void aqc111_configure_rx(struct usbnet *dev,
netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host);
}
+static void aqc111_configure_csum_offload(struct usbnet *dev)
+{
+ u8 reg8 = 0;
+
+ if (dev->net->features & NETIF_F_RXCSUM) {
+ reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP |
+ SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6;
+ }
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8);
+
+ reg8 = 0;
+ if (dev->net->features & NETIF_F_IP_CSUM)
+ reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP;
+
+ if (dev->net->features & NETIF_F_IPV6_CSUM)
+ reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6;
+
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8);
+}
+
static int aqc111_link_reset(struct usbnet *dev)
{
u8 reg8 = 0;
@@ -580,6 +600,8 @@ static int aqc111_link_reset(struct usbnet *dev)
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
+ aqc111_configure_csum_offload(dev);
+
aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
2, 2, ®16);
@@ -713,6 +735,21 @@ static int aqc111_stop(struct usbnet *dev)
return 0;
}
+static void aqc111_rx_checksum(struct sk_buff *skb, void *pkt_hdr)
+{
+ struct aq_rx_packet_desc *hdr = (struct aq_rx_packet_desc *)pkt_hdr;
+
+ skb->ip_summed = CHECKSUM_NONE;
+ /* checksum error bit is set */
+ if (hdr->l4_err || hdr->l3_err)
+ return;
+
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if (hdr->l4_pkt_type == AQ_RXHDR_L4_TYPE_TCP ||
+ hdr->l4_pkt_type == AQ_RXHDR_L4_TYPE_UDP)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct sk_buff *new_skb = NULL;
@@ -788,6 +825,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 679ca9f992f7..1632e78ebe9b 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -63,8 +63,11 @@
#define AQ_USB_SET_TIMEOUT 4000
/* Feature. ********************************************/
-#define AQ_SUPPORT_FEATURE (NETIF_F_SG)
-#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG)
+#define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)
+
+#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)
/* SFR Reg. ********************************************/
@@ -230,6 +233,22 @@ struct aqc111_int_data {
#define AQ_INT_SPEED_1G 0x11
#define AQ_INT_SPEED_100M 0x13
+#define AQ_RXHDR_L4_ERR BIT(8)
+#define AQ_RXHDR_L3_ERR BIT(9)
+
+#define AQ_RXHDR_L4_TYPE_ICMP 0x02
+#define AQ_RXHDR_L4_TYPE_IGMP 0x03
+#define AQ_RXHDR_L4_TYPE_TCMPV6 0x05
+
+#define AQ_RXHDR_L3_TYPE_IP 0x01
+#define AQ_RXHDR_L3_TYPE_IPV6 0x02
+
+#define AQ_RXHDR_L4_TYPE_MASK 0x1c
+#define AQ_RXHDR_L4_TYPE_UDP 0x04
+#define AQ_RXHDR_L4_TYPE_TCP 0x10
+#define AQ_RXHDR_L3CSUM_ERR 0x02
+#define AQ_RXHDR_L4CSUM_ERR 0x01
+
#define AQ_RX_HW_PAD 0x02
struct aq_tx_packet_desc {
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 09/19] net: usb: aqc111: Implement RX data path
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 100 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 39 ++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 46832fd56f0a..fc068e731335 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -362,6 +362,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
if (ret)
goto out;
+ /* Set Rx urb size */
+ dev->rx_urb_size = URB_SIZE;
+
/* Set TX needed headroom & tailroom */
dev->net->needed_headroom += AQ_TX_HEADER_SIZE;
dev->net->needed_tailroom += AQ_TX_HEADER_SIZE;
@@ -621,6 +624,8 @@ static int aqc111_reset(struct usbnet *dev)
usb_speed = dev->udev->speed;
+ dev->rx_urb_size = URB_SIZE;
+
if (usb_device_no_sg_constraint(dev->udev))
dev->can_dma_sg = 1;
@@ -708,6 +713,100 @@ 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 skb_len = 0;
+ u32 desc_offset = 0; /*RX Header Offset*/
+ u32 start_of_descs = 0;
+ u16 pkt_count = 0;
+ u32 pkt_total_offset = 0;
+ struct aq_rx_packet_desc *pkt_desc = NULL;
+ struct aq_rx_desc_header desc_hdr;
+
+ if (!skb)
+ goto err;
+
+ if (skb->len == 0)
+ goto err;
+
+ skb_len = skb->len;
+ /* RX Offset Header */
+ skb_trim(skb, skb->len - sizeof(struct aq_rx_desc_header));
+ memcpy(&desc_hdr, skb_tail_pointer(skb),
+ sizeof(struct aq_rx_desc_header));
+ le64_to_cpus(&desc_hdr);
+
+ /* Check these packets */
+ desc_offset = (u32)desc_hdr.desc_offset;
+ pkt_count = desc_hdr.pkt_count;
+ start_of_descs = skb_len - ((pkt_count + 1) *
+ sizeof(struct aq_rx_desc_header));
+
+ /* 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 header */
+ pkt_desc = (struct aq_rx_packet_desc *)(skb->data + desc_offset);
+
+ while (pkt_count--) {
+ u32 pkt_len = (u32)(pkt_desc->length & 0x7FFF);
+ u32 pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8);
+
+ le64_to_cpus(pkt_desc);
+
+ 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->drop || !pkt_desc->rx_ok ||
+ pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) {
+ skb_pull(skb, pkt_len_with_padd);
+ /* Next RX Packet Header */
+ 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)
{
@@ -769,6 +868,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 049012e26b26..679ca9f992f7 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
@@ -228,6 +230,8 @@ struct aqc111_int_data {
#define AQ_INT_SPEED_1G 0x11
#define AQ_INT_SPEED_100M 0x13
+#define AQ_RX_HW_PAD 0x02
+
struct aq_tx_packet_desc {
struct {
u32 length:21;
@@ -246,6 +250,41 @@ struct aq_tx_packet_desc {
#define AQ_TX_HEADER_SIZE sizeof(struct aq_tx_packet_desc)
+struct aq_rx_packet_desc {
+ struct {
+ u16 l4_err:1;
+ u16 l3_err:1;
+ u16 l4_pkt_type:3;
+ u16 l3_pkt_type:2;
+ u16 ce:1;
+ u16 tco_match:1;
+ u16 node_id_match:1;
+ u16 vlan_ind : 1;
+ u16 rx_ok:1;
+ u16 reserved1 : 3;
+ u16 bmc:1;
+ };
+ struct {
+ u16 length:15;
+ u16 drop:1;
+ };
+ u16 vlan_tag;
+ struct {
+ u8 wuf_detect:1;
+ u8 wuf_wake:1;
+ u8 wuf_ind:6;
+ u8 reserved2:8;
+ };
+};
+
+struct aq_rx_desc_header {
+ struct {
+ u32 pkt_count:13;
+ u32 desc_offset:19;
+ };
+ u32 rx_throughput;
+};
+
static struct {
unsigned char ctrl;
unsigned char timer_l;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 07/19] net: usb: aqc111: Add support for getting and setting of MAC address
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 1 +
2 files changed, 52 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 1d366f4a1c51..075f51cd04ab 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>
@@ -266,11 +267,46 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
}
+static int aqc111_set_mac_addr(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sockaddr *addr = p;
+
+ if (netif_running(net))
+ return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+ /* 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_get_mac(struct usbnet *dev, u8 *buf)
+{
+ int ret;
+
+ ret = aqc111_read_cmd(dev, AQ_FLASH_PARAMETERS, 0, 0, 6, buf);
+ if (ret < 0)
+ goto out;
+
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+ memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
+
+ return 0;
+out:
+ return ret;
+}
+
static void aqc111_read_fw_version(struct usbnet *dev,
struct aqc111_data *aqc111_data)
{
@@ -289,6 +325,7 @@ static void aqc111_read_fw_version(struct usbnet *dev,
static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
{
+ u8 buf[6] = { 0 };
int ret;
struct usb_device *udev = interface_to_usbdev(intf);
struct aqc111_data *aqc111_data;
@@ -316,6 +353,12 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
dev->data[0] = (unsigned long)aqc111_data;
memset(aqc111_data, 0, sizeof(*aqc111_data));
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ ret = aqc111_get_mac(dev, buf);
+ if (ret)
+ goto out;
+
dev->net->netdev_ops = &aqc111_netdev_ops;
aqc111_read_fw_version(dev, aqc111_data);
@@ -324,6 +367,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)
@@ -587,6 +634,10 @@ static int aqc111_reset(struct usbnet *dev)
4, &aqc111_data->phy_ops);
}
+ /* Set the MAC address */
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_NODE_ID, ETH_ALEN,
+ ETH_ALEN, dev->net->dev_addr);
+
reg8 = 0xFF;
aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8);
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index 5c5602e6d236..7ca5c5a6ec82 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -11,6 +11,7 @@
#define __LINUX_USBNET_AQC111_H
#define AQ_ACCESS_MAC 0x01
+#define AQ_FLASH_PARAMETERS 0x20
#define AQ_PHY_POWER 0x31
#define AQ_PHY_CMD 0x32
#define AQ_PHY_OPS 0x61
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 08/19] net: usb: aqc111: Implement TX data path
From: Igor Russkikh @ 2018-10-05 10:25 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.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 | 73 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 22 +++++++++++++++
2 files changed, 95 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 075f51cd04ab..46832fd56f0a 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -287,6 +287,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,
};
@@ -359,8 +362,18 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
if (ret)
goto out;
+ /* Set TX needed headroom & tailroom */
+ dev->net->needed_headroom += AQ_TX_HEADER_SIZE;
+ dev->net->needed_tailroom += AQ_TX_HEADER_SIZE;
+
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) ?
@@ -608,6 +621,12 @@ static int aqc111_reset(struct usbnet *dev)
usb_speed = dev->udev->speed;
+ 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_ops.advertising = 0;
aqc111_data->phy_ops.phy_ctrl1 = 0;
@@ -689,6 +708,57 @@ 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)
+{
+ struct aq_tx_packet_desc tx_hdr;
+ int frame_size = dev->maxpacket;
+ int headroom = 0;
+ int tailroom = 0;
+ int padding_size = 0;
+ struct sk_buff *new_skb = NULL;
+
+ memset(&tx_hdr, 0x00, sizeof(tx_hdr));
+
+ /*Length of actual data*/
+ tx_hdr.length = (skb->len & 0x1FFFFF);
+
+ headroom = (skb->len + AQ_TX_HEADER_SIZE) % 8;
+ if (headroom != 0)
+ padding_size = 8 - headroom;
+
+ if (((skb->len + AQ_TX_HEADER_SIZE + padding_size) % frame_size) == 0) {
+ padding_size += 8;
+ tx_hdr.drop_padding = 1;
+ }
+
+ 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 >= AQ_TX_HEADER_SIZE && tailroom >= padding_size)) {
+ new_skb = skb_copy_expand(skb, AQ_TX_HEADER_SIZE,
+ 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, AQ_TX_HEADER_SIZE);
+ cpu_to_le64s(&tx_hdr);
+ skb_copy_to_linear_data(skb, &tx_hdr, 8);
+
+ 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,
@@ -697,6 +767,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 7ca5c5a6ec82..049012e26b26 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -60,6 +60,10 @@
#define AQ_USB_PHY_SET_TIMEOUT 10000
#define AQ_USB_SET_TIMEOUT 4000
+/* Feature. ********************************************/
+#define AQ_SUPPORT_FEATURE (NETIF_F_SG)
+#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG)
+
/* SFR Reg. ********************************************/
#define SFR_GENERAL_STATUS 0x03
@@ -224,6 +228,24 @@ struct aqc111_int_data {
#define AQ_INT_SPEED_1G 0x11
#define AQ_INT_SPEED_100M 0x13
+struct aq_tx_packet_desc {
+ struct {
+ u32 length:21;
+ u32 checksum:7;
+ u32 drop_padding:1;
+ u32 vlan_tag:1;
+ u32 cphi:1;
+ u32 dicf:1;
+ };
+ struct {
+ u32 max_seg_size:15;
+ u32 reserved:1;
+ u32 vlan_info:16;
+ };
+};
+
+#define AQ_TX_HEADER_SIZE sizeof(struct aq_tx_packet_desc)
+
static struct {
unsigned char ctrl;
unsigned char timer_l;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 02/19] net: usb: aqc111: Add bind and empty unbind callbacks
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Initialize net_device_ops structure
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/aqc111.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 250e8ff65110..c914e19387f2 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -14,8 +14,43 @@
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
+static const struct net_device_ops aqc111_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+};
+
+static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ /* Check if vendor configuration */
+ if (udev->actconfig->desc.bConfigurationValue != 1) {
+ usb_driver_set_configuration(udev, 1);
+ return -ENODEV;
+ }
+
+ usb_reset_configuration(dev->udev);
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "usbnet_get_endpoints failed");
+ return ret;
+ }
+
+ dev->net->netdev_ops = &aqc111_netdev_ops;
+
+ return 0;
+}
+
+static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+}
+
static const struct driver_info aqc111_info = {
.description = "Aquantia AQtion USB to 5GbE Controller",
+ .bind = aqc111_bind,
+ .unbind = aqc111_unbind,
};
#define AQC111_USB_ETH_DEV(vid, pid, table) \
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 01/19] net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh,
Dmitry Bezrukov
In-Reply-To: <cover.1538734658.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Initialize usb_driver structure skeleton
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
drivers/net/usb/Kconfig | 12 +++++++++++
drivers/net/usb/Makefile | 1 +
drivers/net/usb/aqc111.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+)
create mode 100644 drivers/net/usb/aqc111.c
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 418b0904cecb..e5fb8ef2d815 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -613,4 +613,16 @@ config USB_NET_CH9200
To compile this driver as a module, choose M here: the
module will be called ch9200.
+config USB_NET_AQC111
+ tristate "Aquantia AQtion USB to 5/2.5GbE Controllers support"
+ depends on USB_USBNET
+ select CRC32
+ default y
+ help
+ This option adds support for Aquantia AQtion USB
+ Ethernet adapters based on AQC111U/AQC112 chips.
+
+ This driver should work with at least the following devices:
+ * Aquantia AQtion USB to 5GbE
+
endif # USB_NET_DRIVERS
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 27307a4ab003..99fd12be2111 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_USB_VL600) += lg-vl600.o
obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o
obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o
obj-$(CONFIG_USB_NET_CH9200) += ch9200.o
+obj-$(CONFIG_USB_NET_AQC111) += aqc111.o
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
new file mode 100644
index 000000000000..250e8ff65110
--- /dev/null
+++ b/drivers/net/usb/aqc111.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2002-2003 TiVo Inc.
+ * Copyright (C) 2017-2018 ASIX
+ * Copyright (C) 2018 Aquantia Corp.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+
+static const struct driver_info aqc111_info = {
+ .description = "Aquantia AQtion USB to 5GbE Controller",
+};
+
+#define AQC111_USB_ETH_DEV(vid, pid, table) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS, \
+ USB_DEVICE(vid, pid), \
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+ .driver_info = (unsigned long)&table, \
+}, \
+{ \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_INFO, \
+ USB_DEVICE(vid, pid), \
+ .bInterfaceClass = USB_CLASS_COMM, \
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE
+
+static const struct usb_device_id products[] = {
+ {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)},
+ { },/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver aq_driver = {
+ .name = "aqc111",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+};
+
+module_usb_driver(aq_driver);
+
+MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers");
+MODULE_LICENSE("GPL");
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 00/19] Add support for Aquantia AQtion USB to 5/2.5GbE devices
From: Igor Russkikh @ 2018-10-05 10:24 UTC (permalink / raw)
To: David S . Miller
Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, Igor Russkikh
This patchset introduces support for new multigig ethernet to USB dongle,
developed jointly by Aquantia (Phy) and ASIX (USB MAC).
The driver has similar structure with other ASIX MAC drivers (AX88179), but
with a number of important differences:
- Driver supports both direct Phy and custom firmware interface for Phy
programming. This is due to different firmware modules available with this
product.
- Driver handles new 2.5G/5G link speed configuration and reporting.
- Device support all speeds from 100M up to 5G.
- Device supports MTU up to 16K.
Device supports various standard networking features, like
checksum offloads, vlan tagging/filtering, TSO.
The code of this driver is based on original ASIX sources and was extended
by Aquantia for 5G multigig support.
Dmitry Bezrukov (19):
net: usb: aqc111: Driver skeleton for Aquantia AQtion USB to 5GbE
net: usb: aqc111: Add bind and empty unbind callbacks
net: usb: aqc111: Add implementation of read and write commands
net: usb: aqc111: Various callbacks implementation
net: usb: aqc111: Introduce PHY access
net: usb: aqc111: Introduce link management
net: usb: aqc111: Add support for getting and setting of MAC address
net: usb: aqc111: Implement TX data path
net: usb: aqc111: Implement RX data path
net: usb: aqc111: Add checksum offload support
net: usb: aqc111: Add support for changing MTU
net: usb: aqc111: Add support for enable/disable checksum offload
net: usb: aqc111: Add support for TSO
net: usb: aqc111: Implement set_rx_mode callback
net: usb: aqc111: Add support for VLAN_CTAG_TX/RX offload
net: usb: aqc111: Add RX VLAN filtering support
net: usb: aqc111: Initialize ethtool_ops structure
net: usb: aqc111: Implement get/set_link_ksettings callbacks
net: usb: aqc111: Add support for wake on LAN by MAGIC packet
drivers/net/usb/Kconfig | 12 +
drivers/net/usb/Makefile | 1 +
drivers/net/usb/aqc111.c | 1583 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 345 ++++++++++
4 files changed, 1941 insertions(+)
create mode 100644 drivers/net/usb/aqc111.c
create mode 100644 drivers/net/usb/aqc111.h
--
2.7.4
^ permalink raw reply
* Re: [PATCH] bpf: fix building without CONFIG_INET
From: Joe Stringer @ 2018-10-05 17:19 UTC (permalink / raw)
To: arnd
Cc: ast, daniel, David Miller, john fastabend, Martin KaFai Lau,
makita.toshiaki, brakmo, rdna, Jesper Brouer, jakub.kicinski,
m.xhonneux, dsahern, netdev, LKML
In-Reply-To: <20181005161526.843924-1-arnd@arndb.de>
On Fri, 5 Oct 2018 at 09:16, Arnd Bergmann <arnd@arndb.de> wrote:
>
> The newly added TCP and UDP handling fails to link when CONFIG_INET
> is disabled:
>
> net/core/filter.o: In function `sk_lookup':
> filter.c:(.text+0x7ff8): undefined reference to `tcp_hashinfo'
> filter.c:(.text+0x7ffc): undefined reference to `tcp_hashinfo'
> filter.c:(.text+0x8020): undefined reference to `__inet_lookup_established'
> filter.c:(.text+0x8058): undefined reference to `__inet_lookup_listener'
> filter.c:(.text+0x8068): undefined reference to `udp_table'
> filter.c:(.text+0x8070): undefined reference to `udp_table'
> filter.c:(.text+0x808c): undefined reference to `__udp4_lib_lookup'
> net/core/filter.o: In function `bpf_sk_release':
> filter.c:(.text+0x82e8): undefined reference to `sock_gen_put'
>
> The compiler can optimize it out and avoid those references for
> the most part, but we are missing a few steps here:
>
> - sk_lookup() should always have been marked 'static', this also
> avoids a warning about a missing prototype when building with
> 'make W=1'.
> - The BPF_CALL_x() macro needs a little change to allow marking
> the unneeded BPF call as 'static' and having the compiler
> drop them.
> - The reference to the bpf_func_proto must be made conditional.
>
> Fixes: 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
Thanks for the fix.
> include/linux/filter.h | 2 +-
> net/core/filter.c | 18 +++++++++++-------
> 2 files changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index 6791a0ac0139..d9ec9d908bbe 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -428,9 +428,9 @@ struct sock_reuseport;
> u64, __ur_3, u64, __ur_4, u64, __ur_5)
>
> #define BPF_CALL_x(x, name, ...) \
> + u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \
> static __always_inline \
> u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \
> - u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \
> u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \
> { \
> return ____##name(__BPF_MAP(x,__BPF_CAST,__BPF_N,__VA_ARGS__));\
For what it's worth, other similar cases in net/core/filter.c avoid
this by just wrapping the relevant sections of the code in the #ifdef
as well.
Might be a bit simpler to follow that style (only checked with make
M=net/core W=1):
$ git di
diff --git a/net/core/filter.c b/net/core/filter.c
index 30c6b2d3ef16..4bbc6567fcb8 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4817,8 +4817,9 @@ static const struct bpf_func_proto
bpf_lwt_seg6_adjust_srh_proto = {
};
#endif /* CONFIG_IPV6_SEG6_BPF */
-struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple,
- struct sk_buff *skb, u8 family, u8 proto)
+#ifdef CONFIG_INET
+static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple,
+ struct sk_buff *skb, u8 family, u8 proto)
{
int dif = skb->dev->ifindex;
bool refcounted = false;
@@ -4951,6 +4952,7 @@ static const struct bpf_func_proto
bpf_sk_release_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_SOCKET,
};
+#endif /* CONFIG_INET */
bool bpf_helper_changes_pkt_data(void *func)
{
@@ -5158,12 +5160,14 @@ tc_cls_act_func_proto(enum bpf_func_id
func_id, const struct bpf_prog *prog)
case BPF_FUNC_skb_ancestor_cgroup_id:
return &bpf_skb_ancestor_cgroup_id_proto;
#endif
+#ifdef CONFIG_INET
case BPF_FUNC_sk_lookup_tcp:
return &bpf_sk_lookup_tcp_proto;
case BPF_FUNC_sk_lookup_udp:
return &bpf_sk_lookup_udp_proto;
case BPF_FUNC_sk_release:
return &bpf_sk_release_proto;
+#endif
default:
return bpf_base_func_proto(func_id);
}
@@ -5264,12 +5268,14 @@ sk_skb_func_proto(enum bpf_func_id func_id,
const struct bpf_prog *prog)
return &bpf_sk_redirect_hash_proto;
case BPF_FUNC_get_local_storage:
return &bpf_get_local_storage_proto;
+#ifdef CONFIG_INET
case BPF_FUNC_sk_lookup_tcp:
return &bpf_sk_lookup_tcp_proto;
case BPF_FUNC_sk_lookup_udp:
return &bpf_sk_lookup_udp_proto;
case BPF_FUNC_sk_release:
return &bpf_sk_release_proto;
+#endif
default:
return bpf_base_func_proto(func_id);
}
^ permalink raw reply related
* [PATCH net-next 4/6] net: hns3: Drop depricated mta table support
From: Salil Mehta @ 2018-10-05 17:03 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Jian Shen, Zhongzhu Liu
In-Reply-To: <20181005170329.6512-1-salil.mehta@huawei.com>
From: Jian Shen <shenjian15@huawei.com>
For mta table support has been dropped, remove the code for mta table.
Signed-off-by: Zhongzhu Liu <liuzhongzhu@huawei.com>
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 3 -
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 -
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 3 -
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 30 ---
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 222 +--------------------
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 24 ---
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 58 ------
.../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 129 ------------
.../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 5 -
9 files changed, 2 insertions(+), 474 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
index be9dc08..038326c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -46,9 +46,6 @@ enum hclge_mbx_mac_vlan_subcode {
HCLGE_MBX_MAC_VLAN_MC_MODIFY, /* modify MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_ADD, /* add new MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */
- HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE, /* config func MTA enable */
- HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ, /* read func MTA type */
- HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE, /* update MTA status */
};
/* below are per-VF vlan cfg subcodes */
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 591ee2e..1b49c5d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -355,8 +355,6 @@ struct hnae3_ae_ops {
const unsigned char *addr);
int (*rm_mc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
- int (*update_mta_status)(struct hnae3_handle *handle);
-
void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
void (*update_stats)(struct hnae3_handle *handle,
struct net_device_stats *net_stats);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index d8b8ccf..3f36c38 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -476,9 +476,6 @@ static void hns3_nic_set_rx_mode(struct net_device *netdev)
if (netdev->flags & IFF_MULTICAST) {
if (__dev_mc_sync(netdev, hns3_nic_mc_sync, hns3_nic_mc_unsync))
netdev_err(netdev, "sync mc address fail\n");
-
- if (h->ae_algo->ops->update_mta_status)
- h->ae_algo->ops->update_mta_status(h);
}
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 6098dacb..1ccde67 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -179,12 +179,6 @@ enum hclge_opcode_type {
HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
- /* Multicast linear table commands */
- HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020,
- HCLGE_OPC_MTA_MAC_FUNC_CFG = 0x1021,
- HCLGE_OPC_MTA_TBL_ITEM_CFG = 0x1022,
- HCLGE_OPC_MTA_TBL_ITEM_QUERY = 0x1023,
-
/* VLAN commands */
HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100,
HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
@@ -623,30 +617,6 @@ struct hclge_mac_mgr_tbl_entry_cmd {
u8 rsv3[2];
};
-#define HCLGE_CFG_MTA_MAC_SEL_S 0
-#define HCLGE_CFG_MTA_MAC_SEL_M GENMASK(1, 0)
-#define HCLGE_CFG_MTA_MAC_EN_B 7
-struct hclge_mta_filter_mode_cmd {
- u8 dmac_sel_en; /* Use lowest 2 bit as sel_mode, bit 7 as enable */
- u8 rsv[23];
-};
-
-#define HCLGE_CFG_FUNC_MTA_ACCEPT_B 0
-struct hclge_cfg_func_mta_filter_cmd {
- u8 accept; /* Only used lowest 1 bit */
- u8 function_id;
- u8 rsv[22];
-};
-
-#define HCLGE_CFG_MTA_ITEM_ACCEPT_B 0
-#define HCLGE_CFG_MTA_ITEM_IDX_S 0
-#define HCLGE_CFG_MTA_ITEM_IDX_M GENMASK(11, 0)
-struct hclge_cfg_func_mta_item_cmd {
- __le16 item_idx; /* Only used lowest 12 bit */
- u8 accept; /* Only used lowest 1 bit */
- u8 rsv[21];
-};
-
struct hclge_mac_vlan_add_cmd {
__le16 flags;
__le16 mac_addr_hi16;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index d346d0a..d95ea9b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -25,9 +25,6 @@
#define HCLGE_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset))))
#define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f))
-static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
- enum hclge_mta_dmac_sel_type mta_mac_sel,
- bool enable);
static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu);
static int hclge_init_vlan_config(struct hclge_dev *hdev);
static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev);
@@ -1952,10 +1949,8 @@ static int hclge_mac_init(struct hclge_dev *hdev)
struct hnae3_handle *handle = &hdev->vport[0].nic;
struct net_device *netdev = handle->kinfo.netdev;
struct hclge_mac *mac = &hdev->hw.mac;
- struct hclge_vport *vport;
int mtu;
int ret;
- int i;
hdev->hw.mac.duplex = HCLGE_MAC_FULL;
ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed,
@@ -1968,32 +1963,6 @@ static int hclge_mac_init(struct hclge_dev *hdev)
mac->link = 0;
- /* Initialize the MTA table work mode */
- hdev->enable_mta = true;
- hdev->mta_mac_sel_type = HCLGE_MAC_ADDR_47_36;
-
- ret = hclge_set_mta_filter_mode(hdev,
- hdev->mta_mac_sel_type,
- hdev->enable_mta);
- if (ret) {
- dev_err(&hdev->pdev->dev, "set mta filter mode failed %d\n",
- ret);
- return ret;
- }
-
- for (i = 0; i < hdev->num_alloc_vport; i++) {
- vport = &hdev->vport[i];
- vport->accept_mta_mc = false;
-
- memset(vport->mta_shadow, 0, sizeof(vport->mta_shadow));
- ret = hclge_cfg_func_mta_filter(hdev, vport->vport_id, false);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "set mta filter mode fail ret=%d\n", ret);
- return ret;
- }
- }
-
if (netdev)
mtu = netdev->mtu;
else
@@ -4954,174 +4923,6 @@ static void hclge_prepare_mac_addr(struct hclge_mac_vlan_tbl_entry_cmd *new_req,
new_req->mac_addr_lo16 = cpu_to_le16(low_val & 0xffff);
}
-static u16 hclge_get_mac_addr_to_mta_index(struct hclge_vport *vport,
- const u8 *addr)
-{
- u16 high_val = addr[1] | (addr[0] << 8);
- struct hclge_dev *hdev = vport->back;
- u32 rsh = 4 - hdev->mta_mac_sel_type;
- u16 ret_val = (high_val >> rsh) & 0xfff;
-
- return ret_val;
-}
-
-static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
- enum hclge_mta_dmac_sel_type mta_mac_sel,
- bool enable)
-{
- struct hclge_mta_filter_mode_cmd *req;
- struct hclge_desc desc;
- int ret;
-
- req = (struct hclge_mta_filter_mode_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_MODE_CFG, false);
-
- hnae3_set_bit(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_EN_B,
- enable);
- hnae3_set_field(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_SEL_M,
- HCLGE_CFG_MTA_MAC_SEL_S, mta_mac_sel);
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Config mat filter mode failed for cmd_send, ret =%d.\n",
- ret);
-
- return ret;
-}
-
-int hclge_cfg_func_mta_filter(struct hclge_dev *hdev,
- u8 func_id,
- bool enable)
-{
- struct hclge_cfg_func_mta_filter_cmd *req;
- struct hclge_desc desc;
- int ret;
-
- req = (struct hclge_cfg_func_mta_filter_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_FUNC_CFG, false);
-
- hnae3_set_bit(req->accept, HCLGE_CFG_FUNC_MTA_ACCEPT_B,
- enable);
- req->function_id = func_id;
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Config func_id enable failed for cmd_send, ret =%d.\n",
- ret);
-
- return ret;
-}
-
-static int hclge_set_mta_table_item(struct hclge_vport *vport,
- u16 idx,
- bool enable)
-{
- struct hclge_dev *hdev = vport->back;
- struct hclge_cfg_func_mta_item_cmd *req;
- struct hclge_desc desc;
- u16 item_idx = 0;
- int ret;
-
- req = (struct hclge_cfg_func_mta_item_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_TBL_ITEM_CFG, false);
- hnae3_set_bit(req->accept, HCLGE_CFG_MTA_ITEM_ACCEPT_B, enable);
-
- hnae3_set_field(item_idx, HCLGE_CFG_MTA_ITEM_IDX_M,
- HCLGE_CFG_MTA_ITEM_IDX_S, idx);
- req->item_idx = cpu_to_le16(item_idx);
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Config mta table item failed for cmd_send, ret =%d.\n",
- ret);
- return ret;
- }
-
- if (enable)
- set_bit(idx, vport->mta_shadow);
- else
- clear_bit(idx, vport->mta_shadow);
-
- return 0;
-}
-
-static int hclge_update_mta_status(struct hnae3_handle *handle)
-{
- unsigned long mta_status[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)];
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct net_device *netdev = handle->kinfo.netdev;
- struct netdev_hw_addr *ha;
- u16 tbl_idx;
-
- memset(mta_status, 0, sizeof(mta_status));
-
- /* update mta_status from mc addr list */
- netdev_for_each_mc_addr(ha, netdev) {
- tbl_idx = hclge_get_mac_addr_to_mta_index(vport, ha->addr);
- set_bit(tbl_idx, mta_status);
- }
-
- return hclge_update_mta_status_common(vport, mta_status,
- 0, HCLGE_MTA_TBL_SIZE, true);
-}
-
-int hclge_update_mta_status_common(struct hclge_vport *vport,
- unsigned long *status,
- u16 idx,
- u16 count,
- bool update_filter)
-{
- struct hclge_dev *hdev = vport->back;
- u16 update_max = idx + count;
- u16 check_max;
- int ret = 0;
- bool used;
- u16 i;
-
- /* setup mta check range */
- if (update_filter) {
- i = 0;
- check_max = HCLGE_MTA_TBL_SIZE;
- } else {
- i = idx;
- check_max = update_max;
- }
-
- used = false;
- /* check and update all mta item */
- for (; i < check_max; i++) {
- /* ignore unused item */
- if (!test_bit(i, vport->mta_shadow))
- continue;
-
- /* if i in update range then update it */
- if (i >= idx && i < update_max)
- if (!test_bit(i - idx, status))
- hclge_set_mta_table_item(vport, i, false);
-
- if (!used && test_bit(i, vport->mta_shadow))
- used = true;
- }
-
- /* no longer use mta, disable it */
- if (vport->accept_mta_mc && update_filter && !used) {
- ret = hclge_cfg_func_mta_filter(hdev,
- vport->vport_id,
- false);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "disable func mta filter fail ret=%d\n",
- ret);
- else
- vport->accept_mta_mc = false;
- }
-
- return ret;
-}
-
static int hclge_remove_mac_vlan_tbl(struct hclge_vport *vport,
struct hclge_mac_vlan_tbl_entry_cmd *req)
{
@@ -5477,7 +5278,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
struct hclge_dev *hdev = vport->back;
struct hclge_mac_vlan_tbl_entry_cmd req;
struct hclge_desc desc[3];
- u16 tbl_idx;
int status;
/* mac addr check */
@@ -5507,25 +5307,8 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
status = hclge_add_mac_vlan_tbl(vport, &req, desc);
}
- /* If mc mac vlan table is full, use MTA table */
- if (status == -ENOSPC) {
- if (!vport->accept_mta_mc) {
- status = hclge_cfg_func_mta_filter(hdev,
- vport->vport_id,
- true);
- if (status) {
- dev_err(&hdev->pdev->dev,
- "set mta filter mode fail ret=%d\n",
- status);
- return status;
- }
- vport->accept_mta_mc = true;
- }
-
- /* Set MTA table for this MAC address */
- tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr);
- status = hclge_set_mta_table_item(vport, tbl_idx, true);
- }
+ if (status == -ENOSPC)
+ dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n");
return status;
}
@@ -7428,7 +7211,6 @@ static const struct hnae3_ae_ops hclge_ops = {
.rm_uc_addr = hclge_rm_uc_addr,
.add_mc_addr = hclge_add_mc_addr,
.rm_mc_addr = hclge_rm_mc_addr,
- .update_mta_status = hclge_update_mta_status,
.set_autoneg = hclge_set_autoneg,
.get_autoneg = hclge_get_autoneg,
.get_pauseparam = hclge_get_pauseparam,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index d0c7c62..e3dfd65 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -59,8 +59,6 @@
#define HCLGE_DEFAULT_UMV_SPACE_PER_PF \
(HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM)
-#define HCLGE_MTA_TBL_SIZE 4096
-
#define HCLGE_TQP_RESET_TRY_TIMES 10
#define HCLGE_PHY_PAGE_MDIX 0
@@ -168,13 +166,6 @@ enum HCLGE_MAC_DUPLEX {
HCLGE_MAC_FULL
};
-enum hclge_mta_dmac_sel_type {
- HCLGE_MAC_ADDR_47_36,
- HCLGE_MAC_ADDR_46_35,
- HCLGE_MAC_ADDR_45_34,
- HCLGE_MAC_ADDR_44_33,
-};
-
struct hclge_mac {
u8 phy_addr;
u8 flag;
@@ -677,9 +668,6 @@ struct hclge_dev {
u32 pkt_buf_size; /* Total pf buf size for tx/rx */
u32 mps; /* Max packet size */
- enum hclge_mta_dmac_sel_type mta_mac_sel_type;
- bool enable_mta; /* Multicast filter enable */
-
struct hclge_vlan_type_cfg vlan_type_cfg;
unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)];
@@ -754,9 +742,6 @@ struct hclge_vport {
struct hclge_dev *back; /* Back reference to associated dev */
struct hnae3_handle nic;
struct hnae3_handle roce;
-
- bool accept_mta_mc; /* whether to accept mta filter multicast */
- unsigned long mta_shadow[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)];
};
void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
@@ -771,15 +756,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
int hclge_rm_mc_addr_common(struct hclge_vport *vport,
const unsigned char *addr);
-int hclge_cfg_func_mta_filter(struct hclge_dev *hdev,
- u8 func_id,
- bool enable);
-int hclge_update_mta_status_common(struct hclge_vport *vport,
- unsigned long *status,
- u16 idx,
- u16 count,
- bool update_filter);
-
struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle);
int hclge_bind_ring_with_vector(struct hclge_vport *vport,
int vector_id, bool en,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
index f34851c..04462a3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -233,43 +233,6 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
return 0;
}
-static int hclge_set_vf_mc_mta_status(struct hclge_vport *vport,
- u8 *msg, u8 idx, bool is_end)
-{
-#define HCLGE_MTA_STATUS_MSG_SIZE 13
-#define HCLGE_MTA_STATUS_MSG_BITS \
- (HCLGE_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE)
-#define HCLGE_MTA_STATUS_MSG_END_BITS \
- (HCLGE_MTA_TBL_SIZE % HCLGE_MTA_STATUS_MSG_BITS)
- unsigned long status[BITS_TO_LONGS(HCLGE_MTA_STATUS_MSG_BITS)];
- u16 tbl_cnt;
- u16 tbl_idx;
- u8 msg_ofs;
- u8 msg_bit;
-
- tbl_cnt = is_end ? HCLGE_MTA_STATUS_MSG_END_BITS :
- HCLGE_MTA_STATUS_MSG_BITS;
-
- /* set msg field */
- msg_ofs = 0;
- msg_bit = 0;
- memset(status, 0, sizeof(status));
- for (tbl_idx = 0; tbl_idx < tbl_cnt; tbl_idx++) {
- if (msg[msg_ofs] & BIT(msg_bit))
- set_bit(tbl_idx, status);
-
- msg_bit++;
- if (msg_bit == BITS_PER_BYTE) {
- msg_bit = 0;
- msg_ofs++;
- }
- }
-
- return hclge_update_mta_status_common(vport,
- status, idx * HCLGE_MTA_STATUS_MSG_BITS,
- tbl_cnt, is_end);
-}
-
static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req,
bool gen_resp)
@@ -284,27 +247,6 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
status = hclge_add_mc_addr_common(vport, mac_addr);
} else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_REMOVE) {
status = hclge_rm_mc_addr_common(vport, mac_addr);
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE) {
- u8 func_id = vport->vport_id;
- bool enable = mbx_req->msg[2];
-
- status = hclge_cfg_func_mta_filter(hdev, func_id, enable);
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ) {
- resp_data = hdev->mta_mac_sel_type;
- resp_len = sizeof(u8);
- gen_resp = true;
- status = 0;
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE) {
- /* mta status update msg format
- * msg[2.6 : 2.0] msg index
- * msg[2.7] msg is end
- * msg[15 : 3] mta status bits[103 : 0]
- */
- bool is_end = (mbx_req->msg[2] & 0x80) ? true : false;
-
- status = hclge_set_vf_mc_mta_status(vport, &mbx_req->msg[3],
- mbx_req->msg[2] & 0x7F,
- is_end);
} else {
dev_err(&hdev->pdev->dev,
"failed to set mcast mac addr, unknown subcode %d\n",
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 8f858cb..ca4a9f7 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -746,126 +746,6 @@ static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle)
}
}
-static int hclgevf_cfg_func_mta_type(struct hclgevf_dev *hdev)
-{
- u8 resp_msg = HCLGEVF_MTA_TYPE_SEL_MAX;
- int ret;
-
- ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST,
- HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ,
- NULL, 0, true, &resp_msg, sizeof(u8));
-
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Read mta type fail, ret=%d.\n", ret);
- return ret;
- }
-
- if (resp_msg > HCLGEVF_MTA_TYPE_SEL_MAX) {
- dev_err(&hdev->pdev->dev,
- "Read mta type invalid, resp=%d.\n", resp_msg);
- return -EINVAL;
- }
-
- hdev->mta_mac_sel_type = resp_msg;
-
- return 0;
-}
-
-static u16 hclgevf_get_mac_addr_to_mta_index(struct hclgevf_dev *hdev,
- const u8 *addr)
-{
- u32 rsh = HCLGEVF_MTA_TYPE_SEL_MAX - hdev->mta_mac_sel_type;
- u16 high_val = addr[1] | (addr[0] << 8);
-
- return (high_val >> rsh) & 0xfff;
-}
-
-static int hclgevf_do_update_mta_status(struct hclgevf_dev *hdev,
- unsigned long *status)
-{
-#define HCLGEVF_MTA_STATUS_MSG_SIZE 13
-#define HCLGEVF_MTA_STATUS_MSG_BITS \
- (HCLGEVF_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE)
-#define HCLGEVF_MTA_STATUS_MSG_END_BITS \
- (HCLGEVF_MTA_TBL_SIZE % HCLGEVF_MTA_STATUS_MSG_BITS)
- u16 tbl_cnt;
- u16 tbl_idx;
- u8 msg_cnt;
- u8 msg_idx;
- int ret;
-
- msg_cnt = DIV_ROUND_UP(HCLGEVF_MTA_TBL_SIZE,
- HCLGEVF_MTA_STATUS_MSG_BITS);
- tbl_idx = 0;
- msg_idx = 0;
- while (msg_cnt--) {
- u8 msg[HCLGEVF_MTA_STATUS_MSG_SIZE + 1];
- u8 *p = &msg[1];
- u8 msg_ofs;
- u8 msg_bit;
-
- memset(msg, 0, sizeof(msg));
-
- /* set index field */
- msg[0] = 0x7F & msg_idx;
-
- /* set end flag field */
- if (msg_cnt == 0) {
- msg[0] |= 0x80;
- tbl_cnt = HCLGEVF_MTA_STATUS_MSG_END_BITS;
- } else {
- tbl_cnt = HCLGEVF_MTA_STATUS_MSG_BITS;
- }
-
- /* set status field */
- msg_ofs = 0;
- msg_bit = 0;
- while (tbl_cnt--) {
- if (test_bit(tbl_idx, status))
- p[msg_ofs] |= BIT(msg_bit);
-
- tbl_idx++;
-
- msg_bit++;
- if (msg_bit == BITS_PER_BYTE) {
- msg_bit = 0;
- msg_ofs++;
- }
- }
-
- ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST,
- HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE,
- msg, sizeof(msg), false, NULL, 0);
- if (ret)
- break;
-
- msg_idx++;
- }
-
- return ret;
-}
-
-static int hclgevf_update_mta_status(struct hnae3_handle *handle)
-{
- unsigned long mta_status[BITS_TO_LONGS(HCLGEVF_MTA_TBL_SIZE)];
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct net_device *netdev = hdev->nic.kinfo.netdev;
- struct netdev_hw_addr *ha;
- u16 tbl_idx;
-
- /* clear status */
- memset(mta_status, 0, sizeof(mta_status));
-
- /* update status from mc addr list */
- netdev_for_each_mc_addr(ha, netdev) {
- tbl_idx = hclgevf_get_mac_addr_to_mta_index(hdev, ha->addr);
- set_bit(tbl_idx, mta_status);
- }
-
- return hclgevf_do_update_mta_status(hdev, mta_status);
-}
-
static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
@@ -1871,14 +1751,6 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
goto err_config;
}
- /* Initialize mta type for this VF */
- ret = hclgevf_cfg_func_mta_type(hdev);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "failed(%d) to initialize MTA type\n", ret);
- goto err_config;
- }
-
/* Initialize RSS for this VF */
ret = hclgevf_rss_init_hw(hdev);
if (ret) {
@@ -2038,7 +1910,6 @@ static const struct hnae3_ae_ops hclgevf_ops = {
.rm_uc_addr = hclgevf_rm_uc_addr,
.add_mc_addr = hclgevf_add_mc_addr,
.rm_mc_addr = hclgevf_rm_mc_addr,
- .update_mta_status = hclgevf_update_mta_status,
.get_stats = hclgevf_get_stats,
.update_stats = hclgevf_update_stats,
.get_strings = hclgevf_get_strings,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index 2af01f1..cf5fbf7 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -47,9 +47,6 @@
#define HCLGEVF_RSS_CFG_TBL_NUM \
(HCLGEVF_RSS_IND_TBL_SIZE / HCLGEVF_RSS_CFG_TBL_SIZE)
-#define HCLGEVF_MTA_TBL_SIZE 4096
-#define HCLGEVF_MTA_TYPE_SEL_MAX 4
-
/* states of hclgevf device & tasks */
enum hclgevf_states {
/* device states */
@@ -157,8 +154,6 @@ struct hclgevf_dev {
u16 *vector_status;
int *vector_irq;
- bool accept_mta_mc; /* whether to accept mta filter multicast */
- u8 mta_mac_sel_type;
bool mbx_event_pending;
struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 3/6] net: hns3: Optimize for unicast mac vlan table
From: Salil Mehta @ 2018-10-05 17:03 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Jian Shen
In-Reply-To: <20181005170329.6512-1-salil.mehta@huawei.com>
From: Jian Shen <shenjian15@huawei.com>
In previously implement for unicast mac vlan table, the space is
shared by all the functions, driver does nothing when the space is
exhausted. This patch preallocates the space of unicast mac vlan
table for each function by software. Each function can only use its
private space and available shared space, avoiding single function
exhausts too much space, and other functions are unable to add
unicast mac address.
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 11 ++
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 147 ++++++++++++++++++++-
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 18 +++
3 files changed, 174 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 26fda05..6098dacb 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -175,6 +175,7 @@ enum hclge_opcode_type {
HCLGE_OPC_MAC_VLAN_REMOVE = 0x1001,
HCLGE_OPC_MAC_VLAN_TYPE_ID = 0x1002,
HCLGE_OPC_MAC_VLAN_INSERT = 0x1003,
+ HCLGE_OPC_MAC_VLAN_ALLOCATE = 0x1004,
HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
@@ -401,6 +402,8 @@ struct hclge_pf_res_cmd {
#define HCLGE_CFG_RSS_SIZE_M GENMASK(31, 24)
#define HCLGE_CFG_SPEED_ABILITY_S 0
#define HCLGE_CFG_SPEED_ABILITY_M GENMASK(7, 0)
+#define HCLGE_CFG_UMV_TBL_SPACE_S 16
+#define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16)
struct hclge_cfg_param_cmd {
__le32 offset;
@@ -590,6 +593,14 @@ struct hclge_mac_vlan_tbl_entry_cmd {
u8 rsv2[6];
};
+#define HCLGE_UMV_SPC_ALC_B 0
+struct hclge_umv_spc_alc_cmd {
+ u8 allocate;
+ u8 rsv1[3];
+ __le32 space_size;
+ u8 rsv2[16];
+};
+
#define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0)
#define HCLGE_MAC_MGR_MASK_MAC_B BIT(1)
#define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 0106c1b..d346d0a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -31,6 +31,8 @@ static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu);
static int hclge_init_vlan_config(struct hclge_dev *hdev);
static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev);
+static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
+ u16 *allocated_size, bool is_alloc);
static struct hnae3_ae_algo ae_algo;
@@ -778,6 +780,11 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
cfg->speed_ability = hnae3_get_field(__le32_to_cpu(req->param[1]),
HCLGE_CFG_SPEED_ABILITY_M,
HCLGE_CFG_SPEED_ABILITY_S);
+ cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]),
+ HCLGE_CFG_UMV_TBL_SPACE_M,
+ HCLGE_CFG_UMV_TBL_SPACE_S);
+ if (!cfg->umv_space)
+ cfg->umv_space = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
}
/* hclge_get_cfg: query the static parameter from flash
@@ -856,6 +863,7 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tm_info.num_pg = 1;
hdev->tc_max = cfg.tc_num;
hdev->tm_info.hw_pfc_map = 0;
+ hdev->wanted_umv_size = cfg.umv_space;
ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
if (ret) {
@@ -5237,6 +5245,118 @@ static int hclge_add_mac_vlan_tbl(struct hclge_vport *vport,
return cfg_status;
}
+static int hclge_init_umv_space(struct hclge_dev *hdev)
+{
+ u16 allocated_size = 0;
+ int ret;
+
+ ret = hclge_set_umv_space(hdev, hdev->wanted_umv_size, &allocated_size,
+ true);
+ if (ret)
+ return ret;
+
+ if (allocated_size < hdev->wanted_umv_size)
+ dev_warn(&hdev->pdev->dev,
+ "Alloc umv space failed, want %d, get %d\n",
+ hdev->wanted_umv_size, allocated_size);
+
+ mutex_init(&hdev->umv_mutex);
+ hdev->max_umv_size = allocated_size;
+ hdev->priv_umv_size = hdev->max_umv_size / (hdev->num_req_vfs + 2);
+ hdev->share_umv_size = hdev->priv_umv_size +
+ hdev->max_umv_size % (hdev->num_req_vfs + 2);
+
+ return 0;
+}
+
+static int hclge_uninit_umv_space(struct hclge_dev *hdev)
+{
+ int ret;
+
+ if (hdev->max_umv_size > 0) {
+ ret = hclge_set_umv_space(hdev, hdev->max_umv_size, NULL,
+ false);
+ if (ret)
+ return ret;
+ hdev->max_umv_size = 0;
+ }
+ mutex_destroy(&hdev->umv_mutex);
+
+ return 0;
+}
+
+static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
+ u16 *allocated_size, bool is_alloc)
+{
+ struct hclge_umv_spc_alc_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ req = (struct hclge_umv_spc_alc_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ALLOCATE, false);
+ hnae3_set_bit(req->allocate, HCLGE_UMV_SPC_ALC_B, !is_alloc);
+ req->space_size = cpu_to_le32(space_size);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "%s umv space failed for cmd_send, ret =%d\n",
+ is_alloc ? "allocate" : "free", ret);
+ return ret;
+ }
+
+ if (is_alloc && allocated_size)
+ *allocated_size = le32_to_cpu(desc.data[1]);
+
+ return 0;
+}
+
+static void hclge_reset_umv_space(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport;
+ int i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ vport = &hdev->vport[i];
+ vport->used_umv_num = 0;
+ }
+
+ mutex_lock(&hdev->umv_mutex);
+ hdev->share_umv_size = hdev->priv_umv_size +
+ hdev->max_umv_size % (hdev->num_req_vfs + 2);
+ mutex_unlock(&hdev->umv_mutex);
+}
+
+static bool hclge_is_umv_space_full(struct hclge_vport *vport)
+{
+ struct hclge_dev *hdev = vport->back;
+ bool is_full;
+
+ mutex_lock(&hdev->umv_mutex);
+ is_full = (vport->used_umv_num >= hdev->priv_umv_size &&
+ hdev->share_umv_size == 0);
+ mutex_unlock(&hdev->umv_mutex);
+
+ return is_full;
+}
+
+static void hclge_update_umv_space(struct hclge_vport *vport, bool is_free)
+{
+ struct hclge_dev *hdev = vport->back;
+
+ mutex_lock(&hdev->umv_mutex);
+ if (is_free) {
+ if (vport->used_umv_num > hdev->priv_umv_size)
+ hdev->share_umv_size++;
+ vport->used_umv_num--;
+ } else {
+ if (vport->used_umv_num >= hdev->priv_umv_size)
+ hdev->share_umv_size--;
+ vport->used_umv_num++;
+ }
+ mutex_unlock(&hdev->umv_mutex);
+}
+
static int hclge_add_uc_addr(struct hnae3_handle *handle,
const unsigned char *addr)
{
@@ -5282,8 +5402,19 @@ int hclge_add_uc_addr_common(struct hclge_vport *vport,
* is not allowed in the mac vlan table.
*/
ret = hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false);
- if (ret == -ENOENT)
- return hclge_add_mac_vlan_tbl(vport, &req, NULL);
+ if (ret == -ENOENT) {
+ if (!hclge_is_umv_space_full(vport)) {
+ ret = hclge_add_mac_vlan_tbl(vport, &req, NULL);
+ if (!ret)
+ hclge_update_umv_space(vport, false);
+ return ret;
+ }
+
+ dev_err(&hdev->pdev->dev, "UC MAC table full(%u)\n",
+ hdev->priv_umv_size);
+
+ return -ENOSPC;
+ }
/* check if we just hit the duplicate */
if (!ret)
@@ -5326,6 +5457,8 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport,
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
hclge_prepare_mac_addr(&req, addr);
ret = hclge_remove_mac_vlan_tbl(vport, &req);
+ if (!ret)
+ hclge_update_umv_space(vport, true);
return ret;
}
@@ -6714,6 +6847,12 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
}
}
+ ret = hclge_init_umv_space(hdev);
+ if (ret) {
+ dev_err(&pdev->dev, "umv space init error, ret=%d.\n", ret);
+ goto err_msi_irq_uninit;
+ }
+
ret = hclge_mac_init(hdev);
if (ret) {
dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret);
@@ -6834,6 +6973,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
+ hclge_reset_umv_space(hdev);
+
ret = hclge_mac_init(hdev);
if (ret) {
dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret);
@@ -6887,6 +7028,8 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
if (mac->phydev)
mdiobus_unregister(mac->mdio_bus);
+ hclge_uninit_umv_space(hdev);
+
/* Disable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, false);
synchronize_irq(hdev->misc_vector.vector_irq);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index 06adbdd..d0c7c62 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -14,6 +14,8 @@
#define HCLGE_MOD_VERSION "1.0"
#define HCLGE_DRIVER_NAME "hclge"
+#define HCLGE_MAX_PF_NUM 8
+
#define HCLGE_INVALID_VPORT 0xffff
#define HCLGE_PF_CFG_BLOCK_SIZE 32
@@ -53,6 +55,10 @@
#define HCLGE_RSS_TC_SIZE_6 64
#define HCLGE_RSS_TC_SIZE_7 128
+#define HCLGE_UMV_TBL_SIZE 3072
+#define HCLGE_DEFAULT_UMV_SPACE_PER_PF \
+ (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM)
+
#define HCLGE_MTA_TBL_SIZE 4096
#define HCLGE_TQP_RESET_TRY_TIMES 10
@@ -251,6 +257,7 @@ struct hclge_cfg {
u8 default_speed;
u32 numa_node_map;
u8 speed_ability;
+ u16 umv_space;
};
struct hclge_tm_info {
@@ -680,6 +687,15 @@ struct hclge_dev {
struct hclge_fd_cfg fd_cfg;
struct hlist_head fd_rule_list;
u16 hclge_fd_rule_num;
+
+ u16 wanted_umv_size;
+ /* max available unicast mac vlan space */
+ u16 max_umv_size;
+ /* private unicast mac vlan space, it's same for PF and its VFs */
+ u16 priv_umv_size;
+ /* unicast mac vlan space shared by PF and its VFs */
+ u16 share_umv_size;
+ struct mutex umv_mutex; /* protect share_umv_size */
};
/* VPort level vlan tag configuration for TX direction */
@@ -732,6 +748,8 @@ struct hclge_vport {
struct hclge_tx_vtag_cfg txvlan_cfg;
struct hclge_rx_vtag_cfg rxvlan_cfg;
+ u16 used_umv_num;
+
int vport_id;
struct hclge_dev *back; /* Back reference to associated dev */
struct hnae3_handle nic;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 2/6] net: hns3: Clear mac vlan table entries when unload driver or function reset
From: Salil Mehta @ 2018-10-05 17:03 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Jian Shen
In-Reply-To: <20181005170329.6512-1-salil.mehta@huawei.com>
From: Jian Shen <shenjian15@huawei.com>
In original codes, the mac vlan table entries are not cleared when
unload hns3 driver. The dirty mac vlan table entries will make the
result of looking up mac vlan table being unexpected.
When doing core reset or global reset, the firmware will clear all
the tables for driver, and driver shouldn't send any commands to
firmware during reset. But when doing function reset, the driver
needs to clear the tables itself.
This patch clears the mac vlan table entries for each client when
unload driver or reset.
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 45 +++++++++++++++----------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index c269256..d8b8ccf 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -21,6 +21,7 @@
static void hns3_clear_all_ring(struct hnae3_handle *h);
static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h);
+static void hns3_remove_hw_addr(struct net_device *netdev);
static const char hns3_driver_name[] = "hns3";
const char hns3_driver_version[] = VERMAGIC_STRING;
@@ -3155,15 +3156,6 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init)
}
-static void hns3_uninit_mac_addr(struct net_device *netdev)
-{
- struct hns3_nic_priv *priv = netdev_priv(netdev);
- struct hnae3_handle *h = priv->ae_handle;
-
- if (h->ae_algo->ops->rm_uc_addr)
- h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr);
-}
-
static int hns3_restore_fd_rules(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
@@ -3296,6 +3288,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
+ hns3_remove_hw_addr(netdev);
+
if (netdev->reg_state != NETREG_UNINITIALIZED)
unregister_netdev(netdev);
@@ -3319,8 +3313,6 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
priv->ring_data = NULL;
- hns3_uninit_mac_addr(netdev);
-
free_netdev(netdev);
}
@@ -3392,6 +3384,25 @@ static void hns3_recover_hw_addr(struct net_device *ndev)
hns3_nic_mc_sync(ndev, ha->addr);
}
+static void hns3_remove_hw_addr(struct net_device *netdev)
+{
+ struct netdev_hw_addr_list *list;
+ struct netdev_hw_addr *ha, *tmp;
+
+ hns3_nic_uc_unsync(netdev, netdev->dev_addr);
+
+ /* go through and unsync uc_addr entries to the device */
+ list = &netdev->uc;
+ list_for_each_entry_safe(ha, tmp, &list->list, list)
+ hns3_nic_uc_unsync(netdev, ha->addr);
+
+ /* go through and unsync mc_addr entries to the device */
+ list = &netdev->mc;
+ list_for_each_entry_safe(ha, tmp, &list->list, list)
+ if (ha->refcount > 1)
+ hns3_nic_mc_unsync(netdev, ha->addr);
+}
+
static void hns3_clear_tx_ring(struct hns3_enet_ring *ring)
{
while (ring->next_to_clean != ring->next_to_use) {
@@ -3637,14 +3648,14 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
if (ret)
netdev_err(netdev, "uninit ring error\n");
- hns3_uninit_mac_addr(netdev);
-
- /* it is cumbersome for hardware to pick-and-choose rules for deletion
- * from TCAM. Hence, for function reset software intervention is
- * required to delete the rules
+ /* it is cumbersome for hardware to pick-and-choose entries for deletion
+ * from table space. Hence, for function reset software intervention is
+ * required to delete the entries
*/
- if (hns3_dev_ongoing_func_reset(ae_dev))
+ if (hns3_dev_ongoing_func_reset(ae_dev)) {
+ hns3_remove_hw_addr(netdev);
hns3_del_all_fd_rules(netdev, false);
+ }
return ret;
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 1/6] net: hns3: Remove the default mask configuration for mac vlan table
From: Salil Mehta @ 2018-10-05 17:03 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Jian Shen, Zhongzhu Liu
In-Reply-To: <20181005170329.6512-1-salil.mehta@huawei.com>
From: Jian Shen <shenjian15@huawei.com>
The default mask configuration has been done by firmware, so the driver
doesn't need to do it any more.
Signed-off-by: Zhongzhu Liu <liuzhongzhu@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 10 -------
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 32 ----------------------
2 files changed, 42 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index e5e66b2..26fda05 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -177,7 +177,6 @@ enum hclge_opcode_type {
HCLGE_OPC_MAC_VLAN_INSERT = 0x1003,
HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
- HCLGE_OPC_MAC_VLAN_MASK_SET = 0x1012,
/* Multicast linear table commands */
HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020,
@@ -591,15 +590,6 @@ struct hclge_mac_vlan_tbl_entry_cmd {
u8 rsv2[6];
};
-#define HCLGE_VLAN_MASK_EN_B 0
-struct hclge_mac_vlan_mask_entry_cmd {
- u8 rsv0[2];
- u8 vlan_mask;
- u8 rsv1;
- u8 mac_mask[6];
- u8 rsv2[14];
-};
-
#define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0)
#define HCLGE_MAC_MGR_MASK_MAC_B BIT(1)
#define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 21ca4af..0106c1b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -1939,36 +1939,11 @@ static int hclge_get_autoneg(struct hnae3_handle *handle)
return hdev->hw.mac.autoneg;
}
-static int hclge_set_default_mac_vlan_mask(struct hclge_dev *hdev,
- bool mask_vlan,
- u8 *mac_mask)
-{
- struct hclge_mac_vlan_mask_entry_cmd *req;
- struct hclge_desc desc;
- int status;
-
- req = (struct hclge_mac_vlan_mask_entry_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_MASK_SET, false);
-
- hnae3_set_bit(req->vlan_mask, HCLGE_VLAN_MASK_EN_B,
- mask_vlan ? 1 : 0);
- ether_addr_copy(req->mac_mask, mac_mask);
-
- status = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (status)
- dev_err(&hdev->pdev->dev,
- "Config mac_vlan_mask failed for cmd_send, ret =%d\n",
- status);
-
- return status;
-}
-
static int hclge_mac_init(struct hclge_dev *hdev)
{
struct hnae3_handle *handle = &hdev->vport[0].nic;
struct net_device *netdev = handle->kinfo.netdev;
struct hclge_mac *mac = &hdev->hw.mac;
- u8 mac_mask[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct hclge_vport *vport;
int mtu;
int ret;
@@ -2011,13 +1986,6 @@ static int hclge_mac_init(struct hclge_dev *hdev)
}
}
- ret = hclge_set_default_mac_vlan_mask(hdev, true, mac_mask);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "set default mac_vlan_mask fail ret=%d\n", ret);
- return ret;
- }
-
if (netdev)
mtu = netdev->mtu;
else
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 0/6] Fixes, minor changes & cleanups for the Unicast MAC VLAN table
From: Salil Mehta @ 2018-10-05 17:03 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm
This patch-set presents necessary modifications, fixes & cleanups related
to Unicast MAC Vlan Table to support revision 0x21 hardware.
Jian Shen (5):
net: hns3: Remove the default mask configuration for mac vlan table
net: hns3: Clear mac vlan table entries when unload driver or function
reset
net: hns3: Optimize for unicast mac vlan table
net: hns3: Drop depricated mta table support
net: hns3: Fix for rx vlan id handle to support Rev 0x21 hardware
Zhongzhu Liu (1):
net: hns3: Add egress/ingress vlan filter for revision 0x21
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 3 -
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 -
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 78 ++--
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 47 +--
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 446 +++++++++------------
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 40 +-
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 58 ---
.../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 129 ------
.../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 5 -
9 files changed, 250 insertions(+), 558 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH net-next] cxgb4: use FW_PORT_ACTION_L1_CFG32 for 32 bit capability
From: Ganesh Goudar @ 2018-10-05 9:34 UTC (permalink / raw)
To: netdev, davem; +Cc: nirranjan, indranil, dt, Ganesh Goudar, Casey Leedom
when 32 bit port capability is in use, use FW_PORT_ACTION_L1_CFG32
rather than FW_PORT_ACTION_L1_CFG.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index f85eab5..cb52394 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -4204,6 +4204,7 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox,
*/
int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
{
+ unsigned int fw_caps = adap->params.fw_caps_support;
struct fw_port_cmd c;
memset(&c, 0, sizeof(c));
@@ -4211,9 +4212,14 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_PORT_CMD_PORTID_V(port));
c.action_to_len16 =
- cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+ cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+ ? FW_PORT_ACTION_L1_CFG
+ : FW_PORT_ACTION_L1_CFG32) |
FW_LEN16(c));
- c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP32_ANEG);
+ if (fw_caps == FW_CAPS16)
+ c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG);
+ else
+ c.u.l1cfg32.rcap32 = cpu_to_be32(FW_PORT_CAP32_ANEG);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
--
2.1.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox