qlcnic: NIC Partitioning - Add non privileged mode support
authorAnirban Chakraborty <anirban.chakraborty@qlogic.com>
Tue, 1 Jun 2010 11:33:09 +0000 (11:33 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jun 2010 09:24:03 +0000 (02:24 -0700)
Added support for NIC functions that work in non privileged mode where these
functions are privileged to do IO only, the control operations are handled via
privileged functions.
Bumped up version number to 5.0.3.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_hdr.h
drivers/net/qlcnic/qlcnic_main.c

index 31a0b430a9d739d4db11129e852125fdb08343e1..02db363f20cd1f0067bbd8974ddf15bea85cc513 100644 (file)
@@ -51,8 +51,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 2
-#define QLCNIC_LINUX_VERSIONID  "5.0.2"
+#define _QLCNIC_LINUX_SUBVERSION 3
+#define QLCNIC_LINUX_VERSIONID  "5.0.3"
 #define QLCNIC_DRV_IDC_VER  0x01
 
 #define QLCNIC_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
@@ -891,6 +891,7 @@ struct qlcnic_mac_req {
 #define QLCNIC_LRO_ENABLED             0x08
 #define QLCNIC_BRIDGE_ENABLED          0X10
 #define QLCNIC_DIAG_ENABLED            0x20
+#define QLCNIC_NPAR_ENABLED            0x40
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
@@ -1159,13 +1160,6 @@ int qlcnic_check_loopback_buff(unsigned char *data);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 
-/* Functions from qlcnic_vf.c */
-int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
-int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
-int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter);
-void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter);
-void qlcnicvf_set_port_mode(struct qlcnic_adapter *adapter);
-
 /* Management functions */
 int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
 int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
@@ -1234,6 +1228,7 @@ struct qlcnic_nic_template {
        int (*config_led) (struct qlcnic_adapter *, u32, u32);
        int (*set_ilb_mode) (struct qlcnic_adapter *);
        void (*clear_ilb_mode) (struct qlcnic_adapter *);
+       int (*start_firmware) (struct qlcnic_adapter *);
 };
 
 #define QLCDB(adapter, lvl, _fmt, _args...) do {       \
index 1bcfb121a89568a8338c75c7b29675253ed68f9c..7b81cab270023809addbf1b8ef81f98323a94127 100644 (file)
@@ -701,10 +701,11 @@ enum {
 #define QLCNIC_CRB_DEV_REF_COUNT       (QLCNIC_CAM_RAM(0x138))
 #define QLCNIC_CRB_DEV_STATE           (QLCNIC_CAM_RAM(0x140))
 
-#define QLCNIC_CRB_DRV_STATE               (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH             (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO      (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_STATE           (QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH         (QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO  (QLCNIC_CAM_RAM(0x14c))
 #define QLCNIC_CRB_DRV_IDC_VER         (QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_CRB_DEV_NPAR_STATE      (QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT    (0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT   (0x3e8860)
 
@@ -717,6 +718,9 @@ enum {
 #define QLCNIC_DEV_FAILED              0x6
 #define QLCNIC_DEV_QUISCENT            0x7
 
+#define QLCNIC_DEV_NPAR_NOT_RDY        0
+#define QLCNIC_DEV_NPAR_RDY            1
+
 #define QLC_DEV_CHECK_ACTIVE(VAL, FN)          ((VAL) &= (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)           ((VAL) &= ~(1 << (FN * 4)))
@@ -732,8 +736,8 @@ enum {
 #define QLCNIC_TYPE_ISCSI              3
 
 #define QLCNIC_RCODE_DRIVER_INFO               0x20000000
-#define QLCNIC_RCODE_DRIVER_CAN_RELOAD         0x40000000
-#define QLCNIC_RCODE_FATAL_ERROR               0x80000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD         BIT_30
+#define QLCNIC_RCODE_FATAL_ERROR               BIT_31
 #define QLCNIC_FWERROR_PEGNUM(code)            ((code) & 0xff)
 #define QLCNIC_FWERROR_CODE(code)              ((code >> 8) & 0xfffff)
 
index 1e5e66facabd263268b94355a0ab8e198b9b5a77..119bcae5e74bdcdcef9b69809addfb5ab8c3c677 100644 (file)
@@ -103,7 +103,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
 static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
-
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
+
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -375,7 +382,8 @@ static struct qlcnic_nic_template qlcnic_ops = {
        .config_bridged_mode = qlcnic_config_bridged_mode,
        .config_led = qlcnic_config_led,
        .set_ilb_mode = qlcnic_set_ilb_mode,
-       .clear_ilb_mode = qlcnic_clear_ilb_mode
+       .clear_ilb_mode = qlcnic_clear_ilb_mode,
+       .start_firmware = qlcnic_start_firmware
 };
 
 static struct qlcnic_nic_template qlcnic_pf_ops = {
@@ -383,7 +391,17 @@ static struct qlcnic_nic_template qlcnic_pf_ops = {
        .config_bridged_mode = qlcnic_config_bridged_mode,
        .config_led = qlcnic_config_led,
        .set_ilb_mode = qlcnic_set_ilb_mode,
-       .clear_ilb_mode = qlcnic_clear_ilb_mode
+       .clear_ilb_mode = qlcnic_clear_ilb_mode,
+       .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+       .get_mac_addr = qlcnic_get_mac_address,
+       .config_bridged_mode = qlcnicvf_config_bridged_mode,
+       .config_led = qlcnicvf_config_led,
+       .set_ilb_mode = qlcnicvf_set_ilb_mode,
+       .clear_ilb_mode = qlcnicvf_clear_ilb_mode,
+       .start_firmware = qlcnicvf_start_firmware
 };
 
 static void
@@ -467,7 +485,6 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
                iounmap(adapter->ahw.pci_base0);
 }
 
-/* Use api lock to access this function */
 static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
@@ -567,6 +584,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
                /* Set privilege level for other functions */
                if (qlcnic_config_npars)
                        qlcnic_set_function_modes(adapter);
+               qlcnic_dev_set_npar_ready(adapter);
                dev_info(&adapter->pdev->dev,
                        "HAL Version: %d, Management function\n",
                        adapter->fw_hal_version);
@@ -578,6 +596,13 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
                        adapter->fw_hal_version);
                adapter->nic_ops = &qlcnic_pf_ops;
                break;
+       case QLCNIC_NON_PRIV_FUNC:
+               adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d Non Privileged function\n",
+                       adapter->fw_hal_version);
+               adapter->nic_ops = &qlcnic_vf_ops;
+               break;
        default:
                dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
                        priv_level);
