qlcnic: refactor 83xx diagnostic loopback test
authorJitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Sat, 9 Feb 2013 09:29:51 +0000 (09:29 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 11 Feb 2013 07:04:13 +0000 (02:04 -0500)
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>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c

index 3a840e7419821f46f81854ef9f2e5165cf8f089d..61b594c6d9d7c4b45d0e38343272d8f52337c5a3 100644 (file)
@@ -1442,7 +1442,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);
 
 /* Functions from qlcnic_ethtool.c */
-int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
+int qlcnic_check_loopback_buff(unsigned char *, u8 []);
+int qlcnic_do_lb_test(struct qlcnic_adapter *, u8);
+int qlcnic_loopback_test(struct net_device *, u8);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
index 3d628c638247b6a4f8f87af1318df88e24558c95..3d4813121d2e968c88f1fb5c45e50deb0c3331c2 100644 (file)
@@ -257,8 +257,6 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
        .config_intr_coal               = qlcnic_83xx_config_intr_coal,
        .config_rss                     = qlcnic_83xx_config_rss,
        .config_hw_lro                  = qlcnic_83xx_config_hw_lro,
-       .config_loopback                = qlcnic_83xx_set_lb_mode,
-       .clear_loopback                 = qlcnic_83xx_clear_lb_mode,
        .config_promisc_mode            = qlcnic_83xx_nic_set_promisc,
        .change_l2_filter               = qlcnic_83xx_change_l2_filter,
        .get_board_info                 = qlcnic_83xx_get_port_info,
@@ -1118,6 +1116,100 @@ out:
        return err;
 }
 
+static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_rds_ring *rds_ring;
+       u8 ring;
+       int ret;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               __qlcnic_down(adapter, netdev);
+
+       qlcnic_detach(adapter);
+
+       adapter->max_sds_rings = 1;
+       adapter->ahw->diag_test = test;
+       adapter->ahw->linkup = 0;
+
+       ret = qlcnic_attach(adapter);
+       if (ret) {
+               netif_device_attach(netdev);
+               return ret;
+       }
+
+       ret = qlcnic_fw_create_ctx(adapter);
+       if (ret) {
+               qlcnic_detach(adapter);
+               netif_device_attach(netdev);
+               return ret;
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &adapter->recv_ctx->rds_rings[ring];
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
+       }
+
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx->sds_rings[ring];
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+               }
+       }
+
+       if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+               /* disable and free mailbox interrupt */
+               qlcnic_83xx_free_mbx_intr(adapter);
+               adapter->ahw->loopback_state = 0;
+               adapter->ahw->hw_ops->setup_link_event(adapter, 1);
+       }
+
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
+       return 0;
+}
+
+static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
+                                       int max_sds_rings)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       int ring, err;
+
+       clear_bit(__QLCNIC_DEV_UP, &adapter->state);
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx->sds_rings[ring];
+                       writel(1, sds_ring->crb_intr_mask);
+               }
+       }
+
+       qlcnic_fw_destroy_ctx(adapter);
+       qlcnic_detach(adapter);
+
+       if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed to setup mbx interrupt\n",
+                               __func__);
+                       goto out;
+               }
+       }
+       adapter->ahw->diag_test = 0;
+       adapter->max_sds_rings = max_sds_rings;
+
+       if (qlcnic_attach(adapter))
+               goto out;
+
+       if (netif_running(netdev))
+               __qlcnic_up(adapter, netdev);
+out:
+       netif_device_attach(netdev);
+}
+
 int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
                           u32 beacon)
 {
@@ -1265,6 +1357,57 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
        return err;
 }
 
