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/falcon.c | |
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/falcon.c')
-rw-r--r-- | drivers/net/sfc/falcon.c | 198 |
1 files changed, 175 insertions, 23 deletions
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); |