]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
qlcnic: Replace poll mode mailbox interface with interrupt based mailbox interface
[linux.git] / drivers / net / ethernet / qlogic / qlcnic / qlcnic_83xx_hw.c
index 74c8d84dc43d5b465627d9e52e14e9638fea83b8..1eeeed89ef6fe4bd2a933164c5906d99e0d367e2 100644 (file)
@@ -362,6 +362,10 @@ static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
                                     struct qlcnic_cmd_args *cmd)
 {
        int i;
+
+       if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)
+               return;
+
        for (i = 0; i < cmd->rsp.num; i++)
                cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
 }
@@ -406,22 +410,25 @@ static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
 
 static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
 {
-       u32 resp, event;
+       u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
+       struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
        unsigned long flags;
 
-       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-
+       spin_lock_irqsave(&mbx->aen_lock, flags);
        resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
        if (!(resp & QLCNIC_SET_OWNER))
                goto out;
 
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+       if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
-
+       } else {
+               if (atomic_read(&mbx->rsp_status) != rsp_status)
+                       qlcnic_83xx_notify_mbx_response(mbx);
+       }
 out:
        qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
-       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+       spin_unlock_irqrestore(&mbx->aen_lock, flags);
 }
 
 irqreturn_t qlcnic_83xx_intr(int irq, void *data)
@@ -694,6 +701,9 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
 {
        int i;
 
+       if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)
+               return;
+
        dev_info(&adapter->pdev->dev,
                 "Host MBX regs(%d)\n", cmd->req.num);
        for (i = 0; i < cmd->req.num; i++) {
@@ -712,120 +722,74 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
        pr_info("\n");
 }
 
-/* Mailbox response for mac rcode */
-u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+static inline void
+qlcnic_83xx_poll_for_mbx_completion(struct qlcnic_adapter *adapter,
+                                   struct qlcnic_cmd_args *cmd)
 {
-       u32 fw_data;
-       u8 mac_cmd_rcode;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int opcode = LSW(cmd->req.arg[0]);
+       unsigned long max_loops;
 
-       fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
-       mac_cmd_rcode = (u8)fw_data;
-       if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
-           mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
-           mac_cmd_rcode == QLC_83XX_MAC_ABSENT)
-               return QLCNIC_RCODE_SUCCESS;
-       return 1;
-}
+       max_loops = cmd->total_cmds * QLC_83XX_MBX_CMD_LOOP;
 
-u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time)
-{
-       u32 data;
-       struct qlcnic_hardware_context *ahw = adapter->ahw;
-       /* wait for mailbox completion */
-       do {
-               data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
-               if (++(*wait_time) > QLCNIC_MBX_TIMEOUT) {
-                       data = QLCNIC_RCODE_TIMEOUT;
-                       break;
-               }
-               mdelay(1);
-       } while (!data);
-       return data;
+       for (; max_loops; max_loops--) {
+               if (atomic_read(&cmd->rsp_status) ==
+                   QLC_83XX_MBX_RESPONSE_ARRIVED)
+                       return;
+
+               udelay(1);
+       }
+
+       dev_err(&adapter->pdev->dev,
+               "%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+               __func__, opcode, cmd->type, ahw->pci_func, ahw->op_mode);
+       flush_workqueue(ahw->mailbox->work_q);
+       return;
 }
 
 int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,
                          struct qlcnic_cmd_args *cmd)
 {
-       int i;
-       u16 opcode;
-       u8 mbx_err_code;
-       unsigned long flags;
+       struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
-       u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, wait_time = 0;
+       int cmd_type, err, opcode;
+       unsigned long timeout;
 
        opcode = LSW(cmd->req.arg[0]);
-       if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
-               dev_info(&adapter->pdev->dev,
-                        "Mailbox cmd attempted, 0x%x\n", opcode);
-               dev_info(&adapter->pdev->dev, "Mailbox detached\n");
-               return 0;
+       cmd_type = cmd->type;
+       err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Mailbox not available, cmd_op=0x%x, cmd_context=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+                       __func__, opcode, cmd->type, ahw->pci_func,
+                       ahw->op_mode);
+               return err;
        }
 
