Skip to content

Commit 20ff556

Browse files
WoojungHuhdavem330
authored andcommitted
lan78xx: handle statistics counter rollover
Update to handle statistics counter rollover. Check statistics counter periodically and compensate it when counter value rolls over at max (20 or 32bits). Simple mechanism adjusts monitoring timer to allow USB auto suspend. Signed-off-by: Woojung Huh <woojung.huh@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 7fa7728 commit 20ff556

File tree

1 file changed

+239
-13
lines changed

1 file changed

+239
-13
lines changed

drivers/net/usb/lan78xx.c

Lines changed: 239 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>"
3737
#define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices"
3838
#define DRIVER_NAME "lan78xx"
39-
#define DRIVER_VERSION "1.0.3"
39+
#define DRIVER_VERSION "1.0.4"
4040

4141
#define TX_TIMEOUT_JIFFIES (5 * HZ)
4242
#define THROTTLE_JIFFIES (HZ / 8)
@@ -86,6 +86,9 @@
8686
/* default autosuspend delay (mSec)*/
8787
#define DEFAULT_AUTOSUSPEND_DELAY (10 * 1000)
8888

89+
/* statistic update interval (mSec) */
90+
#define STAT_UPDATE_TIMER (1 * 1000)
91+
8992
static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = {
9093
"RX FCS Errors",
9194
"RX Alignment Errors",
@@ -186,6 +189,56 @@ struct lan78xx_statstage {
186189
u32 eee_tx_lpi_time;
187190
};
188191

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+
189242
struct lan78xx_net;
190243

191244
struct lan78xx_priv {
@@ -232,6 +285,15 @@ struct usb_context {
232285
#define EVENT_DEV_WAKING 6
233286
#define EVENT_DEV_ASLEEP 7
234287
#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+
};
235297

236298
struct lan78xx_net {
237299
struct net_device *net;
@@ -272,6 +334,7 @@ struct lan78xx_net {
272334

273335
unsigned maxpacket;
274336
struct timer_list delay;
337+
struct timer_list stat_monitor;
275338

276339
unsigned long data[5];
277340

@@ -284,6 +347,9 @@ struct lan78xx_net {
284347

285348
int fc_autoneg;
286349
u8 fc_request_control;
350+
351+
int delta;
352+
struct statstage stats;
287353
};
288354

289355
/* use ethtool to change the level for any given device */
@@ -382,6 +448,93 @@ static int lan78xx_read_stats(struct lan78xx_net *dev,
382448
return ret;
383449
}
384450

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+
385538
/* Loop until the read is completed with timeout called with phy_mutex held */
386539
static int lan78xx_phy_wait_not_busy(struct lan78xx_net *dev)
387540
{
@@ -967,6 +1120,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
9671120
return -EIO;
9681121

9691122
phy_mac_interrupt(phydev, 0);
1123+
1124+
del_timer(&dev->stat_monitor);
9701125
} else if (phydev->link && !dev->link_on) {
9711126
dev->link_on = true;
9721127

@@ -1007,6 +1162,12 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
10071162

10081163
ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv);
10091164
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+
}
10101171
}
10111172

10121173
return ret;
@@ -1099,20 +1260,12 @@ static void lan78xx_get_stats(struct net_device *netdev,
10991260
struct ethtool_stats *stats, u64 *data)
11001261
{
11011262
struct lan78xx_net *dev = netdev_priv(netdev);
1102-
struct lan78xx_statstage lan78xx_stat;
1103-
u32 *p;
1104-
int i;
11051263

1106-
if (usb_autopm_get_interface(dev->intf) < 0)
1107-
return;
1264+
lan78xx_update_stats(dev);
11081265

1109-
if (lan78xx_read_stats(dev, &lan78xx_stat) > 0) {
1110-
p = (u32 *)&lan78xx_stat;
1111-
for (i = 0; i < (sizeof(lan78xx_stat) / (sizeof(u32))); i++)
1112-
data[i] = p[i];
1113-
}
1114-
1115-
usb_autopm_put_interface(dev->intf);
1266+
mutex_lock(&dev->stats.access_lock);
1267+
memcpy(data, &dev->stats.curr_stat, sizeof(dev->stats.curr_stat));
1268+
mutex_unlock(&dev->stats.access_lock);
11161269
}
11171270

11181271
static void lan78xx_get_wol(struct net_device *netdev,
@@ -2095,6 +2248,32 @@ static int lan78xx_reset(struct lan78xx_net *dev)
20952248
return 0;
20962249
}
20972250

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+
20982277
static int lan78xx_open(struct net_device *net)
20992278
{
21002279
struct lan78xx_net *dev = netdev_priv(net);
@@ -2122,6 +2301,8 @@ static int lan78xx_open(struct net_device *net)
21222301
}
21232302
}
21242303

2304+
lan78xx_init_stats(dev);
2305+
21252306
set_bit(EVENT_DEV_OPEN, &dev->flags);
21262307

21272308
netif_start_queue(net);
@@ -2166,6 +2347,9 @@ int lan78xx_stop(struct net_device *net)
21662347
{
21672348
struct lan78xx_net *dev = netdev_priv(net);
21682349

2350+
if (timer_pending(&dev->stat_monitor))
2351+
del_timer_sync(&dev->stat_monitor);
2352+
21692353
phy_stop(net->phydev);
21702354
phy_disconnect(net->phydev);
21712355
net->phydev = NULL;
@@ -2910,6 +3094,13 @@ static void lan78xx_bh(unsigned long param)
29103094
}
29113095

29123096
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+
29133104
if (!skb_queue_empty(&dev->txq_pend))
29143105
lan78xx_tx_bh(dev);
29153106

@@ -2984,6 +3175,17 @@ static void lan78xx_delayedwork(struct work_struct *work)
29843175
usb_autopm_put_interface(dev->intf);
29853176
}
29863177
}
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+
}
29873189
}
29883190

29893191
static void intr_complete(struct urb *urb)
@@ -3074,6 +3276,15 @@ static const struct net_device_ops lan78xx_netdev_ops = {
30743276
.ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid,
30753277
};
30763278

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+
30773288
static int lan78xx_probe(struct usb_interface *intf,
30783289
const struct usb_device_id *id)
30793290
{
@@ -3120,6 +3331,13 @@ static int lan78xx_probe(struct usb_interface *intf,
31203331
netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES;
31213332
netdev->ethtool_ops = &lan78xx_ethtool_ops;
31223333

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+
31233341
ret = lan78xx_bind(dev, intf);
31243342
if (ret < 0)
31253343
goto out2;
@@ -3397,6 +3615,8 @@ int lan78xx_suspend(struct usb_interface *intf, pm_message_t message)
33973615
}
33983616

33993617
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) {
3618+
del_timer(&dev->stat_monitor);
3619+
34003620
if (PMSG_IS_AUTO(message)) {
34013621
/* auto suspend (selective suspend) */
34023622
ret = lan78xx_read_reg(dev, MAC_TX, &buf);
@@ -3457,6 +3677,12 @@ int lan78xx_resume(struct usb_interface *intf)
34573677
int ret;
34583678
u32 buf;
34593679

3680+
if (!timer_pending(&dev->stat_monitor)) {
3681+
dev->delta = 1;
3682+
mod_timer(&dev->stat_monitor,
3683+
jiffies + STAT_UPDATE_TIMER);
3684+
}
3685+
34603686
if (!--dev->suspend_count) {
34613687
/* resume interrupt URBs */
34623688
if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags))

0 commit comments

Comments
 (0)