qlcnic: enable 83xx virtual NIC mode
authorSony Chacko <sony.chacko@qlogic.com>
Tue, 1 Jan 2013 03:20:26 +0000 (03:20 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jan 2013 10:43:27 +0000 (02:43 -0800)
Enable 83xx virtual NIC mode

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/Makefile
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c

index 799325db5c7989916fd0161b2a0aa47f406c2d2f..25b73f163886df1214c28bb17c29615adf9c965d 100644 (file)
@@ -7,4 +7,4 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
        qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
        qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \
-       qlcnic_83xx_init.o
+       qlcnic_83xx_init.o qlcnic_83xx_vnic.o
index 5b36d92b237d613d2a78f1eff69c2599fc299fb4..af8510bdfb9e805c69b1a6d5c86c1f2de68e5abf 100644 (file)
@@ -1523,7 +1523,10 @@ int __qlcnic_up(struct qlcnic_adapter *, struct net_device *);
 void qlcnic_restore_indev_addr(struct net_device *, unsigned long);
 
 int qlcnic_check_temp(struct qlcnic_adapter *);
-
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
 /*
  * QLOGIC Board information
  */
index 969bda8e32c4e194cc802d547cebad87d858467a..f378d21716159f40a2dccbed515bb122851c416b 100644 (file)
@@ -400,4 +400,11 @@ int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
 void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);
 int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *);
 int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
+                                   struct qlcnic_info *, u8);
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
 #endif
index d222ee291e7c2711b5fc9e23d359dd6dad3e4aa6..b14fb83fcdd6bf7612e73dfb9900d3b6e9ab9a3d 100644 (file)
@@ -643,6 +643,52 @@ int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *adapter)
        return 0;
 }
 
+/**
+ * qlcnic_83xx_idc_vnic_pf_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Ensure vNIC mode privileged function starts only after vNIC mode is
+ * enabled by management function.
+ * If vNIC mode is ready, start initialization.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Privileged function waits till mgmt function enables VNIC mode */
+       state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
+       if (state != QLCNIC_DEV_NPAR_OPER) {
+               if (!ahw->idc.vnic_wait_limit--) {
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+               dev_info(&adapter->pdev->dev, "vNIC mode disabled\n");
+               return -EIO;
+
+       } else {
+               /* Perform one time initialization from ready state */
+               if (ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
+                       qlcnic_83xx_idc_update_idc_params(adapter);
+
+                       /* If the previous state is UNKNOWN, device will be
+                          already attached properly by Init routine*/
+                       if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_UNKNOWN) {
+                               if (qlcnic_83xx_idc_reattach_driver(adapter))
+                                       return -EIO;
+                       }
+                       adapter->ahw->idc.vnic_state =  QLCNIC_DEV_NPAR_OPER;
+                       dev_info(&adapter->pdev->dev, "vNIC mode enabled\n");
+               }
+       }
+
+       return 0;
+}
+
 static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
 {
        adapter->ahw->idc.err_code = -EIO;
@@ -802,6 +848,8 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
                qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
                set_bit(__QLCNIC_RESETTING, &adapter->state);
                clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+               if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+                       qlcnic_83xx_disable_vnic_mode(adapter, 1);
                qlcnic_83xx_idc_detach_driver(adapter);
        }
 
@@ -1887,7 +1935,10 @@ static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
        if (ret == -EIO)
                return -EIO;
 
-       if (ret == QLC_83XX_DEFAULT_MODE) {
+       if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+               if (qlcnic_83xx_config_vnic_opmode(adapter))
+                       return -EIO;
+       } else if (ret == QLC_83XX_DEFAULT_MODE) {
                if (qlcnic_83xx_config_default_opmode(adapter))
                        return -EIO;
        }
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644 (file)
index 0000000..d394471
--- /dev/null
@@ -0,0 +1,216 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u8 id;
+       int i, ret = -EBUSY;
+       u32 data = QLCNIC_MGMT_FUNC;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_lock_driver(adapter))
+               return ret;
+
+       if (qlcnic_config_npars) {
+               for (i = 0; i < ahw->act_pci_func; i++) {
+                       id = adapter->npars[i].pci_func;
+                       if (id == ahw->pci_func)
+                               continue;
+                       data |= qlcnic_config_npars &
+                               QLC_83XX_SET_FUNC_OPMODE(0x3, id);
+               }
+       } else {
+               data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+               data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+                      QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+                                               ahw->pci_func);
+       }
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+       qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+       } else if (ahw->port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+       }
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management virtual NIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns: Success(0) or error code.
+ *
+ **/
+static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+               if (qlcnic_init_pci_info(adapter))
+                       return err;
+
+               if (qlcnic_83xx_set_vnic_opmode(adapter))
+                       return err;
+
+               if (qlcnic_set_default_offload_settings(adapter))
+                       return err;
+       } else {
+               if (qlcnic_reset_npar_config(adapter))
+                       return err;
+       }
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+       qlcnic_83xx_enable_vnic_mode(adapter, 1);
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+                adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+static int qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev,
+                "HAL Version: %d, Privileged function\n",
+                adapter->ahw->fw_hal_version);
+       return 0;
+}
+
+static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_fw_version(adapter);
+       if (qlcnic_set_eswitch_port_config(adapter))
+               return err;
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+                adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns: Success(0) or error code.
+ *
+ **/
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u32 op_mode, priv_level;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_nic_template *nic_ops = adapter->nic_ops;
+
+       qlcnic_get_func_no(adapter);
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+                                                        ahw->pci_func);
+
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
+       } else if (priv_level == QLCNIC_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_PRIV_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
+       } else if (priv_level == QLCNIC_MGMT_FUNC) {
+               ahw->op_mode = QLCNIC_MGMT_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
+       } else {
+               return -EIO;
+       }
+
+       if (ahw->capabilities & BIT_23)
+               adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+       else
+               adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+       adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+       adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+       return 0;
+}
index c71e1dc7295da21ddfbdb4bc997520ac8ee2b38f..da04432f36ecaa7f0b0242ac6e679dacfeabc51c 100644 (file)
@@ -502,7 +502,8 @@ static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
        kfree(pci_info);
        return ret;
 }
-static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+
+int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_pci_info *pci_info;
        int i, ret = 0, j = 0;
@@ -851,7 +852,7 @@ void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
        qlcnic_set_netdev_features(adapter, esw_cfg);
 }
 
-static int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
 
@@ -950,7 +951,7 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
        return err;
 }
 
-static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
        struct qlcnic_npar_info *npar;
@@ -1007,7 +1008,7 @@ qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
 {
        int i, err;
        struct qlcnic_npar_info *npar;