summaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/Kconfig5
-rw-r--r--drivers/net/usb/asix_devices.c10
-rw-r--r--drivers/net/usb/ax88172a.c10
-rw-r--r--drivers/net/usb/ax88179_178a.c21
-rw-r--r--drivers/net/usb/catc.c1
-rw-r--r--drivers/net/usb/cdc-phonet.c12
-rw-r--r--drivers/net/usb/cdc_ether.c66
-rw-r--r--drivers/net/usb/cdc_mbim.c21
-rw-r--r--drivers/net/usb/cdc_ncm.c19
-rw-r--r--drivers/net/usb/kaweth.c1
-rw-r--r--drivers/net/usb/lan78xx.c463
-rw-r--r--drivers/net/usb/lan78xx.h14
-rw-r--r--drivers/net/usb/pegasus.c1
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/usb/r8152.c45
-rw-r--r--drivers/net/usb/rtl8150.c1
-rw-r--r--drivers/net/usb/sierra_net.c13
-rw-r--r--drivers/net/usb/smsc75xx.c4
-rw-r--r--drivers/net/usb/usbnet.c4
19 files changed, 505 insertions, 207 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index cdde59089f72..3dd490f53e48 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -114,6 +114,11 @@ config USB_LAN78XX
help
This option adds support for Microchip LAN78XX based USB 2
& USB 3 10/100/1000 Ethernet adapters.
+ LAN7800 : USB 3 to 10/100/1000 Ethernet adapter
+ LAN7850 : USB 2 to 10/100/1000 Ethernet adapter
+ LAN7801 : USB 3 to 10/100/1000 Ethernet adapter (MAC only)
+
+ Proper PHY driver is required for LAN7801.
To compile this driver as a module, choose M here: the
module will be called lan78xx.
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index cce24950a0ab..6c646e228833 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -603,12 +603,12 @@ static void ax88772_suspend(struct usbnet *dev)
u16 medium;
/* Stop MAC operation */
- medium = asix_read_medium_status(dev, 0);
+ medium = asix_read_medium_status(dev, 1);
medium &= ~AX_MEDIUM_RE;
- asix_write_medium_mode(dev, medium, 0);
+ asix_write_medium_mode(dev, medium, 1);
netdev_dbg(dev->net, "ax88772_suspend: medium=0x%04x\n",
- asix_read_medium_status(dev, 0));
+ asix_read_medium_status(dev, 1));
/* Preserve BMCR for restoring */
priv->presvd_phy_bmcr =
@@ -1026,9 +1026,6 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu)
netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu);
- if (new_mtu <= 0 || ll_mtu > 16384)
- return -EINVAL;
-
if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM;
@@ -1081,6 +1078,7 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->netdev_ops = &ax88178_netdev_ops;
dev->net->ethtool_ops = &ax88178_ethtool_ops;
+ dev->net->max_mtu = 16384 - (dev->net->hard_header_len + 4);
/* Blink LEDS so users know driver saw dongle */
asix_sw_reset(dev, 0, 0);
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index 49a3bc107d05..6308386b09df 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -149,14 +149,6 @@ static const struct net_device_ops ax88172a_netdev_ops = {
.ndo_set_rx_mode = asix_set_multicast,
};
-static int ax88172a_nway_reset(struct net_device *net)
-{
- if (!net->phydev)
- return -ENODEV;
-
- return phy_start_aneg(net->phydev);
-}
-
static const struct ethtool_ops ax88172a_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = usbnet_get_link,
@@ -167,7 +159,7 @@ static const struct ethtool_ops ax88172a_ethtool_ops = {
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
.set_eeprom = asix_set_eeprom,
- .nway_reset = ax88172a_nway_reset,
+ .nway_reset = phy_ethtool_nway_reset,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index e6338c16081a..a3a7db0702d8 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -907,9 +907,6 @@ static int ax88179_change_mtu(struct net_device *net, int new_mtu)
struct usbnet *dev = netdev_priv(net);
u16 tmp16;
- if (new_mtu <= 0 || new_mtu > 4088)
- return -EINVAL;
-
net->mtu = new_mtu;
dev->hard_mtu = net->mtu + net->hard_header_len;
@@ -1266,6 +1263,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->netdev_ops = &ax88179_netdev_ops;
dev->net->ethtool_ops = &ax88179_ethtool_ops;
dev->net->needed_headroom = 8;
+ dev->net->max_mtu = 4088;
/* Initialize MII structure */
dev->mii.dev = dev->net;
@@ -1656,6 +1654,19 @@ static const struct driver_info ax88178a_info = {
.tx_fixup = ax88179_tx_fixup,
};
+static const struct driver_info cypress_GX3_info = {
+ .description = "Cypress GX3 SuperSpeed to Gigabit Ethernet Controller",
+ .bind = ax88179_bind,
+ .unbind = ax88179_unbind,
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
+ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+};
+
static const struct driver_info dlink_dub1312_info = {
.description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
.bind = ax88179_bind,
@@ -1718,6 +1729,10 @@ static const struct usb_device_id products[] = {
USB_DEVICE(0x0b95, 0x178a),
.driver_info = (unsigned long)&ax88178a_info,
}, {
+ /* Cypress GX3 SuperSpeed to Gigabit Ethernet Bridge Controller */
+ USB_DEVICE(0x04b4, 0x3610),
+ .driver_info = (unsigned long)&cypress_GX3_info,
+}, {
/* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
USB_DEVICE(0x2001, 0x4a00),
.driver_info = (unsigned long)&dlink_dub1312_info,
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index d9ca05d3ac8e..a1f2f6f1e614 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -761,7 +761,6 @@ static const struct net_device_ops catc_netdev_ops = {
.ndo_tx_timeout = catc_tx_timeout,
.ndo_set_rx_mode = catc_set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index ff2270ead2e6..eb52de8205f0 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -276,21 +276,11 @@ static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -ENOIOCTLCMD;
}
-static int usbpn_set_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
- return -EINVAL;
-
- dev->mtu = new_mtu;
- return 0;
-}
-
static const struct net_device_ops usbpn_ops = {
.ndo_open = usbpn_open,
.ndo_stop = usbpn_close,
.ndo_start_xmit = usbpn_xmit,
.ndo_do_ioctl = usbpn_ioctl,
- .ndo_change_mtu = usbpn_set_mtu,
};
static void usbpn_setup(struct net_device *dev)
@@ -301,6 +291,8 @@ static void usbpn_setup(struct net_device *dev)
dev->type = ARPHRD_PHONET;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->mtu = PHONET_MAX_MTU;
+ dev->min_mtu = PHONET_MIN_MTU;
+ dev->max_mtu = PHONET_MAX_MTU;
dev->hard_header_len = 1;
dev->dev_addr[0] = PN_MEDIA_USB;
dev->addr_len = 1;
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index c47ec0a04c8e..fe7b2886cb6b 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -388,12 +388,6 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
event->wValue ? "on" : "off");
-
- /* Work-around for devices with broken off-notifications */
- if (event->wValue &&
- !test_bit(__LINK_STATE_NOCARRIER, &dev->net->state))
- usbnet_link_change(dev, 0, 0);
-
usbnet_link_change(dev, !!event->wValue, 0);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
@@ -466,6 +460,36 @@ static int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 1;
}
+/* Ensure correct link state
+ *
+ * Some devices (ZTE MF823/831/910) export two carrier on notifications when
+ * connected. This causes the link state to be incorrect. Work around this by
+ * always setting the state to off, then on.
+ */
+void usbnet_cdc_zte_status(struct usbnet *dev, struct urb *urb)
+{
+ struct usb_cdc_notification *event;
+
+ if (urb->actual_length < sizeof(*event))
+ return;
+
+ event = urb->transfer_buffer;
+
+ if (event->bNotificationType != USB_CDC_NOTIFY_NETWORK_CONNECTION) {
+ usbnet_cdc_status(dev, urb);
+ return;
+ }
+
+ netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
+ event->wValue ? "on" : "off");
+
+ if (event->wValue &&
+ netif_carrier_ok(dev->net))
+ netif_carrier_off(dev->net);
+
+ usbnet_link_change(dev, !!event->wValue, 0);
+}
+
static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device",
.flags = FLAG_ETHER | FLAG_POINTTOPOINT,
@@ -481,7 +505,7 @@ static const struct driver_info zte_cdc_info = {
.flags = FLAG_ETHER | FLAG_POINTTOPOINT,
.bind = usbnet_cdc_zte_bind,
.unbind = usbnet_cdc_unbind,
- .status = usbnet_cdc_status,
+ .status = usbnet_cdc_zte_status,
.set_rx_mode = usbnet_cdc_update_filter,
.manage_power = usbnet_manage_power,
.rx_fixup = usbnet_cdc_zte_rx_fixup,
@@ -687,6 +711,20 @@ static const struct usb_device_id products[] = {
.driver_info = 0,
},
+/* ThinkPad USB-C Dock (based on Realtek RTL8153) */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3062, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
+/* ThinkPad Thunderbolt 3 Dock (based on Realtek RTL8153) */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3069, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
{
USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
@@ -694,6 +732,20 @@ static const struct usb_device_id products[] = {
.driver_info = 0,
},
+/* Lenovo USB C to Ethernet Adapter (based on Realtek RTL8153) */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x720c, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
+/* Lenovo USB-C Travel Hub (based on Realtek RTL8153) */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7214, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* NVIDIA Tegra USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
{
USB_DEVICE_AND_INTERFACE_INFO(NVIDIA_VENDOR_ID, 0x09ff, USB_CLASS_COMM,
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 96a5028621c8..3a98f3762a4c 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -602,6 +602,21 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = {
.data = CDC_NCM_FLAG_NDP_TO_END,
};
+/* Some modems (e.g. Telit LE922A6) do not work properly with altsetting
+ * toggle done in cdc_ncm_bind_common. CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
+ * flag is used to avoid this procedure.
+ */
+static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = {
+ .description = "CDC MBIM",
+ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+ .bind = cdc_mbim_bind,
+ .unbind = cdc_mbim_unbind,
+ .manage_power = cdc_mbim_manage_power,
+ .rx_fixup = cdc_mbim_rx_fixup,
+ .tx_fixup = cdc_mbim_tx_fixup,
+ .data = CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE,
+};
+
static const struct usb_device_id mbim_devs[] = {
/* This duplicate NCM entry is intentional. MBIM devices can
* be disguised as NCM by default, and this is necessary to
@@ -626,6 +641,12 @@ static const struct usb_device_id mbim_devs[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
},
+
+ /* Telit LE922A6 in MBIM composition */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1041, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+ },
+
/* default entry */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info_zlp,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 877c9516e781..2d1a6f2e16ab 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -740,10 +740,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
{
struct usbnet *dev = netdev_priv(net);
- int maxmtu = cdc_ncm_max_dgram_size(dev) - cdc_ncm_eth_hlen(dev);
-
- if (new_mtu <= 0 || new_mtu > maxmtu)
- return -EINVAL;
net->mtu = new_mtu;
cdc_ncm_set_dgram_size(dev, new_mtu + cdc_ncm_eth_hlen(dev));
@@ -839,11 +835,18 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
+ /* Device-specific flags */
+ ctx->drvflags = drvflags;
+
/* Reset data interface. Some devices will not reset properly
* unless they are configured first. Toggle the altsetting to
- * force a reset
+ * force a reset.
+ * Some other devices do not work properly with this procedure
+ * that can be avoided using quirk CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
*/
- usb_set_interface(dev->udev, iface_no, data_altsetting);
+ if (!(ctx->drvflags & CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE))
+ usb_set_interface(dev->udev, iface_no, data_altsetting);
+
temp = usb_set_interface(dev->udev, iface_no, 0);
if (temp) {
dev_dbg(&intf->dev, "set interface failed\n");
@@ -890,9 +893,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
/* finish setting up the device specific data */
cdc_ncm_setup(dev);
- /* Device-specific flags */
- ctx->drvflags = drvflags;
-
/* Allocate the delayed NDP if needed. */
if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
@@ -909,6 +909,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
/* must handle MTU changes */
dev->net->netdev_ops = &cdc_ncm_netdev_ops;
+ dev->net->max_mtu = cdc_ncm_max_dgram_size(dev) - cdc_ncm_eth_hlen(dev);
return 0;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 66b34ddbe216..338aed5da14d 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -982,7 +982,6 @@ static const struct net_device_ops kaweth_netdev_ops = {
.ndo_tx_timeout = kaweth_tx_timeout,
.ndo_set_rx_mode = kaweth_set_rx_mode,
.ndo_get_stats = kaweth_netdev_stats,
- .ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index db558b8b32fe..08f8703e4d54 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -30,13 +30,17 @@
#include <linux/ipv6.h>
#include <linux/mdio.h>
#include <net/ip6_checksum.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/microchipphy.h>
#include "lan78xx.h"
#define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>"
#define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices"
#define DRIVER_NAME "lan78xx"
-#define DRIVER_VERSION "1.0.4"
+#define DRIVER_VERSION "1.0.6"
#define TX_TIMEOUT_JIFFIES (5 * HZ)
#define THROTTLE_JIFFIES (HZ / 8)
@@ -63,6 +67,7 @@
#define LAN78XX_USB_VENDOR_ID (0x0424)
#define LAN7800_USB_PRODUCT_ID (0x7800)
#define LAN7850_USB_PRODUCT_ID (0x7850)
+#define LAN7801_USB_PRODUCT_ID (0x7801)
#define LAN78XX_EEPROM_MAGIC (0x78A5)
#define LAN78XX_OTP_MAGIC (0x78F3)
@@ -89,6 +94,38 @@
/* statistic update interval (mSec) */
#define STAT_UPDATE_TIMER (1 * 1000)
+/* defines interrupts from interrupt EP */
+#define MAX_INT_EP (32)
+#define INT_EP_INTEP (31)
+#define INT_EP_OTP_WR_DONE (28)
+#define INT_EP_EEE_TX_LPI_START (26)
+#define INT_EP_EEE_TX_LPI_STOP (25)
+#define INT_EP_EEE_RX_LPI (24)
+#define INT_EP_MAC_RESET_TIMEOUT (23)
+#define INT_EP_RDFO (22)
+#define INT_EP_TXE (21)
+#define INT_EP_USB_STATUS (20)
+#define INT_EP_TX_DIS (19)
+#define INT_EP_RX_DIS (18)
+#define INT_EP_PHY (17)
+#define INT_EP_DP (16)
+#define INT_EP_MAC_ERR (15)
+#define INT_EP_TDFU (14)
+#define INT_EP_TDFO (13)
+#define INT_EP_UTX (12)
+#define INT_EP_GPIO_11 (11)
+#define INT_EP_GPIO_10 (10)
+#define INT_EP_GPIO_9 (9)
+#define INT_EP_GPIO_8 (8)
+#define INT_EP_GPIO_7 (7)
+#define INT_EP_GPIO_6 (6)
+#define INT_EP_GPIO_5 (5)
+#define INT_EP_GPIO_4 (4)
+#define INT_EP_GPIO_3 (3)
+#define INT_EP_GPIO_2 (2)
+#define INT_EP_GPIO_1 (1)
+#define INT_EP_GPIO_0 (0)
+
static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = {
"RX FCS Errors",
"RX Alignment Errors",
@@ -296,6 +333,15 @@ struct statstage {
struct lan78xx_statstage64 curr_stat;
};
+struct irq_domain_data {
+ struct irq_domain *irqdomain;
+ unsigned int phyirq;
+ struct irq_chip *irqchip;
+ irq_flow_handler_t irq_handler;
+ u32 irqenable;
+ struct mutex irq_lock; /* for irq bus access */
+};
+
struct lan78xx_net {
struct net_device *net;
struct usb_device *udev;
@@ -345,14 +391,21 @@ struct lan78xx_net {
u32 chipid;
u32 chiprev;
struct mii_bus *mdiobus;
+ phy_interface_t interface;
int fc_autoneg;
u8 fc_request_control;
int delta;
struct statstage stats;
+
+ struct irq_domain_data domain_data;
};
+/* define external phy id */
+#define PHY_LAN8835 (0x0007C130)
+#define PHY_KSZ9031RNX (0x00221620)
+
/* use ethtool to change the level for any given device */
static int msg_level = -1;
module_param(msg_level, int, 0);
@@ -1092,15 +1145,10 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
static int lan78xx_link_reset(struct lan78xx_net *dev)
{
struct phy_device *phydev = dev->net->phydev;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ethtool_link_ksettings ecmd;
int ladv, radv, ret;
u32 buf;
- /* clear PHY interrupt status */
- ret = phy_read(phydev, LAN88XX_INT_STS);
- if (unlikely(ret < 0))
- return -EIO;
-
/* clear LAN78xx interrupt status */
ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_);
if (unlikely(ret < 0))
@@ -1120,18 +1168,14 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
if (unlikely(ret < 0))
return -EIO;
- phy_mac_interrupt(phydev, 0);
-
del_timer(&dev->stat_monitor);
} else if (phydev->link && !dev->link_on) {
dev->link_on = true;
- phy_ethtool_gset(phydev, &ecmd);
-
- ret = phy_read(phydev, LAN88XX_INT_STS);
+ phy_ethtool_ksettings_get(phydev, &ecmd);
if (dev->udev->speed == USB_SPEED_SUPER) {
- if (ethtool_cmd_speed(&ecmd) == 1000) {
+ if (ecmd.base.speed == 1000) {
/* disable U2 */
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
buf &= ~USB_CFG1_DEV_U2_INIT_EN_;
@@ -1159,10 +1203,10 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
netif_dbg(dev, link, dev->net,
"speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x",
- ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv);
+ ecmd.base.speed, ecmd.base.duplex, ladv, radv);
- ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv);
- phy_mac_interrupt(phydev, 1);
+ ret = lan78xx_update_flowcontrol(dev, ecmd.base.duplex, ladv,
+ radv);
if (!timer_pending(&dev->stat_monitor)) {
dev->delta = 1;
@@ -1201,7 +1245,10 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb)
if (intdata & INT_ENP_PHY_INT) {
netif_dbg(dev, link, dev->net, "PHY INTR: 0x%08x\n", intdata);
- lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
+ lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
+
+ if (dev->domain_data.phyirq > 0)
+ generic_handle_irq(dev->domain_data.phyirq);
} else
netdev_warn(dev->net,
"unexpected interrupt: 0x%08x\n", intdata);
@@ -1406,11 +1453,6 @@ static u32 lan78xx_get_link(struct net_device *net)
return net->phydev->link;
}
-static int lan78xx_nway_reset(struct net_device *net)
-{
- return phy_start_aneg(net->phydev);
-}
-
static void lan78xx_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
@@ -1435,88 +1477,26 @@ static void lan78xx_set_msglevel(struct net_device *net, u32 level)
dev->msg_enable = level;
}
-static int lan78xx_get_mdix_status(struct net_device *net)
-{
- struct phy_device *phydev = net->phydev;
- int buf;
-
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_1);
- buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
-
- return buf;
-}
-
-static void lan78xx_set_mdix_status(struct net_device *net, __u8 mdix_ctrl)
-{
- struct lan78xx_net *dev = netdev_priv(net);
- struct phy_device *phydev = net->phydev;
- int buf;
-
- if (mdix_ctrl == ETH_TP_MDI) {
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_1);
- buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- buf | LAN88XX_EXT_MODE_CTRL_MDI_);
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_0);
- } else if (mdix_ctrl == ETH_TP_MDI_X) {
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_1);
- buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- buf | LAN88XX_EXT_MODE_CTRL_MDI_X_);
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_0);
- } else if (mdix_ctrl == ETH_TP_MDI_AUTO) {
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_1);
- buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- buf | LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_);
- phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- LAN88XX_EXT_PAGE_SPACE_0);
- }
- dev->mdix_ctrl = mdix_ctrl;
-}
-
-static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
+static int lan78xx_get_link_ksettings(struct net_device *net,
+ struct ethtool_link_ksettings *cmd)
{
struct lan78xx_net *dev = netdev_priv(net);
struct phy_device *phydev = net->phydev;
int ret;
- int buf;
ret = usb_autopm_get_interface(dev->intf);
if (ret < 0)
return ret;
- ret = phy_ethtool_gset(phydev, cmd);
-
- buf = lan78xx_get_mdix_status(net);
-
- buf &= LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- if (buf == LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_) {
- cmd->eth_tp_mdix = ETH_TP_MDI_AUTO;
- cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
- } else if (buf == LAN88XX_EXT_MODE_CTRL_MDI_) {
- cmd->eth_tp_mdix = ETH_TP_MDI;
- cmd->eth_tp_mdix_ctrl = ETH_TP_MDI;
- } else if (buf == LAN88XX_EXT_MODE_CTRL_MDI_X_) {
- cmd->eth_tp_mdix = ETH_TP_MDI_X;
- cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_X;
- }
+ ret = phy_ethtool_ksettings_get(phydev, cmd);
usb_autopm_put_interface(dev->intf);
return ret;
}
-static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+static int lan78xx_set_link_ksettings(struct net_device *net,
+ const struct ethtool_link_ksettings *cmd)
{
struct lan78xx_net *dev = netdev_priv(net);
struct phy_device *phydev = net->phydev;
@@ -1527,14 +1507,10 @@ static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
if (ret < 0)
return ret;
- if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) {
- lan78xx_set_mdix_status(net, cmd->eth_tp_mdix_ctrl);
- }
-
/* change speed & duplex */
- ret = phy_ethtool_sset(phydev, cmd);
+ ret = phy_ethtool_ksettings_set(phydev, cmd);
- if (!cmd->autoneg) {
+ if (!cmd->base.autoneg) {
/* force link down */
temp = phy_read(phydev, MII_BMCR);
phy_write(phydev, MII_BMCR, temp | BMCR_LOOPBACK);
@@ -1552,9 +1528,9 @@ static void lan78xx_get_pause(struct net_device *net,
{
struct lan78xx_net *dev = netdev_priv(net);
struct phy_device *phydev = net->phydev;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ethtool_link_ksettings ecmd;
- phy_ethtool_gset(phydev, &ecmd);
+ phy_ethtool_ksettings_get(phydev, &ecmd);
pause->autoneg = dev->fc_autoneg;
@@ -1570,12 +1546,12 @@ static int lan78xx_set_pause(struct net_device *net,
{
struct lan78xx_net *dev = netdev_priv(net);
struct phy_device *phydev = net->phydev;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ethtool_link_ksettings ecmd;
int ret;
- phy_ethtool_gset(phydev, &ecmd);
+ phy_ethtool_ksettings_get(phydev, &ecmd);
- if (pause->autoneg && !ecmd.autoneg) {
+ if (pause->autoneg && !ecmd.base.autoneg) {
ret = -EINVAL;
goto exit;
}
@@ -1587,13 +1563,21 @@ static int lan78xx_set_pause(struct net_device *net,
if (pause->tx_pause)
dev->fc_request_control |= FLOW_CTRL_TX;
- if (ecmd.autoneg) {
+ if (ecmd.base.autoneg) {
u32 mii_adv;
+ u32 advertising;
- ecmd.advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ ethtool_convert_link_mode_to_legacy_u32(
+ &advertising, ecmd.link_modes.advertising);
+
+ advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
- ecmd.advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
- phy_ethtool_sset(phydev, &ecmd);
+ advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+
+ ethtool_convert_legacy_u32_to_link_mode(
+ ecmd.link_modes.advertising, advertising);
+
+ phy_ethtool_ksettings_set(phydev, &ecmd);
}
dev->fc_autoneg = pause->autoneg;
@@ -1605,12 +1589,10 @@ exit:
static const struct ethtool_ops lan78xx_ethtool_ops = {
.get_link = lan78xx_get_link,
- .nway_reset = lan78xx_nway_reset,
+ .nway_reset = phy_ethtool_nway_reset,
.get_drvinfo = lan78xx_get_drvinfo,
.get_msglevel = lan78xx_get_msglevel,
.set_msglevel = lan78xx_set_msglevel,
- .get_settings = lan78xx_get_settings,
- .set_settings = lan78xx_set_settings,
.get_eeprom_len = lan78xx_ethtool_get_eeprom_len,
.get_eeprom = lan78xx_ethtool_get_eeprom,
.set_eeprom = lan78xx_ethtool_set_eeprom,
@@ -1623,6 +1605,8 @@ static const struct ethtool_ops lan78xx_ethtool_ops = {
.set_eee = lan78xx_set_eee,
.get_pauseparam = lan78xx_get_pause,
.set_pauseparam = lan78xx_set_pause,
+ .get_link_ksettings = lan78xx_get_link_ksettings,
+ .set_link_ksettings = lan78xx_set_link_ksettings,
};
static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -1719,6 +1703,7 @@ static int lan78xx_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
done:
mutex_unlock(&dev->phy_mutex);
usb_autopm_put_interface(dev->intf);
+
return ret;
}
@@ -1781,6 +1766,10 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
/* set to internal PHY id */
dev->mdiobus->phy_mask = ~(1 << 1);
break;
+ case ID_REV_CHIP_ID_7801_:
+ /* scan thru PHYAD[2..0] */
+ dev->mdiobus->phy_mask = ~(0xFF);
+ break;
}
ret = mdiobus_register(dev->mdiobus);
@@ -1834,6 +1823,168 @@ static void lan78xx_link_status_change(struct net_device *net)
}
}
+static int irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct irq_domain_data *data = d->host_data;
+
+ irq_set_chip_data(irq, data);
+ irq_set_chip_and_handler(irq, data->irqchip, data->irq_handler);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static void irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops chip_domain_ops = {
+ .map = irq_map,
+ .unmap = irq_unmap,
+};
+
+static void lan78xx_irq_mask(struct irq_data *irqd)
+{
+ struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+
+ data->irqenable &= ~BIT(irqd_to_hwirq(irqd));
+}
+
+static void lan78xx_irq_unmask(struct irq_data *irqd)
+{
+ struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+
+ data->irqenable |= BIT(irqd_to_hwirq(irqd));
+}
+
+static void lan78xx_irq_bus_lock(struct irq_data *irqd)
+{
+ struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+
+ mutex_lock(&data->irq_lock);
+}
+
+static void lan78xx_irq_bus_sync_unlock(struct irq_data *irqd)
+{
+ struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+ struct lan78xx_net *dev =
+ container_of(data, struct lan78xx_net, domain_data);
+ u32 buf;
+ int ret;
+
+ /* call register access here because irq_bus_lock & irq_bus_sync_unlock
+ * are only two callbacks executed in non-atomic contex.
+ */
+ ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
+ if (buf != data->irqenable)
+ ret = lan78xx_write_reg(dev, INT_EP_CTL, data->irqenable);
+
+ mutex_unlock(&data->irq_lock);
+}
+
+static struct irq_chip lan78xx_irqchip = {
+ .name = "lan78xx-irqs",
+ .irq_mask = lan78xx_irq_mask,
+ .irq_unmask = lan78xx_irq_unmask,
+ .irq_bus_lock = lan78xx_irq_bus_lock,
+ .irq_bus_sync_unlock = lan78xx_irq_bus_sync_unlock,
+};
+
+static int lan78xx_setup_irq_domain(struct lan78xx_net *dev)
+{
+ struct device_node *of_node;
+ struct irq_domain *irqdomain;
+ unsigned int irqmap = 0;
+ u32 buf;
+ int ret = 0;
+
+ of_node = dev->udev->dev.parent->of_node;
+
+ mutex_init(&dev->domain_data.irq_lock);
+
+ lan78xx_read_reg(dev, INT_EP_CTL, &buf);
+ dev->domain_data.irqenable = buf;
+
+ dev->domain_data.irqchip = &lan78xx_irqchip;
+ dev->domain_data.irq_handler = handle_simple_irq;
+
+ irqdomain = irq_domain_add_simple(of_node, MAX_INT_EP, 0,
+ &chip_domain_ops, &dev->domain_data);
+ if (irqdomain) {
+ /* create mapping for PHY interrupt */
+ irqmap = irq_create_mapping(irqdomain, INT_EP_PHY);
+ if (!irqmap) {
+ irq_domain_remove(irqdomain);
+
+ irqdomain = NULL;
+ ret = -EINVAL;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ dev->domain_data.irqdomain = irqdomain;
+ dev->domain_data.phyirq = irqmap;
+
+ return ret;
+}
+
+static void lan78xx_remove_irq_domain(struct lan78xx_net *dev)
+{
+ if (dev->domain_data.phyirq > 0) {
+ irq_dispose_mapping(dev->domain_data.phyirq);
+
+ if (dev->domain_data.irqdomain)
+ irq_domain_remove(dev->domain_data.irqdomain);
+ }
+ dev->domain_data.phyirq = 0;
+ dev->domain_data.irqdomain = NULL;
+}
+
+static int lan8835_fixup(struct phy_device *phydev)
+{
+ int buf;
+ int ret;
+ struct lan78xx_net *dev = netdev_priv(phydev->attached_dev);
+
+ /* LED2/PME_N/IRQ_N/RGMII_ID pin to IRQ_N mode */
+ buf = phy_read_mmd_indirect(phydev, 0x8010, 3);
+ buf &= ~0x1800;
+ buf |= 0x0800;
+ phy_write_mmd_indirect(phydev, 0x8010, 3, buf);
+
+ /* RGMII MAC TXC Delay Enable */
+ ret = lan78xx_write_reg(dev, MAC_RGMII_ID,
+ MAC_RGMII_ID_TXC_DELAY_EN_);
+
+ /* RGMII TX DLL Tune Adjust */
+ ret = lan78xx_write_reg(dev, RGMII_TX_BYP_DLL, 0x3D00);
+
+ dev->interface = PHY_INTERFACE_MODE_RGMII_TXID;
+
+ return 1;
+}
+
+static int ksz9031rnx_fixup(struct phy_device *phydev)
+{
+ struct lan78xx_net *dev = netdev_priv(phydev->attached_dev);
+
+ /* Micrel9301RNX PHY configuration */
+ /* RGMII Control Signal Pad Skew */
+ phy_write_mmd_indirect(phydev, 4, 2, 0x0077);
+ /* RGMII RX Data Pad Skew */
+ phy_write_mmd_indirect(phydev, 5, 2, 0x7777);
+ /* RGMII RX Clock Pad Skew */
+ phy_write_mmd_indirect(phydev, 8, 2, 0x1FF);
+
+ dev->interface = PHY_INTERFACE_MODE_RGMII_RXID;
+
+ return 1;
+}
+
static int lan78xx_phy_init(struct lan78xx_net *dev)
{
int ret;
@@ -1846,28 +1997,61 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
return -EIO;
}
- /* Enable PHY interrupts.
- * We handle our own interrupt
- */
- ret = phy_read(phydev, LAN88XX_INT_STS);
- ret = phy_write(phydev, LAN88XX_INT_MASK,
- LAN88XX_INT_MASK_MDINTPIN_EN_ |
- LAN88XX_INT_MASK_LINK_CHANGE_);
+ if ((dev->chipid == ID_REV_CHIP_ID_7800_) ||
+ (dev->chipid == ID_REV_CHIP_ID_7850_)) {
+ phydev->is_internal = true;
+ dev->interface = PHY_INTERFACE_MODE_GMII;
- phydev->irq = PHY_IGNORE_INTERRUPT;
+ } else if (dev->chipid == ID_REV_CHIP_ID_7801_) {
+ if (!phydev->drv) {
+ netdev_err(dev->net, "no PHY driver found\n");
+ return -EIO;
+ }
+
+ dev->interface = PHY_INTERFACE_MODE_RGMII;
+
+ /* external PHY fixup for KSZ9031RNX */
+ ret = phy_register_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0,
+ ksz9031rnx_fixup);
+ if (ret < 0) {
+ netdev_err(dev->net, "fail to register fixup\n");
+ return ret;
+ }
+ /* external PHY fixup for LAN8835 */
+ ret = phy_register_fixup_for_uid(PHY_LAN8835, 0xfffffff0,
+ lan8835_fixup);
+ if (ret < 0) {
+ netdev_err(dev->net, "fail to register fixup\n");
+ return ret;
+ }
+ /* add more external PHY fixup here if needed */
+
+ phydev->is_internal = false;
+ } else {
+ netdev_err(dev->net, "unknown ID found\n");
+ ret = -EIO;
+ goto error;
+ }
+
+ /* if phyirq is not set, use polling mode in phylib */
+ if (dev->domain_data.phyirq > 0)
+ phydev->irq = dev->domain_data.phyirq;
+ else
+ phydev->irq = 0;
+ netdev_dbg(dev->net, "phydev->irq = %d\n", phydev->irq);
+
+ /* set to AUTOMDIX */
+ phydev->mdix = ETH_TP_MDI_AUTO;
ret = phy_connect_direct(dev->net, phydev,
lan78xx_link_status_change,
- PHY_INTERFACE_MODE_GMII);
+ dev->interface);
if (ret) {
netdev_err(dev->net, "can't attach PHY to %s\n",
dev->mdiobus->id);
return -EIO;
}
- /* set to AUTOMDIX */
- lan78xx_set_mdix_status(dev->net, ETH_TP_MDI_AUTO);
-
/* MAC doesn't support 1000T Half */
phydev->supported &= ~SUPPORTED_1000baseT_Half;
@@ -1886,6 +2070,12 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
return 0;
+
+error:
+ phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
+ phy_unregister_fixup_for_uid(PHY_LAN8835, 0xfffffff0);
+
+ return ret;
}
static int lan78xx_set_rx_max_frame_length(struct lan78xx_net *dev, int size)
@@ -1970,11 +2160,6 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu)
int old_rx_urb_size = dev->rx_urb_size;
int ret;
- if (new_mtu > MAX_SINGLE_PACKET_SIZE)
- return -EINVAL;
-
- if (new_mtu <= 0)
- return -EINVAL;
/* no second zero-length packet read wanted after mtu-sized packets */
if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM;
@@ -2247,14 +2432,12 @@ static int lan78xx_reset(struct lan78xx_net *dev)
} while ((buf & PMT_CTL_PHY_RST_) || !(buf & PMT_CTL_READY_));
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
+ /* LAN7801 only has RGMII mode */
+ if (dev->chipid == ID_REV_CHIP_ID_7801_)
+ buf &= ~MAC_CR_GMII_EN_;
buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
ret = lan78xx_write_reg(dev, MAC_CR, buf);
- /* enable PHY interrupts */
- ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
- buf |= INT_ENP_PHY_INT;
- ret = lan78xx_write_reg(dev, INT_EP_CTL, buf);
-
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
buf |= MAC_TX_TXEN_;
ret = lan78xx_write_reg(dev, MAC_TX, buf);
@@ -2378,8 +2561,12 @@ static int lan78xx_stop(struct net_device *net)
if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor);
+ phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
+ phy_unregister_fixup_for_uid(PHY_LAN8835, 0xfffffff0);
+
phy_stop(net->phydev);
phy_disconnect(net->phydev);
+
net->phydev = NULL;
clear_bit(EVENT_DEV_OPEN, &dev->flags);
@@ -2663,6 +2850,14 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
dev->net->hw_features = dev->net->features;
+ ret = lan78xx_setup_irq_domain(dev);
+ if (ret < 0) {
+ netdev_warn(dev->net,
+ "lan78xx_setup_irq_domain() failed : %d", ret);
+ kfree(pdata);
+ return ret;
+ }
+
/* Init all registers */
ret = lan78xx_reset(dev);
@@ -2679,6 +2874,8 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf)
{
struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
+ lan78xx_remove_irq_domain(dev);
+
lan78xx_remove_mdio(dev);
if (pdata) {
@@ -3378,6 +3575,9 @@ static int lan78xx_probe(struct usb_interface *intf,
if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len))
netdev->mtu = dev->hard_mtu - netdev->hard_header_len;
+ /* MTU range: 68 - 9000 */
+ netdev->max_mtu = MAX_SINGLE_PACKET_SIZE;
+
dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0;
dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1;
dev->ep_intr = (intf->cur_altsetting)->endpoint + 2;
@@ -3395,6 +3595,7 @@ static int lan78xx_probe(struct usb_interface *intf,
if (buf) {
dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb_intr) {
+ ret = -ENOMEM;
kfree(buf);
goto out3;
} else {
@@ -3788,6 +3989,10 @@ static const struct usb_device_id products[] = {
/* LAN7850 USB Gigabit Ethernet Device */
USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7850_USB_PRODUCT_ID),
},
+ {
+ /* LAN7801 USB Gigabit Ethernet Device */
+ USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7801_USB_PRODUCT_ID),
+ },
{},
};
MODULE_DEVICE_TABLE(usb, products);
diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h
index 40927906109a..25aa54611774 100644
--- a/drivers/net/usb/lan78xx.h
+++ b/drivers/net/usb/lan78xx.h
@@ -108,6 +108,7 @@
#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
#define ID_REV_CHIP_ID_7800_ (0x7800)
#define ID_REV_CHIP_ID_7850_ (0x7850)
+#define ID_REV_CHIP_ID_7801_ (0x7801)
#define FPGA_REV (0x04)
#define FPGA_REV_MINOR_MASK_ (0x0000FF00)
@@ -550,6 +551,7 @@
#define LTM_INACTIVE1_TIMER10_ (0x0000FFFF)
#define MAC_CR (0x100)
+#define MAC_CR_GMII_EN_ (0x00080000)
#define MAC_CR_EEE_TX_CLK_STOP_EN_ (0x00040000)
#define MAC_CR_EEE_EN_ (0x00020000)
#define MAC_CR_EEE_TLAR_EN_ (0x00010000)
@@ -787,6 +789,18 @@
#define PHY_DEV_ID_MODEL_MASK_ (0x0FC00000)
#define PHY_DEV_ID_OUI_MASK_ (0x003FFFFF)
+#define RGMII_TX_BYP_DLL (0x708)
+#define RGMII_TX_BYP_DLL_TX_TUNE_ADJ_MASK_ (0x000FC00)
+#define RGMII_TX_BYP_DLL_TX_TUNE_SEL_MASK_ (0x00003F0)
+#define RGMII_TX_BYP_DLL_TX_DLL_RESET_ (0x0000002)
+#define RGMII_TX_BYP_DLL_TX_DLL_BYPASS_ (0x0000001)
+
+#define RGMII_RX_BYP_DLL (0x70C)
+#define RGMII_RX_BYP_DLL_RX_TUNE_ADJ_MASK_ (0x000FC00)
+#define RGMII_RX_BYP_DLL_RX_TUNE_SEL_MASK_ (0x00003F0)
+#define RGMII_RX_BYP_DLL_RX_DLL_RESET_ (0x0000002)
+#define RGMII_RX_BYP_DLL_RX_DLL_BYPASS_ (0x0000001)
+
#define OTP_BASE_ADDR (0x00001000)
#define OTP_ADDR_RANGE_ (0x1FF)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 1434e5dd5f9c..399f7ee57aea 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1273,7 +1273,6 @@ static const struct net_device_ops pegasus_netdev_ops = {
.ndo_set_rx_mode = pegasus_set_multicast,
.ndo_get_stats = pegasus_netdev_stats,
.ndo_tx_timeout = pegasus_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3ff76c6db4f6..6fe1cdb0174f 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -894,6 +894,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
+ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 44d439f50961..7dc61228c55b 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1730,7 +1730,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
u8 checksum = CHECKSUM_NONE;
u32 opts2, opts3;
- if (tp->version == RTL_VER_01)
+ if (tp->version == RTL_VER_01 || tp->version == RTL_VER_02)
goto return_result;
opts2 = le32_to_cpu(rx_desc->opts2);
@@ -1745,7 +1745,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
checksum = CHECKSUM_NONE;
else
checksum = CHECKSUM_UNNECESSARY;
- } else if (RD_IPV6_CS) {
+ } else if (opts2 & RD_IPV6_CS) {
if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
checksum = CHECKSUM_UNNECESSARY;
else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
@@ -3266,10 +3266,8 @@ static int rtl8152_open(struct net_device *netdev)
goto out;
res = usb_autopm_get_interface(tp->intf);
- if (res < 0) {
- free_all_mem(tp);
- goto out;
- }
+ if (res < 0)
+ goto out_free;
mutex_lock(&tp->control);
@@ -3285,10 +3283,9 @@ static int rtl8152_open(struct net_device *netdev)
netif_device_detach(tp->netdev);
netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
res);
- free_all_mem(tp);
- } else {
- napi_enable(&tp->napi);
+ goto out_unlock;
}
+ napi_enable(&tp->napi);
mutex_unlock(&tp->control);
@@ -3297,7 +3294,13 @@ static int rtl8152_open(struct net_device *netdev)
tp->pm_notifier.notifier_call = rtl_notifier;
register_pm_notifier(&tp->pm_notifier);
#endif
+ return 0;
+out_unlock:
+ mutex_unlock(&tp->control);
+ usb_autopm_put_interface(tp->intf);
+out_free:
+ free_all_mem(tp);
out:
return res;
}
@@ -4113,14 +4116,12 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)
switch (tp->version) {
case RTL_VER_01:
case RTL_VER_02:
- return eth_change_mtu(dev, new_mtu);
+ dev->mtu = new_mtu;
+ return 0;
default:
break;
}
- if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU)
- return -EINVAL;
-
ret = usb_autopm_get_interface(tp->intf);
if (ret < 0)
return ret;
@@ -4310,6 +4311,18 @@ static int rtl8152_probe(struct usb_interface *intf,
netdev->ethtool_ops = &ops;
netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
+ /* MTU range: 68 - 1500 or 9194 */
+ netdev->min_mtu = ETH_MIN_MTU;
+ switch (tp->version) {
+ case RTL_VER_01:
+ case RTL_VER_02:
+ netdev->max_mtu = ETH_DATA_LEN;
+ break;
+ default:
+ netdev->max_mtu = RTL8153_MAX_MTU;
+ break;
+ }
+
tp->mii.dev = netdev;
tp->mii.mdio_read = read_mii_word;
tp->mii.mdio_write = write_mii_word;
@@ -4410,8 +4423,12 @@ static struct usb_device_id rtl8152_table[] = {
{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
{REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
- {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)},
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)},
+ {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)},
+ {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3069)},
+ {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)},
+ {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c)},
+ {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)},
{REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)},
{}
};
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 7c72bfac89d0..93a1bda1c1e5 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -847,7 +847,6 @@ static const struct net_device_ops rtl8150_netdev_ops = {
.ndo_set_rx_mode = rtl8150_set_multicast,
.ndo_set_mac_address = rtl8150_set_mac_address,
- .ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index a251588762ec..12071f1582df 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -165,7 +165,6 @@ struct lsi_umts {
/* Forward definitions */
static void sierra_sync_timer(unsigned long syncdata);
-static int sierra_net_change_mtu(struct net_device *net, int new_mtu);
/* Our own net device operations structure */
static const struct net_device_ops sierra_net_device_ops = {
@@ -173,7 +172,7 @@ static const struct net_device_ops sierra_net_device_ops = {
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = sierra_net_change_mtu,
+ .ndo_change_mtu = usbnet_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -622,15 +621,6 @@ static const struct ethtool_ops sierra_net_ethtool_ops = {
.nway_reset = usbnet_nway_reset,
};
-/* MTU can not be more than 1500 bytes, enforce it. */
-static int sierra_net_change_mtu(struct net_device *net, int new_mtu)
-{
- if (new_mtu > SIERRA_NET_MAX_SUPPORTED_MTU)
- return -EINVAL;
-
- return usbnet_change_mtu(net, new_mtu);
-}
-
static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
{
int result = 0;
@@ -720,6 +710,7 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ dev->net->max_mtu = SIERRA_NET_MAX_SUPPORTED_MTU;
/* Set up the netdev */
dev->net->flags |= IFF_NOARP;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 9af9799935db..0b17b40d7a4f 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -925,9 +925,6 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
struct usbnet *dev = netdev_priv(netdev);
int ret;
- if (new_mtu > MAX_SINGLE_PACKET_SIZE)
- return -EINVAL;
-
ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);
if (ret < 0) {
netdev_warn(dev->net, "Failed to set mac rx frame length\n");
@@ -1448,6 +1445,7 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->flags |= IFF_MULTICAST;
dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ dev->net->max_mtu = MAX_SINGLE_PACKET_SIZE;
return 0;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index d5071e364d40..3de65ea6531a 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -384,8 +384,6 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu)
int old_hard_mtu = dev->hard_mtu;
int old_rx_urb_size = dev->rx_urb_size;
- if (new_mtu <= 0)
- return -EINVAL;
// no second zero-length packet read wanted after mtu-sized packets
if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM;
@@ -1669,6 +1667,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
* bind() should set rx_urb_size in that case.
*/
dev->hard_mtu = net->mtu + net->hard_header_len;
+ net->min_mtu = 0;
+ net->max_mtu = ETH_MAX_MTU;
net->netdev_ops = &usbnet_netdev_ops;
net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
OpenPOWER on IntegriCloud