+int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
+
+       QLCDB(adapter, DRV, "%s loopback test in progress\n",
+             mode == QLCNIC_ILB_MODE ? "internal" : "external");
+       if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               dev_warn(&adapter->pdev->dev,
+                        "Loopback test not supported for non privilege function\n");
+               return ret;
+       }
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EBUSY;
+
+       ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+       if (ret)
+               goto fail_diag_alloc;
+
+       ret = qlcnic_83xx_set_lb_mode(adapter, mode);
+       if (ret)
+               goto free_diag_res;
+
+       /* Poll for link up event before running traffic */
+       do {
+               msleep(500);
+               qlcnic_83xx_process_aen(adapter);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       dev_info(&adapter->pdev->dev,
+                                "Firmware didn't sent link up event to loopback request\n");
+                       ret = -QLCNIC_FW_NOT_RESPOND;
+                       qlcnic_83xx_clear_lb_mode(adapter, mode);
+                       goto free_diag_res;
+               }
+       } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+
+       ret = qlcnic_do_lb_test(adapter, mode);
+
+       qlcnic_83xx_clear_lb_mode(adapter, mode);
+
+free_diag_res:
+       qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_alloc:
+       adapter->max_sds_rings = max_sds_rings;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return ret;
+}
+
 int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
        struct qlcnic_hardware_context *ahw = adapter->ahw;
index 16c5df62661619792899d1e0e0049d3105e7fca6..87f2e08c31f4407bffd78fce985473c362df44f7 100644 (file)
@@ -428,6 +428,7 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *);
 int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
 int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
 int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
+int qlcnic_83xx_loopback_test(struct net_device *, u8);
 int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *,
                               struct qlcnic_cmd_args *);
 int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
index 6320d551c63d272937f2a2116a15bf0d4de0a131..58e255437d5afc0165f4ed4ba6bcfa31733953ca 100644 (file)
@@ -883,7 +883,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
        return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
 }
 
-static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 {
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
        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)
        return 0;
 }
 
-static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
+int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int max_sds_rings = adapter->max_sds_rings;
@@ -935,13 +935,14 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
        int ret;
 
        if (qlcnic_83xx_check(adapter))
-               goto skip_cap;
+               return qlcnic_83xx_loopback_test(netdev, mode);
+
        if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
                dev_info(&adapter->pdev->dev,
                         "Firmware do not support loopback test\n");
                return -EOPNOTSUPP;
        }
-skip_cap:
+
        dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
                 mode == QLCNIC_ILB_MODE ? "internal" : "external");
        if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
@@ -962,9 +963,6 @@ skip_cap:
        if (ret)
                goto free_res;
 
-       if (qlcnic_83xx_check(adapter))
-               goto skip_fw_msg;
-
        ahw->diag_cnt = 0;
        do {
                msleep(500);
@@ -979,21 +977,9 @@ skip_cap:
                        goto free_res;
                }
        } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
-skip_fw_msg:
-       if (qlcnic_83xx_check(adapter)) {
-               /* wait until firmware report link up before running traffic */
-               loop = 0;
-               do {
-                       msleep(500);
-                       if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
-                               dev_info(&adapter->pdev->dev,
-                                        "No linkup event after LB req\n");
-                               ret = -QLCNIC_FW_NOT_RESPOND;
-                               goto free_res;
-                       }
-               } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
-       }
+
        ret = qlcnic_do_lb_test(adapter, mode);
+
        qlcnic_clear_lb_mode(adapter, mode);
 
  free_res:
index dcb990d3d559a4776deeaafea3306732b54b44a7..30aa1f295224a4c20d951d1c6132b99b101c71d9 100644 (file)
@@ -1503,10 +1503,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       if (qlcnic_83xx_check(adapter))
-                               writel(1, sds_ring->crb_intr_mask);
-                       else
-                               qlcnic_disable_int(sds_ring);
+                       qlcnic_disable_int(sds_ring);
                }
        }
 
@@ -1599,10 +1596,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       if (qlcnic_82xx_check(adapter))
-                               qlcnic_enable_int(sds_ring);
-                       else
-                               qlcnic_83xx_enable_intr(adapter, sds_ring);
+                       qlcnic_enable_int(sds_ring);
                }
        }