diff options
| -rw-r--r-- | drivers/net/usb/lan78xx.c | 252 |
1 files changed, 239 insertions, 13 deletions
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 705c180163c5..f20890ee03f3 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" | 36 | #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" |
| 37 | #define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" | 37 | #define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" |
| 38 | #define DRIVER_NAME "lan78xx" | 38 | #define DRIVER_NAME "lan78xx" |
| 39 | #define DRIVER_VERSION "1.0.3" | 39 | #define DRIVER_VERSION "1.0.4" |
| 40 | 40 | ||
| 41 | #define TX_TIMEOUT_JIFFIES (5 * HZ) | 41 | #define TX_TIMEOUT_JIFFIES (5 * HZ) |
| 42 | #define THROTTLE_JIFFIES (HZ / 8) | 42 | #define THROTTLE_JIFFIES (HZ / 8) |
| @@ -86,6 +86,9 @@ | |||
| 86 | /* default autosuspend delay (mSec)*/ | 86 | /* default autosuspend delay (mSec)*/ |
| 87 | #define DEFAULT_AUTOSUSPEND_DELAY (10 * 1000) | 87 | #define DEFAULT_AUTOSUSPEND_DELAY (10 * 1000) |
| 88 | 88 | ||
| 89 | /* statistic update interval (mSec) */ | ||
| 90 | #define STAT_UPDATE_TIMER (1 * 1000) | ||
| 91 | |||
| 89 | static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = { | 92 | static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = { |
| 90 | "RX FCS Errors", | 93 | "RX FCS Errors", |
| 91 | "RX Alignment Errors", | 94 | "RX Alignment Errors", |
| @@ -186,6 +189,56 @@ struct lan78xx_statstage { | |||
| 186 | u32 eee_tx_lpi_time; | 189 | u32 eee_tx_lpi_time; |
| 187 | }; | 190 | }; |
| 188 | 191 | ||
| 192 | struct lan78xx_statstage64 { | ||
| 193 | u64 rx_fcs_errors; | ||
| 194 | u64 rx_alignment_errors; | ||
| 195 | u64 rx_fragment_errors; | ||
| 196 | u64 rx_jabber_errors; | ||
| 197 | u64 rx_undersize_frame_errors; | ||
| 198 | u64 rx_oversize_frame_errors; | ||
| 199 | u64 rx_dropped_frames; | ||
| 200 | u64 rx_unicast_byte_count; | ||
| 201 | u64 rx_broadcast_byte_count; | ||
| 202 | u64 rx_multicast_byte_count; | ||
| 203 | u64 rx_unicast_frames; | ||
| 204 | u64 rx_broadcast_frames; | ||
| 205 | u64 rx_multicast_frames; | ||
| 206 | u64 rx_pause_frames; | ||
| 207 | u64 rx_64_byte_frames; | ||
| 208 | u64 rx_65_127_byte_frames; | ||
| 209 | u64 rx_128_255_byte_frames; | ||
| 210 | u64 rx_256_511_bytes_frames; | ||
| 211 | u64 rx_512_1023_byte_frames; | ||
| 212 | u64 rx_1024_1518_byte_frames; | ||
| 213 | u64 rx_greater_1518_byte_frames; | ||
| 214 | u64 eee_rx_lpi_transitions; | ||
| 215 | u64 eee_rx_lpi_time; | ||
| 216 | u64 tx_fcs_errors; | ||
| 217 | u64 tx_excess_deferral_errors; | ||
| 218 | u64 tx_carrier_errors; | ||
| 219 | u64 tx_bad_byte_count; | ||
| 220 | u64 tx_single_collisions; | ||
| 221 | u64 tx_multiple_collisions; | ||
| 222 | u64 tx_excessive_collision; | ||
| 223 | u64 tx_late_collisions; | ||
| 224 | u64 tx_unicast_byte_count; | ||
| 225 | u64 tx_broadcast_byte_count; | ||
| 226 | u64 tx_multicast_byte_count; | ||
| 227 | u64 tx_unicast_frames; | ||
| 228 | u64 tx_broadcast_frames; | ||
| 229 | u64 tx_multicast_frames; | ||
| 230 | u64 tx_pause_frames; | ||
| 231 | u64 tx_64_byte_frames; | ||
| 232 | u64 tx_65_127_byte_frames; | ||
| 233 | u64 tx_128_255_byte_frames; | ||
| 234 | u64 tx_256_511_bytes_frames; | ||
| 235 | u64 tx_512_1023_byte_frames; | ||
| 236 | u64 tx_1024_1518_byte_frames; | ||
| 237 | u64 tx_greater_1518_byte_frames; | ||
| 238 | u64 eee_tx_lpi_transitions; | ||
| 239 | u64 eee_tx_lpi_time; | ||
| 240 | }; | ||
| 241 | |||
| 189 | struct lan78xx_net; | 242 | struct lan78xx_net; |
| 190 | 243 | ||
| 191 | struct lan78xx_priv { | 244 | struct lan78xx_priv { |
| @@ -232,6 +285,15 @@ struct usb_context { | |||
| 232 | #define EVENT_DEV_WAKING 6 | 285 | #define EVENT_DEV_WAKING 6 |
| 233 | #define EVENT_DEV_ASLEEP 7 | 286 | #define EVENT_DEV_ASLEEP 7 |
| 234 | #define EVENT_DEV_OPEN 8 | 287 | #define EVENT_DEV_OPEN 8 |
| 288 | #define EVENT_STAT_UPDATE 9 | ||
| 289 | |||
| 290 | struct statstage { | ||
| 291 | struct mutex access_lock; /* for stats access */ | ||
| 292 | struct lan78xx_statstage saved; | ||
| 293 | struct lan78xx_statstage rollover_count; | ||
| 294 | struct lan78xx_statstage rollover_max; | ||
| 295 | struct lan78xx_statstage64 curr_stat; | ||
| 296 | }; | ||
| 235 | 297 | ||
| 236 | struct lan78xx_net { | 298 | struct lan78xx_net { |
| 237 | struct net_device *net; | 299 | struct net_device *net; |
| @@ -272,6 +334,7 @@ struct lan78xx_net { | |||
| 272 | 334 | ||
| 273 | unsigned maxpacket; | 335 | unsigned maxpacket; |
| 274 | struct timer_list delay; | 336 | struct timer_list delay; |
| 337 | struct timer_list stat_monitor; | ||
| 275 | 338 | ||
| 276 | unsigned long data[5]; | 339 | unsigned long data[5]; |
| 277 | 340 | ||
| @@ -284,6 +347,9 @@ struct lan78xx_net { | |||
| 284 | 347 | ||
| 285 | int fc_autoneg; | 348 | int fc_autoneg; |
| 286 | u8 fc_request_control; | 349 | u8 fc_request_control; |
| 350 | |||
| 351 | int delta; | ||
| 352 | struct statstage stats; | ||
| 287 | }; | 353 | }; |
| 288 | 354 | ||
| 289 | /* use ethtool to change the level for any given device */ | 355 | /* use ethtool to change the level for any given device */ |
| @@ -382,6 +448,93 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, | |||
| 382 | return ret; | 448 | return ret; |
| 383 | } | 449 | } |
| 384 | 450 | ||
| 451 | #define check_counter_rollover(struct1, dev_stats, member) { \ | ||
| 452 | if (struct1->member < dev_stats.saved.member) \ | ||
| 453 | dev_stats.rollover_count.member++; \ | ||
| 454 | } | ||
| 455 | |||
| 456 | static void lan78xx_check_stat_rollover(struct lan78xx_net *dev, | ||
| 457 | struct lan78xx_statstage *stats) | ||
| 458 | { | ||
| 459 | check_counter_rollover(stats, dev->stats, rx_fcs_errors); | ||
| 460 | check_counter_rollover(stats, dev->stats, rx_alignment_errors); | ||
| 461 | check_counter_rollover(stats, dev->stats, rx_fragment_errors); | ||
| 462 | check_counter_rollover(stats, dev->stats, rx_jabber_errors); | ||
| 463 | check_counter_rollover(stats, dev->stats, rx_undersize_frame_errors); | ||
| 464 | check_counter_rollover(stats, dev->stats, rx_oversize_frame_errors); | ||
| 465 | check_counter_rollover(stats, dev->stats, rx_dropped_frames); | ||
| 466 | check_counter_rollover(stats, dev->stats, rx_unicast_byte_count); | ||
| 467 | check_counter_rollover(stats, dev->stats, rx_broadcast_byte_count); | ||
| 468 | check_counter_rollover(stats, dev->stats, rx_multicast_byte_count); | ||
| 469 | check_counter_rollover(stats, dev->stats, rx_unicast_frames); | ||
| 470 | check_counter_rollover(stats, dev->stats, rx_broadcast_frames); | ||
| 471 | check_counter_rollover(stats, dev->stats, rx_multicast_frames); | ||
| 472 | check_counter_rollover(stats, dev->stats, rx_pause_frames); | ||
| 473 | check_counter_rollover(stats, dev->stats, rx_64_byte_frames); | ||
| 474 | check_counter_rollover(stats, dev->stats, rx_65_127_byte_frames); | ||
| 475 | check_counter_rollover(stats, dev->stats, rx_128_255_byte_frames); | ||
| 476 | check_counter_rollover(stats, dev->stats, rx_256_511_bytes_frames); | ||
| 477 | check_counter_rollover(stats, dev->stats, rx_512_1023_byte_frames); | ||
| 478 | check_counter_rollover(stats, dev->stats, rx_1024_1518_byte_frames); | ||
| 479 | check_counter_rollover(stats, dev->stats, rx_greater_1518_byte_frames); | ||
| 480 | check_counter_rollover(stats, dev->stats, eee_rx_lpi_transitions); | ||
| 481 | check_counter_rollover(stats, dev->stats, eee_rx_lpi_time); | ||
| 482 | check_counter_rollover(stats, dev->stats, tx_fcs_errors); | ||
| 483 | check_counter_rollover(stats, dev->stats, tx_excess_deferral_errors); | ||
| 484 | check_counter_rollover(stats, dev->stats, tx_carrier_errors); | ||
| 485 | check_counter_rollover(stats, dev->stats, tx_bad_byte_count); | ||
| 486 | check_counter_rollover(stats, dev->stats, tx_single_collisions); | ||
| 487 | check_counter_rollover(stats, dev->stats, tx_multiple_collisions); | ||
| 488 | check_counter_rollover(stats, dev->stats, tx_excessive_collision); | ||
| 489 | check_counter_rollover(stats, dev->stats, tx_late_collisions); | ||
| 490 | check_counter_rollover(stats, dev->stats, tx_unicast_byte_count); | ||
| 491 | check_counter_rollover(stats, dev->stats, tx_broadcast_byte_count); | ||
| 492 | check_counter_rollover(stats, dev->stats, tx_multicast_byte_count); | ||
| 493 | check_counter_rollover(stats, dev->stats, tx_unicast_frames); | ||
| 494 | check_counter_rollover(stats, dev->stats, tx_broadcast_frames); | ||
| 495 | check_counter_rollover(stats, dev->stats, tx_multicast_frames); | ||
| 496 | check_counter_rollover(stats, dev->stats, tx_pause_frames); | ||
| 497 | check_counter_rollover(stats, dev->stats, tx_64_byte_frames); | ||
| 498 | check_counter_rollover(stats, dev->stats, tx_65_127_byte_frames); | ||
| 499 | check_counter_rollover(stats, dev->stats, tx_128_255_byte_frames); | ||
| 500 | check_counter_rollover(stats, dev->stats, tx_256_511_bytes_frames); | ||
| 501 | check_counter_rollover(stats, dev->stats, tx_512_1023_byte_frames); | ||
| 502 | check_counter_rollover(stats, dev->stats, tx_1024_1518_byte_frames); | ||
| 503 | check_counter_rollover(stats, dev->stats, tx_greater_1518_byte_frames); | ||
| 504 | check_counter_rollover(stats, dev->stats, eee_tx_lpi_transitions); | ||
| 505 | check_counter_rollover(stats, dev->stats, eee_tx_lpi_time); | ||
| 506 | |||
| 507 | memcpy(&dev->stats.saved, stats, sizeof(struct lan78xx_statstage)); | ||
| 508 | } | ||
| 509 | |||
| 510 | static void lan78xx_update_stats(struct lan78xx_net *dev) | ||
| 511 | { | ||
| 512 | u32 *p, *count, *max; | ||
| 513 | u64 *data; | ||
| 514 | int i; | ||
| 515 | struct lan78xx_statstage lan78xx_stats; | ||
| 516 | |||
| 517 | if (usb_autopm_get_interface(dev->intf) < 0) | ||
| 518 | return; | ||
| 519 | |||
| 520 | p = (u32 *)&lan78xx_stats; | ||
| 521 | count = (u32 *)&dev->stats.rollover_count; | ||
| 522 | max = (u32 *)&dev->stats.rollover_max; | ||
| 523 | data = (u64 *)&dev->stats.curr_stat; | ||
| 524 | |||
| 525 | mutex_lock(&dev->stats.access_lock); | ||
| 526 | |||
| 527 | if (lan78xx_read_stats(dev, &lan78xx_stats) > 0) | ||
| 528 | lan78xx_check_stat_rollover(dev, &lan78xx_stats); | ||
| 529 | |||
| 530 | for (i = 0; i < (sizeof(lan78xx_stats) / (sizeof(u32))); i++) | ||
| 531 | data[i] = (u64)p[i] + ((u64)count[i] * ((u64)max[i] + 1)); | ||
| 532 | |||
| 533 | mutex_unlock(&dev->stats.access_lock); | ||
| 534 | |||
| 535 | usb_autopm_put_interface(dev->intf); | ||
| 536 | } | ||
| 537 | |||
| 385 | /* Loop until the read is completed with timeout called with phy_mutex held */ | 538 | /* Loop until the read is completed with timeout called with phy_mutex held */ |
| 386 | static int lan78xx_phy_wait_not_busy(struct lan78xx_net *dev) | 539 | static int lan78xx_phy_wait_not_busy(struct lan78xx_net *dev) |
| 387 | { | 540 | { |
| @@ -967,6 +1120,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) | |||
| 967 | return -EIO; | 1120 | return -EIO; |
| 968 | 1121 | ||
| 969 | phy_mac_interrupt(phydev, 0); | 1122 | phy_mac_interrupt(phydev, 0); |
| 1123 | |||
| 1124 | del_timer(&dev->stat_monitor); | ||
| 970 | } else if (phydev->link && !dev->link_on) { | 1125 | } else if (phydev->link && !dev->link_on) { |
| 971 | dev->link_on = true; | 1126 | dev->link_on = true; |
| 972 | 1127 | ||
| @@ -1007,6 +1162,12 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) | |||
| 1007 | 1162 | ||
| 1008 | ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); | 1163 | ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); |
| 1009 | phy_mac_interrupt(phydev, 1); | 1164 | phy_mac_interrupt(phydev, 1); |
| 1165 | |||
| 1166 | if (!timer_pending(&dev->stat_monitor)) { | ||
| 1167 | dev->delta = 1; | ||
| 1168 | mod_timer(&dev->stat_monitor, | ||
| 1169 | jiffies + STAT_UPDATE_TIMER); | ||
| 1170 | } | ||
| 1010 | } | 1171 | } |
| 1011 | 1172 | ||
| 1012 | return ret; | 1173 | return ret; |
| @@ -1099,20 +1260,12 @@ static void lan78xx_get_stats(struct net_device *netdev, | |||
| 1099 | struct ethtool_stats *stats, u64 *data) | 1260 | struct ethtool_stats *stats, u64 *data) |
| 1100 | { | 1261 | { |
| 1101 | struct lan78xx_net *dev = netdev_priv(netdev); | 1262 | struct lan78xx_net *dev = netdev_priv(netdev); |
| 1102 | struct lan78xx_statstage lan78xx_stat; | ||
| 1103 | u32 *p; | ||
| 1104 | int i; | ||
| 1105 | 1263 | ||
| 1106 | if (usb_autopm_get_interface(dev->intf) < 0) | 1264 | lan78xx_update_stats(dev); |
| 1107 | return; | ||
| 1108 | 1265 | ||
| 1109 | if (lan78xx_read_stats(dev, &lan78xx_stat) > 0) { | 1266 | mutex_lock(&dev->stats.access_lock); |
| 1110 | p = (u32 *)&lan78xx_stat; | 1267 | memcpy(data, &dev->stats.curr_stat, sizeof(dev->stats.curr_stat)); |
| 1111 | for (i = 0; i < (sizeof(lan78xx_stat) / (sizeof(u32))); i++) | 1268 | mutex_unlock(&dev->stats.access_lock); |
| 1112 | data[i] = p[i]; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | usb_autopm_put_interface(dev->intf); | ||
| 1116 | } | 1269 | } |
| 1117 | 1270 | ||
| 1118 | static void lan78xx_get_wol(struct net_device *netdev, | 1271 | static void lan78xx_get_wol(struct net_device *netdev, |
| @@ -2095,6 +2248,32 @@ static int lan78xx_reset(struct lan78xx_net *dev) | |||
| 2095 | return 0; | 2248 | return 0; |
| 2096 | } | 2249 | } |
| 2097 | 2250 | ||
| 2251 | static void lan78xx_init_stats(struct lan78xx_net *dev) | ||
| 2252 | { | ||
| 2253 | u32 *p; | ||
| 2254 | int i; | ||
| 2255 | |||
| 2256 | /* initialize for stats update | ||
| 2257 | * some counters are 20bits and some are 32bits | ||
| 2258 | */ | ||
| 2259 | p = (u32 *)&dev->stats.rollover_max; | ||
| 2260 | for (i = 0; i < (sizeof(dev->stats.rollover_max) / (sizeof(u32))); i++) | ||
| 2261 | p[i] = 0xFFFFF; | ||
| 2262 | |||
| 2263 | dev->stats.rollover_max.rx_unicast_byte_count = 0xFFFFFFFF; | ||
| 2264 | dev->stats.rollover_max.rx_broadcast_byte_count = 0xFFFFFFFF; | ||
| 2265 | dev->stats.rollover_max.rx_multicast_byte_count = 0xFFFFFFFF; | ||
| 2266 | dev->stats.rollover_max.eee_rx_lpi_transitions = 0xFFFFFFFF; | ||
| 2267 | dev->stats.rollover_max.eee_rx_lpi_time = 0xFFFFFFFF; | ||
| 2268 | dev->stats.rollover_max.tx_unicast_byte_count = 0xFFFFFFFF; | ||
| 2269 | dev->stats.rollover_max.tx_broadcast_byte_count = 0xFFFFFFFF; | ||
| 2270 | dev->stats.rollover_max.tx_multicast_byte_count = 0xFFFFFFFF; | ||
| 2271 | dev->stats.rollover_max.eee_tx_lpi_transitions = 0xFFFFFFFF; | ||
| 2272 | dev->stats.rollover_max.eee_tx_lpi_time = 0xFFFFFFFF; | ||
| 2273 | |||
| 2274 | lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE); | ||
| 2275 | } | ||
| 2276 | |||
| 2098 | static int lan78xx_open(struct net_device *net) | 2277 | static int lan78xx_open(struct net_device *net) |
| 2099 | { | 2278 | { |
| 2100 | struct lan78xx_net *dev = netdev_priv(net); | 2279 | struct lan78xx_net *dev = netdev_priv(net); |
| @@ -2122,6 +2301,8 @@ static int lan78xx_open(struct net_device *net) | |||
| 2122 | } | 2301 | } |
| 2123 | } | 2302 | } |
| 2124 | 2303 | ||
| 2304 | lan78xx_init_stats(dev); | ||
| 2305 | |||
| 2125 | set_bit(EVENT_DEV_OPEN, &dev->flags); | 2306 | set_bit(EVENT_DEV_OPEN, &dev->flags); |
| 2126 | 2307 | ||
| 2127 | netif_start_queue(net); | 2308 | netif_start_queue(net); |
| @@ -2166,6 +2347,9 @@ int lan78xx_stop(struct net_device *net) | |||
| 2166 | { | 2347 | { |
| 2167 | struct lan78xx_net *dev = netdev_priv(net); | 2348 | struct lan78xx_net *dev = netdev_priv(net); |
| 2168 | 2349 | ||
| 2350 | if (timer_pending(&dev->stat_monitor)) | ||
| 2351 | del_timer_sync(&dev->stat_monitor); | ||
| 2352 | |||
| 2169 | phy_stop(net->phydev); | 2353 | phy_stop(net->phydev); |
| 2170 | phy_disconnect(net->phydev); | 2354 | phy_disconnect(net->phydev); |
| 2171 | net->phydev = NULL; | 2355 | net->phydev = NULL; |
| @@ -2910,6 +3094,13 @@ static void lan78xx_bh(unsigned long param) | |||
| 2910 | } | 3094 | } |
| 2911 | 3095 | ||
| 2912 | if (netif_device_present(dev->net) && netif_running(dev->net)) { | 3096 | if (netif_device_present(dev->net) && netif_running(dev->net)) { |
| 3097 | /* reset update timer delta */ | ||
| 3098 | if (timer_pending(&dev->stat_monitor) && (dev->delta != 1)) { | ||
| 3099 | dev->delta = 1; | ||
| 3100 | mod_timer(&dev->stat_monitor, | ||
| 3101 | jiffies + STAT_UPDATE_TIMER); | ||
| 3102 | } | ||
| 3103 | |||
| 2913 | if (!skb_queue_empty(&dev->txq_pend)) | 3104 | if (!skb_queue_empty(&dev->txq_pend)) |
| 2914 | lan78xx_tx_bh(dev); | 3105 | lan78xx_tx_bh(dev); |
| 2915 | 3106 | ||
| @@ -2984,6 +3175,17 @@ skip_reset: | |||
| 2984 | usb_autopm_put_interface(dev->intf); | 3175 | usb_autopm_put_interface(dev->intf); |
| 2985 | } | 3176 | } |
| 2986 | } | 3177 | } |
| 3178 | |||
| 3179 | if (test_bit(EVENT_STAT_UPDATE, &dev->flags)) { | ||
| 3180 | lan78xx_update_stats(dev); | ||
| 3181 | |||
| 3182 | clear_bit(EVENT_STAT_UPDATE, &dev->flags); | ||
| 3183 | |||
| 3184 | mod_timer(&dev->stat_monitor, | ||
| 3185 | jiffies + (STAT_UPDATE_TIMER * dev->delta)); | ||
| 3186 | |||
| 3187 | dev->delta = min((dev->delta * 2), 50); | ||
| 3188 | } | ||
| 2987 | } | 3189 | } |
| 2988 | 3190 | ||
| 2989 | static void intr_complete(struct urb *urb) | 3191 | static void intr_complete(struct urb *urb) |
| @@ -3074,6 +3276,15 @@ static const struct net_device_ops lan78xx_netdev_ops = { | |||
| 3074 | .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, | 3276 | .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, |
| 3075 | }; | 3277 | }; |
| 3076 | 3278 | ||
| 3279 | static void lan78xx_stat_monitor(unsigned long param) | ||
| 3280 | { | ||
| 3281 | struct lan78xx_net *dev; | ||
| 3282 | |||
| 3283 | dev = (struct lan78xx_net *)param; | ||
| 3284 | |||
| 3285 | lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE); | ||
| 3286 | } | ||
| 3287 | |||
| 3077 | static int lan78xx_probe(struct usb_interface *intf, | 3288 | static int lan78xx_probe(struct usb_interface *intf, |
| 3078 | const struct usb_device_id *id) | 3289 | const struct usb_device_id *id) |
| 3079 | { | 3290 | { |
| @@ -3120,6 +3331,13 @@ static int lan78xx_probe(struct usb_interface *intf, | |||
| 3120 | netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES; | 3331 | netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES; |
| 3121 | netdev->ethtool_ops = &lan78xx_ethtool_ops; | 3332 | netdev->ethtool_ops = &lan78xx_ethtool_ops; |
| 3122 | 3333 | ||
| 3334 | dev->stat_monitor.function = lan78xx_stat_monitor; | ||
| 3335 | dev->stat_monitor.data = (unsigned long)dev; | ||
| 3336 | dev->delta = 1; | ||
| 3337 | init_timer(&dev->stat_monitor); | ||
| 3338 | |||
| 3339 | mutex_init(&dev->stats.access_lock); | ||
| 3340 | |||
| 3123 | ret = lan78xx_bind(dev, intf); | 3341 | ret = lan78xx_bind(dev, intf); |
| 3124 | if (ret < 0) | 3342 | if (ret < 0) |
| 3125 | goto out2; | 3343 | goto out2; |
| @@ -3397,6 +3615,8 @@ int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 3397 | } | 3615 | } |
| 3398 | 3616 | ||
| 3399 | if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { | 3617 | if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { |
| 3618 | del_timer(&dev->stat_monitor); | ||
| 3619 | |||
| 3400 | if (PMSG_IS_AUTO(message)) { | 3620 | if (PMSG_IS_AUTO(message)) { |
| 3401 | /* auto suspend (selective suspend) */ | 3621 | /* auto suspend (selective suspend) */ |
| 3402 | ret = lan78xx_read_reg(dev, MAC_TX, &buf); | 3622 | ret = lan78xx_read_reg(dev, MAC_TX, &buf); |
| @@ -3457,6 +3677,12 @@ int lan78xx_resume(struct usb_interface *intf) | |||
| 3457 | int ret; | 3677 | int ret; |
| 3458 | u32 buf; | 3678 | u32 buf; |
| 3459 | 3679 | ||
| 3680 | if (!timer_pending(&dev->stat_monitor)) { | ||
| 3681 | dev->delta = 1; | ||
| 3682 | mod_timer(&dev->stat_monitor, | ||
| 3683 | jiffies + STAT_UPDATE_TIMER); | ||
| 3684 | } | ||
| 3685 | |||
| 3460 | if (!--dev->suspend_count) { | 3686 | if (!--dev->suspend_count) { |
| 3461 | /* resume interrupt URBs */ | 3687 | /* resume interrupt URBs */ |
| 3462 | if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags)) | 3688 | if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags)) |
