1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /* Copyright © 2003-2011 Emulex. All rights reserved.  */
  23 
  24 /*
  25  * Source file containing the implementation of the MailBox queue handling
  26  * and related helper functions
  27  */
  28 
  29 #include <oce_impl.h>
  30 
  31 /*
  32  * function to drain a MCQ and process its CQEs
  33  *
  34  * dev - software handle to the device
  35  * cq - pointer to the cq to drain
  36  *
  37  * return the number of CQEs processed
  38  */
  39 uint16_t
  40 oce_drain_mq_cq(void *arg)
  41 {
  42         struct oce_mq_cqe *cqe = NULL;
  43         uint16_t num_cqe = 0;
  44         link_state_t link_status;
  45         struct oce_async_cqe_link_state *acqe;
  46         struct oce_mq *mq;
  47         struct oce_cq  *cq;
  48         struct oce_dev *dev;
  49 
  50         /* do while we do not reach a cqe that is not valid */
  51         mq = (struct oce_mq *)arg;
  52         cq = mq->cq;
  53         dev = mq->parent;
  54         mutex_enter(&mq->lock);
  55         cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
  56         while (cqe->u0.dw[3]) {
  57                 DW_SWAP(u32ptr(cqe), sizeof (struct oce_mq_cqe));
  58                 if (cqe->u0.s.async_event) {
  59                         acqe = (struct oce_async_cqe_link_state *)cqe;
  60                         if (acqe->u0.s.event_code ==
  61                             ASYNC_EVENT_CODE_LINK_STATE) {
  62                                 /*
  63                                  * don't care logical or not,
  64                                  * just check up down
  65                                  */
  66 
  67                                 link_status = ((acqe->u0.s.link_status &
  68                                     ~ASYNC_EVENT_LOGICAL) ==
  69                                     ASYNC_EVENT_LINK_UP) ?
  70                                     LINK_STATE_UP: LINK_STATE_DOWN;
  71                                 mac_link_update(dev->mac_handle, link_status);
  72                                 dev->link_status = link_status;
  73                                 dev->link_speed = -1;
  74                         }
  75                 }
  76                 cqe->u0.dw[3] = 0;
  77                 RING_GET(cq->ring, 1);
  78                 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
  79                 num_cqe++;
  80         } /* for all valid CQE */
  81         mutex_exit(&mq->lock);
  82         oce_arm_cq(dev, cq->cq_id, num_cqe, B_TRUE);
  83         return (num_cqe);
  84 } /* oce_drain_mq_cq */
  85 
  86 int
  87 oce_start_mq(struct oce_mq *mq)
  88 {
  89         oce_arm_cq(mq->parent, mq->cq->cq_id, 0, B_TRUE);
  90         return (0);
  91 }
  92 
  93 
  94 void
  95 oce_clean_mq(struct oce_mq *mq)
  96 {
  97         struct oce_cq  *cq;
  98         struct oce_dev *dev;
  99         uint16_t num_cqe = 0;
 100         struct oce_mq_cqe *cqe = NULL;
 101 
 102         cq = mq->cq;
 103         dev = mq->parent;
 104         cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
 105         while (cqe->u0.dw[3]) {
 106                 DW_SWAP(u32ptr(cqe), sizeof (struct oce_mq_cqe));
 107                 cqe->u0.dw[3] = 0;
 108                 RING_GET(cq->ring, 1);
 109                 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
 110                 num_cqe++;
 111         } /* for all valid CQE */
 112         if (num_cqe)
 113                 oce_arm_cq(dev, cq->cq_id, num_cqe, B_FALSE);
 114         /* Drain the Event queue now */
 115         oce_drain_eq(mq->cq->eq);
 116 }