From patchwork Wed Apr 25 11:47:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Padmanabh Ratnakar X-Patchwork-Id: 154891 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 82BE7B6EF3 for ; Wed, 25 Apr 2012 21:48:09 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759099Ab2DYLsH (ORCPT ); Wed, 25 Apr 2012 07:48:07 -0400 Received: from exht1.emulex.com ([138.239.113.183]:29218 "EHLO exht1.ad.emulex.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1758562Ab2DYLsG (ORCPT ); Wed, 25 Apr 2012 07:48:06 -0400 Received: from localhost.localdomain (10.192.201.1) by exht1.ad.emulex.com (138.239.113.183) with Microsoft SMTP Server id 8.3.159.2; Wed, 25 Apr 2012 04:48:00 -0700 From: Padmanabh Ratnakar To: CC: Padmanabh Ratnakar Subject: [PATCH net-next 6/7] be2net: Fix wrong status getting returned for MCC commands Date: Wed, 25 Apr 2012 17:17:03 +0530 X-Mailer: git-send-email 1.6.0.2 MIME-Version: 1.0 Message-ID: <1bdc8f06-3559-46d2-945a-90de6e8cf541@exht1.ad.emulex.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org MCC Response CQEs are processed as part of NAPI poll routine and also synchronously. If MCC completionare 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 --- drivers/net/ethernet/emulex/benet/be.h | 5 ++ drivers/net/ethernet/emulex/benet/be_cmds.c | 81 ++++++++++++++++++-------- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 ++- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index ad69cf8..4bc18ef 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -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); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 4e07e58..2673081 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -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: diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 3c54361..944f031 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -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 */ };