OSDN Git Service

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 ad69cf8..4bc18ef 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 4e07e58..2673081 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 3c54361..944f031 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 */
 };