qlcnic: fix mac override capability
[firefly-linux-kernel-4.4.55.git] / drivers / net / qlcnic / qlcnic_ctx.c
index 1e1dc58cddca38105ec3b56cd0039de4112cd67f..95a821e0b66ff82cbb7332f2204c6f161247467b 100644 (file)
@@ -152,9 +152,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 
        prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
 
-       cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN);
+       cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN
+                                               | QLCNIC_CAP0_VALIDOFF);
        cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
+       prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
+                                                        msix_handler);
+       prq->txrx_sds_binding = nsds_rings - 1;
+
        prq->capabilities[0] = cpu_to_le32(cap);
        prq->host_int_crb_mode =
                cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
@@ -175,6 +180,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        for (i = 0; i < nrds_rings; i++) {
 
                rds_ring = &recv_ctx->rds_rings[i];
+               rds_ring->producer = 0;
 
                prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
                prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
@@ -188,6 +194,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        for (i = 0; i < nsds_rings; i++) {
 
                sds_ring = &recv_ctx->sds_rings[i];
+               sds_ring->consumer = 0;
+               memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
 
                prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
                prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
@@ -216,12 +224,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                rds_ring = &recv_ctx->rds_rings[i];
 
                reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
-               if (adapter->fw_hal_version == QLCNIC_FW_BASE)
-                       rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_REG(reg - 0x200));
-               else
-                       rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 +
-                               reg;
+               rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg;
        }
 
        prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -233,16 +236,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
                reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
 
-               if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
-                       sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_REG(reg - 0x200));
-                       sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_REG(reg2 - 0x200));
-               } else {
-                       sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 +
-                               reg;
-                       sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
-               }
+               sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg;
+               sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
        }
 
        recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -272,6 +267,8 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
                dev_err(&adapter->pdev->dev,
                        "Failed to destroy rx ctx in firmware\n");
        }
+
+       recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
 }
 
 static int
@@ -288,6 +285,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        dma_addr_t      rq_phys_addr, rsp_phys_addr;
        struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
+       /* reset host resources */
+       tx_ring->producer = 0;
+       tx_ring->sw_consumer = 0;
+       *(tx_ring->hw_consumer) = 0;
+
        rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
        rq_addr = pci_alloc_consistent(adapter->pdev,
                rq_size, &rq_phys_addr);
@@ -337,12 +339,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
 
        if (err == QLCNIC_RCODE_SUCCESS) {
                temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
-               if (adapter->fw_hal_version == QLCNIC_FW_BASE)
-                       tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_REG(temp - 0x200));
-               else
-                       tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 +
-                               temp;
+               tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp;
 
                adapter->tx_context_id =
                        le16_to_cpu(prsp->context_id);
@@ -471,15 +468,6 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
                sds_ring->desc_head = (struct status_desc *)addr;
        }
 
-
-       err = qlcnic_fw_cmd_create_rx_ctx(adapter);
-       if (err)
-               goto err_out_free;
-       err = qlcnic_fw_cmd_create_tx_ctx(adapter);
-       if (err)
-               goto err_out_free;
-
-       set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
        return 0;
 
 err_out_free:
@@ -487,15 +475,27 @@ err_out_free:
        return err;
 }
 
-void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
 {
-       struct qlcnic_recv_context *recv_ctx;
-       struct qlcnic_host_rds_ring *rds_ring;
-       struct qlcnic_host_sds_ring *sds_ring;
-       struct qlcnic_host_tx_ring *tx_ring;
-       int ring;
+       int err;
+
+       err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+       if (err)
+               return err;
+
+       err = qlcnic_fw_cmd_create_tx_ctx(adapter);
+       if (err) {
+               qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+               return err;
+       }
 
+       set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+       return 0;
+}
 
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
+{
        if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
                qlcnic_fw_cmd_destroy_rx_ctx(adapter);
                qlcnic_fw_cmd_destroy_tx_ctx(adapter);
@@ -503,6 +503,15 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
                /* Allow dma queues to drain after context reset */
                msleep(20);
        }
+}
+
+void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       int ring;
 
        recv_ctx = &adapter->recv_ctx;
 
@@ -589,11 +598,10 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
                        0,
                        QLCNIC_CDRP_CMD_MAC_ADDRESS);
 
-       if (err == QLCNIC_RCODE_SUCCESS) {
+       if (err == QLCNIC_RCODE_SUCCESS)
                qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
                                QLCNIC_ARG2_CRB_OFFSET, 0, mac);
