aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/falcon.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-09-01 07:49:02 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-09-03 09:53:48 -0400
commit8c8661e4cefdd1ddbfe7d5120f046694555d9e5c (patch)
tree0618e0392140bccadf012381e64a795dfe2e41a4 /drivers/net/sfc/falcon.c
parenta515089c963b045f65c495cee1d344d8cb75e1d1 (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.c198
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
2233int 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 */
2292static 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
2330static 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
2337int 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, &reg, address);
2362 falcon_read(efx, &buf, address);
2363
2364 if (efx_masked_compare_oword(&reg, &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, &reg, address);
2372 falcon_read(efx, &buf, address);
2373
2374 if (efx_masked_compare_oword(&reg, &buf, &mask))
2375 goto fail;
2376 }
2377
2378 falcon_write(efx, &original, address);
2379 }
2380
2381 return 0;
2382
2383fail:
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)
2404static int falcon_probe_nvconfig(struct efx_nic *efx) 2568static 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);