summaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/Kconfig13
-rw-r--r--drivers/net/usb/ax88179_178a.c264
-rw-r--r--drivers/net/usb/cdc-phonet.c2
-rw-r--r--drivers/net/usb/cdc_subset.c27
-rw-r--r--drivers/net/usb/hso.c4
-rw-r--r--drivers/net/usb/r8152.c188
-rw-r--r--drivers/net/usb/usbnet.c8
7 files changed, 428 insertions, 78 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 7e7269fd370..37eed4d84e9 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -1,12 +1,16 @@
#
# USB Network devices configuration
#
-comment "Networking support is needed for USB Network Adapter support"
- depends on USB && !NET
+comment "Host-side USB support is needed for USB Network Adapter support"
+ depends on !USB && NET
-menu "USB Network Adapters"
+menuconfig USB_NET_DRIVERS
+ tristate "USB Network Adapters"
+ default USB if USB
depends on USB && NET
+if USB_NET_DRIVERS
+
config USB_CATC
tristate "USB CATC NetMate-based Ethernet device support"
select CRC32
@@ -568,5 +572,4 @@ config USB_VL600
http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
-
-endmenu
+endif # USB_NET_DRIVERS
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 054e59ca694..be427572103 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -23,6 +23,8 @@
#include <linux/usb.h>
#include <linux/crc32.h>
#include <linux/usb/usbnet.h>
+#include <uapi/linux/mdio.h>
+#include <linux/mdio.h>
#define AX88179_PHY_ID 0x03
#define AX_EEPROM_LEN 0x100
@@ -170,8 +172,12 @@
#define GMII_PHY_PAGE_SELECT 0x1f
#define GMII_PHY_PGSEL_EXT 0x0007
#define GMII_PHY_PGSEL_PAGE0 0x0000
+ #define GMII_PHY_PGSEL_PAGE3 0x0003
+ #define GMII_PHY_PGSEL_PAGE5 0x0005
struct ax88179_data {
+ u8 eee_enabled;
+ u8 eee_active;
u16 rxctl;
u16 reserved;
};
@@ -373,6 +379,60 @@ static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,
ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
}
+static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad,
+ u16 devad)
+{
+ u16 tmp16;
+ int ret;
+
+ tmp16 = devad;
+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_MMD_CTRL, 2, &tmp16);
+
+ tmp16 = prtad;
+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_MMD_DATA, 2, &tmp16);
+
+ tmp16 = devad | MII_MMD_CTRL_NOINCR;
+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_MMD_CTRL, 2, &tmp16);
+
+ return ret;
+}
+
+static int
+ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad)
+{
+ int ret;
+ u16 tmp16;
+
+ ax88179_phy_mmd_indirect(dev, prtad, devad);
+
+ ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_MMD_DATA, 2, &tmp16);
+ if (ret < 0)
+ return ret;
+
+ return tmp16;
+}
+
+static int
+ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad,
+ u16 data)
+{
+ int ret;
+
+ ax88179_phy_mmd_indirect(dev, prtad, devad);
+
+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_MMD_DATA, 2, &data);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int ax88179_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
@@ -572,6 +632,185 @@ static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
return mii_ethtool_sset(&dev->mii, cmd);
}
+static int
+ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data)
+{
+ int val;
+
+ /* Get Supported EEE */
+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE,
+ MDIO_MMD_PCS);
+ if (val < 0)
+ return val;
+ data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
+
+ /* Get advertisement EEE */
+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV,
+ MDIO_MMD_AN);
+ if (val < 0)
+ return val;
+ data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+ /* Get LP advertisement EEE */
+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE,
+ MDIO_MMD_AN);
+ if (val < 0)
+ return val;
+ data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+ return 0;
+}
+
+static int
+ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data)
+{
+ u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
+
+ return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV,
+ MDIO_MMD_AN, tmp16);
+}
+
+static int ax88179_chk_eee(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
+
+ mii_ethtool_gset(&dev->mii, &ecmd);
+
+ if (ecmd.duplex & DUPLEX_FULL) {
+ int eee_lp, eee_cap, eee_adv;
+ u32 lp, cap, adv, supported = 0;
+
+ eee_cap = ax88179_phy_read_mmd_indirect(dev,
+ MDIO_PCS_EEE_ABLE,
+ MDIO_MMD_PCS);
+ if (eee_cap < 0) {
+ priv->eee_active = 0;
+ return false;
+ }
+
+ cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
+ if (!cap) {
+ priv->eee_active = 0;
+ return false;
+ }
+
+ eee_lp = ax88179_phy_read_mmd_indirect(dev,
+ MDIO_AN_EEE_LPABLE,
+ MDIO_MMD_AN);
+ if (eee_lp < 0) {
+ priv->eee_active = 0;
+ return false;
+ }
+
+ eee_adv = ax88179_phy_read_mmd_indirect(dev,
+ MDIO_AN_EEE_ADV,
+ MDIO_MMD_AN);
+
+ if (eee_adv < 0) {
+ priv->eee_active = 0;
+ return false;
+ }
+
+ adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
+ lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
+ supported = (ecmd.speed == SPEED_1000) ?
+ SUPPORTED_1000baseT_Full :
+ SUPPORTED_100baseT_Full;
+
+ if (!(lp & adv & supported)) {
+ priv->eee_active = 0;
+ return false;
+ }
+
+ priv->eee_active = 1;
+ return true;
+ }
+
+ priv->eee_active = 0;
+ return false;
+}
+
+static void ax88179_disable_eee(struct usbnet *dev)
+{
+ u16 tmp16;
+
+ tmp16 = GMII_PHY_PGSEL_PAGE3;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
+
+ tmp16 = 0x3246;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_PHYADDR, 2, &tmp16);
+
+ tmp16 = GMII_PHY_PGSEL_PAGE0;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
+}
+
+static void ax88179_enable_eee(struct usbnet *dev)
+{
+ u16 tmp16;
+
+ tmp16 = GMII_PHY_PGSEL_PAGE3;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
+
+ tmp16 = 0x3247;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_PHYADDR, 2, &tmp16);
+
+ tmp16 = GMII_PHY_PGSEL_PAGE5;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
+
+ tmp16 = 0x0680;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_BMSR, 2, &tmp16);
+
+ tmp16 = GMII_PHY_PGSEL_PAGE0;
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
+}
+
+static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
+
+ edata->eee_enabled = priv->eee_enabled;
+ edata->eee_active = priv->eee_active;
+
+ return ax88179_ethtool_get_eee(dev, edata);
+}
+
+static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
+ int ret = -EOPNOTSUPP;
+
+ priv->eee_enabled = edata->eee_enabled;
+ if (!priv->eee_enabled) {
+ ax88179_disable_eee(dev);
+ } else {
+ priv->eee_enabled = ax88179_chk_eee(dev);
+ if (!priv->eee_enabled)
+ return -EOPNOTSUPP;
+
+ ax88179_enable_eee(dev);
+ }
+
+ ret = ax88179_ethtool_set_eee(dev, edata);
+ if (ret)
+ return ret;
+
+ mii_nway_restart(&dev->mii);
+
+ usbnet_link_change(dev, 0, 0);
+
+ return ret;
+}
static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
@@ -589,6 +828,8 @@ static const struct ethtool_ops ax88179_ethtool_ops = {
.get_eeprom = ax88179_get_eeprom,
.get_settings = ax88179_get_settings,
.set_settings = ax88179_set_settings,
+ .get_eee = ax88179_get_eee,
+ .set_eee = ax88179_set_eee,
.nway_reset = usbnet_nway_reset,
};
@@ -980,6 +1221,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
u16 *tmp16;
u8 *tmp;
struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+ struct ethtool_eee eee_data;
usbnet_get_endpoints(dev, intf);
@@ -1062,6 +1304,15 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
ax88179_led_setting(dev);
+ ax179_data->eee_enabled = 0;
+ ax179_data->eee_active = 0;
+
+ ax88179_disable_eee(dev);
+
+ ax88179_ethtool_get_eee(dev, &eee_data);
+ eee_data.advertised = 0;
+ ax88179_ethtool_set_eee(dev, &eee_data);
+
/* Restart autoneg */
mii_nway_restart(&dev->mii);
@@ -1261,6 +1512,8 @@ static int ax88179_link_reset(struct usbnet *dev)
ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
2, 2, &mode);
+ ax179_data->eee_enabled = ax88179_chk_eee(dev);
+
netif_carrier_on(dev->net);
return 0;
@@ -1271,6 +1524,8 @@ static int ax88179_reset(struct usbnet *dev)
u8 buf[5];
u16 *tmp16;
u8 *tmp;
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
+ struct ethtool_eee eee_data;
tmp16 = (u16 *)buf;
tmp = (u8 *)buf;
@@ -1340,6 +1595,15 @@ static int ax88179_reset(struct usbnet *dev)
ax88179_led_setting(dev);
+ ax179_data->eee_enabled = 0;
+ ax179_data->eee_active = 0;
+
+ ax88179_disable_eee(dev);
+
+ ax88179_ethtool_get_eee(dev, &eee_data);
+ eee_data.advertised = 0;
+ ax88179_ethtool_set_eee(dev, &eee_data);
+
/* Restart autoneg */
mii_nway_restart(&dev->mii);
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 6358d420e18..2ec1500d007 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -387,7 +387,7 @@ static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *i
return -EINVAL;
dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
- ifname, usbpn_setup);
+ ifname, NET_NAME_UNKNOWN, usbpn_setup);
if (!dev)
return -ENOMEM;
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index 91f0919fe27..6ea98cff2d3 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -85,14 +85,28 @@ static int always_connected (struct usbnet *dev)
*
*-------------------------------------------------------------------------*/
+static void m5632_recover(struct usbnet *dev)
+{
+ struct usb_device *udev = dev->udev;
+ struct usb_interface *intf = dev->intf;
+ int r;
+
+ r = usb_lock_device_for_reset(udev, intf);
+ if (r < 0)
+ return;
+
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+}
+
static const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
.flags = FLAG_POINTTOPOINT,
+ .recover = m5632_recover,
};
#endif
-
#ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE
@@ -326,12 +340,23 @@ static const struct usb_device_id products [] = {
MODULE_DEVICE_TABLE(usb, products);
/*-------------------------------------------------------------------------*/
+static int dummy_prereset(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static int dummy_postreset(struct usb_interface *intf)
+{
+ return 0;
+}
static struct usb_driver cdc_subset_driver = {
.name = "cdc_subset",
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .pre_reset = dummy_prereset,
+ .post_reset = dummy_postreset,
.disconnect = usbnet_disconnect,
.id_table = products,
.disable_hub_initiated_lpm = 1,
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index a4272ed62da..babda7d8693 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -467,6 +467,7 @@ static const struct usb_device_id hso_ids[] = {
{USB_DEVICE(0x0af0, 0x8800)},
{USB_DEVICE(0x0af0, 0x8900)},
{USB_DEVICE(0x0af0, 0x9000)},
+ {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */
{USB_DEVICE(0x0af0, 0xd035)},
{USB_DEVICE(0x0af0, 0xd055)},
{USB_DEVICE(0x0af0, 0xd155)},
@@ -2504,7 +2505,8 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface,
/* allocate our network device, then we can put in our private data */
/* call hso_net_init to do the basic initialization */
- net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init);
+ net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN,
+ hso_net_init);
if (!net) {
dev_err(&interface->dev, "Unable to create ethernet device\n");
goto exit;
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 3eab74c7c55..604ef210a4d 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -24,7 +24,7 @@
#include <net/ip6_checksum.h>
/* Version Information */
-#define DRIVER_VERSION "v1.06.0 (2014/03/03)"
+#define DRIVER_VERSION "v1.06.1 (2014/10/01)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -59,6 +59,7 @@
#define PLA_WDT6_CTRL 0xe428
#define PLA_TCR0 0xe610
#define PLA_TCR1 0xe612
+#define PLA_MTPS 0xe615
#define PLA_TXFIFO_CTRL 0xe618
#define PLA_RSTTALLY 0xe800
#define PLA_CR 0xe813
@@ -180,6 +181,10 @@
/* PLA_TCR1 */
#define VERSION_MASK 0x7cf0
+/* PLA_MTPS */
+#define MTPS_JUMBO (12 * 1024 / 64)
+#define MTPS_DEFAULT (6 * 1024 / 64)
+
/* PLA_RSTTALLY */
#define TALLY_RESET 0x0001
@@ -440,8 +445,11 @@ enum rtl_register_content {
#define BYTE_EN_START_MASK 0x0f
#define BYTE_EN_END_MASK 0xf0
+#define RTL8153_MAX_PACKET 9216 /* 9K */
+#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN)
#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN)
-#define RTL8152_TX_TIMEOUT (HZ)
+#define RTL8153_RMS RTL8153_MAX_PACKET
+#define RTL8152_TX_TIMEOUT (5 * HZ)
/* rtl8152 flags */
enum rtl8152_flags {
@@ -1941,10 +1949,34 @@ static void rxdy_gated_en(struct r8152 *tp, bool enable)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
}
+static int rtl_start_rx(struct r8152 *tp)
+{
+ int i, ret = 0;
+
+ INIT_LIST_HEAD(&tp->rx_done);
+ for (i = 0; i < RTL8152_MAX_RX; i++) {
+ INIT_LIST_HEAD(&tp->rx_info[i].list);
+ ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int rtl_stop_rx(struct r8152 *tp)
+{
+ int i;
+
+ for (i = 0; i < RTL8152_MAX_RX; i++)
+ usb_kill_urb(tp->rx_info[i].urb);
+
+ return 0;
+}
+
static int rtl_enable(struct r8152 *tp)
{
u32 ocp_data;
- int i, ret;
r8152b_reset_packet_filter(tp);
@@ -1954,14 +1986,7 @@ static int rtl_enable(struct r8152 *tp)
rxdy_gated_en(tp, false);
- INIT_LIST_HEAD(&tp->rx_done);
- ret = 0;
- for (i = 0; i < RTL8152_MAX_RX; i++) {
- INIT_LIST_HEAD(&tp->rx_info[i].list);
- ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
- }
-
- return ret;
+ return rtl_start_rx(tp);
}
static int rtl8152_enable(struct r8152 *tp)
@@ -2011,7 +2036,7 @@ static int rtl8153_enable(struct r8152 *tp)
return rtl_enable(tp);
}
-static void rtl8152_disable(struct r8152 *tp)
+static void rtl_disable(struct r8152 *tp)
{
u32 ocp_data;
int i;
@@ -2045,8 +2070,7 @@ static void rtl8152_disable(struct r8152 *tp)
mdelay(1);
}
- for (i = 0; i < RTL8152_MAX_RX; i++)
- usb_kill_urb(tp->rx_info[i].urb);
+ rtl_stop_rx(tp);
rtl8152_nic_reset(tp);
}
@@ -2177,28 +2201,6 @@ static void rtl_phy_reset(struct r8152 *tp)
}
}
-static void rtl_clear_bp(struct r8152 *tp)
-{
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
- mdelay(3);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
-}
-
-static void r8153_clear_bp(struct r8152 *tp)
-{
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
- ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
- rtl_clear_bp(tp);
-}
-
static void r8153_teredo_off(struct r8152 *tp)
{
u32 ocp_data;
@@ -2224,6 +2226,13 @@ static inline void r8152b_enable_aldps(struct r8152 *tp)
LINKENA | DIS_SDSAVE);
}
+static void rtl8152_disable(struct r8152 *tp)
+{
+ r8152b_disable_aldps(tp);
+ rtl_disable(tp);
+ r8152b_enable_aldps(tp);
+}
+
static void r8152b_hw_phy_cfg(struct r8152 *tp)
{
u16 data;
@@ -2234,11 +2243,6 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp)
r8152_mdio_write(tp, MII_BMCR, data);
}
- r8152b_disable_aldps(tp);
-
- rtl_clear_bp(tp);
-
- r8152b_enable_aldps(tp);
set_bit(PHY_RESET, &tp->flags);
}
@@ -2247,9 +2251,6 @@ static void r8152b_exit_oob(struct r8152 *tp)
u32 ocp_data;
int i;
- if (test_bit(RTL8152_UNPLUG, &tp->flags))
- return;
-
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
@@ -2339,7 +2340,7 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
- rtl8152_disable(tp);
+ rtl_disable(tp);
for (i = 0; i < 1000; i++) {
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
@@ -2392,8 +2393,6 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
r8152_mdio_write(tp, MII_BMCR, data);
}
- r8153_clear_bp(tp);
-
if (tp->version == RTL_VER_03) {
data = ocp_reg_read(tp, OCP_EEE_CFG);
data &= ~CTAP_SHORT_EN;
@@ -2477,9 +2476,6 @@ static void r8153_first_init(struct r8152 *tp)
u32 ocp_data;
int i;
- if (test_bit(RTL8152_UNPLUG, &tp->flags))
- return;
-
rxdy_gated_en(tp, true);
r8153_teredo_off(tp);
@@ -2521,7 +2517,8 @@ static void r8153_first_init(struct r8152 *tp)
ocp_data &= ~CPCR_RX_VLAN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS);
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
ocp_data |= TCR0_AUTO_FIFO;
@@ -2551,7 +2548,7 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_data &= ~NOW_IS_OOB;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
- rtl8152_disable(tp);
+ rtl_disable(tp);
for (i = 0; i < 1000; i++) {
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
@@ -2571,7 +2568,7 @@ static void r8153_enter_oob(struct r8152 *tp)
mdelay(1);
}
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
ocp_data &= ~TEREDO_WAKE_MASK;
@@ -2615,6 +2612,13 @@ static void r8153_enable_aldps(struct r8152 *tp)
ocp_reg_write(tp, OCP_POWER_CFG, data);
}
+static void rtl8153_disable(struct r8152 *tp)
+{
+ r8153_disable_aldps(tp);
+ rtl_disable(tp);
+ r8153_enable_aldps(tp);
+}
+
static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
{
u16 bmcr, anar, gbcr;
@@ -2705,6 +2709,16 @@ out:
return ret;
}
+static void rtl8152_up(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
+ return;
+
+ r8152b_disable_aldps(tp);
+ r8152b_exit_oob(tp);
+ r8152b_enable_aldps(tp);
+}
+
static void rtl8152_down(struct r8152 *tp)
{
if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
@@ -2718,6 +2732,16 @@ static void rtl8152_down(struct r8152 *tp)
r8152b_enable_aldps(tp);
}
+static void rtl8153_up(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
+ return;
+
+ r8153_disable_aldps(tp);
+ r8153_first_init(tp);
+ r8153_enable_aldps(tp);
+}
+
static void rtl8153_down(struct r8152 *tp)
{
if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
@@ -2937,6 +2961,8 @@ static void r8152b_init(struct r8152 *tp)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
+ r8152b_disable_aldps(tp);
+
if (tp->version == RTL_VER_01) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
ocp_data &= ~LED_MODE_MASK;
@@ -2975,6 +3001,7 @@ static void r8153_init(struct r8152 *tp)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
+ r8153_disable_aldps(tp);
r8153_u1u2en(tp, false);
for (i = 0; i < 500; i++) {
@@ -3046,13 +3073,14 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
+ tasklet_disable(&tp->tl);
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ rtl_stop_rx(tp);
rtl_runtime_suspend_enable(tp, true);
} else {
- tasklet_disable(&tp->tl);
tp->rtl_ops.down(tp);
- tasklet_enable(&tp->tl);
}
+ tasklet_enable(&tp->tl);
}
return 0;
@@ -3071,17 +3099,18 @@ static int rtl8152_resume(struct usb_interface *intf)
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
rtl_runtime_suspend_enable(tp, false);
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ set_bit(WORK_ENABLE, &tp->flags);
if (tp->speed & LINK_STATUS)
- tp->rtl_ops.disable(tp);
+ rtl_start_rx(tp);
} else {
tp->rtl_ops.up(tp);
rtl8152_set_speed(tp, AUTONEG_ENABLE,
tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL);
+ tp->speed = 0;
+ netif_carrier_off(tp->netdev);
+ set_bit(WORK_ENABLE, &tp->flags);
}
- tp->speed = 0;
- netif_carrier_off(tp->netdev);
- set_bit(WORK_ENABLE, &tp->flags);
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
}
@@ -3288,6 +3317,26 @@ out:
return res;
}
+static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct r8152 *tp = netdev_priv(dev);
+
+ switch (tp->version) {
+ case RTL_VER_01:
+ case RTL_VER_02:
+ return eth_change_mtu(dev, new_mtu);
+ default:
+ break;
+ }
+
+ if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
static const struct net_device_ops rtl8152_netdev_ops = {
.ndo_open = rtl8152_open,
.ndo_stop = rtl8152_close,
@@ -3296,8 +3345,7 @@ static const struct net_device_ops rtl8152_netdev_ops = {
.ndo_tx_timeout = rtl8152_tx_timeout,
.ndo_set_rx_mode = rtl8152_set_rx_mode,
.ndo_set_mac_address = rtl8152_set_mac_address,
-
- .ndo_change_mtu = eth_change_mtu,
+ .ndo_change_mtu = rtl8152_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
@@ -3349,7 +3397,7 @@ static void rtl8153_unload(struct r8152 *tp)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
- r8153_power_cut_en(tp, true);
+ r8153_power_cut_en(tp, false);
}
static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
@@ -3364,7 +3412,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8152b_init;
ops->enable = rtl8152_enable;
ops->disable = rtl8152_disable;
- ops->up = r8152b_exit_oob;
+ ops->up = rtl8152_up;
ops->down = rtl8152_down;
ops->unload = rtl8152_unload;
ret = 0;
@@ -3372,8 +3420,8 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
case PRODUCT_ID_RTL8153:
ops->init = r8153_init;
ops->enable = rtl8153_enable;
- ops->disable = rtl8152_disable;
- ops->up = r8153_first_init;
+ ops->disable = rtl8153_disable;
+ ops->up = rtl8153_up;
ops->down = rtl8153_down;
ops->unload = rtl8153_unload;
ret = 0;
@@ -3388,8 +3436,8 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
case PRODUCT_ID_SAMSUNG:
ops->init = r8153_init;
ops->enable = rtl8153_enable;
- ops->disable = rtl8152_disable;
- ops->up = r8153_first_init;
+ ops->disable = rtl8153_disable;
+ ops->up = rtl8153_up;
ops->down = rtl8153_down;
ops->unload = rtl8153_unload;
ret = 0;
@@ -3502,7 +3550,11 @@ static void rtl8152_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
if (tp) {
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ struct usb_device *udev = tp->udev;
+
+ if (udev->state == USB_STATE_NOTATTACHED)
+ set_bit(RTL8152_UNPLUG, &tp->flags);
+
tasklet_kill(&tp->tl);
unregister_netdev(tp->netdev);
tp->rtl_ops.unload(tp);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f9e96c42755..5173821a957 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1218,8 +1218,12 @@ void usbnet_tx_timeout (struct net_device *net)
unlink_urbs (dev, &dev->txq);
tasklet_schedule (&dev->bh);
-
- // FIXME: device recovery -- reset?
+ /* this needs to be handled individually because the generic layer
+ * doesn't know what is sufficient and could not restore private
+ * information if a remedy of an unconditional reset were used.
+ */
+ if (dev->driver_info->recover)
+ (dev->driver_info->recover)(dev);
}
EXPORT_SYMBOL_GPL(usbnet_tx_timeout);