-               dev_info(&adapter->pdev->dev, "MAC address: %pM\n", mac);
-       } else {
+       else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get mac address%d\n", err);
                err = -EIO;
@@ -603,7 +611,8 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 }
 
 /* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+                               struct qlcnic_info *npar_info, u8 func_id)
 {
        int     err;
        dma_addr_t nic_dma_t;
@@ -627,24 +636,25 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
                        QLCNIC_CDRP_CMD_GET_NIC_INFO);
 
        if (err == QLCNIC_RCODE_SUCCESS) {
-               adapter->physical_port = le16_to_cpu(nic_info->phys_port);
-               adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
-               adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
-               adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-               adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-               adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
-               adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
-               adapter->capabilities = le32_to_cpu(nic_info->capabilities);
-               adapter->max_mac_filters = nic_info->max_mac_filters;
+               npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
+               npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+               npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+               npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+               npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+               npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+               npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+               npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+               npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+               npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
 
                dev_info(&adapter->pdev->dev,
                        "phy port: %d switch_mode: %d,\n"
                        "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
                        "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-                       adapter->physical_port, adapter->switch_mode,
-                       adapter->max_tx_ques, adapter->max_rx_ques,
-                       adapter->min_tx_bw, adapter->max_tx_bw,
-                       adapter->max_mtu, adapter->capabilities);
+                       npar_info->phys_port, npar_info->switch_mode,
+                       npar_info->max_tx_ques, npar_info->max_rx_ques,
+                       npar_info->min_tx_bw, npar_info->max_tx_bw,
+                       npar_info->max_mtu, npar_info->capabilities);
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get nic info%d\n", err);
@@ -659,7 +669,6 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
 int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 {
        int err = -EIO;
-       u32 func_state;
        dma_addr_t nic_dma_t;
        void *nic_info_addr;
        struct qlcnic_info *nic_info;
@@ -668,17 +677,6 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
        if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return err;
 
-       if (qlcnic_api_lock(adapter))
-               return err;
-
-       func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-       if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
-               qlcnic_api_unlock(adapter);
-               return err;
-       }
-
-       qlcnic_api_unlock(adapter);
-
        nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
                        &nic_dma_t);
        if (!nic_info_addr)
@@ -703,7 +701,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
                        adapter->fw_hal_version,
                        MSD(nic_dma_t),
                        LSD(nic_dma_t),
-                       nic_size,
+                       ((nic->pci_func << 16) | nic_size),
                        QLCNIC_CDRP_CMD_SET_NIC_INFO);
 
        if (err != QLCNIC_RCODE_SUCCESS) {
@@ -717,7 +715,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 }
 
 /* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+                               struct qlcnic_pci_info *pci_info)
 {
        int err = 0, i;
        dma_addr_t pci_info_dma_t;
@@ -732,21 +731,6 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
                return -ENOMEM;
        memset(pci_info_addr, 0, pci_size);
 
-       if (!adapter->npars)
-               adapter->npars = kzalloc(pci_size, GFP_KERNEL);
-       if (!adapter->npars) {
-               err = -ENOMEM;
-               goto err_npar;
-       }
-
-       if (!adapter->eswitch)
-               adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
-                               QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
-       if (!adapter->eswitch) {
-               err = -ENOMEM;
-               goto err_eswitch;
-       }
-
        npar = (struct qlcnic_pci_info *) pci_info_addr;
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
@@ -757,31 +741,24 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
                        QLCNIC_CDRP_CMD_GET_PCI_INFO);
 
        if (err == QLCNIC_RCODE_SUCCESS) {
-               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
-                       adapter->npars[i].id = le32_to_cpu(npar->id);
-                       adapter->npars[i].active = le32_to_cpu(npar->active);
-                       adapter->npars[i].type = le32_to_cpu(npar->type);
-                       adapter->npars[i].default_port =
+               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
+                       pci_info->id = le32_to_cpu(npar->id);
+                       pci_info->active = le32_to_cpu(npar->active);
+                       pci_info->type = le32_to_cpu(npar->type);
+                       pci_info->default_port =
                                le32_to_cpu(npar->default_port);
-                       adapter->npars[i].tx_min_bw =
+                       pci_info->tx_min_bw =
                                le32_to_cpu(npar->tx_min_bw);
-                       adapter->npars[i].tx_max_bw =
+                       pci_info->tx_max_bw =
                                le32_to_cpu(npar->tx_max_bw);
-                       memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
+                       memcpy(pci_info->mac, npar->mac, ETH_ALEN);
                }
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get PCI Info%d\n", err);
-               kfree(adapter->npars);
                err = -EIO;
        }
-       goto err_npar;
-
-err_eswitch:
-       kfree(adapter->npars);
-       adapter->npars = NULL;
 
-err_npar:
        pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
                pci_info_dma_t);
        return err;
@@ -836,9 +813,8 @@ int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
                arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
 
                eswitch->port = arg1 & 0xf;
-               eswitch->active_vports = LSB(arg2);
-               eswitch->max_ucast_filters = MSB(arg2);
-               eswitch->max_active_vlans = LSB(MSW(arg2));
+               eswitch->max_ucast_filters = LSW(arg2);
+               eswitch->max_active_vlans = MSW(arg2) & 0xfff;
                if (arg1 & BIT_6)
                        eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
                if (arg1 & BIT_7)
@@ -966,45 +942,271 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
        return err;
 }
 
-/* Configure eSwitch port */
-int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
-               int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
-               u8 mac_learn, u8 pci_func, u16 vlan_id)
+int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
+               const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
+
+       size_t stats_size = sizeof(struct __qlcnic_esw_statistics);
+       struct __qlcnic_esw_statistics *stats;
+       dma_addr_t stats_dma_t;
+       void *stats_addr;
+       u32 arg1;
+       int err;
+
+       if (esw_stats == NULL)
+               return -ENOMEM;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC &&
+           func != adapter->ahw.pci_func) {
+               dev_err(&adapter->pdev->dev,
+                       "Not privilege to query stats for func=%d", func);
+               return -EIO;
+       }
+
+       stats_addr = pci_alloc_consistent(adapter->pdev, stats_size,
+                       &stats_dma_t);
+       if (!stats_addr) {
+               dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
+               return -ENOMEM;
+       }
+       memset(stats_addr, 0, stats_size);
+
+       arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
+       arg1 |= rx_tx << 15 | stats_size << 16;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       MSD(stats_dma_t),
+                       LSD(stats_dma_t),
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+
+       if (!err) {
+               stats = (struct __qlcnic_esw_statistics *)stats_addr;
+               esw_stats->context_id = le16_to_cpu(stats->context_id);
+               esw_stats->version = le16_to_cpu(stats->version);
+               esw_stats->size = le16_to_cpu(stats->size);
+               esw_stats->multicast_frames =
+                               le64_to_cpu(stats->multicast_frames);
+               esw_stats->broadcast_frames =
+                               le64_to_cpu(stats->broadcast_frames);
+               esw_stats->unicast_frames = le64_to_cpu(stats->unicast_frames);
+               esw_stats->dropped_frames = le64_to_cpu(stats->dropped_frames);
+               esw_stats->local_frames = le64_to_cpu(stats->local_frames);
+               esw_stats->errors = le64_to_cpu(stats->errors);
+               esw_stats->numbytes = le64_to_cpu(stats->numbytes);
+       }
+
+       pci_free_consistent(adapter->pdev, stats_size, stats_addr,
+               stats_dma_t);
+       return err;
+}
+
+int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
+               const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
+
+       struct __qlcnic_esw_statistics port_stats;
+       u8 i;
+       int ret = -EIO;
+
+       if (esw_stats == NULL)
+               return -ENOMEM;
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return -EIO;
+       if (adapter->npars == NULL)
+               return -EIO;
+
+       memset(esw_stats, 0, sizeof(struct __qlcnic_esw_statistics));
+       esw_stats->context_id = eswitch;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               if (adapter->npars[i].phy_port != eswitch)
+                       continue;
+
+               memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics));
+               if (qlcnic_get_port_stats(adapter, i, rx_tx, &port_stats))
+                       continue;
+
+               esw_stats->size = port_stats.size;
+               esw_stats->version = port_stats.version;
+               esw_stats->unicast_frames += port_stats.unicast_frames;
+               esw_stats->multicast_frames += port_stats.multicast_frames;
+               esw_stats->broadcast_frames += port_stats.broadcast_frames;
+               esw_stats->dropped_frames += port_stats.dropped_frames;
+               esw_stats->errors += port_stats.errors;
+               esw_stats->local_frames += port_stats.local_frames;
+               esw_stats->numbytes += port_stats.numbytes;
+
+               ret = 0;
+       }
+       return ret;
+}
+
+int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
+               const u8 port, const u8 rx_tx)
 {
-       int err = -EIO;
+
        u32 arg1;
-       struct qlcnic_eswitch *eswitch;
 
        if (adapter->op_mode != QLCNIC_MGMT_FUNC)
-               return err;
+               return -EIO;
 
-       eswitch = &adapter->eswitch[id];
-       if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+       if (func_esw == QLCNIC_STATS_PORT) {
+               if (port >= QLCNIC_MAX_PCI_FUNC)
+                       goto err_ret;
+       } else if (func_esw == QLCNIC_STATS_ESWITCH) {
+               if (port >= QLCNIC_NIU_MAX_XG_PORTS)
+                       goto err_ret;
+       } else {
+               goto err_ret;
+       }
+
+       if (rx_tx > QLCNIC_QUERY_TX_COUNTER)
+               goto err_ret;
+
+       arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
+       arg1 |= BIT_14 | rx_tx << 15;
+
+       return qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+
+err_ret:
+       dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
+               "rx_ctx=%d\n", func_esw, port, rx_tx);
+       return -EIO;
+}
+
+static int
+__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+                                       u32 *arg1, u32 *arg2)
+{
+       int err = -EIO;
+       u8 pci_func;
+       pci_func = (*arg1 >> 8);
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       *arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               *arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               *arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+               dev_info(&adapter->pdev->dev,
+                       "eSwitch port config for pci func %d\n", pci_func);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get eswitch port config for pci func %d\n",
+                                                               pci_func);
+       }
+       return err;
+}
+/* Configure eSwitch port
+op_mode = 0 for setting default port behavior
+op_mode = 1 for setting  vlan id
+op_mode = 2 for deleting vlan id
+op_type = 0 for vlan_id
+op_type = 1 for port vlan_id
+*/
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
+               struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       int err = -EIO;
+       u32 arg1, arg2 = 0;
+       u8 pci_func;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return err;
+       pci_func = esw_cfg->pci_func;
+       arg1 = (adapter->npars[pci_func].phy_port & BIT_0);
+       arg1 |= (pci_func << 8);
 
