diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-09-01 07:49:02 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-09-03 09:53:48 -0400 |
commit | 8c8661e4cefdd1ddbfe7d5120f046694555d9e5c (patch) | |
tree | 0618e0392140bccadf012381e64a795dfe2e41a4 /drivers/net/sfc | |
parent | a515089c963b045f65c495cee1d344d8cb75e1d1 (diff) |
sfc: Extend self-tests
Include PMA/PMD in loopback self-tests as intended.
Add NVRAM checksum validation and include it in self-tests.
Add register self-tests.
Run PHY self-tests where available.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/bitfield.h | 19 | ||||
-rw-r--r-- | drivers/net/sfc/efx.c | 20 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 6 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 22 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 198 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.h | 6 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_hwdefs.h | 4 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 14 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 16 | ||||
-rw-r--r-- | drivers/net/sfc/selftest.c | 277 | ||||
-rw-r--r-- | drivers/net/sfc/selftest.h | 9 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 22 |
12 files changed, 429 insertions, 184 deletions
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index b757a39f078e..d95c21828014 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h | |||
@@ -416,12 +416,23 @@ typedef union efx_oword { | |||
416 | * for read-modify-write operations. | 416 | * for read-modify-write operations. |
417 | * | 417 | * |
418 | */ | 418 | */ |
419 | |||
420 | #define EFX_INVERT_OWORD(oword) do { \ | 419 | #define EFX_INVERT_OWORD(oword) do { \ |
421 | (oword).u64[0] = ~((oword).u64[0]); \ | 420 | (oword).u64[0] = ~((oword).u64[0]); \ |
422 | (oword).u64[1] = ~((oword).u64[1]); \ | 421 | (oword).u64[1] = ~((oword).u64[1]); \ |
423 | } while (0) | 422 | } while (0) |
424 | 423 | ||
424 | #define EFX_AND_OWORD(oword, from, mask) \ | ||
425 | do { \ | ||
426 | (oword).u64[0] = (from).u64[0] & (mask).u64[0]; \ | ||
427 | (oword).u64[1] = (from).u64[1] & (mask).u64[1]; \ | ||
428 | } while (0) | ||
429 | |||
430 | #define EFX_OR_OWORD(oword, from, mask) \ | ||
431 | do { \ | ||
432 | (oword).u64[0] = (from).u64[0] | (mask).u64[0]; \ | ||
433 | (oword).u64[1] = (from).u64[1] | (mask).u64[1]; \ | ||
434 | } while (0) | ||
435 | |||
425 | #define EFX_INSERT64(min, max, low, high, value) \ | 436 | #define EFX_INSERT64(min, max, low, high, value) \ |
426 | cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value)) | 437 | cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value)) |
427 | 438 | ||
@@ -529,4 +540,10 @@ typedef union efx_oword { | |||
529 | #define EFX_DMA_TYPE_WIDTH(width) \ | 540 | #define EFX_DMA_TYPE_WIDTH(width) \ |
530 | (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH) | 541 | (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH) |
531 | 542 | ||
543 | |||
544 | /* Static initialiser */ | ||
545 | #define EFX_OWORD32(a, b, c, d) \ | ||
546 | { .u32 = { __constant_cpu_to_le32(a), __constant_cpu_to_le32(b), \ | ||
547 | __constant_cpu_to_le32(c), __constant_cpu_to_le32(d) } } | ||
548 | |||
532 | #endif /* EFX_BITFIELD_H */ | 549 | #endif /* EFX_BITFIELD_H */ |
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f34dbf2c5b69..e1e2f8060563 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -508,6 +508,11 @@ static void efx_link_status_changed(struct efx_nic *efx) | |||
508 | if (!netif_running(efx->net_dev)) | 508 | if (!netif_running(efx->net_dev)) |
509 | return; | 509 | return; |
510 | 510 | ||
511 | if (efx->port_inhibited) { | ||
512 | netif_carrier_off(efx->net_dev); | ||
513 | return; | ||
514 | } | ||
515 | |||
511 | if (efx->link_up != netif_carrier_ok(efx->net_dev)) { | 516 | if (efx->link_up != netif_carrier_ok(efx->net_dev)) { |
512 | efx->n_link_state_changes++; | 517 | efx->n_link_state_changes++; |
513 | 518 | ||
@@ -549,7 +554,7 @@ static void efx_link_status_changed(struct efx_nic *efx) | |||
549 | 554 | ||
550 | /* This call reinitialises the MAC to pick up new PHY settings. The | 555 | /* This call reinitialises the MAC to pick up new PHY settings. The |
551 | * caller must hold the mac_lock */ | 556 | * caller must hold the mac_lock */ |
552 | static void __efx_reconfigure_port(struct efx_nic *efx) | 557 | void __efx_reconfigure_port(struct efx_nic *efx) |
553 | { | 558 | { |
554 | WARN_ON(!mutex_is_locked(&efx->mac_lock)); | 559 | WARN_ON(!mutex_is_locked(&efx->mac_lock)); |
555 | 560 | ||
@@ -634,6 +639,7 @@ static int efx_init_port(struct efx_nic *efx) | |||
634 | return rc; | 639 | return rc; |
635 | 640 | ||
636 | efx->port_initialized = true; | 641 | efx->port_initialized = true; |
642 | efx->stats_enabled = true; | ||
637 | 643 | ||
638 | /* Reconfigure port to program MAC registers */ | 644 | /* Reconfigure port to program MAC registers */ |
639 | falcon_reconfigure_xmac(efx); | 645 | falcon_reconfigure_xmac(efx); |
@@ -1311,7 +1317,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) | |||
1311 | */ | 1317 | */ |
1312 | if (!spin_trylock(&efx->stats_lock)) | 1318 | if (!spin_trylock(&efx->stats_lock)) |
1313 | return stats; | 1319 | return stats; |
1314 | if (efx->state == STATE_RUNNING) { | 1320 | if (efx->stats_enabled) { |
1315 | falcon_update_stats_xmac(efx); | 1321 | falcon_update_stats_xmac(efx); |
1316 | falcon_update_nic_stats(efx); | 1322 | falcon_update_nic_stats(efx); |
1317 | } | 1323 | } |
@@ -1529,7 +1535,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) | |||
1529 | 1535 | ||
1530 | /* Tears down the entire software state and most of the hardware state | 1536 | /* Tears down the entire software state and most of the hardware state |
1531 | * before reset. */ | 1537 | * before reset. */ |
1532 | static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) | 1538 | void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) |
1533 | { | 1539 | { |
1534 | int rc; | 1540 | int rc; |
1535 | 1541 | ||
@@ -1538,6 +1544,7 @@ static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) | |||
1538 | /* The net_dev->get_stats handler is quite slow, and will fail | 1544 | /* The net_dev->get_stats handler is quite slow, and will fail |
1539 | * if a fetch is pending over reset. Serialise against it. */ | 1545 | * if a fetch is pending over reset. Serialise against it. */ |
1540 | spin_lock(&efx->stats_lock); | 1546 | spin_lock(&efx->stats_lock); |
1547 | efx->stats_enabled = false; | ||
1541 | spin_unlock(&efx->stats_lock); | 1548 | spin_unlock(&efx->stats_lock); |
1542 | 1549 | ||
1543 | efx_stop_all(efx); | 1550 | efx_stop_all(efx); |
@@ -1555,8 +1562,7 @@ static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) | |||
1555 | * that we were unable to reinitialise the hardware, and the | 1562 | * that we were unable to reinitialise the hardware, and the |
1556 | * driver should be disabled. If ok is false, then the rx and tx | 1563 | * driver should be disabled. If ok is false, then the rx and tx |
1557 | * engines are not restarted, pending a RESET_DISABLE. */ | 1564 | * engines are not restarted, pending a RESET_DISABLE. */ |
1558 | static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, | 1565 | int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) |
1559 | bool ok) | ||
1560 | { | 1566 | { |
1561 | int rc; | 1567 | int rc; |
1562 | 1568 | ||
@@ -1577,8 +1583,10 @@ static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, | |||
1577 | 1583 | ||
1578 | mutex_unlock(&efx->mac_lock); | 1584 | mutex_unlock(&efx->mac_lock); |
1579 | 1585 | ||
1580 | if (ok) | 1586 | if (ok) { |
1581 | efx_start_all(efx); | 1587 | efx_start_all(efx); |
1588 | efx->stats_enabled = true; | ||
1589 | } | ||
1582 | return rc; | 1590 | return rc; |
1583 | } | 1591 | } |
1584 | 1592 | ||
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 9a8c283fa883..d02937b70eee 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h | |||
@@ -37,6 +37,12 @@ extern void efx_flush_queues(struct efx_nic *efx); | |||
37 | 37 | ||
38 | /* Ports */ | 38 | /* Ports */ |
39 | extern void efx_reconfigure_port(struct efx_nic *efx); | 39 | extern void efx_reconfigure_port(struct efx_nic *efx); |
40 | extern void __efx_reconfigure_port(struct efx_nic *efx); | ||
41 | |||
42 | /* Reset handling */ | ||
43 | extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd); | ||
44 | extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, | ||
45 | bool ok); | ||
40 | 46 | ||
41 | /* Global */ | 47 | /* Global */ |
42 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); | 48 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); |
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 79894160a9a4..fa98af58223e 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -333,7 +333,10 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, | |||
333 | unsigned int n = 0; | 333 | unsigned int n = 0; |
334 | enum efx_loopback_mode mode; | 334 | enum efx_loopback_mode mode; |
335 | 335 | ||
336 | /* Interrupt */ | 336 | efx_fill_test(n++, strings, data, &tests->mii, |
337 | "core", 0, "mii", NULL); | ||
338 | efx_fill_test(n++, strings, data, &tests->nvram, | ||
339 | "core", 0, "nvram", NULL); | ||
337 | efx_fill_test(n++, strings, data, &tests->interrupt, | 340 | efx_fill_test(n++, strings, data, &tests->interrupt, |
338 | "core", 0, "interrupt", NULL); | 341 | "core", 0, "interrupt", NULL); |
339 | 342 | ||
@@ -353,16 +356,17 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, | |||
353 | "eventq.poll", NULL); | 356 | "eventq.poll", NULL); |
354 | } | 357 | } |
355 | 358 | ||
356 | /* PHY presence */ | 359 | efx_fill_test(n++, strings, data, &tests->registers, |
357 | efx_fill_test(n++, strings, data, &tests->phy_ok, | 360 | "core", 0, "registers", NULL); |
358 | EFX_PORT_NAME, "phy_ok", NULL); | 361 | efx_fill_test(n++, strings, data, &tests->phy, |
362 | EFX_PORT_NAME, "phy", NULL); | ||
359 | 363 | ||
360 | /* Loopback tests */ | 364 | /* Loopback tests */ |
361 | efx_fill_test(n++, strings, data, &tests->loopback_speed, | 365 | efx_fill_test(n++, strings, data, &tests->loopback_speed, |
362 | EFX_PORT_NAME, "loopback.speed", NULL); | 366 | EFX_PORT_NAME, "loopback.speed", NULL); |
363 | efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, | 367 | efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, |
364 | EFX_PORT_NAME, "loopback.full_duplex", NULL); | 368 | EFX_PORT_NAME, "loopback.full_duplex", NULL); |
365 | for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { | 369 | for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { |
366 | if (!(efx->loopback_modes & (1 << mode))) | 370 | if (!(efx->loopback_modes & (1 << mode))) |
367 | continue; | 371 | continue; |
368 | n = efx_fill_loopback_test(efx, | 372 | n = efx_fill_loopback_test(efx, |
@@ -500,15 +504,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev, | |||
500 | goto out; | 504 | goto out; |
501 | 505 | ||
502 | /* Perform offline tests only if online tests passed */ | 506 | /* Perform offline tests only if online tests passed */ |
503 | if (offline) { | 507 | if (offline) |
504 | /* Stop the kernel from sending packets during the test. */ | ||
505 | efx_stop_queue(efx); | ||
506 | efx_flush_queues(efx); | ||
507 | |||
508 | rc = efx_offline_test(efx, &efx_tests, | 508 | rc = efx_offline_test(efx, &efx_tests, |
509 | efx->loopback_modes); | 509 | efx->loopback_modes); |
510 | efx_wake_queue(efx); | ||
511 | } | ||
512 | 510 | ||
513 | out: | 511 | out: |
514 | if (!already_up) | 512 | if (!already_up) |
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index e66d6cf03adc..e0c0b23f94ef 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -2223,6 +2223,170 @@ void falcon_set_multicast_hash(struct efx_nic *efx) | |||
2223 | falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); | 2223 | falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); |
2224 | } | 2224 | } |
2225 | 2225 | ||
2226 | |||
2227 | /************************************************************************** | ||
2228 | * | ||
2229 | * Falcon test code | ||
2230 | * | ||
2231 | **************************************************************************/ | ||
2232 | |||
2233 | int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) | ||
2234 | { | ||
2235 | struct falcon_nvconfig *nvconfig; | ||
2236 | struct efx_spi_device *spi; | ||
2237 | void *region; | ||
2238 | int rc, magic_num, struct_ver; | ||
2239 | __le16 *word, *limit; | ||
2240 | u32 csum; | ||
2241 | |||
2242 | region = kmalloc(NVCONFIG_END, GFP_KERNEL); | ||
2243 | if (!region) | ||
2244 | return -ENOMEM; | ||
2245 | nvconfig = region + NVCONFIG_OFFSET; | ||
2246 | |||
2247 | spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; | ||
2248 | rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region); | ||
2249 | if (rc) { | ||
2250 | EFX_ERR(efx, "Failed to read %s\n", | ||
2251 | efx->spi_flash ? "flash" : "EEPROM"); | ||
2252 | rc = -EIO; | ||
2253 | goto out; | ||
2254 | } | ||
2255 | |||
2256 | magic_num = le16_to_cpu(nvconfig->board_magic_num); | ||
2257 | struct_ver = le16_to_cpu(nvconfig->board_struct_ver); | ||
2258 | |||
2259 | rc = -EINVAL; | ||
2260 | if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) { | ||
2261 | EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num); | ||
2262 | goto out; | ||
2263 | } | ||
2264 | if (struct_ver < 2) { | ||
2265 | EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver); | ||
2266 | goto out; | ||
2267 | } else if (struct_ver < 4) { | ||
2268 | word = &nvconfig->board_magic_num; | ||
2269 | limit = (__le16 *) (nvconfig + 1); | ||
2270 | } else { | ||
2271 | word = region; | ||
2272 | limit = region + NVCONFIG_END; | ||
2273 | } | ||
2274 | for (csum = 0; word < limit; ++word) | ||
2275 | csum += le16_to_cpu(*word); | ||
2276 | |||
2277 | if (~csum & 0xffff) { | ||
2278 | EFX_ERR(efx, "NVRAM has incorrect checksum\n"); | ||
2279 | goto out; | ||
2280 | } | ||
2281 | |||
2282 | rc = 0; | ||
2283 | if (nvconfig_out) | ||
2284 | memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig)); | ||
2285 | |||
2286 | out: | ||
2287 | kfree(region); | ||
2288 | return rc; | ||
2289 | } | ||
2290 | |||
2291 | /* Registers tested in the falcon register test */ | ||
2292 | static struct { | ||
2293 | unsigned address; | ||
2294 | efx_oword_t mask; | ||
2295 | } efx_test_registers[] = { | ||
2296 | { ADR_REGION_REG_KER, | ||
2297 | EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, | ||
2298 | { RX_CFG_REG_KER, | ||
2299 | EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, | ||
2300 | { TX_CFG_REG_KER, | ||
2301 | EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, | ||
2302 | { TX_CFG2_REG_KER, | ||
2303 | EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, | ||
2304 | { MAC0_CTRL_REG_KER, | ||
2305 | EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, | ||
2306 | { SRM_TX_DC_CFG_REG_KER, | ||
2307 | EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, | ||
2308 | { RX_DC_CFG_REG_KER, | ||
2309 | EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, | ||
2310 | { RX_DC_PF_WM_REG_KER, | ||
2311 | EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, | ||
2312 | { DP_CTRL_REG, | ||
2313 | EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, | ||
2314 | { XM_GLB_CFG_REG, | ||
2315 | EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, | ||
2316 | { XM_TX_CFG_REG, | ||
2317 | EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, | ||
2318 | { XM_RX_CFG_REG, | ||
2319 | EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, | ||
2320 | { XM_RX_PARAM_REG, | ||
2321 | EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, | ||
2322 | { XM_FC_REG, | ||
2323 | EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, | ||
2324 | { XM_ADR_LO_REG, | ||
2325 | EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, | ||
2326 | { XX_SD_CTL_REG, | ||
2327 | EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, | ||
2328 | }; | ||
2329 | |||
2330 | static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, | ||
2331 | const efx_oword_t *mask) | ||
2332 | { | ||
2333 | return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || | ||
2334 | ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); | ||
2335 | } | ||
2336 | |||
2337 | int falcon_test_registers(struct efx_nic *efx) | ||
2338 | { | ||
2339 | unsigned address = 0, i, j; | ||
2340 | efx_oword_t mask, imask, original, reg, buf; | ||
2341 | |||
2342 | /* Falcon should be in loopback to isolate the XMAC from the PHY */ | ||
2343 | WARN_ON(!LOOPBACK_INTERNAL(efx)); | ||
2344 | |||
2345 | for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { | ||
2346 | address = efx_test_registers[i].address; | ||
2347 | mask = imask = efx_test_registers[i].mask; | ||
2348 | EFX_INVERT_OWORD(imask); | ||
2349 | |||
2350 | falcon_read(efx, &original, address); | ||
2351 | |||
2352 | /* bit sweep on and off */ | ||
2353 | for (j = 0; j < 128; j++) { | ||
2354 | if (!EFX_EXTRACT_OWORD32(mask, j, j)) | ||
2355 | continue; | ||
2356 | |||
2357 | /* Test this testable bit can be set in isolation */ | ||
2358 | EFX_AND_OWORD(reg, original, mask); | ||
2359 | EFX_SET_OWORD32(reg, j, j, 1); | ||
2360 | |||
2361 | falcon_write(efx, ®, address); | ||
2362 | falcon_read(efx, &buf, address); | ||
2363 | |||
2364 | if (efx_masked_compare_oword(®, &buf, &mask)) | ||
2365 | goto fail; | ||
2366 | |||
2367 | /* Test this testable bit can be cleared in isolation */ | ||
2368 | EFX_OR_OWORD(reg, original, mask); | ||
2369 | EFX_SET_OWORD32(reg, j, j, 0); | ||
2370 | |||
2371 | falcon_write(efx, ®, address); | ||
2372 | falcon_read(efx, &buf, address); | ||
2373 | |||
2374 | if (efx_masked_compare_oword(®, &buf, &mask)) | ||
2375 | goto fail; | ||
2376 | } | ||
2377 | |||
2378 | falcon_write(efx, &original, address); | ||
2379 | } | ||
2380 | |||
2381 | return 0; | ||
2382 | |||
2383 | fail: | ||
2384 | EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT | ||
2385 | " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), | ||
2386 | EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); | ||
2387 | return -EIO; | ||
2388 | } | ||
2389 | |||
2226 | /************************************************************************** | 2390 | /************************************************************************** |
2227 | * | 2391 | * |
2228 | * Device reset | 2392 | * Device reset |
@@ -2404,37 +2568,22 @@ static void falcon_remove_spi_devices(struct efx_nic *efx) | |||
2404 | static int falcon_probe_nvconfig(struct efx_nic *efx) | 2568 | static int falcon_probe_nvconfig(struct efx_nic *efx) |
2405 | { | 2569 | { |
2406 | struct falcon_nvconfig *nvconfig; | 2570 | struct falcon_nvconfig *nvconfig; |
2407 | struct efx_spi_device *spi; | 2571 | int board_rev; |
2408 | int magic_num, struct_ver, board_rev; | ||
2409 | int rc; | 2572 | int rc; |
2410 | 2573 | ||
2411 | nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); | 2574 | nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); |
2412 | if (!nvconfig) | 2575 | if (!nvconfig) |
2413 | return -ENOMEM; | 2576 | return -ENOMEM; |
2414 | 2577 | ||
2415 | /* Read the whole configuration structure into memory. */ | 2578 | rc = falcon_read_nvram(efx, nvconfig); |
2416 | spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; | 2579 | if (rc == -EINVAL) { |
2417 | rc = falcon_spi_read(spi, NVCONFIG_BASE, sizeof(*nvconfig), | 2580 | EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); |
2418 | NULL, (char *)nvconfig); | ||
2419 | if (rc) { | ||
2420 | EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" : | ||
2421 | "EEPROM"); | ||
2422 | goto fail1; | ||
2423 | } | ||
2424 | |||
2425 | /* Read the MAC addresses */ | ||
2426 | memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); | ||
2427 | |||
2428 | /* Read the board configuration. */ | ||
2429 | magic_num = le16_to_cpu(nvconfig->board_magic_num); | ||
2430 | struct_ver = le16_to_cpu(nvconfig->board_struct_ver); | ||
2431 | |||
2432 | if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) { | ||
2433 | EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x " | ||
2434 | "therefore using defaults\n", magic_num, struct_ver); | ||
2435 | efx->phy_type = PHY_TYPE_NONE; | 2581 | efx->phy_type = PHY_TYPE_NONE; |
2436 | efx->mii.phy_id = PHY_ADDR_INVALID; | 2582 | efx->mii.phy_id = PHY_ADDR_INVALID; |
2437 | board_rev = 0; | 2583 | board_rev = 0; |
2584 | rc = 0; | ||
2585 | } else if (rc) { | ||
2586 | goto fail1; | ||
2438 | } else { | 2587 | } else { |
2439 | struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; | 2588 | struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; |
2440 | struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; | 2589 | struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; |
@@ -2443,7 +2592,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) | |||
2443 | efx->mii.phy_id = v2->port0_phy_addr; | 2592 | efx->mii.phy_id = v2->port0_phy_addr; |
2444 | board_rev = le16_to_cpu(v2->board_revision); | 2593 | board_rev = le16_to_cpu(v2->board_revision); |
2445 | 2594 | ||
2446 | if (struct_ver >= 3) { | 2595 | if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { |
2447 | __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; | 2596 | __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; |
2448 | __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; | 2597 | __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; |
2449 | rc = falcon_spi_device_init(efx, &efx->spi_flash, | 2598 | rc = falcon_spi_device_init(efx, &efx->spi_flash, |
@@ -2459,6 +2608,9 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) | |||
2459 | } | 2608 | } |
2460 | } | 2609 | } |
2461 | 2610 | ||
2611 | /* Read the MAC addresses */ | ||
2612 | memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); | ||
2613 | |||
2462 | EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); | 2614 | EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); |
2463 | 2615 | ||
2464 | efx_set_board_info(efx, board_rev); | 2616 | efx_set_board_info(efx, board_rev); |
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 41b388b65996..30d61e48ac60 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h | |||
@@ -93,6 +93,12 @@ extern void falcon_update_nic_stats(struct efx_nic *efx); | |||
93 | extern void falcon_set_multicast_hash(struct efx_nic *efx); | 93 | extern void falcon_set_multicast_hash(struct efx_nic *efx); |
94 | extern int falcon_reset_xaui(struct efx_nic *efx); | 94 | extern int falcon_reset_xaui(struct efx_nic *efx); |
95 | 95 | ||
96 | /* Tests */ | ||
97 | struct falcon_nvconfig; | ||
98 | extern int falcon_read_nvram(struct efx_nic *efx, | ||
99 | struct falcon_nvconfig *nvconfig); | ||
100 | extern int falcon_test_registers(struct efx_nic *efx); | ||
101 | |||
96 | /************************************************************************** | 102 | /************************************************************************** |
97 | * | 103 | * |
98 | * Falcon MAC stats | 104 | * Falcon MAC stats |
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index a3260dfb49a3..e319fd64d07c 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h | |||
@@ -1150,7 +1150,9 @@ struct falcon_nvconfig_board_v3 { | |||
1150 | #define SPI_DEV_TYPE_FIELD(type, field) \ | 1150 | #define SPI_DEV_TYPE_FIELD(type, field) \ |
1151 | (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) | 1151 | (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) |
1152 | 1152 | ||
1153 | #define NVCONFIG_BASE 0x300 | 1153 | #define NVCONFIG_OFFSET 0x300 |
1154 | #define NVCONFIG_END 0x400 | ||
1155 | |||
1154 | #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C | 1156 | #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C |
1155 | struct falcon_nvconfig { | 1157 | struct falcon_nvconfig { |
1156 | efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ | 1158 | efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ |
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index a9ae06a2ae2d..0d9f68ff71e7 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c | |||
@@ -373,17 +373,9 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) | |||
373 | reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || | 373 | reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || |
374 | (xaui_loopback != old_xaui_loopback) || | 374 | (xaui_loopback != old_xaui_loopback) || |
375 | (xgmii_loopback != old_xgmii_loopback)); | 375 | (xgmii_loopback != old_xgmii_loopback)); |
376 | if (reset_xgxs) { | 376 | |
377 | falcon_read(efx, ®, XX_PWR_RST_REG); | 377 | if (reset_xgxs) |
378 | EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1); | 378 | falcon_reset_xaui(efx); |
379 | EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1); | ||
380 | falcon_write(efx, ®, XX_PWR_RST_REG); | ||
381 | udelay(1); | ||
382 | EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0); | ||
383 | EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0); | ||
384 | falcon_write(efx, ®, XX_PWR_RST_REG); | ||
385 | udelay(1); | ||
386 | } | ||
387 | } | 379 | } |
388 | 380 | ||
389 | falcon_read(efx, ®, XX_CORE_STAT_REG); | 381 | falcon_read(efx, ®, XX_CORE_STAT_REG); |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index df863bcc06f8..531d939b574f 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -515,6 +515,7 @@ struct efx_phy_operations { | |||
515 | void (*clear_interrupt) (struct efx_nic *efx); | 515 | void (*clear_interrupt) (struct efx_nic *efx); |
516 | int (*check_hw) (struct efx_nic *efx); | 516 | int (*check_hw) (struct efx_nic *efx); |
517 | void (*reset_xaui) (struct efx_nic *efx); | 517 | void (*reset_xaui) (struct efx_nic *efx); |
518 | int (*test) (struct efx_nic *efx); | ||
518 | int mmds; | 519 | int mmds; |
519 | unsigned loopbacks; | 520 | unsigned loopbacks; |
520 | }; | 521 | }; |
@@ -533,7 +534,7 @@ enum efx_phy_mode { | |||
533 | 534 | ||
534 | static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode) | 535 | static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode) |
535 | { | 536 | { |
536 | return (mode & ~PHY_MODE_TX_DISABLED) != 0; | 537 | return !!(mode & ~PHY_MODE_TX_DISABLED); |
537 | } | 538 | } |
538 | 539 | ||
539 | /* | 540 | /* |
@@ -655,13 +656,14 @@ union efx_multicast_hash { | |||
655 | * This field will be %NULL if no EEPROM device is present. | 656 | * This field will be %NULL if no EEPROM device is present. |
656 | * @n_rx_nodesc_drop_cnt: RX no descriptor drop count | 657 | * @n_rx_nodesc_drop_cnt: RX no descriptor drop count |
657 | * @nic_data: Hardware dependant state | 658 | * @nic_data: Hardware dependant state |
658 | * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and | 659 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, |
659 | * efx_reconfigure_port() | 660 | * @port_inhibited, efx_monitor() and efx_reconfigure_port() |
660 | * @port_enabled: Port enabled indicator. | 661 | * @port_enabled: Port enabled indicator. |
661 | * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and | 662 | * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and |
662 | * efx_reconfigure_work with kernel interfaces. Safe to read under any | 663 | * efx_reconfigure_work with kernel interfaces. Safe to read under any |
663 | * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must | 664 | * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must |
664 | * be held to modify it. | 665 | * be held to modify it. |
666 | * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock | ||
665 | * @port_initialized: Port initialized? | 667 | * @port_initialized: Port initialized? |
666 | * @net_dev: Operating system network device. Consider holding the rtnl lock | 668 | * @net_dev: Operating system network device. Consider holding the rtnl lock |
667 | * @rx_checksum_enabled: RX checksumming enabled | 669 | * @rx_checksum_enabled: RX checksumming enabled |
@@ -671,14 +673,16 @@ union efx_multicast_hash { | |||
671 | * can provide. Generic code converts these into a standard | 673 | * can provide. Generic code converts these into a standard |
672 | * &struct net_device_stats. | 674 | * &struct net_device_stats. |
673 | * @stats_buffer: DMA buffer for statistics | 675 | * @stats_buffer: DMA buffer for statistics |
674 | * @stats_lock: Statistics update lock | 676 | * @stats_lock: Statistics update lock. Serialises statistics fetches |
677 | * @stats_enabled: Temporarily disable statistics fetches. | ||
678 | * Serialised by @stats_lock | ||
675 | * @mac_address: Permanent MAC address | 679 | * @mac_address: Permanent MAC address |
676 | * @phy_type: PHY type | 680 | * @phy_type: PHY type |
677 | * @phy_lock: PHY access lock | 681 | * @phy_lock: PHY access lock |
678 | * @phy_op: PHY interface | 682 | * @phy_op: PHY interface |
679 | * @phy_data: PHY private data (including PHY-specific stats) | 683 | * @phy_data: PHY private data (including PHY-specific stats) |
680 | * @mii: PHY interface | 684 | * @mii: PHY interface |
681 | * @phy_mode: PHY operating mode | 685 | * @phy_mode: PHY operating mode. Serialised by @mac_lock. |
682 | * @link_up: Link status | 686 | * @link_up: Link status |
683 | * @link_options: Link options (MII/GMII format) | 687 | * @link_options: Link options (MII/GMII format) |
684 | * @n_link_state_changes: Number of times the link has changed state | 688 | * @n_link_state_changes: Number of times the link has changed state |
@@ -733,6 +737,7 @@ struct efx_nic { | |||
733 | 737 | ||
734 | struct mutex mac_lock; | 738 | struct mutex mac_lock; |
735 | bool port_enabled; | 739 | bool port_enabled; |
740 | bool port_inhibited; | ||
736 | 741 | ||
737 | bool port_initialized; | 742 | bool port_initialized; |
738 | struct net_device *net_dev; | 743 | struct net_device *net_dev; |
@@ -744,6 +749,7 @@ struct efx_nic { | |||
744 | struct efx_mac_stats mac_stats; | 749 | struct efx_mac_stats mac_stats; |
745 | struct efx_buffer stats_buffer; | 750 | struct efx_buffer stats_buffer; |
746 | spinlock_t stats_lock; | 751 | spinlock_t stats_lock; |
752 | bool stats_enabled; | ||
747 | 753 | ||
748 | unsigned char mac_address[ETH_ALEN]; | 754 | unsigned char mac_address[ETH_ALEN]; |
749 | 755 | ||
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 2f7def657679..362956e3fe17 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include "boards.h" | 27 | #include "boards.h" |
28 | #include "workarounds.h" | 28 | #include "workarounds.h" |
29 | #include "mac.h" | 29 | #include "mac.h" |
30 | #include "spi.h" | ||
31 | #include "falcon_io.h" | ||
32 | #include "mdio_10g.h" | ||
30 | 33 | ||
31 | /* | 34 | /* |
32 | * Loopback test packet structure | 35 | * Loopback test packet structure |
@@ -51,7 +54,7 @@ static const char *payload_msg = | |||
51 | "Hello world! This is an Efx loopback test in progress!"; | 54 | "Hello world! This is an Efx loopback test in progress!"; |
52 | 55 | ||
53 | /** | 56 | /** |
54 | * efx_selftest_state - persistent state during a selftest | 57 | * efx_loopback_state - persistent state during a loopback selftest |
55 | * @flush: Drop all packets in efx_loopback_rx_packet | 58 | * @flush: Drop all packets in efx_loopback_rx_packet |
56 | * @packet_count: Number of packets being used in this test | 59 | * @packet_count: Number of packets being used in this test |
57 | * @skbs: An array of skbs transmitted | 60 | * @skbs: An array of skbs transmitted |
@@ -59,7 +62,7 @@ static const char *payload_msg = | |||
59 | * @rx_bad: RX bad packet count | 62 | * @rx_bad: RX bad packet count |
60 | * @payload: Payload used in tests | 63 | * @payload: Payload used in tests |
61 | */ | 64 | */ |
62 | struct efx_selftest_state { | 65 | struct efx_loopback_state { |
63 | bool flush; | 66 | bool flush; |
64 | int packet_count; | 67 | int packet_count; |
65 | struct sk_buff **skbs; | 68 | struct sk_buff **skbs; |
@@ -74,21 +77,65 @@ struct efx_selftest_state { | |||
74 | 77 | ||
75 | /************************************************************************** | 78 | /************************************************************************** |
76 | * | 79 | * |
77 | * Configurable values | 80 | * MII, NVRAM and register tests |
78 | * | 81 | * |
79 | **************************************************************************/ | 82 | **************************************************************************/ |
80 | 83 | ||
81 | /* Level of loopback testing | 84 | static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) |
82 | * | 85 | { |
83 | * The maximum packet burst length is 16**(n-1), i.e. | 86 | int rc = 0; |
84 | * | 87 | u16 physid1, physid2; |
85 | * - Level 0 : no packets | 88 | struct mii_if_info *mii = &efx->mii; |
86 | * - Level 1 : 1 packet | 89 | struct net_device *net_dev = efx->net_dev; |
87 | * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets) | 90 | |
88 | * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets) | 91 | if (efx->phy_type == PHY_TYPE_NONE) |
89 | * | 92 | return 0; |
90 | */ | 93 | |
91 | static unsigned int loopback_test_level = 3; | 94 | mutex_lock(&efx->mac_lock); |
95 | tests->mii = -1; | ||
96 | |||
97 | physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); | ||
98 | physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); | ||
99 | |||
100 | if ((physid1 == 0x0000) || (physid1 == 0xffff) || | ||
101 | (physid2 == 0x0000) || (physid2 == 0xffff)) { | ||
102 | EFX_ERR(efx, "no MII PHY present with ID %d\n", | ||
103 | mii->phy_id); | ||
104 | rc = -EINVAL; | ||
105 | goto out; | ||
106 | } | ||
107 | |||
108 | rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); | ||
109 | if (rc) | ||
110 | goto out; | ||
111 | |||
112 | out: | ||
113 | mutex_unlock(&efx->mac_lock); | ||
114 | tests->mii = rc ? -1 : 1; | ||
115 | return rc; | ||
116 | } | ||
117 | |||
118 | static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) | ||
119 | { | ||
120 | int rc; | ||
121 | |||
122 | rc = falcon_read_nvram(efx, NULL); | ||
123 | tests->nvram = rc ? -1 : 1; | ||
124 | return rc; | ||
125 | } | ||
126 | |||
127 | static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) | ||
128 | { | ||
129 | int rc; | ||
130 | |||
131 | /* Not supported on A-series silicon */ | ||
132 | if (falcon_rev(efx) < FALCON_REV_B0) | ||
133 | return 0; | ||
134 | |||
135 | rc = falcon_test_registers(efx); | ||
136 | tests->registers = rc ? -1 : 1; | ||
137 | return rc; | ||
138 | } | ||
92 | 139 | ||
93 | /************************************************************************** | 140 | /************************************************************************** |
94 | * | 141 | * |
@@ -199,39 +246,18 @@ static int efx_test_eventq_irq(struct efx_channel *channel, | |||
199 | return 0; | 246 | return 0; |
200 | } | 247 | } |
201 | 248 | ||
202 | /************************************************************************** | 249 | static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) |
203 | * | ||
204 | * PHY testing | ||
205 | * | ||
206 | **************************************************************************/ | ||
207 | |||
208 | /* Check PHY presence by reading the PHY ID registers */ | ||
209 | static int efx_test_phy(struct efx_nic *efx, | ||
210 | struct efx_self_tests *tests) | ||
211 | { | 250 | { |
212 | u16 physid1, physid2; | 251 | int rc; |
213 | struct mii_if_info *mii = &efx->mii; | ||
214 | struct net_device *net_dev = efx->net_dev; | ||
215 | |||
216 | if (efx->phy_type == PHY_TYPE_NONE) | ||
217 | return 0; | ||
218 | |||
219 | EFX_LOG(efx, "testing PHY presence\n"); | ||
220 | tests->phy_ok = -1; | ||
221 | |||
222 | physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); | ||
223 | physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); | ||
224 | 252 | ||
225 | if ((physid1 != 0x0000) && (physid1 != 0xffff) && | 253 | if (!efx->phy_op->test) |
226 | (physid2 != 0x0000) && (physid2 != 0xffff)) { | ||
227 | EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n", | ||
228 | mii->phy_id, physid1, physid2); | ||
229 | tests->phy_ok = 1; | ||
230 | return 0; | 254 | return 0; |
231 | } | ||
232 | 255 | ||
233 | EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id); | 256 | mutex_lock(&efx->mac_lock); |
234 | return -ENODEV; | 257 | rc = efx->phy_op->test(efx); |
258 | mutex_unlock(&efx->mac_lock); | ||
259 | tests->phy = rc ? -1 : 1; | ||
260 | return rc; | ||
235 | } | 261 | } |
236 | 262 | ||
237 | /************************************************************************** | 263 | /************************************************************************** |
@@ -247,7 +273,7 @@ static int efx_test_phy(struct efx_nic *efx, | |||
247 | void efx_loopback_rx_packet(struct efx_nic *efx, | 273 | void efx_loopback_rx_packet(struct efx_nic *efx, |
248 | const char *buf_ptr, int pkt_len) | 274 | const char *buf_ptr, int pkt_len) |
249 | { | 275 | { |
250 | struct efx_selftest_state *state = efx->loopback_selftest; | 276 | struct efx_loopback_state *state = efx->loopback_selftest; |
251 | struct efx_loopback_payload *received; | 277 | struct efx_loopback_payload *received; |
252 | struct efx_loopback_payload *payload; | 278 | struct efx_loopback_payload *payload; |
253 | 279 | ||
@@ -258,7 +284,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, | |||
258 | return; | 284 | return; |
259 | 285 | ||
260 | payload = &state->payload; | 286 | payload = &state->payload; |
261 | 287 | ||
262 | received = (struct efx_loopback_payload *) buf_ptr; | 288 | received = (struct efx_loopback_payload *) buf_ptr; |
263 | received->ip.saddr = payload->ip.saddr; | 289 | received->ip.saddr = payload->ip.saddr; |
264 | if (state->offload_csum) | 290 | if (state->offload_csum) |
@@ -332,7 +358,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, | |||
332 | /* Initialise an efx_selftest_state for a new iteration */ | 358 | /* Initialise an efx_selftest_state for a new iteration */ |
333 | static void efx_iterate_state(struct efx_nic *efx) | 359 | static void efx_iterate_state(struct efx_nic *efx) |
334 | { | 360 | { |
335 | struct efx_selftest_state *state = efx->loopback_selftest; | 361 | struct efx_loopback_state *state = efx->loopback_selftest; |
336 | struct net_device *net_dev = efx->net_dev; | 362 | struct net_device *net_dev = efx->net_dev; |
337 | struct efx_loopback_payload *payload = &state->payload; | 363 | struct efx_loopback_payload *payload = &state->payload; |
338 | 364 | ||
@@ -368,14 +394,14 @@ static void efx_iterate_state(struct efx_nic *efx) | |||
368 | static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | 394 | static int efx_begin_loopback(struct efx_tx_queue *tx_queue) |
369 | { | 395 | { |
370 | struct efx_nic *efx = tx_queue->efx; | 396 | struct efx_nic *efx = tx_queue->efx; |
371 | struct efx_selftest_state *state = efx->loopback_selftest; | 397 | struct efx_loopback_state *state = efx->loopback_selftest; |
372 | struct efx_loopback_payload *payload; | 398 | struct efx_loopback_payload *payload; |
373 | struct sk_buff *skb; | 399 | struct sk_buff *skb; |
374 | int i, rc; | 400 | int i, rc; |
375 | 401 | ||
376 | /* Transmit N copies of buffer */ | 402 | /* Transmit N copies of buffer */ |
377 | for (i = 0; i < state->packet_count; i++) { | 403 | for (i = 0; i < state->packet_count; i++) { |
378 | /* Allocate an skb, holding an extra reference for | 404 | /* Allocate an skb, holding an extra reference for |
379 | * transmit completion counting */ | 405 | * transmit completion counting */ |
380 | skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); | 406 | skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); |
381 | if (!skb) | 407 | if (!skb) |
@@ -416,7 +442,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | |||
416 | 442 | ||
417 | static int efx_poll_loopback(struct efx_nic *efx) | 443 | static int efx_poll_loopback(struct efx_nic *efx) |
418 | { | 444 | { |
419 | struct efx_selftest_state *state = efx->loopback_selftest; | 445 | struct efx_loopback_state *state = efx->loopback_selftest; |
420 | struct efx_channel *channel; | 446 | struct efx_channel *channel; |
421 | 447 | ||
422 | /* NAPI polling is not enabled, so process channels | 448 | /* NAPI polling is not enabled, so process channels |
@@ -432,7 +458,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, | |||
432 | struct efx_loopback_self_tests *lb_tests) | 458 | struct efx_loopback_self_tests *lb_tests) |
433 | { | 459 | { |
434 | struct efx_nic *efx = tx_queue->efx; | 460 | struct efx_nic *efx = tx_queue->efx; |
435 | struct efx_selftest_state *state = efx->loopback_selftest; | 461 | struct efx_loopback_state *state = efx->loopback_selftest; |
436 | struct sk_buff *skb; | 462 | struct sk_buff *skb; |
437 | int tx_done = 0, rx_good, rx_bad; | 463 | int tx_done = 0, rx_good, rx_bad; |
438 | int i, rc = 0; | 464 | int i, rc = 0; |
@@ -491,10 +517,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
491 | struct efx_loopback_self_tests *lb_tests) | 517 | struct efx_loopback_self_tests *lb_tests) |
492 | { | 518 | { |
493 | struct efx_nic *efx = tx_queue->efx; | 519 | struct efx_nic *efx = tx_queue->efx; |
494 | struct efx_selftest_state *state = efx->loopback_selftest; | 520 | struct efx_loopback_state *state = efx->loopback_selftest; |
495 | int i, begin_rc, end_rc; | 521 | int i, begin_rc, end_rc; |
496 | 522 | ||
497 | for (i = 0; i < loopback_test_level; i++) { | 523 | for (i = 0; i < 3; i++) { |
498 | /* Determine how many packets to send */ | 524 | /* Determine how many packets to send */ |
499 | state->packet_count = (efx->type->txd_ring_mask + 1) / 3; | 525 | state->packet_count = (efx->type->txd_ring_mask + 1) / 3; |
500 | state->packet_count = min(1 << (i << 2), state->packet_count); | 526 | state->packet_count = min(1 << (i << 2), state->packet_count); |
@@ -537,42 +563,28 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
537 | return 0; | 563 | return 0; |
538 | } | 564 | } |
539 | 565 | ||
540 | static int efx_test_loopbacks(struct efx_nic *efx, | 566 | static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, |
541 | struct efx_self_tests *tests, | 567 | struct efx_self_tests *tests, |
542 | unsigned int loopback_modes) | 568 | unsigned int loopback_modes) |
543 | { | 569 | { |
544 | struct efx_selftest_state *state = efx->loopback_selftest; | 570 | enum efx_loopback_mode mode; |
545 | struct ethtool_cmd ecmd, ecmd_loopback; | 571 | struct efx_loopback_state *state; |
546 | struct efx_tx_queue *tx_queue; | 572 | struct efx_tx_queue *tx_queue; |
547 | enum efx_loopback_mode old_mode, mode; | ||
548 | bool link_up; | 573 | bool link_up; |
549 | int count, rc; | 574 | int count, rc = 0; |
550 | |||
551 | rc = efx_ethtool_get_settings(efx->net_dev, &ecmd); | ||
552 | if (rc) { | ||
553 | EFX_ERR(efx, "could not get GMII settings\n"); | ||
554 | return rc; | ||
555 | } | ||
556 | old_mode = efx->loopback_mode; | ||
557 | |||
558 | /* Disable autonegotiation for the purposes of loopback */ | ||
559 | memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback)); | ||
560 | if (ecmd_loopback.autoneg == AUTONEG_ENABLE) { | ||
561 | ecmd_loopback.autoneg = AUTONEG_DISABLE; | ||
562 | ecmd_loopback.duplex = DUPLEX_FULL; | ||
563 | ecmd_loopback.speed = SPEED_10000; | ||
564 | } | ||
565 | 575 | ||
566 | rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback); | 576 | /* Set the port loopback_selftest member. From this point on |
567 | if (rc) { | 577 | * all received packets will be dropped. Mark the state as |
568 | EFX_ERR(efx, "could not disable autonegotiation\n"); | 578 | * "flushing" so all inflight packets are dropped */ |
569 | goto out; | 579 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
570 | } | 580 | if (state == NULL) |
571 | tests->loopback_speed = ecmd_loopback.speed; | 581 | return -ENOMEM; |
572 | tests->loopback_full_duplex = ecmd_loopback.duplex; | 582 | BUG_ON(efx->loopback_selftest); |
583 | state->flush = true; | ||
584 | efx->loopback_selftest = state; | ||
573 | 585 | ||
574 | /* Test all supported loopback modes */ | 586 | /* Test all supported loopback modes */ |
575 | for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { | 587 | for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { |
576 | if (!(loopback_modes & (1 << mode))) | 588 | if (!(loopback_modes & (1 << mode))) |
577 | continue; | 589 | continue; |
578 | 590 | ||
@@ -601,7 +613,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
601 | */ | 613 | */ |
602 | link_up = efx->link_up; | 614 | link_up = efx->link_up; |
603 | if (!falcon_xaui_link_ok(efx)) | 615 | if (!falcon_xaui_link_ok(efx)) |
604 | link_up = 0; | 616 | link_up = false; |
605 | 617 | ||
606 | } while ((++count < 20) && !link_up); | 618 | } while ((++count < 20) && !link_up); |
607 | 619 | ||
@@ -629,10 +641,11 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
629 | } | 641 | } |
630 | 642 | ||
631 | out: | 643 | out: |
632 | /* Take out of loopback and restore PHY settings */ | 644 | /* Remove the flush. The caller will remove the loopback setting */ |
633 | state->flush = true; | 645 | state->flush = true; |
634 | efx->loopback_mode = old_mode; | 646 | efx->loopback_selftest = NULL; |
635 | efx_ethtool_set_settings(efx->net_dev, &ecmd); | 647 | wmb(); |
648 | kfree(state); | ||
636 | 649 | ||
637 | return rc; | 650 | return rc; |
638 | } | 651 | } |
@@ -648,18 +661,27 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
648 | int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) | 661 | int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) |
649 | { | 662 | { |
650 | struct efx_channel *channel; | 663 | struct efx_channel *channel; |
651 | int rc; | 664 | int rc, rc2 = 0; |
665 | |||
666 | rc = efx_test_mii(efx, tests); | ||
667 | if (rc && !rc2) | ||
668 | rc2 = rc; | ||
669 | |||
670 | rc = efx_test_nvram(efx, tests); | ||
671 | if (rc && !rc2) | ||
672 | rc2 = rc; | ||
652 | 673 | ||
653 | rc = efx_test_interrupts(efx, tests); | 674 | rc = efx_test_interrupts(efx, tests); |
654 | if (rc) | 675 | if (rc && !rc2) |
655 | return rc; | 676 | rc2 = rc; |
677 | |||
656 | efx_for_each_channel(channel, efx) { | 678 | efx_for_each_channel(channel, efx) { |
657 | rc = efx_test_eventq_irq(channel, tests); | 679 | rc = efx_test_eventq_irq(channel, tests); |
658 | if (rc) | 680 | if (rc && !rc2) |
659 | return rc; | 681 | rc2 = rc; |
660 | } | 682 | } |
661 | rc = efx_test_phy(efx, tests); | 683 | |
662 | return rc; | 684 | return rc2; |
663 | } | 685 | } |
664 | 686 | ||
665 | /* Offline (i.e. disruptive) testing | 687 | /* Offline (i.e. disruptive) testing |
@@ -667,27 +689,66 @@ int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) | |||
667 | int efx_offline_test(struct efx_nic *efx, | 689 | int efx_offline_test(struct efx_nic *efx, |
668 | struct efx_self_tests *tests, unsigned int loopback_modes) | 690 | struct efx_self_tests *tests, unsigned int loopback_modes) |
669 | { | 691 | { |
670 | struct efx_selftest_state *state; | 692 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; |
671 | int rc; | 693 | int phy_mode = efx->phy_mode; |
694 | struct ethtool_cmd ecmd, ecmd_test; | ||
695 | int rc, rc2 = 0; | ||
696 | |||
697 | /* force the carrier state off so the kernel doesn't transmit during | ||
698 | * the loopback test, and the watchdog timeout doesn't fire. Also put | ||
699 | * falcon into loopback for the register test. | ||
700 | */ | ||
701 | mutex_lock(&efx->mac_lock); | ||
702 | efx->port_inhibited = true; | ||
703 | if (efx->loopback_modes) | ||
704 | efx->loopback_mode = __ffs(efx->loopback_modes); | ||
705 | __efx_reconfigure_port(efx); | ||
706 | mutex_unlock(&efx->mac_lock); | ||
707 | |||
708 | /* free up all consumers of SRAM (including all the queues) */ | ||
709 | efx_reset_down(efx, &ecmd); | ||
710 | |||
711 | rc = efx_test_chip(efx, tests); | ||
712 | if (rc && !rc2) | ||
713 | rc2 = rc; | ||
714 | |||
715 | /* reset the chip to recover from the register test */ | ||
716 | rc = falcon_reset_hw(efx, RESET_TYPE_ALL); | ||
717 | |||
718 | /* Modify the saved ecmd so that when efx_reset_up() restores the phy | ||
719 | * state, AN is disabled, and the phy is powered, and out of loopback */ | ||
720 | memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); | ||
721 | if (ecmd_test.autoneg == AUTONEG_ENABLE) { | ||
722 | ecmd_test.autoneg = AUTONEG_DISABLE; | ||
723 | ecmd_test.duplex = DUPLEX_FULL; | ||
724 | ecmd_test.speed = SPEED_10000; | ||
725 | } | ||
726 | efx->loopback_mode = LOOPBACK_NONE; | ||
672 | 727 | ||
673 | /* Create a selftest_state structure to hold state for the test */ | 728 | rc = efx_reset_up(efx, &ecmd_test, rc == 0); |
674 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 729 | if (rc) { |
675 | if (state == NULL) | 730 | EFX_ERR(efx, "Unable to recover from chip test\n"); |
676 | return -ENOMEM; | 731 | efx_schedule_reset(efx, RESET_TYPE_DISABLE); |
732 | return rc; | ||
733 | } | ||
677 | 734 | ||
678 | /* Set the port loopback_selftest member. From this point on | 735 | tests->loopback_speed = ecmd_test.speed; |
679 | * all received packets will be dropped. Mark the state as | 736 | tests->loopback_full_duplex = ecmd_test.duplex; |
680 | * "flushing" so all inflight packets are dropped */ | ||
681 | BUG_ON(efx->loopback_selftest); | ||
682 | state->flush = true; | ||
683 | efx->loopback_selftest = state; | ||
684 | 737 | ||
685 | rc = efx_test_loopbacks(efx, tests, loopback_modes); | 738 | rc = efx_test_phy(efx, tests); |
739 | if (rc && !rc2) | ||
740 | rc2 = rc; | ||
686 | 741 | ||
687 | efx->loopback_selftest = NULL; | 742 | rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); |
688 | wmb(); | 743 | if (rc && !rc2) |
689 | kfree(state); | 744 | rc2 = rc; |
690 | 745 | ||
691 | return rc; | 746 | /* restore the PHY to the previous state */ |
747 | efx->loopback_mode = loopback_mode; | ||
748 | efx->phy_mode = phy_mode; | ||
749 | efx->port_inhibited = false; | ||
750 | efx_ethtool_set_settings(efx->net_dev, &ecmd); | ||
751 | |||
752 | return rc2; | ||
692 | } | 753 | } |
693 | 754 | ||
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index cd59f00e2821..fc15df15d766 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h | |||
@@ -29,14 +29,19 @@ struct efx_loopback_self_tests { | |||
29 | * indicates failure. | 29 | * indicates failure. |
30 | */ | 30 | */ |
31 | struct efx_self_tests { | 31 | struct efx_self_tests { |
32 | /* online tests */ | ||
33 | int mii; | ||
34 | int nvram; | ||
32 | int interrupt; | 35 | int interrupt; |
33 | int eventq_dma[EFX_MAX_CHANNELS]; | 36 | int eventq_dma[EFX_MAX_CHANNELS]; |
34 | int eventq_int[EFX_MAX_CHANNELS]; | 37 | int eventq_int[EFX_MAX_CHANNELS]; |
35 | int eventq_poll[EFX_MAX_CHANNELS]; | 38 | int eventq_poll[EFX_MAX_CHANNELS]; |
36 | int phy_ok; | 39 | /* offline tests */ |
40 | int registers; | ||
41 | int phy; | ||
37 | int loopback_speed; | 42 | int loopback_speed; |
38 | int loopback_full_duplex; | 43 | int loopback_full_duplex; |
39 | struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX]; | 44 | struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; |
40 | }; | 45 | }; |
41 | 46 | ||
42 | extern void efx_loopback_rx_packet(struct efx_nic *efx, | 47 | extern void efx_loopback_rx_packet(struct efx_nic *efx, |
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 499e127f6dd5..8412dbe1e8fb 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -65,25 +65,10 @@ | |||
65 | #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) | 65 | #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) |
66 | 66 | ||
67 | 67 | ||
68 | /* Self test (BIST) control register */ | ||
69 | #define PMA_PMD_BIST_CTRL_REG (0xc014) | ||
70 | #define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */ | ||
71 | #define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */ | ||
72 | #define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */ | ||
73 | /* Self test status register */ | ||
74 | #define PMA_PMD_BIST_STAT_REG (0xc015) | ||
75 | #define PMA_PMD_BIST_ENX_LBN (3) | ||
76 | #define PMA_PMD_BIST_PMA_LBN (2) | ||
77 | #define PMA_PMD_BIST_RXD_LBN (1) | ||
78 | #define PMA_PMD_BIST_AFE_LBN (0) | ||
79 | |||
80 | /* Special Software reset register */ | 68 | /* Special Software reset register */ |
81 | #define PMA_PMD_EXT_CTRL_REG 49152 | 69 | #define PMA_PMD_EXT_CTRL_REG 49152 |
82 | #define PMA_PMD_EXT_SSR_LBN 15 | 70 | #define PMA_PMD_EXT_SSR_LBN 15 |
83 | 71 | ||
84 | #define BIST_MAX_DELAY (1000) | ||
85 | #define BIST_POLL_DELAY (10) | ||
86 | |||
87 | /* Misc register defines */ | 72 | /* Misc register defines */ |
88 | #define PCS_CLOCK_CTRL_REG 0xd801 | 73 | #define PCS_CLOCK_CTRL_REG 0xd801 |
89 | #define PLL312_RST_N_LBN 2 | 74 | #define PLL312_RST_N_LBN 2 |
@@ -491,6 +476,12 @@ static void tenxpress_reset_xaui(struct efx_nic *efx) | |||
491 | udelay(10); | 476 | udelay(10); |
492 | } | 477 | } |
493 | 478 | ||
479 | static int tenxpress_phy_test(struct efx_nic *efx) | ||
480 | { | ||
481 | /* BIST is automatically run after a special software reset */ | ||
482 | return tenxpress_special_reset(efx); | ||
483 | } | ||
484 | |||
494 | struct efx_phy_operations falcon_tenxpress_phy_ops = { | 485 | struct efx_phy_operations falcon_tenxpress_phy_ops = { |
495 | .init = tenxpress_phy_init, | 486 | .init = tenxpress_phy_init, |
496 | .reconfigure = tenxpress_phy_reconfigure, | 487 | .reconfigure = tenxpress_phy_reconfigure, |
@@ -498,6 +489,7 @@ struct efx_phy_operations falcon_tenxpress_phy_ops = { | |||
498 | .fini = tenxpress_phy_fini, | 489 | .fini = tenxpress_phy_fini, |
499 | .clear_interrupt = tenxpress_phy_clear_interrupt, | 490 | .clear_interrupt = tenxpress_phy_clear_interrupt, |
500 | .reset_xaui = tenxpress_reset_xaui, | 491 | .reset_xaui = tenxpress_reset_xaui, |
492 | .test = tenxpress_phy_test, | ||
501 | .mmds = TENXPRESS_REQUIRED_DEVS, | 493 | .mmds = TENXPRESS_REQUIRED_DEVS, |
502 | .loopbacks = TENXPRESS_LOOPBACKS, | 494 | .loopbacks = TENXPRESS_LOOPBACKS, |
503 | }; | 495 | }; |