diff options
Diffstat (limited to 'drivers/net/bnx2x/bnx2x_ethtool.c')
-rw-r--r-- | drivers/net/bnx2x/bnx2x_ethtool.c | 123 |
1 files changed, 96 insertions, 27 deletions
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index fa8f9526f93c..8fb00276dc41 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c | |||
@@ -41,19 +41,19 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
41 | (bp->link_vars.link_up)) { | 41 | (bp->link_vars.link_up)) { |
42 | cmd->speed = bp->link_vars.line_speed; | 42 | cmd->speed = bp->link_vars.line_speed; |
43 | cmd->duplex = bp->link_vars.duplex; | 43 | cmd->duplex = bp->link_vars.duplex; |
44 | if (IS_MF(bp)) { | ||
45 | u16 vn_max_rate; | ||
46 | |||
47 | vn_max_rate = | ||
48 | ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >> | ||
49 | FUNC_MF_CFG_MAX_BW_SHIFT) * 100; | ||
50 | if (vn_max_rate < cmd->speed) | ||
51 | cmd->speed = vn_max_rate; | ||
52 | } | ||
53 | } else { | 44 | } else { |
45 | |||
54 | cmd->speed = bp->link_params.req_line_speed[cfg_idx]; | 46 | cmd->speed = bp->link_params.req_line_speed[cfg_idx]; |
55 | cmd->duplex = bp->link_params.req_duplex[cfg_idx]; | 47 | cmd->duplex = bp->link_params.req_duplex[cfg_idx]; |
56 | } | 48 | } |
49 | if (IS_MF(bp)) { | ||
50 | u16 vn_max_rate = ((bp->mf_config[BP_VN(bp)] & | ||
51 | FUNC_MF_CFG_MAX_BW_MASK) >> FUNC_MF_CFG_MAX_BW_SHIFT) * | ||
52 | 100; | ||
53 | |||
54 | if (vn_max_rate < cmd->speed) | ||
55 | cmd->speed = vn_max_rate; | ||
56 | } | ||
57 | 57 | ||
58 | if (bp->port.supported[cfg_idx] & SUPPORTED_TP) | 58 | if (bp->port.supported[cfg_idx] & SUPPORTED_TP) |
59 | cmd->port = PORT_TP; | 59 | cmd->port = PORT_TP; |
@@ -298,6 +298,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
298 | 298 | ||
299 | #define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE) | 299 | #define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE) |
300 | #define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE) | 300 | #define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE) |
301 | #define IS_E2_ONLINE(info) (((info) & RI_E2_ONLINE) == RI_E2_ONLINE) | ||
301 | 302 | ||
302 | static int bnx2x_get_regs_len(struct net_device *dev) | 303 | static int bnx2x_get_regs_len(struct net_device *dev) |
303 | { | 304 | { |
@@ -315,7 +316,7 @@ static int bnx2x_get_regs_len(struct net_device *dev) | |||
315 | regdump_len += wreg_addrs_e1[i].size * | 316 | regdump_len += wreg_addrs_e1[i].size * |
316 | (1 + wreg_addrs_e1[i].read_regs_count); | 317 | (1 + wreg_addrs_e1[i].read_regs_count); |
317 | 318 | ||
318 | } else { /* E1H */ | 319 | } else if (CHIP_IS_E1H(bp)) { |
319 | for (i = 0; i < REGS_COUNT; i++) | 320 | for (i = 0; i < REGS_COUNT; i++) |
320 | if (IS_E1H_ONLINE(reg_addrs[i].info)) | 321 | if (IS_E1H_ONLINE(reg_addrs[i].info)) |
321 | regdump_len += reg_addrs[i].size; | 322 | regdump_len += reg_addrs[i].size; |
@@ -324,6 +325,15 @@ static int bnx2x_get_regs_len(struct net_device *dev) | |||
324 | if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info)) | 325 | if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info)) |
325 | regdump_len += wreg_addrs_e1h[i].size * | 326 | regdump_len += wreg_addrs_e1h[i].size * |
326 | (1 + wreg_addrs_e1h[i].read_regs_count); | 327 | (1 + wreg_addrs_e1h[i].read_regs_count); |
328 | } else if (CHIP_IS_E2(bp)) { | ||
329 | for (i = 0; i < REGS_COUNT; i++) | ||
330 | if (IS_E2_ONLINE(reg_addrs[i].info)) | ||
331 | regdump_len += reg_addrs[i].size; | ||
332 | |||
333 | for (i = 0; i < WREGS_COUNT_E2; i++) | ||
334 | if (IS_E2_ONLINE(wreg_addrs_e2[i].info)) | ||
335 | regdump_len += wreg_addrs_e2[i].size * | ||
336 | (1 + wreg_addrs_e2[i].read_regs_count); | ||
327 | } | 337 | } |
328 | regdump_len *= 4; | 338 | regdump_len *= 4; |
329 | regdump_len += sizeof(struct dump_hdr); | 339 | regdump_len += sizeof(struct dump_hdr); |
@@ -331,6 +341,23 @@ static int bnx2x_get_regs_len(struct net_device *dev) | |||
331 | return regdump_len; | 341 | return regdump_len; |
332 | } | 342 | } |
333 | 343 | ||
344 | static inline void bnx2x_read_pages_regs_e2(struct bnx2x *bp, u32 *p) | ||
345 | { | ||
346 | u32 i, j, k, n; | ||
347 | |||
348 | for (i = 0; i < PAGE_MODE_VALUES_E2; i++) { | ||
349 | for (j = 0; j < PAGE_WRITE_REGS_E2; j++) { | ||
350 | REG_WR(bp, page_write_regs_e2[j], page_vals_e2[i]); | ||
351 | for (k = 0; k < PAGE_READ_REGS_E2; k++) | ||
352 | if (IS_E2_ONLINE(page_read_regs_e2[k].info)) | ||
353 | for (n = 0; n < | ||
354 | page_read_regs_e2[k].size; n++) | ||
355 | *p++ = REG_RD(bp, | ||
356 | page_read_regs_e2[k].addr + n*4); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
334 | static void bnx2x_get_regs(struct net_device *dev, | 361 | static void bnx2x_get_regs(struct net_device *dev, |
335 | struct ethtool_regs *regs, void *_p) | 362 | struct ethtool_regs *regs, void *_p) |
336 | { | 363 | { |
@@ -350,7 +377,14 @@ static void bnx2x_get_regs(struct net_device *dev, | |||
350 | dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR); | 377 | dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR); |
351 | dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR); | 378 | dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR); |
352 | dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR); | 379 | dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR); |
353 | dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE; | 380 | |
381 | if (CHIP_IS_E1(bp)) | ||
382 | dump_hdr.info = RI_E1_ONLINE; | ||
383 | else if (CHIP_IS_E1H(bp)) | ||
384 | dump_hdr.info = RI_E1H_ONLINE; | ||
385 | else if (CHIP_IS_E2(bp)) | ||
386 | dump_hdr.info = RI_E2_ONLINE | | ||
387 | (BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP); | ||
354 | 388 | ||
355 | memcpy(p, &dump_hdr, sizeof(struct dump_hdr)); | 389 | memcpy(p, &dump_hdr, sizeof(struct dump_hdr)); |
356 | p += dump_hdr.hdr_size + 1; | 390 | p += dump_hdr.hdr_size + 1; |
@@ -362,16 +396,25 @@ static void bnx2x_get_regs(struct net_device *dev, | |||
362 | *p++ = REG_RD(bp, | 396 | *p++ = REG_RD(bp, |
363 | reg_addrs[i].addr + j*4); | 397 | reg_addrs[i].addr + j*4); |
364 | 398 | ||
365 | } else { /* E1H */ | 399 | } else if (CHIP_IS_E1H(bp)) { |
366 | for (i = 0; i < REGS_COUNT; i++) | 400 | for (i = 0; i < REGS_COUNT; i++) |
367 | if (IS_E1H_ONLINE(reg_addrs[i].info)) | 401 | if (IS_E1H_ONLINE(reg_addrs[i].info)) |
368 | for (j = 0; j < reg_addrs[i].size; j++) | 402 | for (j = 0; j < reg_addrs[i].size; j++) |
369 | *p++ = REG_RD(bp, | 403 | *p++ = REG_RD(bp, |
370 | reg_addrs[i].addr + j*4); | 404 | reg_addrs[i].addr + j*4); |
405 | |||
406 | } else if (CHIP_IS_E2(bp)) { | ||
407 | for (i = 0; i < REGS_COUNT; i++) | ||
408 | if (IS_E2_ONLINE(reg_addrs[i].info)) | ||
409 | for (j = 0; j < reg_addrs[i].size; j++) | ||
410 | *p++ = REG_RD(bp, | ||
411 | reg_addrs[i].addr + j*4); | ||
412 | |||
413 | bnx2x_read_pages_regs_e2(bp, p); | ||
371 | } | 414 | } |
372 | } | 415 | } |
373 | 416 | ||
374 | #define PHY_FW_VER_LEN 10 | 417 | #define PHY_FW_VER_LEN 20 |
375 | 418 | ||
376 | static void bnx2x_get_drvinfo(struct net_device *dev, | 419 | static void bnx2x_get_drvinfo(struct net_device *dev, |
377 | struct ethtool_drvinfo *info) | 420 | struct ethtool_drvinfo *info) |
@@ -474,7 +517,7 @@ static u32 bnx2x_get_link(struct net_device *dev) | |||
474 | { | 517 | { |
475 | struct bnx2x *bp = netdev_priv(dev); | 518 | struct bnx2x *bp = netdev_priv(dev); |
476 | 519 | ||
477 | if (bp->flags & MF_FUNC_DIS) | 520 | if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN)) |
478 | return 0; | 521 | return 0; |
479 | 522 | ||
480 | return bp->link_vars.link_up; | 523 | return bp->link_vars.link_up; |
@@ -1235,6 +1278,9 @@ static int bnx2x_test_registers(struct bnx2x *bp) | |||
1235 | 1278 | ||
1236 | for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { | 1279 | for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { |
1237 | u32 offset, mask, save_val, val; | 1280 | u32 offset, mask, save_val, val; |
1281 | if (CHIP_IS_E2(bp) && | ||
1282 | reg_tbl[i].offset0 == HC_REG_AGG_INT_0) | ||
1283 | continue; | ||
1238 | 1284 | ||
1239 | offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; | 1285 | offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; |
1240 | mask = reg_tbl[i].mask; | 1286 | mask = reg_tbl[i].mask; |
@@ -1286,20 +1332,33 @@ static int bnx2x_test_memory(struct bnx2x *bp) | |||
1286 | u32 offset; | 1332 | u32 offset; |
1287 | u32 e1_mask; | 1333 | u32 e1_mask; |
1288 | u32 e1h_mask; | 1334 | u32 e1h_mask; |
1335 | u32 e2_mask; | ||
1289 | } prty_tbl[] = { | 1336 | } prty_tbl[] = { |
1290 | { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0 }, | 1337 | { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0, 0 }, |
1291 | { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2 }, | 1338 | { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2, 0 }, |
1292 | { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0 }, | 1339 | { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0, 0 }, |
1293 | { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0 }, | 1340 | { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0, 0 }, |
1294 | { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0 }, | 1341 | { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0, 0 }, |
1295 | { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0 }, | 1342 | { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0, 0 }, |
1296 | 1343 | ||
1297 | { NULL, 0xffffffff, 0, 0 } | 1344 | { NULL, 0xffffffff, 0, 0, 0 } |
1298 | }; | 1345 | }; |
1299 | 1346 | ||
1300 | if (!netif_running(bp->dev)) | 1347 | if (!netif_running(bp->dev)) |
1301 | return rc; | 1348 | return rc; |
1302 | 1349 | ||
1350 | /* pre-Check the parity status */ | ||
1351 | for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { | ||
1352 | val = REG_RD(bp, prty_tbl[i].offset); | ||
1353 | if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) || | ||
1354 | (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask))) || | ||
1355 | (CHIP_IS_E2(bp) && (val & ~(prty_tbl[i].e2_mask)))) { | ||
1356 | DP(NETIF_MSG_HW, | ||
1357 | "%s is 0x%x\n", prty_tbl[i].name, val); | ||
1358 | goto test_mem_exit; | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1303 | /* Go through all the memories */ | 1362 | /* Go through all the memories */ |
1304 | for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) | 1363 | for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) |
1305 | for (j = 0; j < mem_tbl[i].size; j++) | 1364 | for (j = 0; j < mem_tbl[i].size; j++) |
@@ -1309,7 +1368,8 @@ static int bnx2x_test_memory(struct bnx2x *bp) | |||
1309 | for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { | 1368 | for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { |
1310 | val = REG_RD(bp, prty_tbl[i].offset); | 1369 | val = REG_RD(bp, prty_tbl[i].offset); |
1311 | if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) || | 1370 | if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) || |
1312 | (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) { | 1371 | (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask))) || |
1372 | (CHIP_IS_E2(bp) && (val & ~(prty_tbl[i].e2_mask)))) { | ||
1313 | DP(NETIF_MSG_HW, | 1373 | DP(NETIF_MSG_HW, |
1314 | "%s is 0x%x\n", prty_tbl[i].name, val); | 1374 | "%s is 0x%x\n", prty_tbl[i].name, val); |
1315 | goto test_mem_exit; | 1375 | goto test_mem_exit; |
@@ -1324,7 +1384,7 @@ test_mem_exit: | |||
1324 | 1384 | ||
1325 | static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes) | 1385 | static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes) |
1326 | { | 1386 | { |
1327 | int cnt = 1000; | 1387 | int cnt = 1400; |
1328 | 1388 | ||
1329 | if (link_up) | 1389 | if (link_up) |
1330 | while (bnx2x_link_test(bp, is_serdes) && cnt--) | 1390 | while (bnx2x_link_test(bp, is_serdes) && cnt--) |
@@ -1343,7 +1403,8 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) | |||
1343 | u16 pkt_prod, bd_prod; | 1403 | u16 pkt_prod, bd_prod; |
1344 | struct sw_tx_bd *tx_buf; | 1404 | struct sw_tx_bd *tx_buf; |
1345 | struct eth_tx_start_bd *tx_start_bd; | 1405 | struct eth_tx_start_bd *tx_start_bd; |
1346 | struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; | 1406 | struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; |
1407 | struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; | ||
1347 | dma_addr_t mapping; | 1408 | dma_addr_t mapping; |
1348 | union eth_rx_cqe *cqe; | 1409 | union eth_rx_cqe *cqe; |
1349 | u8 cqe_fp_flags; | 1410 | u8 cqe_fp_flags; |
@@ -1411,7 +1472,9 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) | |||
1411 | /* turn on parsing and get a BD */ | 1472 | /* turn on parsing and get a BD */ |
1412 | bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); | 1473 | bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); |
1413 | pbd_e1x = &fp_tx->tx_desc_ring[bd_prod].parse_bd_e1x; | 1474 | pbd_e1x = &fp_tx->tx_desc_ring[bd_prod].parse_bd_e1x; |
1475 | pbd_e2 = &fp_tx->tx_desc_ring[bd_prod].parse_bd_e2; | ||
1414 | 1476 | ||
1477 | memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); | ||
1415 | memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); | 1478 | memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); |
1416 | 1479 | ||
1417 | wmb(); | 1480 | wmb(); |
@@ -1431,6 +1494,13 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) | |||
1431 | if (tx_idx != tx_start_idx + num_pkts) | 1494 | if (tx_idx != tx_start_idx + num_pkts) |
1432 | goto test_loopback_exit; | 1495 | goto test_loopback_exit; |
1433 | 1496 | ||
1497 | /* Unlike HC IGU won't generate an interrupt for status block | ||
1498 | * updates that have been performed while interrupts were | ||
1499 | * disabled. | ||
1500 | */ | ||
1501 | if (bp->common.int_block == INT_BLOCK_IGU) | ||
1502 | bnx2x_tx_int(fp_tx); | ||
1503 | |||
1434 | rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); | 1504 | rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); |
1435 | if (rx_idx != rx_start_idx + num_pkts) | 1505 | if (rx_idx != rx_start_idx + num_pkts) |
1436 | goto test_loopback_exit; | 1506 | goto test_loopback_exit; |
@@ -1573,8 +1643,7 @@ static int bnx2x_test_intr(struct bnx2x *bp) | |||
1573 | 1643 | ||
1574 | config->hdr.length = 0; | 1644 | config->hdr.length = 0; |
1575 | if (CHIP_IS_E1(bp)) | 1645 | if (CHIP_IS_E1(bp)) |
1576 | /* use last unicast entries */ | 1646 | config->hdr.offset = (BP_PORT(bp) ? 32 : 0); |
1577 | config->hdr.offset = (BP_PORT(bp) ? 63 : 31); | ||
1578 | else | 1647 | else |
1579 | config->hdr.offset = BP_FUNC(bp); | 1648 | config->hdr.offset = BP_FUNC(bp); |
1580 | config->hdr.client_id = bp->fp->cl_id; | 1649 | config->hdr.client_id = bp->fp->cl_id; |