-       arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
-       arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
-       arg1 |= pci_func << 8;
-       if (vlan_tagging)
-               arg1 |= BIT_5 | (vlan_id << 16);
+       if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
+               return err;
+       arg1 &= ~(0x0ff << 8);
+       arg1 |= (pci_func << 8);
+       arg1 &= ~(BIT_2 | BIT_3);
+       switch (esw_cfg->op_mode) {
+       case QLCNIC_PORT_DEFAULTS:
+               arg1 |= (BIT_4 | BIT_6 | BIT_7);
+               arg2 |= (BIT_0 | BIT_1);
+               if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+                       arg2 |= (BIT_2 | BIT_3);
+               if (!(esw_cfg->discard_tagged))
+                       arg1 &= ~BIT_4;
+               if (!(esw_cfg->promisc_mode))
+                       arg1 &= ~BIT_6;
+               if (!(esw_cfg->mac_override))
+                       arg1 &= ~BIT_7;
+               if (!(esw_cfg->mac_anti_spoof))
+                       arg2 &= ~BIT_0;
+               if (!(esw_cfg->offload_flags & BIT_0))
+                       arg2 &= ~(BIT_1 | BIT_2 | BIT_3);
+               if (!(esw_cfg->offload_flags & BIT_1))
+                       arg2 &= ~BIT_2;
+               if (!(esw_cfg->offload_flags & BIT_2))
+                       arg2 &= ~BIT_3;
+               break;
+       case QLCNIC_ADD_VLAN:
+                       arg1 |= (BIT_2 | BIT_5);
+                       arg1 |= (esw_cfg->vlan_id << 16);
+                       break;
+       case QLCNIC_DEL_VLAN:
+                       arg1 |= (BIT_3 | BIT_5);
+                       arg1 &= ~(0x0ffff << 16);
+                       break;
+       default:
+               return err;
+       }
 
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
                        adapter->fw_hal_version,
                        arg1,
