+static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+ u8 id;
+ u32 ref_count;
+ int i, ret = 1;
+ u32 data = QLCNIC_MGMT_FUNC;
+ void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+ /* If other drivers are not in use set their privilege level */
+ ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ ret = qlcnic_api_lock(adapter);
+ if (ret)
+ goto err_lock;
+ if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+ goto err_npar;
+
+ if (qlcnic_config_npars) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ id = adapter->npars[i].id;
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+ id == adapter->ahw.pci_func)
+ continue;
+ data |= (qlcnic_config_npars &
+ QLC_DEV_SET_DRV(0xf, id));
+ }
+ } else {
+ data = readl(priv_op);
+ data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
+ (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
+ adapter->ahw.pci_func));
+ }
+ writel(data, priv_op);
+err_npar:
+ qlcnic_api_unlock(adapter);
+err_lock:
+ return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+ void __iomem *msix_base_addr;
+ void __iomem *priv_op;
+ u32 func;
+ u32 msix_base;
+ u32 op_mode, priv_level;
+
+ /* Determine FW API version */
+ adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+ if (adapter->fw_hal_version == ~0) {
+ adapter->nic_ops = &qlcnic_ops;
+ adapter->fw_hal_version = QLCNIC_FW_BASE;
+ adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn);
+ adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+ dev_info(&adapter->pdev->dev,
+ "FW does not support nic partion\n");
+ return adapter->fw_hal_version;
+ }
+
+ /* Find PCI function number */
+ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+ msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+ msix_base = readl(msix_base_addr);
+ func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+ adapter->ahw.pci_func = func;
+
+ qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ adapter->nic_ops = &qlcnic_ops;
+ return adapter->fw_hal_version;
+ }
+
+ /* Determine function privilege level */
+ priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ op_mode = readl(priv_op);
+ if (op_mode == QLC_DEV_DRV_DEFAULT)
+ priv_level = QLCNIC_MGMT_FUNC;
+ else
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+ switch (priv_level) {
+ case QLCNIC_MGMT_FUNC:
+ adapter->op_mode = QLCNIC_MGMT_FUNC;
+ adapter->nic_ops = &qlcnic_pf_ops;
+ qlcnic_get_pci_info(adapter);
+ /* Set privilege level for other functions */
+ qlcnic_set_function_modes(adapter);
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Management function\n",
+ adapter->fw_hal_version);
+ break;
+ case QLCNIC_PRIV_FUNC:
+ adapter->op_mode = QLCNIC_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Privileged function\n",
+ 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);
+ return 0;
+ }
+ return adapter->fw_hal_version;
+}
+