diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
commit | d635711daa98be86d4c7fd01499c34f566b54ccb (patch) | |
tree | aa5cc3760a27c3d57146498cb82fa549547de06c /drivers/net/usb | |
parent | c91265cd0efb83778f015b4d4b1129bd2cfd075e (diff) |
Linux-libre 4.6.2-gnu
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/asix_common.c | 2 | ||||
-rw-r--r-- | drivers/net/usb/cdc_mbim.c | 9 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 7 | ||||
-rw-r--r-- | drivers/net/usb/lan78xx.c | 401 | ||||
-rw-r--r-- | drivers/net/usb/lan78xx.h | 1 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.c | 10 | ||||
-rw-r--r-- | drivers/net/usb/plusb.c | 2 | ||||
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/smsc75xx.c | 12 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 12 |
10 files changed, 412 insertions, 47 deletions
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 0c5c22b84..7de5ab589 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -66,7 +66,7 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, * buffer. */ if (rx->remaining && (rx->remaining + sizeof(u32) <= skb->len)) { - offset = ((rx->remaining + 1) & 0xfffe) + sizeof(u32); + offset = ((rx->remaining + 1) & 0xfffe); rx->header = get_unaligned_le32(skb->data + offset); offset = 0; diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index bdd83d95e..96a502862 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -617,8 +617,13 @@ static const struct usb_device_id mbim_devs[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&cdc_mbim_info, }, - /* Huawei E3372 fails unless NDP comes after the IP packets */ - { USB_DEVICE_AND_INTERFACE_INFO(0x12d1, 0x157d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), + + /* Some Huawei devices, ME906s-158 (12d1:15c1) and E3372 + * (12d1:157d), are known to fail unless the NDP is placed + * after the IP packets. Applying the quirk to all Huawei + * devices is broader than necessary, but harmless. + */ + { 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, }, /* default entry */ diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 86ba30ba3..2fb31edab 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1626,6 +1626,13 @@ static const struct usb_device_id cdc_devs[] = { .driver_info = (unsigned long) &wwan_info, }, + /* Telit LE910 V2 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x0036, + USB_CLASS_COMM, + USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_noarp_info, + }, + /* DW5812 LTE Verizon Mobile Broadband Card * Unlike DW5550 this device requires FLAG_NOARP */ diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 1c299b8a1..f64778ad9 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -36,7 +36,7 @@ #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.2" +#define DRIVER_VERSION "1.0.4" #define TX_TIMEOUT_JIFFIES (5 * HZ) #define THROTTLE_JIFFIES (HZ / 8) @@ -86,6 +86,9 @@ /* default autosuspend delay (mSec)*/ #define DEFAULT_AUTOSUSPEND_DELAY (10 * 1000) +/* statistic update interval (mSec) */ +#define STAT_UPDATE_TIMER (1 * 1000) + static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = { "RX FCS Errors", "RX Alignment Errors", @@ -186,6 +189,56 @@ struct lan78xx_statstage { u32 eee_tx_lpi_time; }; +struct lan78xx_statstage64 { + u64 rx_fcs_errors; + u64 rx_alignment_errors; + u64 rx_fragment_errors; + u64 rx_jabber_errors; + u64 rx_undersize_frame_errors; + u64 rx_oversize_frame_errors; + u64 rx_dropped_frames; + u64 rx_unicast_byte_count; + u64 rx_broadcast_byte_count; + u64 rx_multicast_byte_count; + u64 rx_unicast_frames; + u64 rx_broadcast_frames; + u64 rx_multicast_frames; + u64 rx_pause_frames; + u64 rx_64_byte_frames; + u64 rx_65_127_byte_frames; + u64 rx_128_255_byte_frames; + u64 rx_256_511_bytes_frames; + u64 rx_512_1023_byte_frames; + u64 rx_1024_1518_byte_frames; + u64 rx_greater_1518_byte_frames; + u64 eee_rx_lpi_transitions; + u64 eee_rx_lpi_time; + u64 tx_fcs_errors; + u64 tx_excess_deferral_errors; + u64 tx_carrier_errors; + u64 tx_bad_byte_count; + u64 tx_single_collisions; + u64 tx_multiple_collisions; + u64 tx_excessive_collision; + u64 tx_late_collisions; + u64 tx_unicast_byte_count; + u64 tx_broadcast_byte_count; + u64 tx_multicast_byte_count; + u64 tx_unicast_frames; + u64 tx_broadcast_frames; + u64 tx_multicast_frames; + u64 tx_pause_frames; + u64 tx_64_byte_frames; + u64 tx_65_127_byte_frames; + u64 tx_128_255_byte_frames; + u64 tx_256_511_bytes_frames; + u64 tx_512_1023_byte_frames; + u64 tx_1024_1518_byte_frames; + u64 tx_greater_1518_byte_frames; + u64 eee_tx_lpi_transitions; + u64 eee_tx_lpi_time; +}; + struct lan78xx_net; struct lan78xx_priv { @@ -216,6 +269,7 @@ struct skb_data { /* skb->cb is one of these */ struct lan78xx_net *dev; enum skb_state state; size_t length; + int num_of_packet; }; struct usb_context { @@ -232,6 +286,15 @@ struct usb_context { #define EVENT_DEV_WAKING 6 #define EVENT_DEV_ASLEEP 7 #define EVENT_DEV_OPEN 8 +#define EVENT_STAT_UPDATE 9 + +struct statstage { + struct mutex access_lock; /* for stats access */ + struct lan78xx_statstage saved; + struct lan78xx_statstage rollover_count; + struct lan78xx_statstage rollover_max; + struct lan78xx_statstage64 curr_stat; +}; struct lan78xx_net { struct net_device *net; @@ -272,14 +335,22 @@ struct lan78xx_net { unsigned maxpacket; struct timer_list delay; + struct timer_list stat_monitor; unsigned long data[5]; int link_on; u8 mdix_ctrl; - u32 devid; + u32 chipid; + u32 chiprev; struct mii_bus *mdiobus; + + int fc_autoneg; + u8 fc_request_control; + + int delta; + struct statstage stats; }; /* use ethtool to change the level for any given device */ @@ -378,6 +449,93 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, return ret; } +#define check_counter_rollover(struct1, dev_stats, member) { \ + if (struct1->member < dev_stats.saved.member) \ + dev_stats.rollover_count.member++; \ + } + +static void lan78xx_check_stat_rollover(struct lan78xx_net *dev, + struct lan78xx_statstage *stats) +{ + check_counter_rollover(stats, dev->stats, rx_fcs_errors); + check_counter_rollover(stats, dev->stats, rx_alignment_errors); + check_counter_rollover(stats, dev->stats, rx_fragment_errors); + check_counter_rollover(stats, dev->stats, rx_jabber_errors); + check_counter_rollover(stats, dev->stats, rx_undersize_frame_errors); + check_counter_rollover(stats, dev->stats, rx_oversize_frame_errors); + check_counter_rollover(stats, dev->stats, rx_dropped_frames); + check_counter_rollover(stats, dev->stats, rx_unicast_byte_count); + check_counter_rollover(stats, dev->stats, rx_broadcast_byte_count); + check_counter_rollover(stats, dev->stats, rx_multicast_byte_count); + check_counter_rollover(stats, dev->stats, rx_unicast_frames); + check_counter_rollover(stats, dev->stats, rx_broadcast_frames); + check_counter_rollover(stats, dev->stats, rx_multicast_frames); + check_counter_rollover(stats, dev->stats, rx_pause_frames); + check_counter_rollover(stats, dev->stats, rx_64_byte_frames); + check_counter_rollover(stats, dev->stats, rx_65_127_byte_frames); + check_counter_rollover(stats, dev->stats, rx_128_255_byte_frames); + check_counter_rollover(stats, dev->stats, rx_256_511_bytes_frames); + check_counter_rollover(stats, dev->stats, rx_512_1023_byte_frames); + check_counter_rollover(stats, dev->stats, rx_1024_1518_byte_frames); + check_counter_rollover(stats, dev->stats, rx_greater_1518_byte_frames); + check_counter_rollover(stats, dev->stats, eee_rx_lpi_transitions); + check_counter_rollover(stats, dev->stats, eee_rx_lpi_time); + check_counter_rollover(stats, dev->stats, tx_fcs_errors); + check_counter_rollover(stats, dev->stats, tx_excess_deferral_errors); + check_counter_rollover(stats, dev->stats, tx_carrier_errors); + check_counter_rollover(stats, dev->stats, tx_bad_byte_count); + check_counter_rollover(stats, dev->stats, tx_single_collisions); + check_counter_rollover(stats, dev->stats, tx_multiple_collisions); + check_counter_rollover(stats, dev->stats, tx_excessive_collision); + check_counter_rollover(stats, dev->stats, tx_late_collisions); + check_counter_rollover(stats, dev->stats, tx_unicast_byte_count); + check_counter_rollover(stats, dev->stats, tx_broadcast_byte_count); + check_counter_rollover(stats, dev->stats, tx_multicast_byte_count); + check_counter_rollover(stats, dev->stats, tx_unicast_frames); + check_counter_rollover(stats, dev->stats, tx_broadcast_frames); + check_counter_rollover(stats, dev->stats, tx_multicast_frames); + check_counter_rollover(stats, dev->stats, tx_pause_frames); + check_counter_rollover(stats, dev->stats, tx_64_byte_frames); + check_counter_rollover(stats, dev->stats, tx_65_127_byte_frames); + check_counter_rollover(stats, dev->stats, tx_128_255_byte_frames); + check_counter_rollover(stats, dev->stats, tx_256_511_bytes_frames); + check_counter_rollover(stats, dev->stats, tx_512_1023_byte_frames); + check_counter_rollover(stats, dev->stats, tx_1024_1518_byte_frames); + check_counter_rollover(stats, dev->stats, tx_greater_1518_byte_frames); + check_counter_rollover(stats, dev->stats, eee_tx_lpi_transitions); + check_counter_rollover(stats, dev->stats, eee_tx_lpi_time); + + memcpy(&dev->stats.saved, stats, sizeof(struct lan78xx_statstage)); +} + +static void lan78xx_update_stats(struct lan78xx_net *dev) +{ + u32 *p, *count, *max; + u64 *data; + int i; + struct lan78xx_statstage lan78xx_stats; + + if (usb_autopm_get_interface(dev->intf) < 0) + return; + + p = (u32 *)&lan78xx_stats; + count = (u32 *)&dev->stats.rollover_count; + max = (u32 *)&dev->stats.rollover_max; + data = (u64 *)&dev->stats.curr_stat; + + mutex_lock(&dev->stats.access_lock); + + if (lan78xx_read_stats(dev, &lan78xx_stats) > 0) + lan78xx_check_stat_rollover(dev, &lan78xx_stats); + + for (i = 0; i < (sizeof(lan78xx_stats) / (sizeof(u32))); i++) + data[i] = (u64)p[i] + ((u64)count[i] * ((u64)max[i] + 1)); + + mutex_unlock(&dev->stats.access_lock); + + usb_autopm_put_interface(dev->intf); +} + /* Loop until the read is completed with timeout called with phy_mutex held */ static int lan78xx_phy_wait_not_busy(struct lan78xx_net *dev) { @@ -471,7 +629,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset, */ ret = lan78xx_read_reg(dev, HW_CFG, &val); saved = val; - if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { + if (dev->chipid == ID_REV_CHIP_ID_7800_) { val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); ret = lan78xx_write_reg(dev, HW_CFG, val); } @@ -505,7 +663,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset, retval = 0; exit: - if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) + if (dev->chipid == ID_REV_CHIP_ID_7800_) ret = lan78xx_write_reg(dev, HW_CFG, saved); return retval; @@ -539,7 +697,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset, */ ret = lan78xx_read_reg(dev, HW_CFG, &val); saved = val; - if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { + if (dev->chipid == ID_REV_CHIP_ID_7800_) { val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); ret = lan78xx_write_reg(dev, HW_CFG, val); } @@ -587,7 +745,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset, retval = 0; exit: - if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) + if (dev->chipid == ID_REV_CHIP_ID_7800_) ret = lan78xx_write_reg(dev, HW_CFG, saved); return retval; @@ -901,11 +1059,15 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex, { u32 flow = 0, fct_flow = 0; int ret; + u8 cap; - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + if (dev->fc_autoneg) + cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + else + cap = dev->fc_request_control; if (cap & FLOW_CTRL_TX) - flow = (FLOW_CR_TX_FCEN_ | 0xFFFF); + flow |= (FLOW_CR_TX_FCEN_ | 0xFFFF); if (cap & FLOW_CTRL_RX) flow |= FLOW_CR_RX_FCEN_; @@ -959,6 +1121,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) return -EIO; phy_mac_interrupt(phydev, 0); + + del_timer(&dev->stat_monitor); } else if (phydev->link && !dev->link_on) { dev->link_on = true; @@ -999,6 +1163,12 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); phy_mac_interrupt(phydev, 1); + + if (!timer_pending(&dev->stat_monitor)) { + dev->delta = 1; + mod_timer(&dev->stat_monitor, + jiffies + STAT_UPDATE_TIMER); + } } return ret; @@ -1091,20 +1261,12 @@ static void lan78xx_get_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct lan78xx_net *dev = netdev_priv(netdev); - struct lan78xx_statstage lan78xx_stat; - u32 *p; - int i; - if (usb_autopm_get_interface(dev->intf) < 0) - return; + lan78xx_update_stats(dev); - if (lan78xx_read_stats(dev, &lan78xx_stat) > 0) { - p = (u32 *)&lan78xx_stat; - for (i = 0; i < (sizeof(lan78xx_stat) / (sizeof(u32))); i++) - data[i] = p[i]; - } - - usb_autopm_put_interface(dev->intf); + mutex_lock(&dev->stats.access_lock); + memcpy(data, &dev->stats.curr_stat, sizeof(dev->stats.curr_stat)); + mutex_unlock(&dev->stats.access_lock); } static void lan78xx_get_wol(struct net_device *netdev, @@ -1385,6 +1547,62 @@ static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd) return ret; } +static void lan78xx_get_pause(struct net_device *net, + struct ethtool_pauseparam *pause) +{ + struct lan78xx_net *dev = netdev_priv(net); + struct phy_device *phydev = net->phydev; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + + phy_ethtool_gset(phydev, &ecmd); + + pause->autoneg = dev->fc_autoneg; + + if (dev->fc_request_control & FLOW_CTRL_TX) + pause->tx_pause = 1; + + if (dev->fc_request_control & FLOW_CTRL_RX) + pause->rx_pause = 1; +} + +static int lan78xx_set_pause(struct net_device *net, + struct ethtool_pauseparam *pause) +{ + struct lan78xx_net *dev = netdev_priv(net); + struct phy_device *phydev = net->phydev; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + int ret; + + phy_ethtool_gset(phydev, &ecmd); + + if (pause->autoneg && !ecmd.autoneg) { + ret = -EINVAL; + goto exit; + } + + dev->fc_request_control = 0; + if (pause->rx_pause) + dev->fc_request_control |= FLOW_CTRL_RX; + + if (pause->tx_pause) + dev->fc_request_control |= FLOW_CTRL_TX; + + if (ecmd.autoneg) { + u32 mii_adv; + + ecmd.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); + } + + dev->fc_autoneg = pause->autoneg; + + ret = 0; +exit: + return ret; +} + static const struct ethtool_ops lan78xx_ethtool_ops = { .get_link = lan78xx_get_link, .nway_reset = lan78xx_nway_reset, @@ -1403,6 +1621,8 @@ static const struct ethtool_ops lan78xx_ethtool_ops = { .set_wol = lan78xx_set_wol, .get_eee = lan78xx_get_eee, .set_eee = lan78xx_set_eee, + .get_pauseparam = lan78xx_get_pause, + .set_pauseparam = lan78xx_set_pause, }; static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -1555,9 +1775,9 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev) snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", dev->udev->bus->busnum, dev->udev->devnum); - switch (dev->devid & ID_REV_CHIP_ID_MASK_) { - case 0x78000000: - case 0x78500000: + switch (dev->chipid) { + case ID_REV_CHIP_ID_7800_: + case ID_REV_CHIP_ID_7850_: /* set to internal PHY id */ dev->mdiobus->phy_mask = ~(1 << 1); break; @@ -1584,12 +1804,40 @@ static void lan78xx_remove_mdio(struct lan78xx_net *dev) static void lan78xx_link_status_change(struct net_device *net) { - /* nothing to do */ + struct phy_device *phydev = net->phydev; + int ret, temp; + + /* At forced 100 F/H mode, chip may fail to set mode correctly + * when cable is switched between long(~50+m) and short one. + * As workaround, set to 10 before setting to 100 + * at forced 100 F/H mode. + */ + if (!phydev->autoneg && (phydev->speed == 100)) { + /* disable phy interrupt */ + temp = phy_read(phydev, LAN88XX_INT_MASK); + temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_; + ret = phy_write(phydev, LAN88XX_INT_MASK, temp); + + temp = phy_read(phydev, MII_BMCR); + temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000); + phy_write(phydev, MII_BMCR, temp); /* set to 10 first */ + temp |= BMCR_SPEED100; + phy_write(phydev, MII_BMCR, temp); /* set to 100 later */ + + /* clear pending interrupt generated while workaround */ + temp = phy_read(phydev, LAN88XX_INT_STS); + + /* enable phy interrupt back */ + temp = phy_read(phydev, LAN88XX_INT_MASK); + temp |= LAN88XX_INT_MASK_MDINTPIN_EN_; + ret = phy_write(phydev, LAN88XX_INT_MASK, temp); + } } static int lan78xx_phy_init(struct lan78xx_net *dev) { int ret; + u32 mii_adv; struct phy_device *phydev = dev->net->phydev; phydev = phy_find_first(dev->mdiobus); @@ -1622,14 +1870,17 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) /* MAC doesn't support 1000T Half */ phydev->supported &= ~SUPPORTED_1000baseT_Half; - phydev->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_Pause | SUPPORTED_Asym_Pause); + + /* support both flow controls */ + dev->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); + phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); + mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control); + phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv); + genphy_config_aneg(phydev); + dev->fc_autoneg = phydev->autoneg; + phy_start(phydev); netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); @@ -1918,7 +2169,8 @@ static int lan78xx_reset(struct lan78xx_net *dev) /* save DEVID for later usage */ ret = lan78xx_read_reg(dev, ID_REV, &buf); - dev->devid = buf; + dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16; + dev->chiprev = buf & ID_REV_CHIP_REV_MASK_; /* Respond to the IN token with a NAK */ ret = lan78xx_read_reg(dev, USB_CFG0, &buf); @@ -2024,6 +2276,32 @@ static int lan78xx_reset(struct lan78xx_net *dev) return 0; } +static void lan78xx_init_stats(struct lan78xx_net *dev) +{ + u32 *p; + int i; + + /* initialize for stats update + * some counters are 20bits and some are 32bits + */ + p = (u32 *)&dev->stats.rollover_max; + for (i = 0; i < (sizeof(dev->stats.rollover_max) / (sizeof(u32))); i++) + p[i] = 0xFFFFF; + + dev->stats.rollover_max.rx_unicast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.rx_broadcast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.rx_multicast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.eee_rx_lpi_transitions = 0xFFFFFFFF; + dev->stats.rollover_max.eee_rx_lpi_time = 0xFFFFFFFF; + dev->stats.rollover_max.tx_unicast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.tx_broadcast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.tx_multicast_byte_count = 0xFFFFFFFF; + dev->stats.rollover_max.eee_tx_lpi_transitions = 0xFFFFFFFF; + dev->stats.rollover_max.eee_tx_lpi_time = 0xFFFFFFFF; + + lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE); +} + static int lan78xx_open(struct net_device *net) { struct lan78xx_net *dev = netdev_priv(net); @@ -2051,6 +2329,8 @@ static int lan78xx_open(struct net_device *net) } } + lan78xx_init_stats(dev); + set_bit(EVENT_DEV_OPEN, &dev->flags); netif_start_queue(net); @@ -2095,6 +2375,9 @@ int lan78xx_stop(struct net_device *net) { struct lan78xx_net *dev = netdev_priv(net); + if (timer_pending(&dev->stat_monitor)) + del_timer_sync(&dev->stat_monitor); + phy_stop(net->phydev); phy_disconnect(net->phydev); net->phydev = NULL; @@ -2209,7 +2492,7 @@ static void tx_complete(struct urb *urb) struct lan78xx_net *dev = entry->dev; if (urb->status == 0) { - dev->net->stats.tx_packets++; + dev->net->stats.tx_packets += entry->num_of_packet; dev->net->stats.tx_bytes += entry->length; } else { dev->net->stats.tx_errors++; @@ -2426,10 +2709,11 @@ void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) return; } - skb->protocol = eth_type_trans(skb, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, dev->net); + netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", skb->len + sizeof(struct ethhdr), skb->protocol); memset(skb->cb, 0, sizeof(struct skb_data)); @@ -2679,13 +2963,16 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) skb_totallen = 0; pkt_cnt = 0; + count = 0; + length = 0; for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { if (skb_is_gso(skb)) { if (pkt_cnt) { /* handle previous packets first */ break; } - length = skb->len; + count = 1; + length = skb->len - TX_OVERHEAD; skb2 = skb_dequeue(tqp); goto gso_skb; } @@ -2706,14 +2993,13 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) for (count = pos = 0; count < pkt_cnt; count++) { skb2 = skb_dequeue(tqp); if (skb2) { + length += (skb2->len - TX_OVERHEAD); memcpy(skb->data + pos, skb2->data, skb2->len); pos += roundup(skb2->len, sizeof(u32)); dev_kfree_skb(skb2); } } - length = skb_totallen; - gso_skb: urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { @@ -2725,6 +3011,7 @@ gso_skb: entry->urb = urb; entry->dev = dev; entry->length = length; + entry->num_of_packet = count; spin_lock_irqsave(&dev->txq.lock, flags); ret = usb_autopm_get_interface_async(dev->intf); @@ -2839,6 +3126,13 @@ static void lan78xx_bh(unsigned long param) } if (netif_device_present(dev->net) && netif_running(dev->net)) { + /* reset update timer delta */ + if (timer_pending(&dev->stat_monitor) && (dev->delta != 1)) { + dev->delta = 1; + mod_timer(&dev->stat_monitor, + jiffies + STAT_UPDATE_TIMER); + } + if (!skb_queue_empty(&dev->txq_pend)) lan78xx_tx_bh(dev); @@ -2913,6 +3207,17 @@ skip_reset: usb_autopm_put_interface(dev->intf); } } + + if (test_bit(EVENT_STAT_UPDATE, &dev->flags)) { + lan78xx_update_stats(dev); + + clear_bit(EVENT_STAT_UPDATE, &dev->flags); + + mod_timer(&dev->stat_monitor, + jiffies + (STAT_UPDATE_TIMER * dev->delta)); + + dev->delta = min((dev->delta * 2), 50); + } } static void intr_complete(struct urb *urb) @@ -3003,6 +3308,15 @@ static const struct net_device_ops lan78xx_netdev_ops = { .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, }; +static void lan78xx_stat_monitor(unsigned long param) +{ + struct lan78xx_net *dev; + + dev = (struct lan78xx_net *)param; + + lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE); +} + static int lan78xx_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -3049,6 +3363,13 @@ static int lan78xx_probe(struct usb_interface *intf, netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES; netdev->ethtool_ops = &lan78xx_ethtool_ops; + dev->stat_monitor.function = lan78xx_stat_monitor; + dev->stat_monitor.data = (unsigned long)dev; + dev->delta = 1; + init_timer(&dev->stat_monitor); + + mutex_init(&dev->stats.access_lock); + ret = lan78xx_bind(dev, intf); if (ret < 0) goto out2; @@ -3326,6 +3647,8 @@ int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) } if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + del_timer(&dev->stat_monitor); + if (PMSG_IS_AUTO(message)) { /* auto suspend (selective suspend) */ ret = lan78xx_read_reg(dev, MAC_TX, &buf); @@ -3386,6 +3709,12 @@ int lan78xx_resume(struct usb_interface *intf) int ret; u32 buf; + if (!timer_pending(&dev->stat_monitor)) { + dev->delta = 1; + mod_timer(&dev->stat_monitor, + jiffies + STAT_UPDATE_TIMER); + } + if (!--dev->suspend_count) { /* resume interrupt URBs */ if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags)) diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h index a93fb653e..409279061 100644 --- a/drivers/net/usb/lan78xx.h +++ b/drivers/net/usb/lan78xx.h @@ -107,6 +107,7 @@ #define ID_REV_CHIP_ID_MASK_ (0xFFFF0000) #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) #define ID_REV_CHIP_ID_7800_ (0x7800) +#define ID_REV_CHIP_ID_7850_ (0x7850) #define FPGA_REV (0x04) #define FPGA_REV_MINOR_MASK_ (0x0000FF00) diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index f84080215..82129eef7 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -411,7 +411,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) int ret; read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); - data[0] = 0xc9; + data[0] = 0xc8; /* TX & RX enable, append status, no CRC */ data[1] = 0; if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) data[1] |= 0x20; /* set full duplex */ @@ -497,7 +497,7 @@ static void read_bulk_callback(struct urb *urb) pkt_len = buf[count - 3] << 8; pkt_len += buf[count - 4]; pkt_len &= 0xfff; - pkt_len -= 8; + pkt_len -= 4; } /* @@ -528,7 +528,7 @@ static void read_bulk_callback(struct urb *urb) goon: usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, + pegasus->rx_skb->data, PEGASUS_MTU, read_bulk_callback, pegasus); rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); if (rx_status == -ENODEV) @@ -569,7 +569,7 @@ static void rx_fixup(unsigned long data) } usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, + pegasus->rx_skb->data, PEGASUS_MTU, read_bulk_callback, pegasus); try_again: status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); @@ -823,7 +823,7 @@ static int pegasus_open(struct net_device *net) usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), - pegasus->rx_skb->data, PEGASUS_MTU + 8, + pegasus->rx_skb->data, PEGASUS_MTU, read_bulk_callback, pegasus); if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { if (res == -ENODEV) diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 1bfe0fcac..22e1a9a99 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -38,7 +38,7 @@ * HEADS UP: this handshaking isn't all that robust. This driver * gets confused easily if you unplug one end of the cable then * try to connect it again; you'll need to restart both ends. The - * "naplink" software (used by some PlayStation/2 deveopers) does + * "naplink" software (used by some PlayStation/2 developers) does * the handshaking much better! Also, sometimes this hardware * seems to get wedged under load. Prolific docs are weak, and * don't identify differences between PL2301 and PL2302, much less diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 1232a8c60..9d1fce8a6 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -882,6 +882,9 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)}, /* Olivetti Olicard 500 */ {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */ {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */ + {QMI_FIXED_INTF(0x1e2d, 0x0082, 4)}, /* Cinterion PHxx,PXxx (2 RmNet) */ + {QMI_FIXED_INTF(0x1e2d, 0x0082, 5)}, /* Cinterion PHxx,PXxx (2 RmNet) */ + {QMI_FIXED_INTF(0x1e2d, 0x0083, 4)}, /* Cinterion PHxx,PXxx (1 RmNet + USB Audio)*/ {QMI_FIXED_INTF(0x413c, 0x81a2, 8)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a3, 8)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 30033dbe6..c369db99c 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -29,6 +29,7 @@ #include <linux/crc32.h> #include <linux/usb/usbnet.h> #include <linux/slab.h> +#include <linux/of_net.h> #include "smsc75xx.h" #define SMSC_CHIPNAME "smsc75xx" @@ -761,6 +762,15 @@ static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) static void smsc75xx_init_mac_address(struct usbnet *dev) { + const u8 *mac_addr; + + /* maybe the boot loader passed the MAC address in devicetree */ + mac_addr = of_get_mac_address(dev->udev->dev.of_node); + if (mac_addr) { + memcpy(dev->net->dev_addr, mac_addr, ETH_ALEN); + return; + } + /* try reading mac address from EEPROM */ if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { @@ -772,7 +782,7 @@ static void smsc75xx_init_mac_address(struct usbnet *dev) } } - /* no eeprom, or eeprom values are invalid. generate random MAC */ + /* no useful static MAC address found. generate a random one */ eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); } diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 66b3ab9f6..2edc2bc6d 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -29,6 +29,7 @@ #include <linux/crc32.h> #include <linux/usb/usbnet.h> #include <linux/slab.h> +#include <linux/of_net.h> #include "smsc95xx.h" #define SMSC_CHIPNAME "smsc95xx" @@ -765,6 +766,15 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) static void smsc95xx_init_mac_address(struct usbnet *dev) { + const u8 *mac_addr; + + /* maybe the boot loader passed the MAC address in devicetree */ + mac_addr = of_get_mac_address(dev->udev->dev.of_node); + if (mac_addr) { + memcpy(dev->net->dev_addr, mac_addr, ETH_ALEN); + return; + } + /* try reading mac address from EEPROM */ if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { @@ -775,7 +785,7 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) } } - /* no eeprom, or eeprom values are invalid. generate random MAC */ + /* no useful static MAC address found. generate a random one */ eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); } |