linux/drivers/infiniband/hw/amso1100/c2_vq.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 <linux/slab.h>
  34#include <linux/spinlock.h>
  35
  36#include "c2_vq.h"
  37#include "c2_provider.h"
  38
  39/*
  40 * Verbs Request Objects:
  41 *
  42 * VQ Request Objects are allocated by the kernel verbs handlers.
  43 * They contain a wait object, a refcnt, an atomic bool indicating that the
  44 * adapter has replied, and a copy of the verb reply work request.
  45 * A pointer to the VQ Request Object is passed down in the context
  46 * field of the work request message, and reflected back by the adapter
  47 * in the verbs reply message.  The function handle_vq() in the interrupt
  48 * path will use this pointer to:
  49 *      1) append a copy of the verbs reply message
  50 *      2) mark that the reply is ready
  51 *      3) wake up the kernel verbs handler blocked awaiting the reply.
  52 *
  53 *
  54 * The kernel verbs handlers do a "get" to put a 2nd reference on the
  55 * VQ Request object.  If the kernel verbs handler exits before the adapter
  56 * can respond, this extra reference will keep the VQ Request object around
  57 * until the adapter's reply can be processed.  The reason we need this is
  58 * because a pointer to this object is stuffed into the context field of
  59 * the verbs work request message, and reflected back in the reply message.
  60 * It is used in the interrupt handler (handle_vq()) to wake up the appropriate
  61 * kernel verb handler that is blocked awaiting the verb reply.
  62 * So handle_vq() will do a "put" on the object when it's done accessing it.
  63 * NOTE:  If we guarantee that the kernel verb handler will never bail before
  64 *        getting the reply, then we don't need these refcnts.
  65 *
  66 *
  67 * VQ Request objects are freed by the kernel verbs handlers only
  68 * after the verb has been processed, or when the adapter fails and
  69 * does not reply.
  70 *
  71 *
  72 * Verbs Reply Buffers:
  73 *
  74 * VQ Reply bufs are local host memory copies of a
  75 * outstanding Verb Request reply
  76 * message.  The are always allocated by the kernel verbs handlers, and _may_ be
  77 * freed by either the kernel verbs handler -or- the interrupt handler.  The
  78 * kernel verbs handler _must_ free the repbuf, then free the vq request object
  79 * in that order.
  80 */
  81
  82int vq_init(struct c2_dev *c2dev)
  83{
  84        sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",
  85                (char) ('0' + c2dev->devnum));
  86        c2dev->host_msg_cache =
  87            kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
  88                              SLAB_HWCACHE_ALIGN, NULL);
  89        if (c2dev->host_msg_cache == NULL) {
  90                return -ENOMEM;
  91        }
  92        return 0;
  93}
  94
  95void vq_term(struct c2_dev *c2dev)
  96{
  97        kmem_cache_destroy(c2dev->host_msg_cache);
  98}
  99
 100/* vq_req_alloc - allocate a VQ Request Object and initialize it.
 101 * The refcnt is set to 1.
 102 */
 103struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
 104{
 105        struct c2_vq_req *r;
 106
 107        r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
 108        if (r) {
 109                init_waitqueue_head(&r->wait_object);
 110                r->reply_msg = 0;
 111                r->event = 0;
 112                r->cm_id = NULL;
 113                r->qp = NULL;
 114                atomic_set(&r->refcnt, 1);
 115                atomic_set(&r->reply_ready, 0);
 116        }
 117        return r;
 118}
 119
 120
 121/* vq_req_free - free the VQ Request Object.  It is assumed the verbs handler
 122 * has already free the VQ Reply Buffer if it existed.
 123 */
 124void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
 125{
 126        r->reply_msg = 0;
 127        if (atomic_dec_and_test(&r->refcnt)) {
 128                kfree(r);
 129        }
 130}
 131
 132/* vq_req_get - reference a VQ Request Object.  Done
 133 * only in the kernel verbs handlers.
 134 */
 135void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
 136{
 137        atomic_inc(&r->refcnt);
 138}
 139
 140
 141/* vq_req_put - dereference and potentially free a VQ Request Object.
 142 *
 143 * This is only called by handle_vq() on the
 144 * interrupt when it is done processing
 145 * a verb reply message.  If the associated
 146 * kernel verbs handler has already bailed,
 147 * then this put will actually free the VQ
 148 * Request object _and_ the VQ Reply Buffer
 149 * if it exists.
 150 */
 151void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
 152{
 153        if (atomic_dec_and_test(&r->refcnt)) {
 154                if (r->reply_msg != 0)
 155                        vq_repbuf_free(c2dev,
 156                                       (void *) (unsigned long) r->reply_msg);
 157                kfree(r);
 158        }
 159}
 160
 161
 162/*
 163 * vq_repbuf_alloc - allocate a VQ Reply Buffer.
 164 */
 165void *vq_repbuf_alloc(struct c2_dev *c2dev)
 166{
 167        return kmem_cache_alloc(c2dev->host_msg_cache, GFP_ATOMIC);
 168}
 169
 170/*
 171 * vq_send_wr - post a verbs request message to the Verbs Request Queue.
 172 * If a message is not available in the MQ, then block until one is available.
 173 * NOTE: handle_mq() on the interrupt context will wake up threads blocked here.
 174 * When the adapter drains the Verbs Request Queue,
 175 * it inserts MQ index 0 in to the
 176 * adapter->host activity fifo and interrupts the host.
 177 */
 178int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)
 179{
 180        void *msg;
 181        wait_queue_t __wait;
 182
 183        /*
 184         * grab adapter vq lock
 185         */
 186        spin_lock(&c2dev->vqlock);
 187
 188        /*
 189         * allocate msg
 190         */
 191        msg = c2_mq_alloc(&c2dev->req_vq);
 192
 193        /*
 194         * If we cannot get a msg, then we'll wait
 195         * When a messages are available, the int handler will wake_up()
 196         * any waiters.
 197         */
 198        while (msg == NULL) {
 199                pr_debug("%s:%d no available msg in VQ, waiting...\n",
 200                       __func__, __LINE__);
 201                init_waitqueue_entry(&__wait, current);
 202                add_wait_queue(&c2dev->req_vq_wo, &__wait);
 203                spin_unlock(&c2dev->vqlock);
 204                for (;;) {
 205                        set_current_state(TASK_INTERRUPTIBLE);
 206                        if (!c2_mq_full(&c2dev->req_vq)) {
 207                                break;
 208                        }
 209                        if (!signal_pending(current)) {
 210                                schedule_timeout(1 * HZ);       /* 1 second... */
 211                                continue;
 212                        }
 213                        set_current_state(TASK_RUNNING);
 214                        remove_wait_queue(&c2dev->req_vq_wo, &__wait);
 215                        return -EINTR;
 216                }
 217                set_current_state(TASK_RUNNING);
 218                remove_wait_queue(&c2dev->req_vq_wo, &__wait);
 219                spin_lock(&c2dev->vqlock);
 220                msg = c2_mq_alloc(&c2dev->req_vq);
 221        }
 222
 223        /*
 224         * copy wr into adapter msg
 225         */
 226        memcpy(msg, wr, c2dev->req_vq.msg_size);
 227
 228        /*
 229         * post msg
 230         */
 231        c2_mq_produce(&c2dev->req_vq);
 232
 233        /*
 234         * release adapter vq lock
 235         */
 236        spin_unlock(&c2dev->vqlock);
 237        return 0;
 238}
 239
 240
 241/*
 242 * vq_wait_for_reply - block until the adapter posts a Verb Reply Message.
 243 */
 244int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)
 245{
 246        if (!wait_event_timeout(req->wait_object,
 247                                atomic_read(&req->reply_ready),
 248                                60*HZ))
 249                return -ETIMEDOUT;
 250
 251        return 0;
 252}
 253
 254/*
 255 * vq_repbuf_free - Free a Verbs Reply Buffer.
 256 */
 257void vq_repbuf_free(struct c2_dev *c2dev, void *reply)
 258{
 259        kmem_cache_free(c2dev->host_msg_cache, reply);
 260}
 261