* [PATCH net-next] net/ncsi: Add NCSI OEM command support
From: Vijay Khemka @ 2018-10-05 17:46 UTC (permalink / raw)
To: Samuel Mendoza-Jonas, David S. Miller, netdev, linux-kernel
Cc: vijaykhemka, openbmc @ lists . ozlabs . org,
Justin . Lee1 @ Dell . com, joel @ jms . id . au,
linux-aspeed @ lists . ozlabs . org, Sai Dasari,
christian @ cmd . nu
This patch adds OEM commands and response handling. It also defines OEM
command and response structure as per NCSI specification along with its
handlers.
ncsi_cmd_handler_oem: This is a generic command request handler for OEM
commands
ncsi_rsp_handler_oem: This is a generic response handler for OEM commands
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Reviewed-by: Justin Lee <justin.lee1@dell.com>
Reviewed-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
net/ncsi/internal.h | 5 +++++
net/ncsi/ncsi-cmd.c | 30 +++++++++++++++++++++++++++---
net/ncsi/ncsi-pkt.h | 14 ++++++++++++++
net/ncsi/ncsi-rsp.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 88 insertions(+), 4 deletions(-)
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 8055e3965cef..3d0a33b874f5 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -68,6 +68,10 @@ enum {
NCSI_MODE_MAX
};
+/* OEM Vendor Manufacture ID */
+#define NCSI_OEM_MFR_MLX_ID 0x8119
+#define NCSI_OEM_MFR_BCM_ID 0x113d
+
struct ncsi_channel_version {
u32 version; /* Supported BCD encoded NCSI version */
u32 alpha2; /* Supported BCD encoded NCSI version */
@@ -305,6 +309,7 @@ struct ncsi_cmd_arg {
unsigned short words[8];
unsigned int dwords[4];
};
+ unsigned char *data; /* NCSI OEM data */
};
extern struct list_head ncsi_dev_list;
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index 7567ca63aae2..82b7d9201db8 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -211,6 +211,25 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
return 0;
}
+static int ncsi_cmd_handler_oem(struct sk_buff *skb,
+ struct ncsi_cmd_arg *nca)
+{
+ struct ncsi_cmd_oem_pkt *cmd;
+ unsigned int len;
+
+ len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
+ if (nca->payload < 26)
+ len += 26;
+ else
+ len += nca->payload;
+
+ cmd = skb_put_zero(skb, len);
+ memcpy(&cmd->mfr_id, nca->data, nca->payload);
+ ncsi_cmd_build_header(&cmd->cmd.common, nca);
+
+ return 0;
+}
+
static struct ncsi_cmd_handler {
unsigned char type;
int payload;
@@ -244,7 +263,7 @@ static struct ncsi_cmd_handler {
{ NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
- { NCSI_PKT_CMD_OEM, 0, NULL },
+ { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
{ NCSI_PKT_CMD_PLDM, 0, NULL },
{ NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
};
@@ -316,8 +335,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
return -ENOENT;
}
- /* Get packet payload length and allocate the request */
- nca->payload = nch->payload;
+ /* Get packet payload length and allocate the request
+ * It is expected that if length set as negative in
+ * handler structure means caller is initializing it
+ * and setting length in nca before calling xmit function
+ */
+ if (nch->payload >= 0)
+ nca->payload = nch->payload;
nr = ncsi_alloc_command(nca);
if (!nr)
return -ENOMEM;
diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
index 91b4b66438df..0f2087c8d42a 100644
--- a/net/ncsi/ncsi-pkt.h
+++ b/net/ncsi/ncsi-pkt.h
@@ -151,6 +151,20 @@ struct ncsi_cmd_snfc_pkt {
unsigned char pad[22];
};
+/* OEM Request Command as per NCSI Specification */
+struct ncsi_cmd_oem_pkt {
+ struct ncsi_cmd_pkt_hdr cmd; /* Command header */
+ __be32 mfr_id; /* Manufacture ID */
+ unsigned char data[]; /* OEM Payload Data */
+};
+
+/* OEM Response Packet as per NCSI Specification */
+struct ncsi_rsp_oem_pkt {
+ struct ncsi_rsp_pkt_hdr rsp; /* Command header */
+ __be32 mfr_id; /* Manufacture ID */
+ unsigned char data[]; /* Payload data */
+};
+
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 930c1d3796f0..d66b34749027 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -596,6 +596,47 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
return 0;
}
+static struct ncsi_rsp_oem_handler {
+ unsigned int mfr_id;
+ int (*handler)(struct ncsi_request *nr);
+} ncsi_rsp_oem_handlers[] = {
+ { NCSI_OEM_MFR_MLX_ID, NULL },
+ { NCSI_OEM_MFR_BCM_ID, NULL }
+};
+
+/* Response handler for OEM command */
+static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
+{
+ struct ncsi_rsp_oem_pkt *rsp;
+ struct ncsi_rsp_oem_handler *nrh = NULL;
+ unsigned int mfr_id, i;
+
+ /* Get the response header */
+ rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+ mfr_id = ntohl(rsp->mfr_id);
+
+ /* Check for manufacturer id and Find the handler */
+ for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
+ if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
+ if (ncsi_rsp_oem_handlers[i].handler)
+ nrh = &ncsi_rsp_oem_handlers[i];
+ else
+ nrh = NULL;
+
+ break;
+ }
+ }
+
+ if (!nrh) {
+ netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
+ mfr_id);
+ return -ENOENT;
+ }
+
+ /* Process the packet */
+ return nrh->handler(nr);
+}
+
static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
{
struct ncsi_rsp_gvi_pkt *rsp;
@@ -932,7 +973,7 @@ static struct ncsi_rsp_handler {
{ NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns },
{ NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts },
{ NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
- { NCSI_PKT_RSP_OEM, 0, NULL },
+ { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
{ NCSI_PKT_RSP_PLDM, 0, NULL },
{ NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }
};
--
2.17.1
^ permalink raw reply related
* Re: [PATCH net 2/2] rxrpc: Fix the data_ready handler
From: Eric Dumazet @ 2018-10-05 17:44 UTC (permalink / raw)
To: David Howells, Eric Dumazet; +Cc: netdev, linux-afs, linux-kernel, Paolo Abeni
In-Reply-To: <25989.1538757200@warthog.procyon.org.uk>
On 10/05/2018 09:33 AM, David Howells wrote:
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
>> sk_data_ready is not meant to process packets, it is meant to signal
>> to another entity (preferably running in process context and thus with proper
>> schedule points, and not blocking BH) that there is data ready to be consumed.
>
> The issue is that I need to route the packets to the appropriate call, and the
> BH appears to be the right place to do this, especially as I can quickly parse
> and discard certain types of packet right there.
>
> If I move all of this to process context then that adds extra context switches
> between the routing process and the destination process.
>
>> Under DOS, it is possible multiple cpus will sk_data_ready in parallel.
>
> Ummm... I've been led to believe that sk_data_ready will *not* be called in
> parallel and that the code it calls can assume non-reentrancy. Is this not
> the case.
Certainly not for UDP.
TCP input processing uses the socket lock, but UDP is fully parallel.
>
> What about the patch I attached, whereby I use the encap_rcv() hook. Do you
> say that won't work?
I am kind of busy today, will look at it next week.
^ permalink raw reply
* [PATCH] iwlwifi: mvm: remove set but not used variable 'he_phy_data'
From: YueHaibing @ 2018-10-05 10:47 UTC (permalink / raw)
To: Johannes Berg, Emmanuel Grumbach, Luca Coelho,
Intel Linux Wireless, Kalle Valo, Golan Ben Ami, Sara Sharon,
Shaul Triebitz, Liad Kaufman
Cc: YueHaibing, linux-wireless, kernel-janitors, netdev
Fixes gcc '-Wunused-but-set-variable' warning:
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c: In function 'iwl_mvm_rx_mpdu_mq':
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c:1386:7: warning:
variable 'he_phy_data' set but not used [-Wunused-but-set-variable]
u64 he_phy_data;
'he_phy_data' never used since be introduce in
commit 18ead597daa1 ("iwlwifi: support new rx_mpdu_desc api")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 894dd63..7eaa586 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -1383,12 +1383,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
/* update aggregation data for monitor sake on default queue */
if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
- u64 he_phy_data;
-
- if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
- he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
- else
- he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
rx_status->ampdu_reference = mvm->ampdu_ref;
^ permalink raw reply related
* Re: question regarding Linux kernel handling of packets received that has src address of interface address
From: Ido Schimmel @ 2018-10-05 10:27 UTC (permalink / raw)
To: Mikael Abrahamsson; +Cc: netdev
In-Reply-To: <alpine.DEB.2.20.1810051035270.4550@uplift.swm.pp.se>
On Fri, Oct 05, 2018 at 10:50:24AM +0200, Mikael Abrahamsson wrote:
> So my question is where in the Linux kernel is this check performed that
> disallows incoming packets that have src IP address the same as an interface
> address? Can it be turned off? Is there a way to "hack around it", for
> instance with iptables and re-write the source address of the packet before
> it hits this check (I don't care about the source address when the packet is
> delivered to the application, it can be re-written to anything).
Did you set 'accept_local' [1] ?
"
accept_local - BOOLEAN
Accept packets with local source addresses. In combination with
suitable routing, this can be used to direct packets between two
local interfaces over the wire and have them accepted properly.
default FALSE
"
I tried to create a setup similar to yours and it seems to be working
for me.
1. https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
^ permalink raw reply
* [PATCH net-next 19/19] net: usb: aqc111: Add support for wake on LAN by MAGIC packet
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 | 203 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/aqc111.h | 11 +++
2 files changed, 214 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 20d4347ea3ad..e2ea8dc54d3a 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -192,6 +192,35 @@ static void aqc111_get_drvinfo(struct net_device *net,
info->regdump_len = 0x00;
}
+static void aqc111_get_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ wolinfo->supported = WAKE_MAGIC;
+ wolinfo->wolopts = 0;
+
+ if (aqc111_data->wol_cfg.flags & AQ_WOL_FLAG_MP)
+ wolinfo->wolopts |= WAKE_MAGIC;
+}
+
+static int aqc111_set_wol(struct net_device *net,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+
+ if (wolinfo->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+
+ aqc111_data->wol_cfg.flags = 0;
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ aqc111_data->wol_cfg.flags |= AQ_WOL_FLAG_MP;
+
+ return 0;
+}
+
static void aqc111_speed_to_link_mode(u32 speed,
struct ethtool_link_ksettings *elk)
{
@@ -441,6 +470,8 @@ static int aqc111_set_link_ksettings(struct net_device *net,
static const struct ethtool_ops aqc111_ethtool_ops = {
.get_drvinfo = aqc111_get_drvinfo,
+ .get_wol = aqc111_get_wol,
+ .set_wol = aqc111_set_wol,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_link = ethtool_op_get_link,
@@ -1346,6 +1377,176 @@ static const struct driver_info aqc111_info = {
.tx_fixup = aqc111_tx_fixup,
};
+static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ u8 reg8;
+ u16 reg16;
+ u16 temp_rx_ctrl = 0x00;
+
+ usbnet_suspend(intf, message);
+
+ aqc111_read_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+ temp_rx_ctrl = reg16;
+ /* Stop RX operations*/
+ reg16 &= ~SFR_RX_CTL_START;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, ®16);
+ /* Force bz */
+ aqc111_read_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+ 2, 2, ®16);
+ reg16 |= SFR_PHYPWR_RSTCTL_BZ;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL,
+ 2, 2, ®16);
+
+ reg8 = SFR_BULK_OUT_EFF_EN;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BULK_OUT_CTRL,
+ 1, 1, ®8);
+
+ temp_rx_ctrl &= ~(SFR_RX_CTL_START | SFR_RX_CTL_RF_WAK |
+ SFR_RX_CTL_AP | SFR_RX_CTL_AM);
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, &temp_rx_ctrl);
+
+ reg8 = 0x00;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+ 1, 1, ®8);
+
+ if (aqc111_data->wol_cfg.flags) {
+ aqc111_data->phy_ops.wol = 1;
+ if (aqc111_data->dpa) {
+ reg8 = 0;
+ if (aqc111_data->wol_cfg.flags & AQ_WOL_FLAG_MP)
+ reg8 |= SFR_MONITOR_MODE_RWMP;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MONITOR_MODE, 1, 1, ®8);
+ } else {
+ memcpy(aqc111_data->wol_cfg.hw_addr,
+ dev->net->dev_addr, ETH_ALEN);
+ }
+
+ temp_rx_ctrl |= (SFR_RX_CTL_AB | SFR_RX_CTL_START);
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL,
+ 2, 2, &temp_rx_ctrl);
+ reg8 = 0x00;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK,
+ 1, 1, ®8);
+ reg8 = SFR_BMRX_DMA_EN;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL,
+ 1, 1, ®8);
+ reg8 = SFR_RX_PATH_READY;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+ 1, 1, ®8);
+ reg8 = 0x07;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QCTRL,
+ 1, 1, ®8);
+ reg8 = 0x00;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_RX_BULKIN_QTIMR_LOW, 1, 1, ®8);
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_RX_BULKIN_QTIMR_HIGH, 1, 1, ®8);
+ reg8 = 0xFF;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QSIZE,
+ 1, 1, ®8);
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_BULKIN_QIFG,
+ 1, 1, ®8);
+
+ aqc111_read_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE,
+ 2, 2, ®16);
+ reg16 |= SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MEDIUM_STATUS_MODE, 2, 2, ®16);
+
+ if (aqc111_data->dpa) {
+ aqc111_set_phy_speed(dev, AUTONEG_DISABLE, SPEED_100);
+ } else {
+ aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
+ WOL_CFG_SIZE, &aqc111_data->wol_cfg);
+ aqc111_write_cmd(dev, AQ_PHY_OPS, 0, 0,
+ 4, &aqc111_data->phy_ops);
+ }
+ } else {
+ aqc111_data->phy_ops.low_power = 1;
+ if (!aqc111_data->dpa) {
+ aqc111_write_cmd(dev, AQ_PHY_OPS, 0, 0,
+ 4, &aqc111_data->phy_ops);
+ } else {
+ reg16 = AQ_PHY_LOW_POWER_MODE;
+ aq_mdio_write_cmd(dev, AQ_GLB_STD_CTRL_REG,
+ AQ_PHY_GLOBAL_ADDR, 2, ®16);
+ }
+
+ /* Disable RX path */
+ aqc111_read_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MEDIUM_STATUS_MODE, 2, 2, ®16);
+ reg16 &= ~SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MEDIUM_STATUS_MODE, 2, 2, ®16);
+ }
+
+ return 0;
+}
+
+static int aqc111_resume(struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ u8 reg8;
+ u16 reg16;
+
+ netif_carrier_off(dev->net);
+
+ /* Power up ethernet PHY */
+ aqc111_data->phy_ops.phy_power = 1;
+ aqc111_data->phy_ops.low_power = 0;
+ aqc111_data->phy_ops.wol = 0;
+ if (aqc111_data->dpa) {
+ aqc111_read_cmd_nopm(dev, AQ_PHY_POWER, 0, 0, 1, ®8);
+ if (reg8 == 0x00) {
+ reg8 = 0x02;
+ aqc111_write_cmd_nopm(dev, AQ_PHY_POWER, 0, 0,
+ 1, ®8);
+ msleep(200);
+ }
+
+ 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);
+ }
+ }
+
+ reg8 = 0xFF;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK,
+ 1, 1, ®8);
+ /* Configure RX control register => start operation */
+ reg16 = aqc111_data->rxctl;
+ reg16 &= ~SFR_RX_CTL_START;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+
+ reg16 |= SFR_RX_CTL_START;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, 2, ®16);
+
+ aqc111_set_phy_speed(dev, aqc111_data->autoneg,
+ aqc111_data->advertised_speed);
+
+ aqc111_read_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MEDIUM_STATUS_MODE, 2, 2, ®16);
+ reg16 |= SFR_MEDIUM_RECEIVE_EN;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC,
+ SFR_MEDIUM_STATUS_MODE, 2, 2, ®16);
+ reg8 = SFR_RX_PATH_READY;
+ aqc111_write_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_ETH_MAC_PATH,
+ 1, 1, ®8);
+ reg8 = 0x0;
+ aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BMRX_DMA_CONTROL, 1, 1, ®8);
+
+ return usbnet_resume(intf);
+}
+
#define AQC111_USB_ETH_DEV(vid, pid, table) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_CLASS, \
@@ -1371,6 +1572,8 @@ static struct usb_driver aq_driver = {
.name = "aqc111",
.id_table = products,
.probe = usbnet_probe,
+ .suspend = aqc111_suspend,
+ .resume = aqc111_resume,
.disconnect = usbnet_disconnect,
};
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index a7ccee225e93..9a900c325273 100644
--- a/drivers/net/usb/aqc111.h
+++ b/drivers/net/usb/aqc111.h
@@ -19,6 +19,7 @@
#define AQ_FLASH_PARAMETERS 0x20
#define AQ_PHY_POWER 0x31
#define AQ_PHY_CMD 0x32
+#define AQ_WOL_CFG 0x60
#define AQ_PHY_OPS 0x61
#define AQC111_PHY_ID 0x00
@@ -169,6 +170,7 @@
#define AQ_FW_VER_MINOR 0xDB
#define AQ_FW_VER_REV 0xDC
+#define AQ_WOL_FLAG_MP 0x2
/******************************************************************************/
struct aqc111_phy_options {
@@ -214,6 +216,14 @@ struct aqc111_phy_options {
};
};
+struct aqc111_wol_cfg {
+ u8 hw_addr[6];
+ u8 flags;
+ u8 rsvd[283];
+};
+
+#define WOL_CFG_SIZE sizeof(struct aqc111_wol_cfg)
+
struct aqc111_data {
u16 rxctl;
u8 rx_checksum;
@@ -228,6 +238,7 @@ struct aqc111_data {
} fw_ver;
u8 dpa; /*direct PHY access*/
struct aqc111_phy_options phy_ops;
+ struct aqc111_wol_cfg wol_cfg;
} __packed;
struct aqc111_int_data {
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 18/19] net: usb: aqc111: Implement get/set_link_ksettings callbacks
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 | 133 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index ade2b60b4811..20d4347ea3ad 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -192,6 +192,97 @@ static void aqc111_get_drvinfo(struct net_device *net,
info->regdump_len = 0x00;
}
+static void aqc111_speed_to_link_mode(u32 speed,
+ struct ethtool_link_ksettings *elk)
+{
+ switch (speed) {
+ case SPEED_5000: {
+ ethtool_link_ksettings_add_link_mode(elk, advertising,
+ 5000baseT_Full);
+ break;
+ }
+ case SPEED_2500: {
+ ethtool_link_ksettings_add_link_mode(elk, advertising,
+ 2500baseT_Full);
+ break;
+ }
+ case SPEED_1000: {
+ ethtool_link_ksettings_add_link_mode(elk, advertising,
+ 1000baseT_Full);
+ break;
+ }
+ case SPEED_100: {
+ ethtool_link_ksettings_add_link_mode(elk, advertising,
+ 100baseT_Full);
+ break;
+ }
+ }
+}
+
+static int aqc111_get_link_ksettings(struct net_device *net,
+ struct ethtool_link_ksettings *elk)
+{
+ struct usbnet *dev = netdev_priv(net);
+ enum usb_device_speed usb_speed = dev->udev->speed;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ u32 speed = SPEED_UNKNOWN;
+
+ ethtool_link_ksettings_zero_link_mode(elk, supported);
+ ethtool_link_ksettings_add_link_mode(elk, supported,
+ 100baseT_Full);
+ ethtool_link_ksettings_add_link_mode(elk, supported,
+ 1000baseT_Full);
+ if (usb_speed == USB_SPEED_SUPER) {
+ ethtool_link_ksettings_add_link_mode(elk, supported,
+ 2500baseT_Full);
+ ethtool_link_ksettings_add_link_mode(elk, supported,
+ 5000baseT_Full);
+ }
+ ethtool_link_ksettings_add_link_mode(elk, supported, TP);
+ ethtool_link_ksettings_add_link_mode(elk, supported, Autoneg);
+
+ elk->base.port = PORT_TP;
+ elk->base.transceiver = XCVR_INTERNAL;
+
+ elk->base.mdio_support = 0x00; /*Not supported*/
+
+ if (aqc111_data->autoneg)
+ bitmap_copy(elk->link_modes.advertising,
+ elk->link_modes.supported,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ else
+ aqc111_speed_to_link_mode(aqc111_data->advertised_speed, elk);
+
+ elk->base.autoneg = aqc111_data->autoneg;
+
+ switch (aqc111_data->link_speed) {
+ case AQ_INT_SPEED_5G:
+ {
+ speed = SPEED_5000;
+ break;
+ }
+ case AQ_INT_SPEED_2_5G:
+ {
+ speed = SPEED_2500;
+ break;
+ }
+ case AQ_INT_SPEED_1G:
+ {
+ speed = SPEED_1000;
+ break;
+ }
+ case AQ_INT_SPEED_100M:
+ {
+ speed = SPEED_100;
+ break;
+ }
+ }
+ elk->base.duplex = DUPLEX_FULL;
+ elk->base.speed = speed;
+
+ return 0;
+}
+
static void aqc111_set_phy_speed_fw_iface(struct usbnet *dev,
struct aqc111_data *aqc111_data)
{
@@ -308,11 +399,53 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
aqc111_set_phy_speed_fw_iface(dev, aqc111_data);
}
+static int aqc111_set_link_ksettings(struct net_device *net,
+ const struct ethtool_link_ksettings *elk)
+{
+ struct usbnet *dev = netdev_priv(net);
+ enum usb_device_speed usb_speed = dev->udev->speed;
+ struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0];
+ u32 speed = elk->base.speed;
+ u8 autoneg = elk->base.autoneg;
+
+ if (autoneg == AUTONEG_ENABLE) {
+ if (aqc111_data->autoneg != AUTONEG_ENABLE) {
+ aqc111_data->autoneg = AUTONEG_ENABLE;
+ aqc111_data->advertised_speed =
+ (usb_speed == USB_SPEED_SUPER) ?
+ SPEED_5000 : SPEED_1000;
+ aqc111_set_phy_speed(dev, aqc111_data->autoneg,
+ aqc111_data->advertised_speed);
+ }
+ } else {
+ if (speed != SPEED_100 &&
+ speed != SPEED_1000 &&
+ speed != SPEED_2500 &&
+ speed != SPEED_5000 &&
+ speed != SPEED_UNKNOWN)
+ return -EINVAL;
+
+ if (usb_speed != USB_SPEED_SUPER && speed > SPEED_1000)
+ return -EINVAL;
+
+ aqc111_data->autoneg = AUTONEG_DISABLE;
+ if (speed != SPEED_UNKNOWN)
+ aqc111_data->advertised_speed = speed;
+
+ aqc111_set_phy_speed(dev, aqc111_data->autoneg,
+ aqc111_data->advertised_speed);
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops aqc111_ethtool_ops = {
.get_drvinfo = aqc111_get_drvinfo,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_link = ethtool_op_get_link,
+ .get_link_ksettings = aqc111_get_link_ksettings,
+ .set_link_ksettings = aqc111_set_link_ksettings
};
static int aqc111_change_mtu(struct net_device *net, int new_mtu)
--
2.7.4
^ permalink raw reply related
* [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
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