diff options
| -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 | }; |