@@ -772,6 +797,8 @@ wait_init:
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
        qlcnic_idc_debug_info(adapter, 1);
 
+       qlcnic_dev_set_npar_ready(adapter);
+
        qlcnic_check_options(adapter);
 
        if (adapter->fw_hal_version != QLCNIC_FW_BASE &&
@@ -1244,7 +1271,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (qlcnic_setup_idc_param(adapter))
                goto err_out_iounmap;
 
-       err = qlcnic_start_firmware(adapter);
+       err = adapter->nic_ops->start_firmware(adapter);
        if (err) {
                dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
                goto err_out_decr_ref;
@@ -1410,7 +1437,7 @@ qlcnic_resume(struct pci_dev *pdev)
        pci_set_master(pdev);
        pci_restore_state(pdev);
 
-       err = qlcnic_start_firmware(adapter);
+       err = adapter->nic_ops->start_firmware(adapter);
        if (err) {
                dev_err(&pdev->dev, "failed to start firmware\n");
                return err;
@@ -2260,7 +2287,7 @@ qlcnic_fwinit_work(struct work_struct *work)
 {
        struct qlcnic_adapter *adapter = container_of(work,
                        struct qlcnic_adapter, fw_work.work);
-       u32 dev_state = 0xf;
+       u32 dev_state = 0xf, npar_state;
 
        if (qlcnic_api_lock(adapter))
                goto err_ret;
@@ -2273,6 +2300,19 @@ qlcnic_fwinit_work(struct work_struct *work)
                return;
        }
 
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+               if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+                       qlcnic_api_unlock(adapter);
+                       goto wait_npar;
+               } else {
+                       qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                               FW_POLL_DELAY);
+                       qlcnic_api_unlock(adapter);
+                       return;
+               }
+       }
+
        if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
                dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
                                        adapter->reset_ack_timeo);
@@ -2305,7 +2345,7 @@ skip_ack_check:
 
                qlcnic_api_unlock(adapter);
 
-               if (!qlcnic_start_firmware(adapter)) {
+               if (!adapter->nic_ops->start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
                        return;
                }
@@ -2314,6 +2354,7 @@ skip_ack_check:
 
        qlcnic_api_unlock(adapter);
 
+wait_npar:
        dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
        QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
@@ -2328,7 +2369,7 @@ skip_ack_check:
                break;
 
        default:
-               if (!qlcnic_start_firmware(adapter)) {
+               if (!adapter->nic_ops->start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
                        return;
                }
@@ -2402,6 +2443,30 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
        qlcnic_api_unlock(adapter);
 }
 
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC ||
+               adapter->fw_hal_version == QLCNIC_FW_BASE)
+               return;
+
+       if (qlcnic_api_lock(adapter))
+               return;
+
+       state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+       if (state != QLCNIC_DEV_NPAR_RDY) {
+               QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+                       QLCNIC_DEV_NPAR_RDY);
+               QLCDB(adapter, DRV, "NPAR READY state set\n");
+       }
+
+       qlcnic_api_unlock(adapter);
+}
+
 static void
 qlcnic_schedule_work(struct qlcnic_adapter *adapter,
                work_func_t func, int delay)
@@ -2889,6 +2954,47 @@ done:
        return NOTIFY_DONE;
 }
 
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+       int err;
+
+       err = qlcnic_can_start_firmware(adapter);
+       if (err)
+               return err;
+
+       qlcnic_check_options(adapter);
+
+       adapter->need_fw_reset = 0;
+
+       return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+       return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+       return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       return -EOPNOTSUPP;
+}
+
+static void
+qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       return;
+}
+
+
 static struct notifier_block   qlcnic_netdev_cb = {
        .notifier_call = qlcnic_netdev_event,
 };