diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-01-29 13:00:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-30 17:06:33 -0500 |
commit | 1974cc205e63cec4a17a6b3fca31fa4240ded77e (patch) | |
tree | d658cbc56064d86f3f57e786b4ebcf33346188bd /drivers/net | |
parent | af4ad9bca0c4039355b20d760b4fd39afa48c59d (diff) |
sfc: Replace stats_enabled flag with a disable count
Currently we use a spin-lock to serialise statistics fetches and also
to inhibit them for short periods of time, plus a flag to
enable/disable statistics fetches for longer periods of time, during
online reset. This was apparently insufficient to deal with the several
reasons for stats being disabled.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sfc/efx.c | 33 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 15 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 5 | ||||
-rw-r--r-- | drivers/net/sfc/sfe4001.c | 15 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 12 |
6 files changed, 57 insertions, 25 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b0e53087bda0..ab0e09bf154d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -685,7 +685,7 @@ static int efx_init_port(struct efx_nic *efx) | |||
685 | efx->mac_op->reconfigure(efx); | 685 | efx->mac_op->reconfigure(efx); |
686 | 686 | ||
687 | efx->port_initialized = true; | 687 | efx->port_initialized = true; |
688 | efx->stats_enabled = true; | 688 | efx_stats_enable(efx); |
689 | return 0; | 689 | return 0; |
690 | 690 | ||
691 | fail: | 691 | fail: |
@@ -734,6 +734,7 @@ static void efx_fini_port(struct efx_nic *efx) | |||
734 | if (!efx->port_initialized) | 734 | if (!efx->port_initialized) |
735 | return; | 735 | return; |
736 | 736 | ||
737 | efx_stats_disable(efx); | ||
737 | efx->phy_op->fini(efx); | 738 | efx->phy_op->fini(efx); |
738 | efx->port_initialized = false; | 739 | efx->port_initialized = false; |
739 | 740 | ||
@@ -1360,6 +1361,20 @@ static int efx_net_stop(struct net_device *net_dev) | |||
1360 | return 0; | 1361 | return 0; |
1361 | } | 1362 | } |
1362 | 1363 | ||
1364 | void efx_stats_disable(struct efx_nic *efx) | ||
1365 | { | ||
1366 | spin_lock(&efx->stats_lock); | ||
1367 | ++efx->stats_disable_count; | ||
1368 | spin_unlock(&efx->stats_lock); | ||
1369 | } | ||
1370 | |||
1371 | void efx_stats_enable(struct efx_nic *efx) | ||
1372 | { | ||
1373 | spin_lock(&efx->stats_lock); | ||
1374 | --efx->stats_disable_count; | ||
1375 | spin_unlock(&efx->stats_lock); | ||
1376 | } | ||
1377 | |||
1363 | /* Context: process, dev_base_lock or RTNL held, non-blocking. */ | 1378 | /* Context: process, dev_base_lock or RTNL held, non-blocking. */ |
1364 | static struct net_device_stats *efx_net_stats(struct net_device *net_dev) | 1379 | static struct net_device_stats *efx_net_stats(struct net_device *net_dev) |
1365 | { | 1380 | { |
@@ -1368,12 +1383,12 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) | |||
1368 | struct net_device_stats *stats = &net_dev->stats; | 1383 | struct net_device_stats *stats = &net_dev->stats; |
1369 | 1384 | ||
1370 | /* Update stats if possible, but do not wait if another thread | 1385 | /* Update stats if possible, but do not wait if another thread |
1371 | * is updating them (or resetting the NIC); slightly stale | 1386 | * is updating them or if MAC stats fetches are temporarily |
1372 | * stats are acceptable. | 1387 | * disabled; slightly stale stats are acceptable. |
1373 | */ | 1388 | */ |
1374 | if (!spin_trylock(&efx->stats_lock)) | 1389 | if (!spin_trylock(&efx->stats_lock)) |
1375 | return stats; | 1390 | return stats; |
1376 | if (efx->stats_enabled) { | 1391 | if (!efx->stats_disable_count) { |
1377 | efx->mac_op->update_stats(efx); | 1392 | efx->mac_op->update_stats(efx); |
1378 | falcon_update_nic_stats(efx); | 1393 | falcon_update_nic_stats(efx); |
1379 | } | 1394 | } |
@@ -1626,12 +1641,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, | |||
1626 | { | 1641 | { |
1627 | EFX_ASSERT_RESET_SERIALISED(efx); | 1642 | EFX_ASSERT_RESET_SERIALISED(efx); |
1628 | 1643 | ||
1629 | /* The net_dev->get_stats handler is quite slow, and will fail | 1644 | efx_stats_disable(efx); |
1630 | * if a fetch is pending over reset. Serialise against it. */ | ||
1631 | spin_lock(&efx->stats_lock); | ||
1632 | efx->stats_enabled = false; | ||
1633 | spin_unlock(&efx->stats_lock); | ||
1634 | |||
1635 | efx_stop_all(efx); | 1645 | efx_stop_all(efx); |
1636 | mutex_lock(&efx->mac_lock); | 1646 | mutex_lock(&efx->mac_lock); |
1637 | mutex_lock(&efx->spi_lock); | 1647 | mutex_lock(&efx->spi_lock); |
@@ -1682,7 +1692,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, | |||
1682 | 1692 | ||
1683 | if (ok) { | 1693 | if (ok) { |
1684 | efx_start_all(efx); | 1694 | efx_start_all(efx); |
1685 | efx->stats_enabled = true; | 1695 | efx_stats_enable(efx); |
1686 | } | 1696 | } |
1687 | return rc; | 1697 | return rc; |
1688 | } | 1698 | } |
@@ -1888,6 +1898,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
1888 | efx->rx_checksum_enabled = true; | 1898 | efx->rx_checksum_enabled = true; |
1889 | spin_lock_init(&efx->netif_stop_lock); | 1899 | spin_lock_init(&efx->netif_stop_lock); |
1890 | spin_lock_init(&efx->stats_lock); | 1900 | spin_lock_init(&efx->stats_lock); |
1901 | efx->stats_disable_count = 1; | ||
1891 | mutex_init(&efx->mac_lock); | 1902 | mutex_init(&efx->mac_lock); |
1892 | efx->mac_op = &efx_dummy_mac_operations; | 1903 | efx->mac_op = &efx_dummy_mac_operations; |
1893 | efx->phy_op = &efx_dummy_phy_operations; | 1904 | efx->phy_op = &efx_dummy_phy_operations; |
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index ac201587a163..55d0f131b0e9 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h | |||
@@ -36,6 +36,8 @@ extern void efx_process_channel_now(struct efx_channel *channel); | |||
36 | extern void efx_flush_queues(struct efx_nic *efx); | 36 | extern void efx_flush_queues(struct efx_nic *efx); |
37 | 37 | ||
38 | /* Ports */ | 38 | /* Ports */ |
39 | extern void efx_stats_disable(struct efx_nic *efx); | ||
40 | extern void efx_stats_enable(struct efx_nic *efx); | ||
39 | extern void efx_reconfigure_port(struct efx_nic *efx); | 41 | extern void efx_reconfigure_port(struct efx_nic *efx); |
40 | extern void __efx_reconfigure_port(struct efx_nic *efx); | 42 | extern void __efx_reconfigure_port(struct efx_nic *efx); |
41 | 43 | ||
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d9412f83a78e..d5378e60fcdd 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -1883,7 +1883,7 @@ static int falcon_reset_macs(struct efx_nic *efx) | |||
1883 | 1883 | ||
1884 | /* MAC stats will fail whilst the TX fifo is draining. Serialise | 1884 | /* MAC stats will fail whilst the TX fifo is draining. Serialise |
1885 | * the drain sequence with the statistics fetch */ | 1885 | * the drain sequence with the statistics fetch */ |
1886 | spin_lock(&efx->stats_lock); | 1886 | efx_stats_disable(efx); |
1887 | 1887 | ||
1888 | falcon_read(efx, ®, MAC0_CTRL_REG_KER); | 1888 | falcon_read(efx, ®, MAC0_CTRL_REG_KER); |
1889 | EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); | 1889 | EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); |
@@ -1913,7 +1913,7 @@ static int falcon_reset_macs(struct efx_nic *efx) | |||
1913 | udelay(10); | 1913 | udelay(10); |
1914 | } | 1914 | } |
1915 | 1915 | ||
1916 | spin_unlock(&efx->stats_lock); | 1916 | efx_stats_enable(efx); |
1917 | 1917 | ||
1918 | /* If we've reset the EM block and the link is up, then | 1918 | /* If we've reset the EM block and the link is up, then |
1919 | * we'll have to kick the XAUI link so the PHY can recover */ | 1919 | * we'll have to kick the XAUI link so the PHY can recover */ |
@@ -2273,6 +2273,10 @@ int falcon_switch_mac(struct efx_nic *efx) | |||
2273 | struct efx_mac_operations *old_mac_op = efx->mac_op; | 2273 | struct efx_mac_operations *old_mac_op = efx->mac_op; |
2274 | efx_oword_t nic_stat; | 2274 | efx_oword_t nic_stat; |
2275 | unsigned strap_val; | 2275 | unsigned strap_val; |
2276 | int rc = 0; | ||
2277 | |||
2278 | /* Don't try to fetch MAC stats while we're switching MACs */ | ||
2279 | efx_stats_disable(efx); | ||
2276 | 2280 | ||
2277 | /* Internal loopbacks override the phy speed setting */ | 2281 | /* Internal loopbacks override the phy speed setting */ |
2278 | if (efx->loopback_mode == LOOPBACK_GMAC) { | 2282 | if (efx->loopback_mode == LOOPBACK_GMAC) { |
@@ -2302,13 +2306,16 @@ int falcon_switch_mac(struct efx_nic *efx) | |||
2302 | } | 2306 | } |
2303 | 2307 | ||
2304 | if (old_mac_op == efx->mac_op) | 2308 | if (old_mac_op == efx->mac_op) |
2305 | return 0; | 2309 | goto out; |
2306 | 2310 | ||
2307 | EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); | 2311 | EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); |
2308 | /* Not all macs support a mac-level link state */ | 2312 | /* Not all macs support a mac-level link state */ |
2309 | efx->mac_up = true; | 2313 | efx->mac_up = true; |
2310 | 2314 | ||
2311 | return falcon_reset_macs(efx); | 2315 | rc = falcon_reset_macs(efx); |
2316 | out: | ||
2317 | efx_stats_enable(efx); | ||
2318 | return rc; | ||
2312 | } | 2319 | } |
2313 | 2320 | ||
2314 | /* This call is responsible for hooking in the MAC and PHY operations */ | 2321 | /* This call is responsible for hooking in the MAC and PHY operations */ |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 8eb411a1c82e..e019ad1fb9a0 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -754,8 +754,7 @@ union efx_multicast_hash { | |||
754 | * &struct net_device_stats. | 754 | * &struct net_device_stats. |
755 | * @stats_buffer: DMA buffer for statistics | 755 | * @stats_buffer: DMA buffer for statistics |
756 | * @stats_lock: Statistics update lock. Serialises statistics fetches | 756 | * @stats_lock: Statistics update lock. Serialises statistics fetches |
757 | * @stats_enabled: Temporarily disable statistics fetches. | 757 | * @stats_disable_count: Nest count for disabling statistics fetches |
758 | * Serialised by @stats_lock | ||
759 | * @mac_op: MAC interface | 758 | * @mac_op: MAC interface |
760 | * @mac_address: Permanent MAC address | 759 | * @mac_address: Permanent MAC address |
761 | * @phy_type: PHY type | 760 | * @phy_type: PHY type |
@@ -837,7 +836,7 @@ struct efx_nic { | |||
837 | struct efx_mac_stats mac_stats; | 836 | struct efx_mac_stats mac_stats; |
838 | struct efx_buffer stats_buffer; | 837 | struct efx_buffer stats_buffer; |
839 | spinlock_t stats_lock; | 838 | spinlock_t stats_lock; |
840 | bool stats_enabled; | 839 | unsigned int stats_disable_count; |
841 | 840 | ||
842 | struct efx_mac_operations *mac_op; | 841 | struct efx_mac_operations *mac_op; |
843 | unsigned char mac_address[ETH_ALEN]; | 842 | unsigned char mac_address[ETH_ALEN]; |
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 853057e87fb2..cb25ae5b257a 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c | |||
@@ -235,12 +235,18 @@ static ssize_t set_phy_flash_cfg(struct device *dev, | |||
235 | } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { | 235 | } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { |
236 | err = -EBUSY; | 236 | err = -EBUSY; |
237 | } else { | 237 | } else { |
238 | /* Reset the PHY, reconfigure the MAC and enable/disable | ||
239 | * MAC stats accordingly. */ | ||
238 | efx->phy_mode = new_mode; | 240 | efx->phy_mode = new_mode; |
241 | if (new_mode & PHY_MODE_SPECIAL) | ||
242 | efx_stats_disable(efx); | ||
239 | if (efx->board_info.type == EFX_BOARD_SFE4001) | 243 | if (efx->board_info.type == EFX_BOARD_SFE4001) |
240 | err = sfe4001_poweron(efx); | 244 | err = sfe4001_poweron(efx); |
241 | else | 245 | else |
242 | err = sfn4111t_reset(efx); | 246 | err = sfn4111t_reset(efx); |
243 | efx_reconfigure_port(efx); | 247 | efx_reconfigure_port(efx); |
248 | if (!(new_mode & PHY_MODE_SPECIAL)) | ||
249 | efx_stats_enable(efx); | ||
244 | } | 250 | } |
245 | rtnl_unlock(); | 251 | rtnl_unlock(); |
246 | 252 | ||
@@ -329,6 +335,11 @@ int sfe4001_init(struct efx_nic *efx) | |||
329 | efx->board_info.monitor = sfe4001_check_hw; | 335 | efx->board_info.monitor = sfe4001_check_hw; |
330 | efx->board_info.fini = sfe4001_fini; | 336 | efx->board_info.fini = sfe4001_fini; |
331 | 337 | ||
338 | if (efx->phy_mode & PHY_MODE_SPECIAL) { | ||
339 | /* PHY won't generate a 156.25 MHz clock and MAC stats fetch | ||
340 | * will fail. */ | ||
341 | efx_stats_disable(efx); | ||
342 | } | ||
332 | rc = sfe4001_poweron(efx); | 343 | rc = sfe4001_poweron(efx); |
333 | if (rc) | 344 | if (rc) |
334 | goto fail_ioexp; | 345 | goto fail_ioexp; |
@@ -405,8 +416,10 @@ int sfn4111t_init(struct efx_nic *efx) | |||
405 | if (rc) | 416 | if (rc) |
406 | goto fail_hwmon; | 417 | goto fail_hwmon; |
407 | 418 | ||
408 | if (efx->phy_mode & PHY_MODE_SPECIAL) | 419 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
420 | efx_stats_disable(efx); | ||
409 | sfn4111t_reset(efx); | 421 | sfn4111t_reset(efx); |
422 | } | ||
410 | 423 | ||
411 | return 0; | 424 | return 0; |
412 | 425 | ||
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 412d209d8313..f0efd246962c 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -370,8 +370,8 @@ static int tenxpress_special_reset(struct efx_nic *efx) | |||
370 | 370 | ||
371 | /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so | 371 | /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so |
372 | * a special software reset can glitch the XGMAC sufficiently for stats | 372 | * a special software reset can glitch the XGMAC sufficiently for stats |
373 | * requests to fail. Since we don't often special_reset, just lock. */ | 373 | * requests to fail. */ |
374 | spin_lock(&efx->stats_lock); | 374 | efx_stats_disable(efx); |
375 | 375 | ||
376 | /* Initiate reset */ | 376 | /* Initiate reset */ |
377 | reg = mdio_clause45_read(efx, efx->mii.phy_id, | 377 | reg = mdio_clause45_read(efx, efx->mii.phy_id, |
@@ -386,17 +386,17 @@ static int tenxpress_special_reset(struct efx_nic *efx) | |||
386 | rc = mdio_clause45_wait_reset_mmds(efx, | 386 | rc = mdio_clause45_wait_reset_mmds(efx, |
387 | TENXPRESS_REQUIRED_DEVS); | 387 | TENXPRESS_REQUIRED_DEVS); |
388 | if (rc < 0) | 388 | if (rc < 0) |
389 | goto unlock; | 389 | goto out; |
390 | 390 | ||
391 | /* Try and reconfigure the device */ | 391 | /* Try and reconfigure the device */ |
392 | rc = tenxpress_init(efx); | 392 | rc = tenxpress_init(efx); |
393 | if (rc < 0) | 393 | if (rc < 0) |
394 | goto unlock; | 394 | goto out; |
395 | 395 | ||
396 | /* Wait for the XGXS state machine to churn */ | 396 | /* Wait for the XGXS state machine to churn */ |
397 | mdelay(10); | 397 | mdelay(10); |
398 | unlock: | 398 | out: |
399 | spin_unlock(&efx->stats_lock); | 399 | efx_stats_enable(efx); |
400 | return rc; | 400 | return rc; |
401 | } | 401 | } |
402 | 402 | ||