Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ben Hutchings and committed by
David S. Miller
1974cc20 af4ad9bc

+57 -25
+22 -11
drivers/net/sfc/efx.c
··· 685 685 efx->mac_op->reconfigure(efx); 686 686 687 687 efx->port_initialized = true; 688 - efx->stats_enabled = true; 688 + efx_stats_enable(efx); 689 689 return 0; 690 690 691 691 fail: ··· 734 734 if (!efx->port_initialized) 735 735 return; 736 736 737 + efx_stats_disable(efx); 737 738 efx->phy_op->fini(efx); 738 739 efx->port_initialized = false; 739 740 ··· 1361 1360 return 0; 1362 1361 } 1363 1362 1363 + void efx_stats_disable(struct efx_nic *efx) 1364 + { 1365 + spin_lock(&efx->stats_lock); 1366 + ++efx->stats_disable_count; 1367 + spin_unlock(&efx->stats_lock); 1368 + } 1369 + 1370 + void efx_stats_enable(struct efx_nic *efx) 1371 + { 1372 + spin_lock(&efx->stats_lock); 1373 + --efx->stats_disable_count; 1374 + spin_unlock(&efx->stats_lock); 1375 + } 1376 + 1364 1377 /* Context: process, dev_base_lock or RTNL held, non-blocking. */ 1365 1378 static struct net_device_stats *efx_net_stats(struct net_device *net_dev) 1366 1379 { ··· 1383 1368 struct net_device_stats *stats = &net_dev->stats; 1384 1369 1385 1370 /* Update stats if possible, but do not wait if another thread 1386 - * is updating them (or resetting the NIC); slightly stale 1387 - * stats are acceptable. 1371 + * is updating them or if MAC stats fetches are temporarily 1372 + * disabled; slightly stale stats are acceptable. 1388 1373 */ 1389 1374 if (!spin_trylock(&efx->stats_lock)) 1390 1375 return stats; 1391 - if (efx->stats_enabled) { 1376 + if (!efx->stats_disable_count) { 1392 1377 efx->mac_op->update_stats(efx); 1393 1378 falcon_update_nic_stats(efx); 1394 1379 } ··· 1641 1626 { 1642 1627 EFX_ASSERT_RESET_SERIALISED(efx); 1643 1628 1644 - /* The net_dev->get_stats handler is quite slow, and will fail 1645 - * if a fetch is pending over reset. Serialise against it. */ 1646 - spin_lock(&efx->stats_lock); 1647 - efx->stats_enabled = false; 1648 - spin_unlock(&efx->stats_lock); 1649 - 1629 + efx_stats_disable(efx); 1650 1630 efx_stop_all(efx); 1651 1631 mutex_lock(&efx->mac_lock); 1652 1632 mutex_lock(&efx->spi_lock); ··· 1692 1682 1693 1683 if (ok) { 1694 1684 efx_start_all(efx); 1695 - efx->stats_enabled = true; 1685 + efx_stats_enable(efx); 1696 1686 } 1697 1687 return rc; 1698 1688 } ··· 1898 1888 efx->rx_checksum_enabled = true; 1899 1889 spin_lock_init(&efx->netif_stop_lock); 1900 1890 spin_lock_init(&efx->stats_lock); 1891 + efx->stats_disable_count = 1; 1901 1892 mutex_init(&efx->mac_lock); 1902 1893 efx->mac_op = &efx_dummy_mac_operations; 1903 1894 efx->phy_op = &efx_dummy_phy_operations;
+2
drivers/net/sfc/efx.h
··· 36 36 extern void efx_flush_queues(struct efx_nic *efx); 37 37 38 38 /* Ports */ 39 + extern void efx_stats_disable(struct efx_nic *efx); 40 + extern void efx_stats_enable(struct efx_nic *efx); 39 41 extern void efx_reconfigure_port(struct efx_nic *efx); 40 42 extern void __efx_reconfigure_port(struct efx_nic *efx); 41 43
+11 -4
drivers/net/sfc/falcon.c
··· 1883 1883 1884 1884 /* MAC stats will fail whilst the TX fifo is draining. Serialise 1885 1885 * the drain sequence with the statistics fetch */ 1886 - spin_lock(&efx->stats_lock); 1886 + efx_stats_disable(efx); 1887 1887 1888 1888 falcon_read(efx, &reg, MAC0_CTRL_REG_KER); 1889 1889 EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); ··· 1913 1913 udelay(10); 1914 1914 } 1915 1915 1916 - spin_unlock(&efx->stats_lock); 1916 + efx_stats_enable(efx); 1917 1917 1918 1918 /* If we've reset the EM block and the link is up, then 1919 1919 * we'll have to kick the XAUI link so the PHY can recover */ ··· 2273 2273 struct efx_mac_operations *old_mac_op = efx->mac_op; 2274 2274 efx_oword_t nic_stat; 2275 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 2281 /* Internal loopbacks override the phy speed setting */ 2278 2282 if (efx->loopback_mode == LOOPBACK_GMAC) { ··· 2306 2302 } 2307 2303 2308 2304 if (old_mac_op == efx->mac_op) 2309 - return 0; 2305 + goto out; 2310 2306 2311 2307 EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); 2312 2308 /* Not all macs support a mac-level link state */ 2313 2309 efx->mac_up = true; 2314 2310 2315 - return falcon_reset_macs(efx); 2311 + rc = falcon_reset_macs(efx); 2312 + out: 2313 + efx_stats_enable(efx); 2314 + return rc; 2316 2315 } 2317 2316 2318 2317 /* This call is responsible for hooking in the MAC and PHY operations */
+2 -3
drivers/net/sfc/net_driver.h
··· 754 754 * &struct net_device_stats. 755 755 * @stats_buffer: DMA buffer for statistics 756 756 * @stats_lock: Statistics update lock. Serialises statistics fetches 757 - * @stats_enabled: Temporarily disable statistics fetches. 758 - * Serialised by @stats_lock 757 + * @stats_disable_count: Nest count for disabling statistics fetches 759 758 * @mac_op: MAC interface 760 759 * @mac_address: Permanent MAC address 761 760 * @phy_type: PHY type ··· 836 837 struct efx_mac_stats mac_stats; 837 838 struct efx_buffer stats_buffer; 838 839 spinlock_t stats_lock; 839 - bool stats_enabled; 840 + unsigned int stats_disable_count; 840 841 841 842 struct efx_mac_operations *mac_op; 842 843 unsigned char mac_address[ETH_ALEN];
+14 -1
drivers/net/sfc/sfe4001.c
··· 235 235 } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { 236 236 err = -EBUSY; 237 237 } else { 238 + /* Reset the PHY, reconfigure the MAC and enable/disable 239 + * MAC stats accordingly. */ 238 240 efx->phy_mode = new_mode; 241 + if (new_mode & PHY_MODE_SPECIAL) 242 + efx_stats_disable(efx); 239 243 if (efx->board_info.type == EFX_BOARD_SFE4001) 240 244 err = sfe4001_poweron(efx); 241 245 else 242 246 err = sfn4111t_reset(efx); 243 247 efx_reconfigure_port(efx); 248 + if (!(new_mode & PHY_MODE_SPECIAL)) 249 + efx_stats_enable(efx); 244 250 } 245 251 rtnl_unlock(); 246 252 ··· 335 329 efx->board_info.monitor = sfe4001_check_hw; 336 330 efx->board_info.fini = sfe4001_fini; 337 331 332 + if (efx->phy_mode & PHY_MODE_SPECIAL) { 333 + /* PHY won't generate a 156.25 MHz clock and MAC stats fetch 334 + * will fail. */ 335 + efx_stats_disable(efx); 336 + } 338 337 rc = sfe4001_poweron(efx); 339 338 if (rc) 340 339 goto fail_ioexp; ··· 416 405 if (rc) 417 406 goto fail_hwmon; 418 407 419 - if (efx->phy_mode & PHY_MODE_SPECIAL) 408 + if (efx->phy_mode & PHY_MODE_SPECIAL) { 409 + efx_stats_disable(efx); 420 410 sfn4111t_reset(efx); 411 + } 421 412 422 413 return 0; 423 414
+6 -6
drivers/net/sfc/tenxpress.c
··· 370 370 371 371 /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so 372 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. */ 374 - spin_lock(&efx->stats_lock); 373 + * requests to fail. */ 374 + efx_stats_disable(efx); 375 375 376 376 /* Initiate reset */ 377 377 reg = mdio_clause45_read(efx, efx->mii.phy_id, ··· 386 386 rc = mdio_clause45_wait_reset_mmds(efx, 387 387 TENXPRESS_REQUIRED_DEVS); 388 388 if (rc < 0) 389 - goto unlock; 389 + goto out; 390 390 391 391 /* Try and reconfigure the device */ 392 392 rc = tenxpress_init(efx); 393 393 if (rc < 0) 394 - goto unlock; 394 + goto out; 395 395 396 396 /* Wait for the XGXS state machine to churn */ 397 397 mdelay(10); 398 - unlock: 399 - spin_unlock(&efx->stats_lock); 398 + out: 399 + efx_stats_enable(efx); 400 400 return rc; 401 401 } 402 402