summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-04-07 02:22:37 +0300
committerDavid S. Miller <davem@davemloft.net>2021-04-07 02:22:37 +0300
commitb3feb439f28ed523e57096142e752d2ffd8ca962 (patch)
treefe2bce0355e4d8813884def52ab4867b5f27852d
parente880f8b3a24a73704731a7227ed5fee14bd90192 (diff)
parentd42ebcbb635386d759985c775b5728c2f93037d1 (diff)
downloadlinux-b3feb439f28ed523e57096142e752d2ffd8ca962.tar.xz
Merge branch 'usbnet-speed'
Grant Grundler says: ==================== usbnet: speed reporting for devices without MDIO This series introduces support for USB network devices that report speed as a part of their protocol, not emulating an MII to be accessed over MDIO. v2: rebased on recent upstream changes v3: incorporated hints on naming and comments v4: fix misplaced hunks; reword some commit messages; add same change for cdc_ether v4-repost: added "net-next" to subject and Andrew Lunn's Reviewed-by I'm reposting Oliver Neukum's <oneukum@suse.com> patch series with fix ups for "misplaced hunks" (landed in the wrong patches). Please fixup the "author" if "git am" fails to attribute the patches 1-3 (of 4) to Oliver. I've tested v4 series with "5.12-rc3+" kernel on Intel NUC6i5SYB and + Sabrent NT-S25G. Google Pixelbook Go (chromeos-4.4 kernel) + Alpha Network AUE2500C were connected directly to the NT-S25G to get 2.5Gbps link rate: Settings for enx002427880815: Supported ports: [ ] Supported link modes: Not reported Supported pause frame use: No Supports auto-negotiation: No Supported FEC modes: Not reported Advertised link modes: Not reported Advertised pause frame use: No Advertised auto-negotiation: No Advertised FEC modes: Not reported Speed: 2500Mb/s Duplex: Half Auto-negotiation: off Port: Twisted Pair PHYAD: 0 Transceiver: internal MDI-X: Unknown Current message level: 0x00000007 (7) drv probe link Link detected: yes "Duplex" is a lie since we get no information about it. I expect "Auto-Negotiation" is always true for cdc_ncm and cdc_ether devices and perhaps someone knows offhand how to have ethtool report "true" instead. But this is good step in the right direction. base-commit: 1c273e10bc0cc7efb933e0ca10e260cdfc9f0b8c ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/asix_devices.c12
-rw-r--r--drivers/net/usb/cdc_ether.c27
-rw-r--r--drivers/net/usb/cdc_ncm.c55
-rw-r--r--drivers/net/usb/dm9601.c4
-rw-r--r--drivers/net/usb/mcs7830.c4
-rw-r--r--drivers/net/usb/sierra_net.c4
-rw-r--r--drivers/net/usb/smsc75xx.c4
-rw-r--r--drivers/net/usb/sr9700.c4
-rw-r--r--drivers/net/usb/sr9800.c4
-rw-r--r--drivers/net/usb/usbnet.c38
-rw-r--r--include/linux/usb/usbnet.h11
11 files changed, 94 insertions, 73 deletions
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 6e13d8165852..19a8fafb8f04 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -125,8 +125,8 @@ static const struct ethtool_ops ax88172_ethtool_ops = {
.get_eeprom = asix_get_eeprom,
.set_eeprom = asix_set_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static void ax88172_set_multicast(struct net_device *net)
@@ -291,8 +291,8 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
.get_eeprom = asix_get_eeprom,
.set_eeprom = asix_set_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static int ax88772_link_reset(struct usbnet *dev)
@@ -782,8 +782,8 @@ static const struct ethtool_ops ax88178_ethtool_ops = {
.get_eeprom = asix_get_eeprom,
.set_eeprom = asix_set_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static int marvell_phy_init(struct usbnet *dev)
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index a9b551028659..7eb0109e9baa 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -92,6 +92,18 @@ void usbnet_cdc_update_filter(struct usbnet *dev)
}
EXPORT_SYMBOL_GPL(usbnet_cdc_update_filter);
+/* We need to override usbnet_*_link_ksettings in bind() */
+static const struct ethtool_ops cdc_ether_ethtool_ops = {
+ .get_link = usbnet_get_link,
+ .nway_reset = usbnet_nway_reset,
+ .get_drvinfo = usbnet_get_drvinfo,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .get_link_ksettings = usbnet_get_link_ksettings_internal,
+ .set_link_ksettings = NULL,
+};
+
/* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
* all pure cdc, except for certain firmware workarounds, and knowing
@@ -310,6 +322,9 @@ skip:
return -ENODEV;
}
+ /* override ethtool_ops */
+ dev->net->ethtool_ops = &cdc_ether_ethtool_ops;
+
return 0;
bad_desc:
@@ -379,12 +394,10 @@ EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
* (by Brad Hards) talked with, with more functionality.
*/
-static void dumpspeed(struct usbnet *dev, __le32 *speeds)
+static void speed_change(struct usbnet *dev, __le32 *speeds)
{
- netif_info(dev, timer, dev->net,
- "link speeds: %u kbps up, %u kbps down\n",
- __le32_to_cpu(speeds[0]) / 1000,
- __le32_to_cpu(speeds[1]) / 1000);
+ dev->tx_speed = __le32_to_cpu(speeds[0]);
+ dev->rx_speed = __le32_to_cpu(speeds[1]);
}
void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
@@ -396,7 +409,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
/* SPEED_CHANGE can get split into two 8-byte packets */
if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
- dumpspeed(dev, (__le32 *) urb->transfer_buffer);
+ speed_change(dev, (__le32 *) urb->transfer_buffer);
return;
}
@@ -413,7 +426,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
if (urb->actual_length != (sizeof(*event) + 8))
set_bit(EVENT_STS_SPLIT, &dev->flags);
else
- dumpspeed(dev, (__le32 *) &event[1]);
+ speed_change(dev, (__le32 *) &event[1]);
break;
/* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
* but there are no standard formats for the response data.
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 8ae565a801b5..b04055fd1b79 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -133,17 +133,17 @@ static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 s
static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx);
static const struct ethtool_ops cdc_ncm_ethtool_ops = {
- .get_link = usbnet_get_link,
- .nway_reset = usbnet_nway_reset,
- .get_drvinfo = usbnet_get_drvinfo,
- .get_msglevel = usbnet_get_msglevel,
- .set_msglevel = usbnet_set_msglevel,
- .get_ts_info = ethtool_op_get_ts_info,
- .get_sset_count = cdc_ncm_get_sset_count,
- .get_strings = cdc_ncm_get_strings,
- .get_ethtool_stats = cdc_ncm_get_ethtool_stats,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link = usbnet_get_link,
+ .nway_reset = usbnet_nway_reset,
+ .get_drvinfo = usbnet_get_drvinfo,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .get_sset_count = cdc_ncm_get_sset_count,
+ .get_strings = cdc_ncm_get_strings,
+ .get_ethtool_stats = cdc_ncm_get_ethtool_stats,
+ .get_link_ksettings = usbnet_get_link_ksettings_internal,
+ .set_link_ksettings = NULL,
};
static u32 cdc_ncm_check_rx_max(struct usbnet *dev, u32 new_rx)
@@ -1825,33 +1825,9 @@ static void
cdc_ncm_speed_change(struct usbnet *dev,
struct usb_cdc_speed_change *data)
{
- uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
- uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
-
- /* if the speed hasn't changed, don't report it.
- * RTL8156 shipped before 2021 sends notification about every 32ms.
- */
- if (dev->rx_speed == rx_speed && dev->tx_speed == tx_speed)
- return;
-
- dev->rx_speed = rx_speed;
- dev->tx_speed = tx_speed;
-
- /*
- * Currently the USB-NET API does not support reporting the actual
- * device speed. Do print it instead.
- */
- if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
- netif_info(dev, link, dev->net,
- "%u mbit/s downlink %u mbit/s uplink\n",
- (unsigned int)(rx_speed / 1000000U),
- (unsigned int)(tx_speed / 1000000U));
- } else {
- netif_info(dev, link, dev->net,
- "%u kbit/s downlink %u kbit/s uplink\n",
- (unsigned int)(rx_speed / 1000U),
- (unsigned int)(tx_speed / 1000U));
- }
+ /* RTL8156 shipped before 2021 sends notification about every 32ms. */
+ dev->rx_speed = le32_to_cpu(data->DLBitRRate);
+ dev->tx_speed = le32_to_cpu(data->ULBitRate);
}
static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
@@ -1877,6 +1853,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
* USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
* sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
*/
+ /* RTL8156 shipped before 2021 sends notification about
+ * every 32ms. Don't forward notification if state is same.
+ */
if (netif_carrier_ok(dev->net) != !!event->wValue)
usbnet_link_change(dev, !!event->wValue, 0);
break;
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index b5d2ac55a874..89cc61d7a675 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -282,8 +282,8 @@ static const struct ethtool_ops dm9601_ethtool_ops = {
.get_eeprom_len = dm9601_get_eeprom_len,
.get_eeprom = dm9601_get_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static void dm9601_set_multicast(struct net_device *net)
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index fc512b780d15..9f9352a4522f 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -452,8 +452,8 @@ static const struct ethtool_ops mcs7830_ethtool_ops = {
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static const struct net_device_ops mcs7830_netdev_ops = {
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index 55a244eca5ca..55025202dc4f 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -629,8 +629,8 @@ static const struct ethtool_ops sierra_net_ethtool_ops = {
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 4353b370249f..f8cdabb9ef5a 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -741,8 +741,8 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {
.set_eeprom = smsc75xx_ethtool_set_eeprom,
.get_wol = smsc75xx_ethtool_get_wol,
.set_wol = smsc75xx_ethtool_set_wol,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 878557ad03ad..ce29261263cd 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -250,8 +250,8 @@ static const struct ethtool_ops sr9700_ethtool_ops = {
.get_eeprom_len = sr9700_get_eeprom_len,
.get_eeprom = sr9700_get_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static void sr9700_set_multicast(struct net_device *netdev)
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
index da56735d7755..a822d81310d5 100644
--- a/drivers/net/usb/sr9800.c
+++ b/drivers/net/usb/sr9800.c
@@ -527,8 +527,8 @@ static const struct ethtool_ops sr9800_ethtool_ops = {
.get_eeprom_len = sr_get_eeprom_len,
.get_eeprom = sr_get_eeprom,
.nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
static int sr9800_link_reset(struct usbnet *dev)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f4f37ecfed58..ecf62849f4c1 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -944,7 +944,10 @@ EXPORT_SYMBOL_GPL(usbnet_open);
* they'll probably want to use this base set.
*/
-int usbnet_get_link_ksettings(struct net_device *net,
+/* These methods are written on the assumption that the device
+ * uses MII
+ */
+int usbnet_get_link_ksettings_mii(struct net_device *net,
struct ethtool_link_ksettings *cmd)
{
struct usbnet *dev = netdev_priv(net);
@@ -956,9 +959,30 @@ int usbnet_get_link_ksettings(struct net_device *net,
return 0;
}
-EXPORT_SYMBOL_GPL(usbnet_get_link_ksettings);
+EXPORT_SYMBOL_GPL(usbnet_get_link_ksettings_mii);
+
+int usbnet_get_link_ksettings_internal(struct net_device *net,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ /* the assumption that speed is equal on tx and rx
+ * is deeply engrained into the networking layer.
+ * For wireless stuff it is not true.
+ * We assume that rx_speed matters more.
+ */
+ if (dev->rx_speed != SPEED_UNSET)
+ cmd->base.speed = dev->rx_speed / 1000000;
+ else if (dev->tx_speed != SPEED_UNSET)
+ cmd->base.speed = dev->tx_speed / 1000000;
+ else
+ cmd->base.speed = SPEED_UNKNOWN;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usbnet_get_link_ksettings_internal);
-int usbnet_set_link_ksettings(struct net_device *net,
+int usbnet_set_link_ksettings_mii(struct net_device *net,
const struct ethtool_link_ksettings *cmd)
{
struct usbnet *dev = netdev_priv(net);
@@ -978,7 +1002,7 @@ int usbnet_set_link_ksettings(struct net_device *net,
return retval;
}
-EXPORT_SYMBOL_GPL(usbnet_set_link_ksettings);
+EXPORT_SYMBOL_GPL(usbnet_set_link_ksettings_mii);
u32 usbnet_get_link (struct net_device *net)
{
@@ -1043,8 +1067,8 @@ static const struct ethtool_ops usbnet_ethtool_ops = {
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_ts_info = ethtool_op_get_ts_info,
- .get_link_ksettings = usbnet_get_link_ksettings,
- .set_link_ksettings = usbnet_set_link_ksettings,
+ .get_link_ksettings = usbnet_get_link_ksettings_mii,
+ .set_link_ksettings = usbnet_set_link_ksettings_mii,
};
/*-------------------------------------------------------------------------*/
@@ -1661,6 +1685,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;
+ dev->rx_speed = SPEED_UNSET;
+ dev->tx_speed = SPEED_UNSET;
net->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!net->tstats)
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index cfbfd6fe01df..8336e86ce606 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -53,6 +53,9 @@ struct usbnet {
u32 hard_mtu; /* count any extra framing */
size_t rx_urb_size; /* size for rx urbs */
struct mii_if_info mii;
+ long rx_speed; /* If MII not used */
+ long tx_speed; /* If MII not used */
+# define SPEED_UNSET -1
/* various kinds of pending driver work */
struct sk_buff_head rxq;
@@ -81,8 +84,6 @@ struct usbnet {
# define EVENT_LINK_CHANGE 11
# define EVENT_SET_RX_MODE 12
# define EVENT_NO_IP_ALIGN 13
- u32 rx_speed; /* in bps - NOT Mbps */
- u32 tx_speed; /* in bps - NOT Mbps */
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -267,10 +268,12 @@ extern void usbnet_pause_rx(struct usbnet *);
extern void usbnet_resume_rx(struct usbnet *);
extern void usbnet_purge_paused_rxq(struct usbnet *);
-extern int usbnet_get_link_ksettings(struct net_device *net,
+extern int usbnet_get_link_ksettings_mii(struct net_device *net,
struct ethtool_link_ksettings *cmd);
-extern int usbnet_set_link_ksettings(struct net_device *net,
+extern int usbnet_set_link_ksettings_mii(struct net_device *net,
const struct ethtool_link_ksettings *cmd);
+extern int usbnet_get_link_ksettings_internal(struct net_device *net,
+ struct ethtool_link_ksettings *cmd);
extern u32 usbnet_get_link(struct net_device *net);
extern u32 usbnet_get_msglevel(struct net_device *);
extern void usbnet_set_msglevel(struct net_device *, u32);