-       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
-
-       if (mbx_val) {
-               QLCDB(adapter, DRV,
-                     "Mailbox cmd attempted, 0x%x\n", opcode);
-               QLCDB(adapter, DRV,
-                     "Mailbox not available, 0x%x, collect FW dump\n",
-                     mbx_val);
-               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
-               spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-               return cmd->rsp.arg[0];
-       }
-
-       /* Fill in mailbox registers */
-       mbx_cmd = cmd->req.arg[0];
-       writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
-       for (i = 1; i < cmd->req.num; i++)
-               writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
-
-       /* Signal FW about the impending command */
-       QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
-poll:
-       rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time);
-       if (rsp != QLCNIC_RCODE_TIMEOUT) {
-               /* Get the FW response data */
-               fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
-               if (fw_data &  QLCNIC_MBX_ASYNC_EVENT) {
-                       __qlcnic_83xx_process_aen(adapter);
-                       goto poll;
-               }
-               mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
-               rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
-               opcode = QLCNIC_MBX_RSP(fw_data);
-               qlcnic_83xx_get_mbx_data(adapter, cmd);
-
-               switch (mbx_err_code) {
-               case QLCNIC_MBX_RSP_OK:
-               case QLCNIC_MBX_PORT_RSP_OK:
-                       rsp = QLCNIC_RCODE_SUCCESS;
-                       break;
-               default:
-                       if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
-                               rsp = qlcnic_83xx_mac_rcode(adapter);
-                               if (!rsp)
-                                       goto out;
-                       }
+       switch (cmd_type) {
+       case QLC_83XX_MBX_CMD_WAIT:
+               if (!wait_for_completion_timeout(&cmd->completion, timeout)) {
                        dev_err(&adapter->pdev->dev,
-                               "MBX command 0x%x failed with err:0x%x\n",
-                               opcode, mbx_err_code);
-                       rsp = mbx_err_code;
-                       qlcnic_dump_mbx(adapter, cmd);
-                       break;
+                               "%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+                               __func__, opcode, cmd_type, ahw->pci_func,
+                               ahw->op_mode);
+                       flush_workqueue(mbx->work_q);
                }
-               goto out;
+               break;
+       case QLC_83XX_MBX_CMD_NO_WAIT:
+               return 0;
+       case QLC_83XX_MBX_CMD_BUSY_WAIT:
+               qlcnic_83xx_poll_for_mbx_completion(adapter, cmd);
+               break;
+       default:
+               dev_err(&adapter->pdev->dev,
+                       "%s: Invalid mailbox command, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+                       __func__, opcode, cmd_type, ahw->pci_func,
+                       ahw->op_mode);
+               qlcnic_83xx_detach_mailbox_work(adapter);
        }
 
-       dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
-               QLCNIC_MBX_RSP(mbx_cmd));
-       rsp = QLCNIC_RCODE_TIMEOUT;
-out:
-       /* clear fw mbx control register */
-       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
-       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-       return rsp;
+       return cmd->rsp_opcode;
 }
 
 int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
@@ -858,6 +822,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
                        memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
                        temp = adapter->ahw->fw_hal_version << 29;
                        mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
+                       mbx->cmd_op = type;
                        return 0;
                }
        }
@@ -941,20 +906,23 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
 
 static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
 {
+       u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
-       u32 resp, event;
+       struct qlcnic_mailbox *mbx = ahw->mailbox;
        unsigned long flags;
 
-       spin_lock_irqsave(&ahw->mbx_lock, flags);
-
+       spin_lock_irqsave(&mbx->aen_lock, flags);
        resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
        if (resp & QLCNIC_SET_OWNER) {
                event = readl(QLCNIC_MBX_FW(ahw, 0));
-               if (event &  QLCNIC_MBX_ASYNC_EVENT)
+               if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                        __qlcnic_83xx_process_aen(adapter);
+               } else {
+                       if (atomic_read(&mbx->rsp_status) != rsp_status)
+                               qlcnic_83xx_notify_mbx_response(mbx);
+               }
        }
-
-       spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+       spin_unlock_irqrestore(&mbx->aen_lock, flags);
 }
 
 static void qlcnic_83xx_mbx_poll_work(struct work_struct *work)
