Print this page
NEX-1890 update oce from source provided by Emulex

*** 17,88 **** * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ ! /* Copyright © 2003-2011 Emulex. All rights reserved. */ /* * Source file containing the implementation of the MailBox queue handling * and related helper functions */ #include <oce_impl.h> /* * function to drain a MCQ and process its CQEs * * dev - software handle to the device * cq - pointer to the cq to drain * * return the number of CQEs processed */ ! uint16_t ! oce_drain_mq_cq(void *arg) { struct oce_mq_cqe *cqe = NULL; uint16_t num_cqe = 0; - link_state_t link_status; - struct oce_async_cqe_link_state *acqe; struct oce_mq *mq; struct oce_cq *cq; struct oce_dev *dev; /* do while we do not reach a cqe that is not valid */ mq = (struct oce_mq *)arg; cq = mq->cq; dev = mq->parent; ! mutex_enter(&mq->lock); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); - while (cqe->u0.dw[3]) { - DW_SWAP(u32ptr(cqe), sizeof (struct oce_mq_cqe)); - if (cqe->u0.s.async_event) { - acqe = (struct oce_async_cqe_link_state *)cqe; - if (acqe->u0.s.event_code == - ASYNC_EVENT_CODE_LINK_STATE) { - /* - * don't care logical or not, - * just check up down - */ ! link_status = ((acqe->u0.s.link_status & ! ~ASYNC_EVENT_LOGICAL) == ! ASYNC_EVENT_LINK_UP) ? ! LINK_STATE_UP: LINK_STATE_DOWN; ! mac_link_update(dev->mac_handle, link_status); ! dev->link_status = link_status; ! dev->link_speed = -1; } ! } ! cqe->u0.dw[3] = 0; RING_GET(cq->ring, 1); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); num_cqe++; } /* for all valid CQE */ ! mutex_exit(&mq->lock); oce_arm_cq(dev, cq->cq_id, num_cqe, B_TRUE); ! return (num_cqe); } /* oce_drain_mq_cq */ int oce_start_mq(struct oce_mq *mq) { --- 17,211 ---- * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ ! /* ! * Copyright (c) 2009-2012 Emulex. All rights reserved. ! * Use is subject to license terms. ! */ + + /* * Source file containing the implementation of the MailBox queue handling * and related helper functions */ #include <oce_impl.h> + int pow10[5] = { + 0, + 10, + 100, + 1000, + 10000 + }; + + static void oce_process_link_event(struct oce_dev *dev, + struct oce_async_cqe_link_state *acqe); + static void oce_async_grp5_qos_speed_process(struct oce_dev *dev, + struct oce_async_event_grp5_qos_link_speed *acqe); + static void oce_async_grp5_pvid_state(struct oce_dev *dev, + struct oce_async_event_grp5_pvid_state *acqe); + static void oce_async_grp5_cos_priority(struct oce_dev *dev, + struct oce_async_event_grp5_cos_priority *acqe); + void oce_process_grp5_event(struct oce_dev *dev, + struct oce_mq_cqe *cqe, uint8_t event_type); + static void oce_process_mq_compl(struct oce_dev *dev, + struct oce_mq_cqe *cqe); + static void oce_process_async_events(struct oce_dev *dev, + struct oce_mq_cqe *cqe); + + + static void + oce_process_debug_event(struct oce_dev *dev, + struct async_event_qnq *acqe, uint8_t event_type) + { + oce_log(dev, CE_NOTE, MOD_CONFIG, + "Debug Event: type = %d, enabled = %d, tag = 0x%x", + acqe->trailer.u0.bits.event_type, acqe->enabled, acqe->vlan_tag); + + if (event_type == ASYNC_DEBUG_EVENT_TYPE_QNQ) { + dev->QnQ_queried = 1; + dev->QnQ_valid = acqe->enabled; + dev->QnQ_tag = LE_16(acqe->vlan_tag); + + if (!dev->QnQ_valid) { + dev->QnQ_tag = 0; + } + } + } + + static void + oce_process_link_event(struct oce_dev *dev, + struct oce_async_cqe_link_state *acqe) + { + link_state_t link_status; + + link_status = ((acqe->link_status & ~ASYNC_EVENT_LOGICAL) == + ASYNC_EVENT_LINK_UP) ? LINK_STATE_UP: LINK_STATE_DOWN; + + /* store the link status */ + dev->link_status = link_status; + + dev->link_speed = (acqe->qos_link_speed > 0) ? + LE_16(acqe->qos_link_speed) * 10 : pow10[acqe->speed]; + dev->link_duplex = acqe->duplex; + + mac_link_update(dev->mac_handle, link_status); + oce_log(dev, CE_NOTE, MOD_CONFIG, " Link Event" + "Link Status %d Link Speed %d Link Duplex %d\n", + dev->link_status, dev->link_speed, dev->link_duplex); + } + + static void + oce_async_grp5_qos_speed_process(struct oce_dev *dev, + struct oce_async_event_grp5_qos_link_speed *acqe) + { + + if (acqe->physical_port == dev->port_id) { + dev->link_speed = LE_16(acqe->qos_link_speed) * 10; + } + oce_log(dev, CE_NOTE, MOD_CONFIG, "GRP5 QOS_SPEED EVENT" + "Physical Port : %d QOS_SPEED %d\n", acqe->physical_port, + acqe->qos_link_speed); + } + + static void + oce_async_grp5_pvid_state(struct oce_dev *dev, + struct oce_async_event_grp5_pvid_state *acqe) + { + + if (acqe->enabled) { + dev->pvid = BE_16(acqe->tag); + } else { + dev->pvid = 0; + } + oce_log(dev, CE_NOTE, MOD_CONFIG, "GRP5 PVID EVENT" + "PVID Configured : 0x%x\n", dev->pvid); + } + + static void + oce_async_grp5_cos_priority(struct oce_dev *dev, + struct oce_async_event_grp5_cos_priority *acqe) + { + if (acqe->valid) { + dev->vlan_prio_bmap = acqe->available_priority_bmap; + dev->reco_priority &= acqe->reco_default_priority; + } + + } + + void + oce_process_grp5_event(struct oce_dev *dev, + struct oce_mq_cqe *cqe, uint8_t event_type) + { + switch (event_type) { + case ASYNC_EVENT_QOS_SPEED: + oce_async_grp5_qos_speed_process(dev, + (struct oce_async_event_grp5_qos_link_speed *)cqe); + break; + case ASYNC_EVENT_COS_PRIORITY: + oce_async_grp5_cos_priority(dev, + (struct oce_async_event_grp5_cos_priority *)cqe); + break; + case ASYNC_EVENT_PVID_STATE: + oce_async_grp5_pvid_state(dev, + (struct oce_async_event_grp5_pvid_state *)cqe); + break; + default: + break; + } + + } /* * function to drain a MCQ and process its CQEs * * dev - software handle to the device * cq - pointer to the cq to drain * * return the number of CQEs processed */ ! void * ! oce_drain_mq_cq(void *arg, int arg2, int arg3) { struct oce_mq_cqe *cqe = NULL; uint16_t num_cqe = 0; struct oce_mq *mq; struct oce_cq *cq; struct oce_dev *dev; + uint32_t flags = 0; + _NOTE(ARGUNUSED(arg2)); + _NOTE(ARGUNUSED(arg3)); + /* do while we do not reach a cqe that is not valid */ mq = (struct oce_mq *)arg; cq = mq->cq; dev = mq->parent; ! ! DBUF_SYNC(cq->ring->dbuf, 0, 0, DDI_DMA_SYNC_FORKERNEL); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); ! while (MQ_CQE_VALID(cqe)) { ! flags = LE_32(cqe->u0.dw[3]); ! ! if (flags & MQ_CQE_ASYNC_MASK) { ! oce_process_async_events(dev, cqe); ! } else if (flags & MQ_CQE_COMPLETED_MASK) { ! oce_process_mq_compl(dev, cqe); ! atomic_add_32(&mq->mq_free, 1); } ! MQ_CQE_INVALIDATE(cqe); RING_GET(cq->ring, 1); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); num_cqe++; } /* for all valid CQE */ ! DBUF_SYNC(cq->ring->dbuf, 0, 0, DDI_DMA_SYNC_FORDEV); oce_arm_cq(dev, cq->cq_id, num_cqe, B_TRUE); ! return (NULL); } /* oce_drain_mq_cq */ int oce_start_mq(struct oce_mq *mq) {
*** 92,116 **** void oce_clean_mq(struct oce_mq *mq) { ! struct oce_cq *cq; ! struct oce_dev *dev; ! uint16_t num_cqe = 0; ! struct oce_mq_cqe *cqe = NULL; ! ! cq = mq->cq; ! dev = mq->parent; ! cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); ! while (cqe->u0.dw[3]) { ! DW_SWAP(u32ptr(cqe), sizeof (struct oce_mq_cqe)); ! cqe->u0.dw[3] = 0; ! RING_GET(cq->ring, 1); ! cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); ! num_cqe++; ! } /* for all valid CQE */ ! if (num_cqe) ! oce_arm_cq(dev, cq->cq_id, num_cqe, B_FALSE); /* Drain the Event queue now */ oce_drain_eq(mq->cq->eq); } --- 215,314 ---- void oce_clean_mq(struct oce_mq *mq) { ! while (mq->mq_free != mq->cfg.q_len) { ! (void) oce_drain_mq_cq(mq, 0, 0); ! } /* Drain the Event queue now */ oce_drain_eq(mq->cq->eq); + } + + /* function to issue mbox on mq */ + int + oce_issue_mq_mbox(struct oce_dev *dev, struct oce_mbx *mbx) + { + struct oce_mq *mq; + struct oce_mbx *mqe; + struct oce_mbx_ctx *mbctx; + uint32_t mqdb = 0; + + mq = dev->mq; + mbctx = (struct oce_mbx_ctx *) + (uintptr_t)ADDR_64(mbx->tag[1], mbx->tag[0]); + + mutex_enter(&mq->lock); + + if (oce_atomic_reserve(&mq->mq_free, 1) < 0) { + mutex_exit(&mq->lock); + oce_log(dev, CE_NOTE, MOD_CONFIG, + "MQ Entries Free(%d) Retry the command Later", + mq->mq_free); + return (MBX_QUEUE_FULL); + } + + mqe = RING_GET_PRODUCER_ITEM_VA(mq->ring, struct oce_mbx); + /* save the mqe pointer in ctx required to copy resp back */ + mbctx->mqe = mqe; + /* enqueue the command */ + bcopy(mbx, mqe, sizeof (struct oce_mbx)); + RING_PUT(mq->ring, 1); + /* ring mq doorbell num posted is 1 */ + mqdb = (1 << 16) | mq->mq_id; + OCE_DB_WRITE32(dev, PD_MQ_DB, mqdb); + mutex_exit(&mq->lock); + return (MBX_SUCCESS); + } + + void + oce_process_mq_compl(struct oce_dev *dev, struct oce_mq_cqe *cqe) + { + struct oce_mbx_ctx *mbctx; + struct oce_mbx *mbx; + + _NOTE(ARGUNUSED(dev)); + + /* retrieve the context pointer */ + mbctx = (struct oce_mbx_ctx *)(uintptr_t)ADDR_64(cqe->u0.s.mq_tag[1], + cqe->u0.s.mq_tag[0]); + + if (mbctx == NULL) { + return; + } + mbx = mbctx->mbx; + + mbctx->compl_status = LE_32(cqe->u0.dw[0]); + if (mbctx->compl_status == 0) { + bcopy(mbctx->mqe, mbx, sizeof (struct oce_mbx)); + } + mutex_enter(&mbctx->cv_lock); + mbctx->mbx_status = MBX_COMPLETED; + cv_signal(&mbctx->cond_var); + mutex_exit(&mbctx->cv_lock); + + } + + static void + oce_process_async_events(struct oce_dev *dev, struct oce_mq_cqe *cqe) + { + struct oce_async_event_trailer trailer; + + trailer.u0.code = LE_32(cqe->u0.dw[3]); + + switch (trailer.u0.bits.event_code) { + case ASYNC_EVENT_CODE_DEBUG: + oce_process_debug_event(dev, (struct async_event_qnq *)cqe, + trailer.u0.bits.event_type); + break; + case ASYNC_EVENT_CODE_LINK_STATE: + oce_process_link_event(dev, + (struct oce_async_cqe_link_state *)cqe); + break; + case ASYNC_EVENT_CODE_GRP_5: + oce_process_grp5_event(dev, cqe, trailer.u0.bits.event_type); + break; + + default: + break; + } }