diff options
author | Jitendra Kalsaria <jitendra.kalsaria@qlogic.com> | 2013-02-09 04:29:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-11 02:04:13 -0500 |
commit | ba4468dbf3364c35652dda14e2ef90c5cf09ab16 (patch) | |
tree | c4c17ea14da629b8762c471ca6368458cf42267c /drivers | |
parent | 483202d590cd76fc794f3aa11a342b718a804a28 (diff) |
qlcnic: refactor 83xx diagnostic loopback test
Cleanly separate 83xx diagnostic loopback test routines from 82xx
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 147 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 28 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 10 |
5 files changed, 158 insertions, 32 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 3a840e741982..61b594c6d9d7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -1442,7 +1442,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); | |||
1442 | void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *); | 1442 | void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *); |
1443 | 1443 | ||
1444 | /* Functions from qlcnic_ethtool.c */ | 1444 | /* Functions from qlcnic_ethtool.c */ |
1445 | int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]); | 1445 | int qlcnic_check_loopback_buff(unsigned char *, u8 []); |
1446 | int qlcnic_do_lb_test(struct qlcnic_adapter *, u8); | ||
1447 | int qlcnic_loopback_test(struct net_device *, u8); | ||
1446 | 1448 | ||
1447 | /* Functions from qlcnic_main.c */ | 1449 | /* Functions from qlcnic_main.c */ |
1448 | int qlcnic_reset_context(struct qlcnic_adapter *); | 1450 | int qlcnic_reset_context(struct qlcnic_adapter *); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 3d628c638247..3d4813121d2e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -257,8 +257,6 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { | |||
257 | .config_intr_coal = qlcnic_83xx_config_intr_coal, | 257 | .config_intr_coal = qlcnic_83xx_config_intr_coal, |
258 | .config_rss = qlcnic_83xx_config_rss, | 258 | .config_rss = qlcnic_83xx_config_rss, |
259 | .config_hw_lro = qlcnic_83xx_config_hw_lro, | 259 | .config_hw_lro = qlcnic_83xx_config_hw_lro, |
260 | .config_loopback = qlcnic_83xx_set_lb_mode, | ||
261 | .clear_loopback = qlcnic_83xx_clear_lb_mode, | ||
262 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, | 260 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, |
263 | .change_l2_filter = qlcnic_83xx_change_l2_filter, | 261 | .change_l2_filter = qlcnic_83xx_change_l2_filter, |
264 | .get_board_info = qlcnic_83xx_get_port_info, | 262 | .get_board_info = qlcnic_83xx_get_port_info, |
@@ -1118,6 +1116,100 @@ out: | |||
1118 | return err; | 1116 | return err; |
1119 | } | 1117 | } |
1120 | 1118 | ||
1119 | static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test) | ||
1120 | { | ||
1121 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
1122 | struct qlcnic_host_sds_ring *sds_ring; | ||
1123 | struct qlcnic_host_rds_ring *rds_ring; | ||
1124 | u8 ring; | ||
1125 | int ret; | ||
1126 | |||
1127 | netif_device_detach(netdev); | ||
1128 | |||
1129 | if (netif_running(netdev)) | ||
1130 | __qlcnic_down(adapter, netdev); | ||
1131 | |||
1132 | qlcnic_detach(adapter); | ||
1133 | |||
1134 | adapter->max_sds_rings = 1; | ||
1135 | adapter->ahw->diag_test = test; | ||
1136 | adapter->ahw->linkup = 0; | ||
1137 | |||
1138 | ret = qlcnic_attach(adapter); | ||
1139 | if (ret) { | ||
1140 | netif_device_attach(netdev); | ||
1141 | return ret; | ||
1142 | } | ||
1143 | |||
1144 | ret = qlcnic_fw_create_ctx(adapter); | ||
1145 | if (ret) { | ||
1146 | qlcnic_detach(adapter); | ||
1147 | netif_device_attach(netdev); | ||
1148 | return ret; | ||
1149 | } | ||
1150 | |||
1151 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { | ||
1152 | rds_ring = &adapter->recv_ctx->rds_rings[ring]; | ||
1153 | qlcnic_post_rx_buffers(adapter, rds_ring, ring); | ||
1154 | } | ||
1155 | |||
1156 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { | ||
1157 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | ||
1158 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; | ||
1159 | qlcnic_83xx_enable_intr(adapter, sds_ring); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { | ||
1164 | /* disable and free mailbox interrupt */ | ||
1165 | qlcnic_83xx_free_mbx_intr(adapter); | ||
1166 | adapter->ahw->loopback_state = 0; | ||
1167 | adapter->ahw->hw_ops->setup_link_event(adapter, 1); | ||
1168 | } | ||
1169 | |||
1170 | set_bit(__QLCNIC_DEV_UP, &adapter->state); | ||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static void qlcnic_83xx_diag_free_res(struct net_device *netdev, | ||
1175 | int max_sds_rings) | ||
1176 | { | ||
1177 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
1178 | struct qlcnic_host_sds_ring *sds_ring; | ||
1179 | int ring, err; | ||
1180 | |||
1181 | clear_bit(__QLCNIC_DEV_UP, &adapter->state); | ||
1182 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { | ||
1183 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | ||
1184 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; | ||
1185 | writel(1, sds_ring->crb_intr_mask); | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | qlcnic_fw_destroy_ctx(adapter); | ||
1190 | qlcnic_detach(adapter); | ||
1191 | |||
1192 | if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { | ||
1193 | err = qlcnic_83xx_setup_mbx_intr(adapter); | ||
1194 | if (err) { | ||
1195 | dev_err(&adapter->pdev->dev, | ||
1196 | "%s: failed to setup mbx interrupt\n", | ||
1197 | __func__); | ||
1198 | goto out; | ||
1199 | } | ||
1200 | } | ||
1201 | adapter->ahw->diag_test = 0; | ||
1202 | adapter->max_sds_rings = max_sds_rings; | ||
1203 | |||
1204 | if (qlcnic_attach(adapter)) | ||
1205 | goto out; | ||
1206 | |||
1207 | if (netif_running(netdev)) | ||
1208 | __qlcnic_up(adapter, netdev); | ||
1209 | out: | ||
1210 | netif_device_attach(netdev); | ||
1211 | } | ||
1212 | |||
1121 | int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state, | 1213 | int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state, |
1122 | u32 beacon) | 1214 | u32 beacon) |
1123 | { | 1215 | { |
@@ -1265,6 +1357,57 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) | |||
1265 | return err; | 1357 | return err; |
1266 | } | 1358 | } |
1267 | 1359 | ||
1360 | int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode) | ||
1361 | { | ||
1362 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
1363 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1364 | int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings; | ||
1365 | |||
1366 | QLCDB(adapter, DRV, "%s loopback test in progress\n", | ||
1367 | mode == QLCNIC_ILB_MODE ? "internal" : "external"); | ||
1368 | if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { | ||
1369 | dev_warn(&adapter->pdev->dev, | ||
1370 | "Loopback test not supported for non privilege function\n"); | ||
1371 | return ret; | ||
1372 | } | ||
1373 | |||
1374 | if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) | ||
1375 | return -EBUSY; | ||
1376 | |||
1377 | ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST); | ||
1378 | if (ret) | ||
1379 | goto fail_diag_alloc; | ||
1380 | |||
1381 | ret = qlcnic_83xx_set_lb_mode(adapter, mode); | ||
1382 | if (ret) | ||
1383 | goto free_diag_res; | ||
1384 | |||
1385 | /* Poll for link up event before running traffic */ | ||
1386 | do { | ||
1387 | msleep(500); | ||
1388 | qlcnic_83xx_process_aen(adapter); | ||
1389 | if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) { | ||
1390 | dev_info(&adapter->pdev->dev, | ||
1391 | "Firmware didn't sent link up event to loopback request\n"); | ||
1392 | ret = -QLCNIC_FW_NOT_RESPOND; | ||
1393 | qlcnic_83xx_clear_lb_mode(adapter, mode); | ||
1394 | goto free_diag_res; | ||
1395 | } | ||
1396 | } while ((adapter->ahw->linkup && ahw->has_link_events) != 1); | ||
1397 | |||
1398 | ret = qlcnic_do_lb_test(adapter, mode); | ||
1399 | |||
1400 | qlcnic_83xx_clear_lb_mode(adapter, mode); | ||
1401 | |||
1402 | free_diag_res: | ||
1403 | qlcnic_83xx_diag_free_res(netdev, max_sds_rings); | ||
1404 | |||
1405 | fail_diag_alloc: | ||
1406 | adapter->max_sds_rings = max_sds_rings; | ||
1407 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1408 | return ret; | ||
1409 | } | ||
1410 | |||
1268 | int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) | 1411 | int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) |
1269 | { | 1412 | { |
1270 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 1413 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 16c5df626616..87f2e08c31f4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -428,6 +428,7 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *); | |||
428 | int qlcnic_83xx_reg_test(struct qlcnic_adapter *); | 428 | int qlcnic_83xx_reg_test(struct qlcnic_adapter *); |
429 | int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *); | 429 | int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *); |
430 | int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *); | 430 | int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *); |
431 | int qlcnic_83xx_loopback_test(struct net_device *, u8); | ||
431 | int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *, | 432 | int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *, |
432 | struct qlcnic_cmd_args *); | 433 | struct qlcnic_cmd_args *); |
433 | int qlcnic_83xx_flash_test(struct qlcnic_adapter *); | 434 | int qlcnic_83xx_flash_test(struct qlcnic_adapter *); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 6320d551c63d..58e255437d5a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | |||
@@ -883,7 +883,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]) | |||
883 | return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE); | 883 | return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE); |
884 | } | 884 | } |
885 | 885 | ||
886 | static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) | 886 | int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) |
887 | { | 887 | { |
888 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; | 888 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; |
889 | struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0]; | 889 | struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0]; |
@@ -925,7 +925,7 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) | |||
925 | return 0; | 925 | return 0; |
926 | } | 926 | } |
927 | 927 | ||
928 | static int qlcnic_loopback_test(struct net_device *netdev, u8 mode) | 928 | int qlcnic_loopback_test(struct net_device *netdev, u8 mode) |
929 | { | 929 | { |
930 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 930 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
931 | int max_sds_rings = adapter->max_sds_rings; | 931 | int max_sds_rings = adapter->max_sds_rings; |
@@ -935,13 +935,14 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode) | |||
935 | int ret; | 935 | int ret; |
936 | 936 | ||
937 | if (qlcnic_83xx_check(adapter)) | 937 | if (qlcnic_83xx_check(adapter)) |
938 | goto skip_cap; | 938 | return qlcnic_83xx_loopback_test(netdev, mode); |
939 | |||
939 | if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) { | 940 | if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) { |
940 | dev_info(&adapter->pdev->dev, | 941 | dev_info(&adapter->pdev->dev, |
941 | "Firmware do not support loopback test\n"); | 942 | "Firmware do not support loopback test\n"); |
942 | return -EOPNOTSUPP; | 943 | return -EOPNOTSUPP; |
943 | } | 944 | } |
944 | skip_cap: | 945 | |
945 | dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n", | 946 | dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n", |
946 | mode == QLCNIC_ILB_MODE ? "internal" : "external"); | 947 | mode == QLCNIC_ILB_MODE ? "internal" : "external"); |
947 | if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { | 948 | if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { |
@@ -962,9 +963,6 @@ skip_cap: | |||
962 | if (ret) | 963 | if (ret) |
963 | goto free_res; | 964 | goto free_res; |
964 | 965 | ||
965 | if (qlcnic_83xx_check(adapter)) | ||
966 | goto skip_fw_msg; | ||
967 | |||
968 | ahw->diag_cnt = 0; | 966 | ahw->diag_cnt = 0; |
969 | do { | 967 | do { |
970 | msleep(500); | 968 | msleep(500); |
@@ -979,21 +977,9 @@ skip_cap: | |||
979 | goto free_res; | 977 | goto free_res; |
980 | } | 978 | } |
981 | } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state)); | 979 | } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state)); |
982 | skip_fw_msg: | 980 | |
983 | if (qlcnic_83xx_check(adapter)) { | ||
984 | /* wait until firmware report link up before running traffic */ | ||
985 | loop = 0; | ||
986 | do { | ||
987 | msleep(500); | ||
988 | if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) { | ||
989 | dev_info(&adapter->pdev->dev, | ||
990 | "No linkup event after LB req\n"); | ||
991 | ret = -QLCNIC_FW_NOT_RESPOND; | ||
992 | goto free_res; | ||
993 | } | ||
994 | } while ((adapter->ahw->linkup && ahw->has_link_events) != 1); | ||
995 | } | ||
996 | ret = qlcnic_do_lb_test(adapter, mode); | 981 | ret = qlcnic_do_lb_test(adapter, mode); |
982 | |||
997 | qlcnic_clear_lb_mode(adapter, mode); | 983 | qlcnic_clear_lb_mode(adapter, mode); |
998 | 984 | ||
999 | free_res: | 985 | free_res: |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index dcb990d3d559..30aa1f295224 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -1503,10 +1503,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) | |||
1503 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { | 1503 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { |
1504 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | 1504 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
1505 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; | 1505 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; |
1506 | if (qlcnic_83xx_check(adapter)) | 1506 | qlcnic_disable_int(sds_ring); |
1507 | writel(1, sds_ring->crb_intr_mask); | ||
1508 | else | ||
1509 | qlcnic_disable_int(sds_ring); | ||
1510 | } | 1507 | } |
1511 | } | 1508 | } |
1512 | 1509 | ||
@@ -1599,10 +1596,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) | |||
1599 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { | 1596 | if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { |
1600 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | 1597 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
1601 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; | 1598 | sds_ring = &adapter->recv_ctx->sds_rings[ring]; |
1602 | if (qlcnic_82xx_check(adapter)) | 1599 | qlcnic_enable_int(sds_ring); |
1603 | qlcnic_enable_int(sds_ring); | ||
1604 | else | ||
1605 | qlcnic_83xx_enable_intr(adapter, sds_ring); | ||
1606 | } | 1600 | } |
1607 | } | 1601 | } |
1608 | 1602 | ||