qlcnic: add loopback diagnostic test
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / net / qlcnic / qlcnic_hw.c
index 8724e56..dc6cd69 100644 (file)
@@ -1221,3 +1221,55 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
 
        return rv;
 }
+
+static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
+{
+       struct qlcnic_nic_req   req;
+       int                     rv;
+       u64                     word;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+                       ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+       req.words[0] = cpu_to_le64(flag);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv)
+               dev_err(&adapter->pdev->dev,
+                       "%sting loopback mode failed.\n",
+                                       flag ? "Set" : "Reset");
+       return rv;
+}
+
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       if (qlcnic_set_fw_loopback(adapter, 1))
+               return -EIO;
+
+       if (qlcnic_nic_set_promisc(adapter,
+                               VPORT_MISS_MODE_ACCEPT_ALL)) {
+               qlcnic_set_fw_loopback(adapter, 0);
+               return -EIO;
+       }
+
+       msleep(1000);
+       return 0;
+}
+
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       int mode = VPORT_MISS_MODE_DROP;
+       struct net_device *netdev = adapter->netdev;
+
+       qlcnic_set_fw_loopback(adapter, 0);
+
+       if (netdev->flags & IFF_PROMISC)
+               mode = VPORT_MISS_MODE_ACCEPT_ALL;
+       else if (netdev->flags & IFF_ALLMULTI)
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+       qlcnic_nic_set_promisc(adapter, mode);
+}