Logo Search packages:      
Sourcecode: linux version File versions  Download package

c2_intr.c

/*
 * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
 * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "c2.h"
#include <rdma/iw_cm.h>
#include "c2_vq.h"

static void handle_mq(struct c2_dev *c2dev, u32 index);
static void handle_vq(struct c2_dev *c2dev, u32 mq_index);

/*
 * Handle RNIC interrupts
 */
void c2_rnic_interrupt(struct c2_dev *c2dev)
{
      unsigned int mq_index;

      while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
            mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
            if (mq_index & 0x80000000) {
                  break;
            }

            c2dev->hints_read++;
            handle_mq(c2dev, mq_index);
      }

}

/*
 * Top level MQ handler
 */
static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
{
      if (c2dev->qptr_array[mq_index] == NULL) {
            pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
                  mq_index);
            return;
      }

      switch (mq_index) {
      case (0):
            /*
             * An index of 0 in the activity queue
             * indicates the req vq now has messages
             * available...
             *
             * Wake up any waiters waiting on req VQ
             * message availability.
             */
            wake_up(&c2dev->req_vq_wo);
            break;
      case (1):
            handle_vq(c2dev, mq_index);
            break;
      case (2):
            /* We have to purge the VQ in case there are pending
             * accept reply requests that would result in the
             * generation of an ESTABLISHED event. If we don't
             * generate these first, a CLOSE event could end up
             * being delivered before the ESTABLISHED event.
             */
            handle_vq(c2dev, 1);

            c2_ae_event(c2dev, mq_index);
            break;
      default:
            /* There is no event synchronization between CQ events
             * and AE or CM events. In fact, CQE could be
             * delivered for all of the I/O up to and including the
             * FLUSH for a peer disconenct prior to the ESTABLISHED
             * event being delivered to the app. The reason for this
             * is that CM events are delivered on a thread, while AE
             * and CM events are delivered on interrupt context.
             */
            c2_cq_event(c2dev, mq_index);
            break;
      }

      return;
}

/*
 * Handles verbs WR replies.
 */
static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
{
      void *adapter_msg, *reply_msg;
      struct c2wr_hdr *host_msg;
      struct c2wr_hdr tmp;
      struct c2_mq *reply_vq;
      struct c2_vq_req *req;
      struct iw_cm_event cm_event;
      int err;

      reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];

      /*
       * get next msg from mq_index into adapter_msg.
       * don't free it yet.
       */
      adapter_msg = c2_mq_consume(reply_vq);
      if (adapter_msg == NULL) {
            return;
      }

      host_msg = vq_repbuf_alloc(c2dev);

      /*
       * If we can't get a host buffer, then we'll still
       * wakeup the waiter, we just won't give him the msg.
       * It is assumed the waiter will deal with this...
       */
      if (!host_msg) {
            pr_debug("handle_vq: no repbufs!\n");

            /*
             * just copy the WR header into a local variable.
             * this allows us to still demux on the context
             */
            host_msg = &tmp;
            memcpy(host_msg, adapter_msg, sizeof(tmp));
            reply_msg = NULL;
      } else {
            memcpy(host_msg, adapter_msg, reply_vq->msg_size);
            reply_msg = host_msg;
      }

      /*
       * consume the msg from the MQ
       */
      c2_mq_free(reply_vq);

      /*
       * wakeup the waiter.
       */
      req = (struct c2_vq_req *) (unsigned long) host_msg->context;
      if (req == NULL) {
            /*
             * We should never get here, as the adapter should
             * never send us a reply that we're not expecting.
             */
            vq_repbuf_free(c2dev, host_msg);
            pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
            return;
      }

      err = c2_errno(reply_msg);
      if (!err) switch (req->event) {
      case IW_CM_EVENT_ESTABLISHED:
            c2_set_qp_state(req->qp,
                        C2_QP_STATE_RTS);
      case IW_CM_EVENT_CLOSE:

            /*
             * Move the QP to RTS if this is
             * the established event
             */
            cm_event.event = req->event;
            cm_event.status = 0;
            cm_event.local_addr = req->cm_id->local_addr;
            cm_event.remote_addr = req->cm_id->remote_addr;
            cm_event.private_data = NULL;
            cm_event.private_data_len = 0;
            req->cm_id->event_handler(req->cm_id, &cm_event);
            break;
      default:
            break;
      }

      req->reply_msg = (u64) (unsigned long) (reply_msg);
      atomic_set(&req->reply_ready, 1);
      wake_up(&req->wait_object);

      /*
       * If the request was cancelled, then this put will
       * free the vq_req memory...and reply_msg!!!
       */
      vq_req_put(c2dev, req);
}

Generated by  Doxygen 1.6.0   Back to index