@@ -1627,26 +1595,33 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,
 
 int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 {
-       int err;
+       struct qlcnic_cmd_args *cmd = NULL;
        u32 temp = 0;
-       struct qlcnic_cmd_args cmd;
+       int err;
 
        if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
                return -EIO;
 
-       err = qlcnic_alloc_mbx_args(&cmd, adapter,
+       cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+       if (!cmd)
+               return -ENOMEM;
+
+       err = qlcnic_alloc_mbx_args(cmd, adapter,
                                    QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
        if (err)
-               return err;
+               goto out;
 
+       cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
        qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
-       cmd.req.arg[1] = (mode ? 1 : 0) | temp;
-       err = qlcnic_issue_cmd(adapter, &cmd);
-       if (err)
-               dev_info(&adapter->pdev->dev,
-                        "Promiscous mode config failed\n");
+       cmd->req.arg[1] = (mode ? 1 : 0) | temp;
+       err = qlcnic_issue_cmd(adapter, cmd);
+       if (!err)
+               return err;
 
-       qlcnic_free_mbx_args(&cmd);
+       qlcnic_free_mbx_args(cmd);
+
+out:
+       kfree(cmd);
        return err;
 }
 
@@ -1967,25 +1942,31 @@ static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter,
 int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
                                   u16 vlan_id, u8 op)
 {
-       int err;
-       u32 *buf, temp = 0;
-       struct qlcnic_cmd_args cmd;
+       struct qlcnic_cmd_args *cmd = NULL;
        struct qlcnic_macvlan_mbx mv;
+       u32 *buf, temp = 0;
+       int err;
 
        if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
                return -EIO;
 
-       err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
+       cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+       if (!cmd)
+               return -ENOMEM;
+
+       err = qlcnic_alloc_mbx_args(cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
        if (err)
-               return err;
+               goto out;
+
+       cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
 
        if (vlan_id)
                op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
                     QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;
 
-       cmd.req.arg[1] = op | (1 << 8);
+       cmd->req.arg[1] = op | (1 << 8);
        qlcnic_83xx_set_interface_id_macaddr(adapter, &temp);
-       cmd.req.arg[1] |= temp;
+       cmd->req.arg[1] |= temp;
        mv.vlan = vlan_id;
        mv.mac_addr0 = addr[0];
        mv.mac_addr1 = addr[1];
@@ -1993,14 +1974,15 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
        mv.mac_addr3 = addr[3];
        mv.mac_addr4 = addr[4];
        mv.mac_addr5 = addr[5];
-       buf = &cmd.req.arg[2];
+       buf = &cmd->req.arg[2];
        memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
-       err = qlcnic_issue_cmd(adapter, &cmd);
-       if (err)
-               dev_err(&adapter->pdev->dev,
-                       "MAC-VLAN %s to CAM failed, err=%d.\n",
-                       ((op == 1) ? "add " : "delete "), err);
-       qlcnic_free_mbx_args(&cmd);
+       err = qlcnic_issue_cmd(adapter, cmd);
+       if (!err)
+               return err;
+
+       qlcnic_free_mbx_args(cmd);
+out:
+       kfree(cmd);
        return err;
 }
 
@@ -2109,10 +2091,12 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
 irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
        struct qlcnic_adapter *adapter = data;
-       unsigned long flags;
+       struct qlcnic_mailbox *mbx;
        u32 mask, resp, event;
+       unsigned long flags;
 
-       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+       mbx = adapter->ahw->mailbox;
+       spin_lock_irqsave(&mbx->aen_lock, flags);
        resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
        if (!(resp & QLCNIC_SET_OWNER))
                goto out;
@@ -2120,11 +2104,13 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
        if (event &  QLCNIC_MBX_ASYNC_EVENT)
                __qlcnic_83xx_process_aen(adapter);
+       else
+               qlcnic_83xx_notify_mbx_response(mbx);
+
 out:
        mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
        writel(0, adapter->ahw->pci_base0 + mask);
-       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-
+       spin_unlock_irqrestore(&mbx->aen_lock, flags);
        return IRQ_HANDLED;
 }