be2net: Fix wrong status getting returned for MCC commands
authorPadmanabh Ratnakar <padmanabh.ratnakar@emulex.com>
Wed, 25 Apr 2012 01:47:03 +0000 (01:47 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 26 Apr 2012 09:03:31 +0000 (05:03 -0400)
MCC Response CQEs are processed as part of NAPI poll routine and
also synchronously. If MCC completions are consumed by NAPI poll
routine, wrong status is returned to synchronously waiting routine.
Fix this by getting status of MCC command from command response
instead of response CQEs.

Signed-off-by: Padmanabh Ratnakar <padmanabh.ratnakar@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h

index ad69cf89491cd6a8fd1106640270556d601edf51..4bc18efb7053c459b7beb1fbbbf80e08c11c9cfd 100644 (file)
@@ -162,6 +162,11 @@ static inline void queue_head_inc(struct be_queue_info *q)
        index_inc(&q->head, q->len);
 }
 
+static inline void index_dec(u16 *index, u16 limit)
+{
+       *index = MODULO((*index - 1), limit);
+}
+
 static inline void queue_tail_inc(struct be_queue_info *q)
 {
        index_inc(&q->tail, q->len);
index 4e07e58286a19f245f5793295e6c8654214c5267..2673081aaf2f15c9da8f59ebfcf20b46c31f05fd 100644 (file)
@@ -61,10 +61,21 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
        compl->flags = 0;
 }
 
+static struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1)
+{
+       unsigned long addr;
+
+       addr = tag1;
+       addr = ((addr << 16) << 16) | tag0;
+       return (void *)addr;
+}
+
 static int be_mcc_compl_process(struct be_adapter *adapter,
-       struct be_mcc_compl *compl)
+                               struct be_mcc_compl *compl)
 {
        u16 compl_status, extd_status;
+       struct be_cmd_resp_hdr *resp_hdr;
+       u8 opcode = 0, subsystem = 0;
 
        /* Just swap the status to host endian; mcc tag is opaquely copied
         * from mcc_wrb */
@@ -73,32 +84,36 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
        compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
                                CQE_STATUS_COMPL_MASK;
 
-       if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) ||
-               (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) &&
-               (compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
+       resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1);
+
+       if (resp_hdr) {
+               opcode = resp_hdr->opcode;
+               subsystem = resp_hdr->subsystem;
+       }
+
+       if (((opcode == OPCODE_COMMON_WRITE_FLASHROM) ||
+            (opcode == OPCODE_COMMON_WRITE_OBJECT)) &&
+           (subsystem == CMD_SUBSYSTEM_COMMON)) {
                adapter->flash_status = compl_status;
                complete(&adapter->flash_compl);
        }
 
        if (compl_status == MCC_STATUS_SUCCESS) {
-               if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) ||
-                        (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) &&
-                       (compl->tag1 == CMD_SUBSYSTEM_ETH)) {
+               if (((opcode == OPCODE_ETH_GET_STATISTICS) ||
+                    (opcode == OPCODE_ETH_GET_PPORT_STATS)) &&
+                   (subsystem == CMD_SUBSYSTEM_ETH)) {
                        be_parse_stats(adapter);
                        adapter->stats_cmd_sent = false;
                }
-               if (compl->tag0 ==
-                               OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) {
-                       struct be_mcc_wrb *mcc_wrb =
-                               queue_index_node(&adapter->mcc_obj.q,
-                                               compl->tag1);
+               if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES &&
+                   subsystem == CMD_SUBSYSTEM_COMMON) {
                        struct be_cmd_resp_get_cntl_addnl_attribs *resp =
-                               embedded_payload(mcc_wrb);
+                               (void *)resp_hdr;
                        adapter->drv_stats.be_on_die_temperature =
                                resp->on_die_temperature;
                }
        } else {
-               if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES)
+               if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES)
                        be_get_temp_freq = 0;
 
                if (compl_status == MCC_STATUS_NOT_SUPPORTED ||
@@ -108,13 +123,13 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
                if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) {
                        dev_warn(&adapter->pdev->dev, "This domain(VM) is not "
                                "permitted to execute this cmd (opcode %d)\n",
-                               compl->tag0);
+                               opcode);
                } else {
                        extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
                                        CQE_STATUS_EXTD_MASK;
                        dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:"
                                "status %d, extd-status %d\n",
-                               compl->tag0, compl_status, extd_status);
+                               opcode, compl_status, extd_status);
                }
        }
 done:
@@ -286,7 +301,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
        if (i == mcc_timeout) {
                dev_err(&adapter->pdev->dev, "FW not responding\n");
                adapter->fw_timeout = true;
-               return -1;
+               return -EIO;
        }
        return status;
 }
@@ -294,8 +309,26 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
 /* Notify MCC requests and wait for completion */
 static int be_mcc_notify_wait(struct be_adapter *adapter)
 {
+       int status;
+       struct be_mcc_wrb *wrb;
+       struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+       u16 index = mcc_obj->q.head;
+       struct be_cmd_resp_hdr *resp;
+
+       index_dec(&index, mcc_obj->q.len);
+       wrb = queue_index_node(&mcc_obj->q, index);
+
+       resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1);
+
        be_mcc_notify(adapter);
-       return be_mcc_wait_compl(adapter);
+
+       status = be_mcc_wait_compl(adapter);
+       if (status == -EIO)
+               goto out;
+
+       status = resp->status;
+out:
+       return status;
 }
 
 static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
@@ -435,14 +468,17 @@ static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
                                struct be_mcc_wrb *wrb, struct be_dma_mem *mem)
 {
        struct be_sge *sge;
+       unsigned long addr = (unsigned long)req_hdr;
+       u64 req_addr = addr;
 
        req_hdr->opcode = opcode;
        req_hdr->subsystem = subsystem;
        req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
        req_hdr->version = 0;
 
-       wrb->tag0 = opcode;
-       wrb->tag1 = subsystem;
+       wrb->tag0 = req_addr & 0xFFFFFFFF;
+       wrb->tag1 = upper_32_bits(req_addr);
+
        wrb->payload_length = cmd_len;
        if (mem) {
                wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) <<
@@ -1283,13 +1319,10 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_cntl_addnl_attribs *req;
-       u16 mccq_index;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
 
-       mccq_index = adapter->mcc_obj.q.head;
-
        wrb = wrb_from_mccq(adapter);
        if (!wrb) {
                status = -EBUSY;
@@ -1301,8 +1334,6 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
                OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req),
                wrb, NULL);
 
-       wrb->tag1 = mccq_index;
-
        be_mcc_notify(adapter);
 
 err:
index 3c543610906a16f88ac333d2804264bbde63fc06..944f031bd31eef2433d945082b9c02c5d316147c 100644 (file)
@@ -225,8 +225,12 @@ struct be_cmd_req_hdr {
 #define RESP_HDR_INFO_OPCODE_SHIFT     0       /* bits 0 - 7 */
 #define RESP_HDR_INFO_SUBSYS_SHIFT     8       /* bits 8 - 15 */
 struct be_cmd_resp_hdr {
-       u32 info;               /* dword 0 */
-       u32 status;             /* dword 1 */
+       u8 opcode;              /* dword 0 */
+       u8 subsystem;           /* dword 0 */
+       u8 rsvd[2];             /* dword 0 */
+       u8 status;              /* dword 1 */
+       u8 add_status;          /* dword 1 */
+       u8 rsvd1[2];            /* dword 1 */
        u32 response_length;    /* dword 2 */
        u32 actual_resp_len;    /* dword 3 */
 };