linux/drivers/infiniband/hw/amso1100/c2_intr.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
   3 * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
   4 *
   5 * This software is available to you under a choice of one of two
   6 * licenses.  You may choose to be licensed under the terms of the GNU
   7 * General Public License (GPL) Version 2, available from the file
   8 * COPYING in the main directory of this source tree, or the
   9 * OpenIB.org BSD license below:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      - Redistributions of source code must retain the above
  16 *        copyright notice, this list of conditions and the following
  17 *        disclaimer.
  18 *
  19 *      - Redistributions in binary form must reproduce the above
  20 *        copyright notice, this list of conditions and the following
  21 *        disclaimer in the documentation and/or other materials
  22 *        provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33#include "c2.h"
  34#include <rdma/iw_cm.h>
  35#include "c2_vq.h"
  36
  37static void handle_mq(struct c2_dev *c2dev, u32 index);
  38static void handle_vq(struct c2_dev *c2dev, u32 mq_index);
  39
  40/*
  41 * Handle RNIC interrupts
  42 */
  43void c2_rnic_interrupt(struct c2_dev *c2dev)
  44{
  45        unsigned int mq_index;
  46
  47        while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
  48                mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
  49                if (mq_index & 0x80000000) {
  50                        break;
  51                }
  52
  53                c2dev->hints_read++;
  54                handle_mq(c2dev, mq_index);
  55        }
  56
  57}
  58
  59/*
  60 * Top level MQ handler
  61 */
  62static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
  63{
  64        if (c2dev->qptr_array[mq_index] == NULL) {
  65                pr_debug("handle_mq: stray activity for mq_index=%d\n",
  66                         mq_index);
  67                return;
  68        }
  69
  70        switch (mq_index) {
  71        case (0):
  72                /*
  73                 * An index of 0 in the activity queue
  74                 * indicates the req vq now has messages
  75                 * available...
  76                 *
  77                 * Wake up any waiters waiting on req VQ
  78                 * message availability.
  79                 */
  80                wake_up(&c2dev->req_vq_wo);
  81                break;
  82        case (1):
  83                handle_vq(c2dev, mq_index);
  84                break;
  85        case (2):
  86                /* We have to purge the VQ in case there are pending
  87                 * accept reply requests that would result in the
  88                 * generation of an ESTABLISHED event. If we don't
  89                 * generate these first, a CLOSE event could end up
  90                 * being delivered before the ESTABLISHED event.
  91                 */
  92                handle_vq(c2dev, 1);
  93
  94                c2_ae_event(c2dev, mq_index);
  95                break;
  96        default:
  97                /* There is no event synchronization between CQ events
  98                 * and AE or CM events. In fact, CQE could be
  99                 * delivered for all of the I/O up to and including the
 100                 * FLUSH for a peer disconenct prior to the ESTABLISHED
 101                 * event being delivered to the app. The reason for this
 102                 * is that CM events are delivered on a thread, while AE
 103                 * and CM events are delivered on interrupt context.
 104                 */
 105                c2_cq_event(c2dev, mq_index);
 106                break;
 107        }
 108
 109        return;
 110}
 111
 112/*
 113 * Handles verbs WR replies.
 114 */
 115static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
 116{
 117        void *adapter_msg, *reply_msg;
 118        struct c2wr_hdr *host_msg;
 119        struct c2wr_hdr tmp;
 120        struct c2_mq *reply_vq;
 121        struct c2_vq_req *req;
 122        struct iw_cm_event cm_event;
 123        int err;
 124
 125        reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];
 126
 127        /*
 128         * get next msg from mq_index into adapter_msg.
 129         * don't free it yet.
 130         */
 131        adapter_msg = c2_mq_consume(reply_vq);
 132        if (adapter_msg == NULL) {
 133                return;
 134        }
 135
 136        host_msg = vq_repbuf_alloc(c2dev);
 137
 138        /*
 139         * If we can't get a host buffer, then we'll still
 140         * wakeup the waiter, we just won't give him the msg.
 141         * It is assumed the waiter will deal with this...
 142         */
 143        if (!host_msg) {
 144                pr_debug("handle_vq: no repbufs!\n");
 145
 146                /*
 147                 * just copy the WR header into a local variable.
 148                 * this allows us to still demux on the context
 149                 */
 150                host_msg = &tmp;
 151                memcpy(host_msg, adapter_msg, sizeof(tmp));
 152                reply_msg = NULL;
 153        } else {
 154                memcpy(host_msg, adapter_msg, reply_vq->msg_size);
 155                reply_msg = host_msg;
 156        }
 157
 158        /*
 159         * consume the msg from the MQ
 160         */
 161        c2_mq_free(reply_vq);
 162
 163        /*
 164         * wakeup the waiter.
 165         */
 166        req = (struct c2_vq_req *) (unsigned long) host_msg->context;
 167        if (req == NULL) {
 168                /*
 169                 * We should never get here, as the adapter should
 170                 * never send us a reply that we're not expecting.
 171                 */
 172                vq_repbuf_free(c2dev, host_msg);
 173                pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
 174                return;
 175        }
 176
 177        if (reply_msg)
 178                err = c2_errno(reply_msg);
 179        else
 180                err = -ENOMEM;
 181
 182        if (!err) switch (req->event) {
 183        case IW_CM_EVENT_ESTABLISHED:
 184                c2_set_qp_state(req->qp,
 185                                C2_QP_STATE_RTS);
 186                /*
 187                 * Until ird/ord negotiation via MPAv2 support is added, send
 188                 * max supported values
 189                 */
 190                cm_event.ird = cm_event.ord = 128;
 191        case IW_CM_EVENT_CLOSE:
 192
 193                /*
 194                 * Move the QP to RTS if this is
 195                 * the established event
 196                 */
 197                cm_event.event = req->event;
 198                cm_event.status = 0;
 199                cm_event.local_addr = req->cm_id->local_addr;
 200                cm_event.remote_addr = req->cm_id->remote_addr;
 201                cm_event.private_data = NULL;
 202                cm_event.private_data_len = 0;
 203                req->cm_id->event_handler(req->cm_id, &cm_event);
 204                break;
 205        default:
 206                break;
 207        }
 208
 209        req->reply_msg = (u64) (unsigned long) (reply_msg);
 210        atomic_set(&req->reply_ready, 1);
 211        wake_up(&req->wait_object);
 212
 213        /*
 214         * If the request was cancelled, then this put will
 215         * free the vq_req memory...and reply_msg!!!
 216         */
 217        vq_req_put(c2dev, req);
 218}
 219