-                       0,
+                       arg2,
                        0,
                        QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
 
        if (err != QLCNIC_RCODE_SUCCESS) {
                dev_err(&adapter->pdev->dev,
-                       "Failed to configure eswitch port%d\n", eswitch->port);
-               eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+                       "Failed to configure eswitch pci func %d\n", pci_func);
        } else {
-               eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
                dev_info(&adapter->pdev->dev,
-                       "Configured eSwitch for port %d\n", eswitch->port);
+                       "Configured eSwitch for pci func %d\n", pci_func);
        }
 
        return err;
 }
+
+int
+qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       u32 arg1, arg2;
+       u8 phy_port;
+       if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+               phy_port = adapter->npars[esw_cfg->pci_func].phy_port;
+       else
+               phy_port = adapter->physical_port;
+       arg1 = phy_port;
+       arg1 |= (esw_cfg->pci_func << 8);
+       if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
+               return -EIO;
+
+       esw_cfg->discard_tagged = !!(arg1 & BIT_4);
+       esw_cfg->host_vlan_tag = !!(arg1 & BIT_5);
+       esw_cfg->promisc_mode = !!(arg1 & BIT_6);
+       esw_cfg->mac_override = !!(arg1 & BIT_7);
+       esw_cfg->vlan_id = LSW(arg1 >> 16);
+       esw_cfg->mac_anti_spoof = (arg2 & 0x1);
+       esw_cfg->offload_flags = ((arg2 >> 1) & 0x7);
+
+       return 0;
+}