From 9aebddd11be42366f89b0296590770c02797aa98 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 13 May 2011 00:37:27 -0700 Subject: be2net: Move the Emulex driver Moves the Emulex driver into drivers/net/ethernet/emulex/ and make the necessary Kconfig and Makefile changes. CC: Sathya Perla CC: Subbu Seetharaman CC: Ajit Khaparde Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2367 +++++++++++++++++++++++++++ 1 file changed, 2367 insertions(+) create mode 100644 drivers/net/ethernet/emulex/benet/be_cmds.c (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c new file mode 100644 index 000000000000..427859532f02 --- /dev/null +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -0,0 +1,2367 @@ +/* + * Copyright (C) 2005 - 2011 Emulex + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@emulex.com + * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 + */ + +#include "be.h" +#include "be_cmds.h" + +/* Must be a power of 2 or else MODULO will BUG_ON */ +static int be_get_temp_freq = 32; + +static void be_mcc_notify(struct be_adapter *adapter) +{ + struct be_queue_info *mccq = &adapter->mcc_obj.q; + u32 val = 0; + + if (adapter->eeh_err) { + dev_info(&adapter->pdev->dev, + "Error in Card Detected! Cannot issue commands\n"); + return; + } + + val |= mccq->id & DB_MCCQ_RING_ID_MASK; + val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; + + wmb(); + iowrite32(val, adapter->db + DB_MCCQ_OFFSET); +} + +/* To check if valid bit is set, check the entire word as we don't know + * the endianness of the data (old entry is host endian while a new entry is + * little endian) */ +static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) +{ + if (compl->flags != 0) { + compl->flags = le32_to_cpu(compl->flags); + BUG_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0); + return true; + } else { + return false; + } +} + +/* Need to reset the entire word that houses the valid bit */ +static inline void be_mcc_compl_use(struct be_mcc_compl *compl) +{ + compl->flags = 0; +} + +static int be_mcc_compl_process(struct be_adapter *adapter, + struct be_mcc_compl *compl) +{ + u16 compl_status, extd_status; + + /* Just swap the status to host endian; mcc tag is opaquely copied + * from mcc_wrb */ + be_dws_le_to_cpu(compl, 4); + + 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)) { + 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)) { + be_parse_stats(adapter); + adapter->stats_cmd_sent = false; + } + } else { + if (compl_status == MCC_STATUS_NOT_SUPPORTED || + compl_status == MCC_STATUS_ILLEGAL_REQUEST) + goto done; + + 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); + } 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); + } + } +done: + return compl_status; +} + +/* Link state evt is a string of bytes; no need for endian swapping */ +static void be_async_link_state_process(struct be_adapter *adapter, + struct be_async_event_link_state *evt) +{ + be_link_status_update(adapter, evt->port_link_status); +} + +/* Grp5 CoS Priority evt */ +static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, + struct be_async_event_grp5_cos_priority *evt) +{ + if (evt->valid) { + adapter->vlan_prio_bmap = evt->available_priority_bmap; + adapter->recommended_prio &= ~VLAN_PRIO_MASK; + adapter->recommended_prio = + evt->reco_default_priority << VLAN_PRIO_SHIFT; + } +} + +/* Grp5 QOS Speed evt */ +static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, + struct be_async_event_grp5_qos_link_speed *evt) +{ + if (evt->physical_port == adapter->port_num) { + /* qos_link_speed is in units of 10 Mbps */ + adapter->link_speed = evt->qos_link_speed * 10; + } +} + +/*Grp5 PVID evt*/ +static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, + struct be_async_event_grp5_pvid_state *evt) +{ + if (evt->enabled) + adapter->pvid = le16_to_cpu(evt->tag); + else + adapter->pvid = 0; +} + +static void be_async_grp5_evt_process(struct be_adapter *adapter, + u32 trailer, struct be_mcc_compl *evt) +{ + u8 event_type = 0; + + event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) & + ASYNC_TRAILER_EVENT_TYPE_MASK; + + switch (event_type) { + case ASYNC_EVENT_COS_PRIORITY: + be_async_grp5_cos_priority_process(adapter, + (struct be_async_event_grp5_cos_priority *)evt); + break; + case ASYNC_EVENT_QOS_SPEED: + be_async_grp5_qos_speed_process(adapter, + (struct be_async_event_grp5_qos_link_speed *)evt); + break; + case ASYNC_EVENT_PVID_STATE: + be_async_grp5_pvid_state_process(adapter, + (struct be_async_event_grp5_pvid_state *)evt); + break; + default: + dev_warn(&adapter->pdev->dev, "Unknown grp5 event!\n"); + break; + } +} + +static inline bool is_link_state_evt(u32 trailer) +{ + return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_LINK_STATE; +} + +static inline bool is_grp5_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_GRP_5); +} + +static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) +{ + struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; + struct be_mcc_compl *compl = queue_tail_node(mcc_cq); + + if (be_mcc_compl_is_new(compl)) { + queue_tail_inc(mcc_cq); + return compl; + } + return NULL; +} + +void be_async_mcc_enable(struct be_adapter *adapter) +{ + spin_lock_bh(&adapter->mcc_cq_lock); + + be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0); + adapter->mcc_obj.rearm_cq = true; + + spin_unlock_bh(&adapter->mcc_cq_lock); +} + +void be_async_mcc_disable(struct be_adapter *adapter) +{ + adapter->mcc_obj.rearm_cq = false; +} + +int be_process_mcc(struct be_adapter *adapter, int *status) +{ + struct be_mcc_compl *compl; + int num = 0; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + + spin_lock_bh(&adapter->mcc_cq_lock); + while ((compl = be_mcc_compl_get(adapter))) { + if (compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ + if (is_link_state_evt(compl->flags)) + be_async_link_state_process(adapter, + (struct be_async_event_link_state *) compl); + else if (is_grp5_evt(compl->flags)) + be_async_grp5_evt_process(adapter, + compl->flags, compl); + } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { + *status = be_mcc_compl_process(adapter, compl); + atomic_dec(&mcc_obj->q.used); + } + be_mcc_compl_use(compl); + num++; + } + + spin_unlock_bh(&adapter->mcc_cq_lock); + return num; +} + +/* Wait till no more pending mcc requests are present */ +static int be_mcc_wait_compl(struct be_adapter *adapter) +{ +#define mcc_timeout 120000 /* 12s timeout */ + int i, num, status = 0; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + + if (adapter->eeh_err) + return -EIO; + + for (i = 0; i < mcc_timeout; i++) { + num = be_process_mcc(adapter, &status); + if (num) + be_cq_notify(adapter, mcc_obj->cq.id, + mcc_obj->rearm_cq, num); + + if (atomic_read(&mcc_obj->q.used) == 0) + break; + udelay(100); + } + if (i == mcc_timeout) { + dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); + return -1; + } + return status; +} + +/* Notify MCC requests and wait for completion */ +static int be_mcc_notify_wait(struct be_adapter *adapter) +{ + be_mcc_notify(adapter); + return be_mcc_wait_compl(adapter); +} + +static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) +{ + int msecs = 0; + u32 ready; + + if (adapter->eeh_err) { + dev_err(&adapter->pdev->dev, + "Error detected in card.Cannot issue commands\n"); + return -EIO; + } + + do { + ready = ioread32(db); + if (ready == 0xffffffff) { + dev_err(&adapter->pdev->dev, + "pci slot disconnected\n"); + return -1; + } + + ready &= MPU_MAILBOX_DB_RDY_MASK; + if (ready) + break; + + if (msecs > 4000) { + dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); + if (!lancer_chip(adapter)) + be_detect_dump_ue(adapter); + return -1; + } + + msleep(1); + msecs++; + } while (true); + + return 0; +} + +/* + * Insert the mailbox address into the doorbell in two steps + * Polls on the mbox doorbell till a command completion (or a timeout) occurs + */ +static int be_mbox_notify_wait(struct be_adapter *adapter) +{ + int status; + u32 val = 0; + void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; + struct be_dma_mem *mbox_mem = &adapter->mbox_mem; + struct be_mcc_mailbox *mbox = mbox_mem->va; + struct be_mcc_compl *compl = &mbox->compl; + + /* wait for ready to be set */ + status = be_mbox_db_ready_wait(adapter, db); + if (status != 0) + return status; + + val |= MPU_MAILBOX_DB_HI_MASK; + /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ + val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; + iowrite32(val, db); + + /* wait for ready to be set */ + status = be_mbox_db_ready_wait(adapter, db); + if (status != 0) + return status; + + val = 0; + /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ + val |= (u32)(mbox_mem->dma >> 4) << 2; + iowrite32(val, db); + + status = be_mbox_db_ready_wait(adapter, db); + if (status != 0) + return status; + + /* A cq entry has been made now */ + if (be_mcc_compl_is_new(compl)) { + status = be_mcc_compl_process(adapter, &mbox->compl); + be_mcc_compl_use(compl); + if (status) + return status; + } else { + dev_err(&adapter->pdev->dev, "invalid mailbox completion\n"); + return -1; + } + return 0; +} + +static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) +{ + u32 sem; + + if (lancer_chip(adapter)) + sem = ioread32(adapter->db + MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET); + else + sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + + *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK; + if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK) + return -1; + else + return 0; +} + +int be_cmd_POST(struct be_adapter *adapter) +{ + u16 stage; + int status, timeout = 0; + struct device *dev = &adapter->pdev->dev; + + do { + status = be_POST_stage_get(adapter, &stage); + if (status) { + dev_err(dev, "POST error; stage=0x%x\n", stage); + return -1; + } else if (stage != POST_STAGE_ARMFW_RDY) { + if (msleep_interruptible(2000)) { + dev_err(dev, "Waiting for POST aborted\n"); + return -EINTR; + } + timeout += 2; + } else { + return 0; + } + } while (timeout < 40); + + dev_err(dev, "POST timeout; stage=0x%x\n", stage); + return -1; +} + +static inline void *embedded_payload(struct be_mcc_wrb *wrb) +{ + return wrb->payload.embedded_payload; +} + +static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) +{ + return &wrb->payload.sgl[0]; +} + +/* Don't touch the hdr after it's prepared */ +static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, + bool embedded, u8 sge_cnt, u32 opcode) +{ + if (embedded) + wrb->embedded |= MCC_WRB_EMBEDDED_MASK; + else + wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << + MCC_WRB_SGE_CNT_SHIFT; + wrb->payload_length = payload_len; + wrb->tag0 = opcode; + be_dws_cpu_to_le(wrb, 8); +} + +/* Don't touch the hdr after it's prepared */ +static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, + u8 subsystem, u8 opcode, int cmd_len) +{ + req_hdr->opcode = opcode; + req_hdr->subsystem = subsystem; + req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); + req_hdr->version = 0; +} + +static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, + struct be_dma_mem *mem) +{ + int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); + u64 dma = (u64)mem->dma; + + for (i = 0; i < buf_pages; i++) { + pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); + pages[i].hi = cpu_to_le32(upper_32_bits(dma)); + dma += PAGE_SIZE_4K; + } +} + +/* Converts interrupt delay in microseconds to multiplier value */ +static u32 eq_delay_to_mult(u32 usec_delay) +{ +#define MAX_INTR_RATE 651042 + const u32 round = 10; + u32 multiplier; + + if (usec_delay == 0) + multiplier = 0; + else { + u32 interrupt_rate = 1000000 / usec_delay; + /* Max delay, corresponding to the lowest interrupt rate */ + if (interrupt_rate == 0) + multiplier = 1023; + else { + multiplier = (MAX_INTR_RATE - interrupt_rate) * round; + multiplier /= interrupt_rate; + /* Round the multiplier to the closest value.*/ + multiplier = (multiplier + round/2) / round; + multiplier = min(multiplier, (u32)1023); + } + } + return multiplier; +} + +static inline struct be_mcc_wrb *wrb_from_mbox(struct be_adapter *adapter) +{ + struct be_dma_mem *mbox_mem = &adapter->mbox_mem; + struct be_mcc_wrb *wrb + = &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; + memset(wrb, 0, sizeof(*wrb)); + return wrb; +} + +static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter) +{ + struct be_queue_info *mccq = &adapter->mcc_obj.q; + struct be_mcc_wrb *wrb; + + if (atomic_read(&mccq->used) >= mccq->len) { + dev_err(&adapter->pdev->dev, "Out of MCCQ wrbs\n"); + return NULL; + } + + wrb = queue_head_node(mccq); + queue_head_inc(mccq); + atomic_inc(&mccq->used); + memset(wrb, 0, sizeof(*wrb)); + return wrb; +} + +/* Tell fw we're about to start firing cmds by writing a + * special pattern across the wrb hdr; uses mbox + */ +int be_cmd_fw_init(struct be_adapter *adapter) +{ + u8 *wrb; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = (u8 *)wrb_from_mbox(adapter); + *wrb++ = 0xFF; + *wrb++ = 0x12; + *wrb++ = 0x34; + *wrb++ = 0xFF; + *wrb++ = 0xFF; + *wrb++ = 0x56; + *wrb++ = 0x78; + *wrb = 0xFF; + + status = be_mbox_notify_wait(adapter); + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Tell fw we're done with firing cmds by writing a + * special pattern across the wrb hdr; uses mbox + */ +int be_cmd_fw_clean(struct be_adapter *adapter) +{ + u8 *wrb; + int status; + + if (adapter->eeh_err) + return -EIO; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = (u8 *)wrb_from_mbox(adapter); + *wrb++ = 0xFF; + *wrb++ = 0xAA; + *wrb++ = 0xBB; + *wrb++ = 0xFF; + *wrb++ = 0xFF; + *wrb++ = 0xCC; + *wrb++ = 0xDD; + *wrb = 0xFF; + + status = be_mbox_notify_wait(adapter); + + mutex_unlock(&adapter->mbox_lock); + return status; +} +int be_cmd_eq_create(struct be_adapter *adapter, + struct be_queue_info *eq, int eq_delay) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_eq_create *req; + struct be_dma_mem *q_mem = &eq->dma_mem; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_COMMON_EQ_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_EQ_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + + AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); + /* 4byte eqe*/ + AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); + AMAP_SET_BITS(struct amap_eq_context, count, req->context, + __ilog2_u32(eq->len/256)); + AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context, + eq_delay_to_mult(eq_delay)); + be_dws_cpu_to_le(req->context, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); + eq->id = le16_to_cpu(resp->eq_id); + eq->created = true; + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses mbox */ +int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + u8 type, bool permanent, u32 if_handle) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_mac_query *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_MAC_QUERY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req)); + + req->type = type; + if (permanent) { + req->permanent = 1; + } else { + req->if_id = cpu_to_le16((u16) if_handle); + req->permanent = 0; + } + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); + memcpy(mac_addr, resp->mac.addr, ETH_ALEN); + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses synchronous MCCQ */ +int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, + u32 if_id, u32 *pmac_id, u32 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_pmac_add *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_PMAC_ADD); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req)); + + req->hdr.domain = domain; + req->if_id = cpu_to_le32(if_id); + memcpy(req->mac_address, mac_addr, ETH_ALEN); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); + *pmac_id = le32_to_cpu(resp->pmac_id); + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchronous MCCQ */ +int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_pmac_del *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_PMAC_DEL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req)); + + req->hdr.domain = dom; + req->if_id = cpu_to_le32(if_id); + req->pmac_id = cpu_to_le32(pmac_id); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses Mbox */ +int be_cmd_cq_create(struct be_adapter *adapter, + struct be_queue_info *cq, struct be_queue_info *eq, + bool sol_evts, bool no_delay, int coalesce_wm) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_cq_create *req; + struct be_dma_mem *q_mem = &cq->dma_mem; + void *ctxt; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_CQ_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_CQ_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + if (lancer_chip(adapter)) { + req->hdr.version = 2; + req->page_size = 1; /* 1 for 4K */ + AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt, + no_delay); + AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt, + __ilog2_u32(cq->len/256)); + AMAP_SET_BITS(struct amap_cq_context_lancer, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_lancer, eventable, + ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_lancer, eqid, + ctxt, eq->id); + AMAP_SET_BITS(struct amap_cq_context_lancer, armed, ctxt, 1); + } else { + AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, + coalesce_wm); + AMAP_SET_BITS(struct amap_cq_context_be, nodelay, + ctxt, no_delay); + AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt, + __ilog2_u32(cq->len/256)); + AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_be, solevent, + ctxt, sol_evts); + AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); + AMAP_SET_BITS(struct amap_cq_context_be, armed, ctxt, 1); + } + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); + cq->id = le16_to_cpu(resp->cq_id); + cq->created = true; + } + + mutex_unlock(&adapter->mbox_lock); + + return status; +} + +static u32 be_encoded_q_len(int q_len) +{ + u32 len_encoded = fls(q_len); /* log2(len) + 1 */ + if (len_encoded == 16) + len_encoded = 0; + return len_encoded; +} + +int be_cmd_mccq_ext_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_mcc_ext_create *req; + struct be_dma_mem *q_mem = &mccq->dma_mem; + void *ctxt; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MCC_CREATE_EXT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + if (lancer_chip(adapter)) { + req->hdr.version = 1; + req->cq_id = cpu_to_le16(cq->id); + + AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id, + ctxt, cq->id); + AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid, + ctxt, 1); + + } else { + AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + } + + /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ + req->async_event_bitmap[0] = cpu_to_le32(0x00000022); + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); + mccq->id = le16_to_cpu(resp->id); + mccq->created = true; + } + mutex_unlock(&adapter->mbox_lock); + + return status; +} + +int be_cmd_mccq_org_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_mcc_create *req; + struct be_dma_mem *q_mem = &mccq->dma_mem; + void *ctxt; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MCC_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MCC_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + + AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); + mccq->id = le16_to_cpu(resp->id); + mccq->created = true; + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +int be_cmd_mccq_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + int status; + + status = be_cmd_mccq_ext_create(adapter, mccq, cq); + if (status && !lancer_chip(adapter)) { + dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " + "or newer to avoid conflicting priorities between NIC " + "and FCoE traffic"); + status = be_cmd_mccq_org_create(adapter, mccq, cq); + } + return status; +} + +int be_cmd_txq_create(struct be_adapter *adapter, + struct be_queue_info *txq, + struct be_queue_info *cq) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_eth_tx_create *req; + struct be_dma_mem *q_mem = &txq->dma_mem; + void *ctxt; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_ETH_TX_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE, + sizeof(*req)); + + if (lancer_chip(adapter)) { + req->hdr.version = 1; + AMAP_SET_BITS(struct amap_tx_context, if_id, ctxt, + adapter->if_handle); + } + + req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); + req->ulp_num = BE_ULP1_NUM; + req->type = BE_ETH_TX_RING_TYPE_STANDARD; + + AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, + be_encoded_q_len(txq->len)); + AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); + AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); + txq->id = le16_to_cpu(resp->cid); + txq->created = true; + } + + mutex_unlock(&adapter->mbox_lock); + + return status; +} + +/* Uses MCC */ +int be_cmd_rxq_create(struct be_adapter *adapter, + struct be_queue_info *rxq, u16 cq_id, u16 frag_size, + u16 max_frame_size, u32 if_id, u32 rss, u8 *rss_id) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_eth_rx_create *req; + struct be_dma_mem *q_mem = &rxq->dma_mem; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_ETH_RX_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE, + sizeof(*req)); + + req->cq_id = cpu_to_le16(cq_id); + req->frag_size = fls(frag_size) - 1; + req->num_pages = 2; + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + req->interface_id = cpu_to_le32(if_id); + req->max_frame_size = cpu_to_le16(max_frame_size); + req->rss_queue = cpu_to_le32(rss); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); + rxq->id = le16_to_cpu(resp->id); + rxq->created = true; + *rss_id = resp->rss_id; + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Generic destroyer function for all types of queues + * Uses Mbox + */ +int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + int queue_type) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_q_destroy *req; + u8 subsys = 0, opcode = 0; + int status; + + if (adapter->eeh_err) + return -EIO; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + switch (queue_type) { + case QTYPE_EQ: + subsys = CMD_SUBSYSTEM_COMMON; + opcode = OPCODE_COMMON_EQ_DESTROY; + break; + case QTYPE_CQ: + subsys = CMD_SUBSYSTEM_COMMON; + opcode = OPCODE_COMMON_CQ_DESTROY; + break; + case QTYPE_TXQ: + subsys = CMD_SUBSYSTEM_ETH; + opcode = OPCODE_ETH_TX_DESTROY; + break; + case QTYPE_RXQ: + subsys = CMD_SUBSYSTEM_ETH; + opcode = OPCODE_ETH_RX_DESTROY; + break; + case QTYPE_MCCQ: + subsys = CMD_SUBSYSTEM_COMMON; + opcode = OPCODE_COMMON_MCC_DESTROY; + break; + default: + BUG(); + } + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, opcode); + + be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); + req->id = cpu_to_le16(q->id); + + status = be_mbox_notify_wait(adapter); + if (!status) + q->created = false; + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses MCC */ +int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_q_destroy *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_RX_DESTROY); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_DESTROY, + sizeof(*req)); + req->id = cpu_to_le16(q->id); + + status = be_mcc_notify_wait(adapter); + if (!status) + q->created = false; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Create an rx filtering policy configuration on an i/f + * Uses mbox + */ +int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, + u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id, + u32 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_if_create *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_INTERFACE_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req)); + + req->hdr.domain = domain; + req->capability_flags = cpu_to_le32(cap_flags); + req->enable_flags = cpu_to_le32(en_flags); + req->pmac_invalid = pmac_invalid; + if (!pmac_invalid) + memcpy(req->mac_addr, mac, ETH_ALEN); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_if_create *resp = embedded_payload(wrb); + *if_handle = le32_to_cpu(resp->interface_id); + if (!pmac_invalid) + *pmac_id = le32_to_cpu(resp->pmac_id); + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses mbox */ +int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_if_destroy *req; + int status; + + if (adapter->eeh_err) + return -EIO; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_INTERFACE_DESTROY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); + + req->hdr.domain = domain; + req->interface_id = cpu_to_le32(interface_id); + + status = be_mbox_notify_wait(adapter); + + mutex_unlock(&adapter->mbox_lock); + + return status; +} + +/* Get stats is a non embedded command: the request is not embedded inside + * WRB but is a separate dma memory block + * Uses asynchronous MCC + */ +int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_hdr *hdr; + struct be_sge *sge; + int status = 0; + + if (MODULO(adapter->work_counter, be_get_temp_freq) == 0) + be_cmd_get_die_temperature(adapter); + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + hdr = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, + OPCODE_ETH_GET_STATISTICS); + + be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size); + + if (adapter->generation == BE_GEN3) + hdr->version = 1; + + wrb->tag1 = CMD_SUBSYSTEM_ETH; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(adapter); + adapter->stats_cmd_sent = true; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Lancer Stats */ +int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd) +{ + + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_pport_stats *req; + struct be_sge *sge; + int status = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, + OPCODE_ETH_GET_PPORT_STATS); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size); + + + req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num); + req->cmd_params.params.reset_stats = 0; + + wrb->tag1 = CMD_SUBSYSTEM_ETH; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(adapter); + adapter->stats_cmd_sent = true; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchronous mcc */ +int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + u16 *link_speed, u32 dom) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_link_status *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_link_status *resp = embedded_payload(wrb); + if (resp->mac_speed != PHY_LINK_SPEED_ZERO) { + *link_speed = le16_to_cpu(resp->link_speed); + *mac_speed = resp->mac_speed; + } + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchronous mcc */ +int be_cmd_get_die_temperature(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_cntl_addnl_attribs *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req)); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_cntl_addnl_attribs *resp = + embedded_payload(wrb); + adapter->drv_stats.be_on_die_temperature = + resp->on_die_temperature; + } + /* If IOCTL fails once, do not bother issuing it again */ + else + be_get_temp_freq = 0; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchronous mcc */ +int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); + req->fat_operation = cpu_to_le32(QUERY_FAT); + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + if (log_size && resp->log_size) + *log_size = le32_to_cpu(resp->log_size) - + sizeof(u32); + } +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +{ + struct be_dma_mem get_fat_cmd; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + struct be_sge *sge; + u32 offset = 0, total_size, buf_size, + log_offset = sizeof(u32), payload_len; + int status; + + if (buf_len == 0) + return; + + total_size = buf_len; + + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + return; + } + + spin_lock_bh(&adapter->mcc_lock); + + while (total_size) { + buf_size = min(total_size, (u32)60*1024); + total_size -= buf_size; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = get_fat_cmd.va; + sge = nonembedded_sgl(wrb); + + payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; + be_wrb_hdr_prepare(wrb, payload_len, false, 1, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, payload_len); + + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma)); + sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(get_fat_cmd.size); + + req->fat_operation = cpu_to_le32(RETRIEVE_FAT); + req->read_log_offset = cpu_to_le32(log_offset); + req->read_log_length = cpu_to_le32(buf_size); + req->data_buffer_size = cpu_to_le32(buf_size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; + memcpy(buf + offset, + resp->data_buffer, + resp->read_log_length); + } else { + dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); + goto err; + } + offset += buf_size; + log_offset += buf_size; + } +err: + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); + spin_unlock_bh(&adapter->mcc_lock); +} + +/* Uses Mbox */ +int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fw_version *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_FW_VERSION); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); + strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* set the EQ delay interval of an EQ to specified value + * Uses async mcc + */ +int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_modify_eq_delay *req; + int status = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MODIFY_EQ_DELAY); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); + + req->num_eq = cpu_to_le32(1); + req->delay[0].eq_id = cpu_to_le32(eq_id); + req->delay[0].phase = 0; + req->delay[0].delay_multiplier = cpu_to_le32(eqd); + + be_mcc_notify(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses sycnhronous mcc */ +int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, + u32 num, bool untagged, bool promiscuous) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_vlan_config *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_VLAN_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req)); + + req->interface_id = if_id; + req->promiscuous = promiscuous; + req->untagged = untagged; + req->num_vlan = num; + if (!promiscuous) { + memcpy(req->normal_vlan, vtag_array, + req->num_vlan * sizeof(vtag_array[0])); + } + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) +{ + struct be_mcc_wrb *wrb; + struct be_dma_mem *mem = &adapter->rx_filter; + struct be_cmd_req_rx_filter *req = mem->va; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + sge = nonembedded_sgl(wrb); + sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma)); + sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(mem->size); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_NTWK_RX_FILTER); + + memset(req, 0, sizeof(*req)); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req)); + + req->if_id = cpu_to_le32(adapter->if_handle); + if (flags & IFF_PROMISC) { + req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | + BE_IF_FLAGS_VLAN_PROMISCUOUS); + if (value == ON) + req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | + BE_IF_FLAGS_VLAN_PROMISCUOUS); + } else if (flags & IFF_ALLMULTI) { + req->if_flags_mask = req->if_flags = + cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); + } else { + struct netdev_hw_addr *ha; + int i = 0; + + req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev)); + netdev_for_each_mc_addr(ha, adapter->netdev) + memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); + } + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchrounous mcc */ +int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_flow_control *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_SET_FLOW_CONTROL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req)); + + req->tx_flow_control = cpu_to_le16((u16)tx_fc); + req->rx_flow_control = cpu_to_le16((u16)rx_fc); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses sycn mcc */ +int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_flow_control *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_FLOW_CONTROL); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_flow_control *resp = + embedded_payload(wrb); + *tx_fc = le16_to_cpu(resp->tx_flow_control); + *rx_fc = le16_to_cpu(resp->rx_flow_control); + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses mbox */ +int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, + u32 *mode, u32 *caps) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_query_fw_cfg *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_QUERY_FIRMWARE_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); + *port_num = le32_to_cpu(resp->phys_port); + *mode = le32_to_cpu(resp->function_mode); + *caps = le32_to_cpu(resp->function_caps); + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses mbox */ +int be_cmd_reset_function(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_hdr *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_FUNCTION_RESET); + + be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); + + status = be_mbox_notify_wait(adapter); + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_rss_config *req; + u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF, + 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF}; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_ETH_RSS_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_RSS_CONFIG, sizeof(*req)); + + req->if_id = cpu_to_le32(adapter->if_handle); + req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4); + req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1); + memcpy(req->cpu_table, rsstable, table_size); + memcpy(req->hash, myhash, sizeof(myhash)); + be_dws_cpu_to_le(req->hash, sizeof(req->hash)); + + status = be_mbox_notify_wait(adapter); + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +/* Uses sync mcc */ +int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, + u8 bcn, u8 sts, u8 state) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_enable_disable_beacon *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_ENABLE_DISABLE_BEACON); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req)); + + req->port_num = port_num; + req->beacon_state = state; + req->beacon_duration = bcn; + req->status_duration = sts; + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses sync mcc */ +int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_beacon_state *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_BEACON_STATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req)); + + req->port_num = port_num; + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_beacon_state *resp = + embedded_payload(wrb); + *state = resp->beacon_state; + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, const char *obj_name, + u32 *data_written, u8 *addn_status) +{ + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_write_object *req; + struct lancer_cmd_resp_write_object *resp; + void *ctxt = NULL; + int status; + + spin_lock_bh(&adapter->mcc_lock); + adapter->flash_status = 0; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err_unlock; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object), + true, 1, OPCODE_COMMON_WRITE_OBJECT); + wrb->tag1 = CMD_SUBSYSTEM_COMMON; + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_OBJECT, + sizeof(struct lancer_cmd_req_write_object)); + + ctxt = &req->context; + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + write_length, ctxt, data_size); + + if (data_size == 0) + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 1); + else + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 0); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + req->write_offset = cpu_to_le32(data_offset); + strcpy(req->object_name, obj_name); + req->descriptor_count = cpu_to_le32(1); + req->buf_len = cpu_to_le32(data_size); + req->addr_low = cpu_to_le32((cmd->dma + + sizeof(struct lancer_cmd_req_write_object)) + & 0xFFFFFFFF); + req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + + sizeof(struct lancer_cmd_req_write_object))); + + be_mcc_notify(adapter); + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, + msecs_to_jiffies(12000))) + status = -1; + else + status = adapter->flash_status; + + resp = embedded_payload(wrb); + if (!status) { + *data_written = le32_to_cpu(resp->actual_write_len); + } else { + *addn_status = resp->additional_status; + status = resp->status; + } + + return status; + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 flash_type, u32 flash_opcode, u32 buf_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_write_flashrom *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + adapter->flash_status = 0; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err_unlock; + } + req = cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, cmd->size, false, 1, + OPCODE_COMMON_WRITE_FLASHROM); + wrb->tag1 = CMD_SUBSYSTEM_COMMON; + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_FLASHROM, cmd->size); + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); + sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd->size); + + req->params.op_type = cpu_to_le32(flash_type); + req->params.op_code = cpu_to_le32(flash_opcode); + req->params.data_buf_size = cpu_to_le32(buf_size); + + be_mcc_notify(adapter); + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, + msecs_to_jiffies(12000))) + status = -1; + else + status = adapter->flash_status; + + return status; + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + int offset) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_write_flashrom *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0, + OPCODE_COMMON_READ_FLASHROM); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4); + + req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT); + req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); + req->params.offset = cpu_to_le32(offset); + req->params.data_buf_size = cpu_to_le32(0x4); + + status = be_mcc_notify_wait(adapter); + if (!status) + memcpy(flashed_crc, req->params.data_buf, 4); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, + struct be_dma_mem *nonemb_cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_acpi_wol_magic_config *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req)); + memcpy(req->magic_mac, mac, ETH_ALEN); + + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, + u8 loopback_type, u8 enable) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_lmode *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_LOWLEVEL_SET_LOOPBACK_MODE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, + sizeof(*req)); + + req->src_port = port_num; + req->dest_port = port_num; + req->loopback_type = loopback_type; + req->loopback_state = enable; + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, + u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_loopback_test *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_LOWLEVEL_LOOPBACK_TEST); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); + req->hdr.timeout = cpu_to_le32(4); + + req->pattern = cpu_to_le64(pattern); + req->src_port = cpu_to_le32(port_num); + req->dest_port = cpu_to_le32(port_num); + req->pkt_size = cpu_to_le32(pkt_size); + req->num_pkts = cpu_to_le32(num_pkts); + req->loopback_type = cpu_to_le32(loopback_type); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb); + status = le32_to_cpu(resp->status); + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, + u32 byte_cnt, struct be_dma_mem *cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_ddrdma_test *req; + struct be_sge *sge; + int status; + int i, j = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = cmd->va; + sge = nonembedded_sgl(wrb); + be_wrb_hdr_prepare(wrb, cmd->size, false, 1, + OPCODE_LOWLEVEL_HOST_DDR_DMA); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size); + + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); + sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd->size); + + req->pattern = cpu_to_le64(pattern); + req->byte_count = cpu_to_le32(byte_cnt); + for (i = 0; i < byte_cnt; i++) { + req->snd_buff[i] = (u8)(pattern >> (j*8)); + j++; + if (j > 7) + j = 0; + } + + status = be_mcc_notify_wait(adapter); + + if (!status) { + struct be_cmd_resp_ddrdma_test *resp; + resp = cmd->va; + if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) || + resp->snd_err) { + status = -1; + } + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_get_seeprom_data(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_seeprom_read *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_SEEPROM_READ); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SEEPROM_READ, sizeof(*req)); + + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_get_phy_info(struct be_adapter *adapter, + struct be_phy_info *phy_info) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_phy_info *req; + struct be_sge *sge; + struct be_dma_mem cmd; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + cmd.size = sizeof(struct be_cmd_req_get_phy_info); + cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, + &cmd.dma); + if (!cmd.va) { + dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); + status = -ENOMEM; + goto err; + } + + req = cmd.va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_GET_PHY_DETAILS); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_PHY_DETAILS, + sizeof(*req)); + + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd.dma)); + sge->pa_lo = cpu_to_le32(cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd.size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_phy_info *resp_phy_info = + cmd.va + sizeof(struct be_cmd_req_hdr); + phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type); + phy_info->interface_type = + le16_to_cpu(resp_phy_info->interface_type); + } + pci_free_consistent(adapter->pdev, cmd.size, + cmd.va, cmd.dma); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_qos *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_SET_QOS); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_QOS, sizeof(*req)); + + req->hdr.domain = domain; + req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC); + req->max_bps_nic = cpu_to_le32(bps); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_get_cntl_attributes(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_cntl_attribs *req; + struct be_cmd_resp_cntl_attribs *resp; + struct be_sge *sge; + int status; + int payload_len = max(sizeof(*req), sizeof(*resp)); + struct mgmt_controller_attrib *attribs; + struct be_dma_mem attribs_cmd; + + memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); + attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); + attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size, + &attribs_cmd.dma); + if (!attribs_cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure\n"); + return -ENOMEM; + } + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = attribs_cmd.va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, payload_len, false, 1, + OPCODE_COMMON_GET_CNTL_ATTRIBUTES); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len); + sge->pa_hi = cpu_to_le32(upper_32_bits(attribs_cmd.dma)); + sge->pa_lo = cpu_to_le32(attribs_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(attribs_cmd.size); + + status = be_mbox_notify_wait(adapter); + if (!status) { + attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); + adapter->hba_port_num = attribs->hba_attribs.phy_port; + } + +err: + mutex_unlock(&adapter->mbox_lock); + pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va, + attribs_cmd.dma); + return status; +} + +/* Uses mbox */ +int be_cmd_req_native_mode(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_func_cap *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, sizeof(*req)); + + req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS | + CAPABILITY_BE3_NATIVE_ERX_API); + req->cap_flags = cpu_to_le32(CAPABILITY_BE3_NATIVE_ERX_API); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb); + adapter->be3_native = le32_to_cpu(resp->cap_flags) & + CAPABILITY_BE3_NATIVE_ERX_API; + } +err: + mutex_unlock(&adapter->mbox_lock); + return status; +} -- cgit v1.2.3 From 939cf3069d31a6e0e335eb5e08ef04895f2d013d Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Thu, 18 Aug 2011 21:51:49 -0700 Subject: be2net: Storing the 'vid' got by the grp5 event instead of storing the vlan_tag Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- drivers/net/ethernet/emulex/benet/be_main.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 427859532f02..bec039d27714 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -140,7 +140,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { if (evt->enabled) - adapter->pvid = le16_to_cpu(evt->tag); + adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK; else adapter->pvid = 0; } diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 7c98d8e99508..ef62594a19cd 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1277,8 +1277,7 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) if (!lancer_chip(adapter)) rxcp->vlan_tag = swab16(rxcp->vlan_tag); - if (((adapter->pvid & VLAN_VID_MASK) == - (rxcp->vlan_tag & VLAN_VID_MASK)) && + if (adapter->pvid == (rxcp->vlan_tag & VLAN_VID_MASK) && !adapter->vlan_tag[rxcp->vlan_tag]) rxcp->vlanf = 0; } -- cgit v1.2.3 From e2edb7d51ff3dee7ba651d27aad77dfa5a82a7fc Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 22 Aug 2011 19:41:54 +0000 Subject: be2net: increase FW update completion timeout Flashing some of the PHYs can take longer thus increasing the total flash update time to a max of 40s. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index bec039d27714..bebeee68b2fa 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1939,7 +1939,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->flash_compl, - msecs_to_jiffies(12000))) + msecs_to_jiffies(40000))) status = -1; else status = adapter->flash_status; -- cgit v1.2.3 From 8e7d3f681ef462e6aaa151f231310452dac409ca Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Tue, 27 Sep 2011 13:29:38 -0400 Subject: be2net: fix multicast filter programming Re-posting with subject fixed! Multicast programming has been broken since commit 5b8821b7. Setting the MULTICAST flag while sending the cmd to the FW was missing. Fixed this. Also fixed-up some indentation in the adjacent lines. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index bebeee68b2fa..6bc07c7515b3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1580,14 +1580,16 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) BE_IF_FLAGS_VLAN_PROMISCUOUS); if (value == ON) req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS); + BE_IF_FLAGS_VLAN_PROMISCUOUS); } else if (flags & IFF_ALLMULTI) { req->if_flags_mask = req->if_flags = - cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); + cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); } else { struct netdev_hw_addr *ha; int i = 0; + req->if_flags_mask = req->if_flags = + cpu_to_le32(BE_IF_FLAGS_MULTICAST); req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev)); netdev_for_each_mc_addr(ha, adapter->netdev) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); -- cgit v1.2.3 From 04b71175f340d4081680440e1b9cbffcd3f4a13c Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Tue, 27 Sep 2011 13:30:27 -0400 Subject: be2net: Show newly flashed FW ver in ethtool This fix provides a newly flashed FW version (appended, in braces) along with the currently running FW version via ethtool. The newly flashed version runs only after a system reset. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 31 +++++++++++++++----------- drivers/net/ethernet/emulex/benet/be_cmds.h | 3 ++- drivers/net/ethernet/emulex/benet/be_ethtool.c | 14 ++++++++++-- drivers/net/ethernet/emulex/benet/be_main.c | 5 +---- 4 files changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 6bc07c7515b3..4b655b854073 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1444,32 +1444,37 @@ err: spin_unlock_bh(&adapter->mcc_lock); } -/* Uses Mbox */ -int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) +/* Uses synchronous mcc */ +int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, + char *fw_on_flash) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_fw_version *req; int status; - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mbox(adapter); - req = embedded_payload(wrb); + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, - OPCODE_COMMON_GET_FW_VERSION); - + OPCODE_COMMON_GET_FW_VERSION); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); + OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); - status = be_mbox_notify_wait(adapter); + status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); - strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); + strcpy(fw_ver, resp->firmware_version_string); + if (fw_on_flash) + strcpy(fw_on_flash, resp->fw_on_flash_version_string); } - - mutex_unlock(&adapter->mbox_lock); +err: + spin_unlock_bh(&adapter->mcc_lock); return status; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index b61eac7ece35..abaa90cbfea2 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1444,7 +1444,8 @@ extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); extern int lancer_cmd_get_pport_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); -extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); +extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, + char *fw_on_flash); extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index f144a6f99862..bf8153ea4ed8 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -118,14 +118,24 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = { #define BE_ONE_PORT_EXT_LOOPBACK 0x2 #define BE_NO_LOOPBACK 0xff -static void -be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +static void be_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) { struct be_adapter *adapter = netdev_priv(netdev); + char fw_on_flash[FW_VER_LEN]; + + memset(fw_on_flash, 0 , sizeof(fw_on_flash)); + be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash); strcpy(drvinfo->driver, DRV_NAME); strcpy(drvinfo->version, DRV_VER); strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN); + if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) { + strcat(drvinfo->fw_version, " ["); + strcat(drvinfo->fw_version, fw_on_flash); + strcat(drvinfo->fw_version, "]"); + } + strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2b7d1ba1e13b..1a7b24cc5da7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2528,6 +2528,7 @@ static int be_setup(struct be_adapter *adapter) adapter->link_speed = -1; + be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); return 0; rx_qs_destroy: @@ -3147,10 +3148,6 @@ static int be_get_config(struct be_adapter *adapter) int status; u8 mac[ETH_ALEN]; - status = be_cmd_get_fw_ver(adapter, adapter->fw_ver); - if (status) - return status; - status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, &adapter->function_mode, &adapter->function_caps); if (status) -- cgit v1.2.3 From 3ab81b5f4278342a2312e3fcafa6833e40753324 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Mon, 3 Oct 2011 08:10:57 +0000 Subject: be2net: Add 60 second delay to allow FAT dump completion on recovery from EEH Add 60s delay before timeout on polling Bit 31 so that FAT dump can complete when reset occurs. Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 4b655b854073..eb58a80aaddd 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -398,7 +398,7 @@ int be_cmd_POST(struct be_adapter *adapter) } else { return 0; } - } while (timeout < 40); + } while (timeout < 60); dev_err(dev, "POST timeout; stage=0x%x\n", stage); return -1; -- cgit v1.2.3 From 92aa921417879e6a18c14613363f11283defc832 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Fri, 30 Sep 2011 07:24:00 +0000 Subject: be2net: Fixed Endianness issues in the response read log length field while retrieving FAT data This was manifesting as a crash when FAT Dump extraction was attempted on a PPC machine. Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index eb58a80aaddd..1ac031e21699 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1429,7 +1429,7 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; memcpy(buf + offset, resp->data_buffer, - resp->read_log_length); + le32_to_cpu(resp->read_log_length)); } else { dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); goto err; -- cgit v1.2.3 From 3de09455cfcde1898fb435ad425b9ad5d13ed362 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Fri, 30 Sep 2011 07:25:05 +0000 Subject: be2net: Making die temperature ioctl call async Also changing it's frequency to once every 64s instead of existing 32s as it was shown to affect performance Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 5 ++++ drivers/net/ethernet/emulex/benet/be_cmds.c | 40 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 15 deletions(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 894f1a91d9c9..644e8fed8364 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -137,6 +137,11 @@ static inline void *queue_tail_node(struct be_queue_info *q) return q->dma_mem.va + q->tail * q->entry_size; } +static inline void *queue_index_node(struct be_queue_info *q, u16 index) +{ + return q->dma_mem.va + index * q->entry_size; +} + static inline void queue_head_inc(struct be_queue_info *q) { index_inc(&q->head, q->len); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 1ac031e21699..6e7b5218c784 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -19,7 +19,12 @@ #include "be_cmds.h" /* Must be a power of 2 or else MODULO will BUG_ON */ -static int be_get_temp_freq = 32; +static int be_get_temp_freq = 64; + +static inline void *embedded_payload(struct be_mcc_wrb *wrb) +{ + return wrb->payload.embedded_payload; +} static void be_mcc_notify(struct be_adapter *adapter) { @@ -85,7 +90,20 @@ static int be_mcc_compl_process(struct be_adapter *adapter, 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); + struct be_cmd_resp_get_cntl_addnl_attribs *resp = + embedded_payload(mcc_wrb); + adapter->drv_stats.be_on_die_temperature = + resp->on_die_temperature; + } } else { + if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) + be_get_temp_freq = 0; + if (compl_status == MCC_STATUS_NOT_SUPPORTED || compl_status == MCC_STATUS_ILLEGAL_REQUEST) goto done; @@ -404,10 +422,6 @@ int be_cmd_POST(struct be_adapter *adapter) return -1; } -static inline void *embedded_payload(struct be_mcc_wrb *wrb) -{ - return wrb->payload.embedded_payload; -} static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) { @@ -1301,10 +1315,13 @@ 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; @@ -1318,16 +1335,9 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req)); - status = be_mcc_notify_wait(adapter); - if (!status) { - struct be_cmd_resp_get_cntl_addnl_attribs *resp = - embedded_payload(wrb); - adapter->drv_stats.be_on_die_temperature = - resp->on_die_temperature; - } - /* If IOCTL fails once, do not bother issuing it again */ - else - be_get_temp_freq = 0; + wrb->tag1 = mccq_index; + + be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); -- cgit v1.2.3 From f9449ab76805a2f0e739f5e85a6d9e32d089f1b2 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 24 Oct 2011 02:45:01 +0000 Subject: be2net: refactor VF setup/teardown code into be_vf_setup/clear() Currently the code for VF setup/teardown done by a PF (if_create, mac_add_config, link_status_query etc) is scattered; this patch refactors this code into be_vf_setup() and be_vf_clear(). The if_create/if_destroy/mac_addr_query cmds are now called after the MCCQ is created; so these cmds are now modified to use the MCCQ instead of MBOX. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 66 ++++---- drivers/net/ethernet/emulex/benet/be_cmds.h | 4 +- drivers/net/ethernet/emulex/benet/be_main.c | 229 +++++++++++++--------------- 3 files changed, 147 insertions(+), 152 deletions(-) (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 6e7b5218c784..e0ff96193c49 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -615,7 +615,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, return status; } -/* Uses mbox */ +/* Use MCC */ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle) { @@ -623,10 +623,13 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, struct be_cmd_req_mac_query *req; int status; - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mbox(adapter); + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, @@ -643,13 +646,14 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, req->permanent = 0; } - status = be_mbox_notify_wait(adapter); + status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); memcpy(mac_addr, resp->mac.addr, ETH_ALEN); } - mutex_unlock(&adapter->mbox_lock); +err: + spin_unlock_bh(&adapter->mcc_lock); return status; } @@ -1111,20 +1115,22 @@ err: } /* Create an rx filtering policy configuration on an i/f - * Uses mbox + * Uses MCCQ */ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, - u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id, - u32 domain) + u8 *mac, u32 *if_handle, u32 *pmac_id, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_if_create *req; int status; - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mbox(adapter); + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, @@ -1136,23 +1142,25 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, req->hdr.domain = domain; req->capability_flags = cpu_to_le32(cap_flags); req->enable_flags = cpu_to_le32(en_flags); - req->pmac_invalid = pmac_invalid; - if (!pmac_invalid) + if (mac) memcpy(req->mac_addr, mac, ETH_ALEN); + else + req->pmac_invalid = true; - status = be_mbox_notify_wait(adapter); + status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_if_create *resp = embedded_payload(wrb); *if_handle = le32_to_cpu(resp->interface_id); - if (!pmac_invalid) + if (mac) *pmac_id = le32_to_cpu(resp->pmac_id); } - mutex_unlock(&adapter->mbox_lock); +err: + spin_unlock_bh(&adapter->mcc_lock); return status; } -/* Uses mbox */ +/* Uses MCCQ */ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) { struct be_mcc_wrb *wrb; @@ -1162,10 +1170,16 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) if (adapter->eeh_err) return -EIO; - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; + if (!interface_id) + return 0; - wrb = wrb_from_mbox(adapter); + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, @@ -1177,10 +1191,9 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) req->hdr.domain = domain; req->interface_id = cpu_to_le32(interface_id); - status = be_mbox_notify_wait(adapter); - - mutex_unlock(&adapter->mbox_lock); - + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); return status; } @@ -1301,7 +1314,8 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) { *link_speed = le16_to_cpu(resp->link_speed); - *mac_speed = resp->mac_speed; + if (mac_speed) + *mac_speed = resp->mac_speed; } } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index abaa90cbfea2..75b75741c80e 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1413,8 +1413,8 @@ extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 domain); extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, - u32 en_flags, u8 *mac, bool pmac_invalid, - u32 *if_handle, u32 *pmac_id, u32 domain); + u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id, + u32 domain); extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle, u32 domain); extern int be_cmd_eq_create(struct be_adapter *adapter, diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index d05b6bb5ae81..d32e3787beb4 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2069,7 +2069,7 @@ done: return; } -static void be_sriov_enable(struct be_adapter *adapter) +static int be_sriov_enable(struct be_adapter *adapter) { be_check_sriov_fn_type(adapter); #ifdef CONFIG_PCI_IOV @@ -2091,8 +2091,17 @@ static void be_sriov_enable(struct be_adapter *adapter) status = pci_enable_sriov(adapter->pdev, num_vfs); adapter->sriov_enabled = status ? false : true; + + if (adapter->sriov_enabled) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), + GFP_KERNEL); + if (!adapter->vf_cfg) + return -ENOMEM; + } } #endif + return 0; } static void be_sriov_disable(struct be_adapter *adapter) @@ -2100,6 +2109,7 @@ static void be_sriov_disable(struct be_adapter *adapter) #ifdef CONFIG_PCI_IOV if (adapter->sriov_enabled) { pci_disable_sriov(adapter->pdev); + kfree(adapter->vf_cfg); adapter->sriov_enabled = false; } #endif @@ -2405,7 +2415,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) */ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) { - u32 vf = 0; + u32 vf; int status = 0; u8 mac[ETH_ALEN]; @@ -2427,7 +2437,7 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) return status; } -static inline void be_vf_eth_addr_rem(struct be_adapter *adapter) +static void be_vf_clear(struct be_adapter *adapter) { u32 vf; @@ -2437,29 +2447,25 @@ static inline void be_vf_eth_addr_rem(struct be_adapter *adapter) adapter->vf_cfg[vf].vf_if_handle, adapter->vf_cfg[vf].vf_pmac_id, vf + 1); } + + for (vf = 0; vf < num_vfs; vf++) + if (adapter->vf_cfg[vf].vf_if_handle) + be_cmd_if_destroy(adapter, + adapter->vf_cfg[vf].vf_if_handle, vf + 1); } static int be_clear(struct be_adapter *adapter) { - int vf; - if (be_physfn(adapter) && adapter->sriov_enabled) - be_vf_eth_addr_rem(adapter); + be_vf_clear(adapter); + + be_cmd_if_destroy(adapter, adapter->if_handle, 0); be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); adapter->eq_next_idx = 0; - if (be_physfn(adapter) && adapter->sriov_enabled) - for (vf = 0; vf < num_vfs; vf++) - if (adapter->vf_cfg[vf].vf_if_handle) - be_cmd_if_destroy(adapter, - adapter->vf_cfg[vf].vf_if_handle, - vf + 1); - - be_cmd_if_destroy(adapter, adapter->if_handle, 0); - adapter->be3_native = false; adapter->promiscuous = false; @@ -2468,83 +2474,99 @@ static int be_clear(struct be_adapter *adapter) return 0; } +static int be_vf_setup(struct be_adapter *adapter) +{ + u32 cap_flags, en_flags, vf; + u16 lnk_speed; + int status; + + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST; + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, + &adapter->vf_cfg[vf].vf_if_handle, + NULL, vf+1); + if (status) + goto err; + adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID; + } + + if (!lancer_chip(adapter)) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto err; + } + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, + vf + 1); + if (status) + goto err; + adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; + } + return 0; +err: + return status; +} + static int be_setup(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; - u32 cap_flags, en_flags, vf = 0; + u32 cap_flags, en_flags; u32 tx_fc, rx_fc; int status; u8 mac[ETH_ALEN]; - be_cmd_req_native_mode(adapter); - - cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | - BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST; + /* Allow all priorities by default. A GRP5 evt may modify this */ + adapter->vlan_prio_bmap = 0xff; + adapter->link_speed = -1; - if (be_physfn(adapter)) { - cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS | - BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_PASS_L3L4_ERRORS; - en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; - - if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { - cap_flags |= BE_IF_FLAGS_RSS; - en_flags |= BE_IF_FLAGS_RSS; - } - } + be_cmd_req_native_mode(adapter); - status = be_cmd_if_create(adapter, cap_flags, en_flags, - netdev->dev_addr, false/* pmac_invalid */, - &adapter->if_handle, &adapter->pmac_id, 0); + status = be_tx_queues_create(adapter); if (status != 0) goto err; - if (be_physfn(adapter)) { - if (adapter->sriov_enabled) { - while (vf < num_vfs) { - cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | - BE_IF_FLAGS_BROADCAST; - status = be_cmd_if_create(adapter, cap_flags, - en_flags, mac, true, - &adapter->vf_cfg[vf].vf_if_handle, - NULL, vf+1); - if (status) { - dev_err(&adapter->pdev->dev, - "Interface Create failed for VF %d\n", - vf); - goto err; - } - adapter->vf_cfg[vf].vf_pmac_id = - BE_INVALID_PMAC_ID; - vf++; - } - } - } else { - status = be_cmd_mac_addr_query(adapter, mac, - MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); - if (!status) { - memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); - memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); - } - } - - status = be_tx_queues_create(adapter); + status = be_rx_queues_create(adapter); if (status != 0) goto err; - status = be_rx_queues_create(adapter); + status = be_mcc_queues_create(adapter); if (status != 0) goto err; - /* Allow all priorities by default. A GRP5 evt may modify this */ - adapter->vlan_prio_bmap = 0xff; + memset(mac, 0, ETH_ALEN); + status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, + true /*permanent */, 0); + if (status) + return status; + memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); + memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); - status = be_mcc_queues_create(adapter); + en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; + cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS | + BE_IF_FLAGS_PROMISCUOUS; + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { + cap_flags |= BE_IF_FLAGS_RSS; + en_flags |= BE_IF_FLAGS_RSS; + } + status = be_cmd_if_create(adapter, cap_flags, en_flags, + netdev->dev_addr, &adapter->if_handle, + &adapter->pmac_id, 0); if (status != 0) goto err; - adapter->link_speed = -1; + /* For BEx, the VF's permanent mac queried from card is incorrect. + * Query the mac configued by the PF using if_handle + */ + if (!be_physfn(adapter) && !lancer_chip(adapter)) { + status = be_cmd_mac_addr_query(adapter, mac, + MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); + if (!status) { + memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); + memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); + } + } be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); @@ -2565,8 +2587,14 @@ static int be_setup(struct be_adapter *adapter) } pcie_set_readrq(adapter->pdev, 4096); - return 0; + if (be_physfn(adapter) && adapter->sriov_enabled) { + status = be_vf_setup(adapter); + if (status) + goto err; + } + + return 0; err: be_clear(adapter); return status; @@ -3123,7 +3151,6 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); - kfree(adapter->vf_cfg); be_sriov_disable(adapter); be_msix_disable(adapter); @@ -3138,30 +3165,12 @@ static void __devexit be_remove(struct pci_dev *pdev) static int be_get_config(struct be_adapter *adapter) { int status; - u8 mac[ETH_ALEN]; status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, &adapter->function_mode, &adapter->function_caps); if (status) return status; - memset(mac, 0, ETH_ALEN); - - /* A default permanent address is given to each VF for Lancer*/ - if (be_physfn(adapter) || lancer_chip(adapter)) { - status = be_cmd_mac_addr_query(adapter, mac, - MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); - - if (status) - return status; - - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; - - memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); - memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); - } - if (adapter->function_mode & 0x400) adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4; else @@ -3310,18 +3319,13 @@ static int __devinit be_probe(struct pci_dev *pdev, } } - be_sriov_enable(adapter); - if (adapter->sriov_enabled) { - adapter->vf_cfg = kcalloc(num_vfs, - sizeof(struct be_vf_cfg), GFP_KERNEL); - - if (!adapter->vf_cfg) - goto free_netdev; - } + status = be_sriov_enable(adapter); + if (status) + goto free_netdev; status = be_ctrl_init(adapter); if (status) - goto free_vf_cfg; + goto disable_sriov; if (lancer_chip(adapter)) { status = lancer_test_and_set_rdy_state(adapter); @@ -3375,33 +3379,11 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status != 0) goto unsetup; - if (be_physfn(adapter) && adapter->sriov_enabled) { - u8 mac_speed; - u16 vf, lnk_speed; - - if (!lancer_chip(adapter)) { - status = be_vf_eth_addr_config(adapter); - if (status) - goto unreg_netdev; - } - - for (vf = 0; vf < num_vfs; vf++) { - status = be_cmd_link_status_query(adapter, &mac_speed, - &lnk_speed, vf + 1); - if (!status) - adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; - else - goto unreg_netdev; - } - } - dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; -unreg_netdev: - unregister_netdev(netdev); unsetup: be_clear(adapter); msix_disable: @@ -3410,10 +3392,9 @@ stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); -free_vf_cfg: - kfree(adapter->vf_cfg); -free_netdev: +disable_sriov: be_sriov_disable(adapter); +free_netdev: free_netdev(netdev); pci_set_drvdata(pdev, NULL); rel_reg: -- cgit v1.2.3