Path: blob/master/drivers/infiniband/hw/amso1100/c2_vq.c
15112 views
/*1* Copyright (c) 2005 Ammasso, Inc. All rights reserved.2* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/32#include <linux/slab.h>33#include <linux/spinlock.h>3435#include "c2_vq.h"36#include "c2_provider.h"3738/*39* Verbs Request Objects:40*41* VQ Request Objects are allocated by the kernel verbs handlers.42* They contain a wait object, a refcnt, an atomic bool indicating that the43* adapter has replied, and a copy of the verb reply work request.44* A pointer to the VQ Request Object is passed down in the context45* field of the work request message, and reflected back by the adapter46* in the verbs reply message. The function handle_vq() in the interrupt47* path will use this pointer to:48* 1) append a copy of the verbs reply message49* 2) mark that the reply is ready50* 3) wake up the kernel verbs handler blocked awaiting the reply.51*52*53* The kernel verbs handlers do a "get" to put a 2nd reference on the54* VQ Request object. If the kernel verbs handler exits before the adapter55* can respond, this extra reference will keep the VQ Request object around56* until the adapter's reply can be processed. The reason we need this is57* because a pointer to this object is stuffed into the context field of58* the verbs work request message, and reflected back in the reply message.59* It is used in the interrupt handler (handle_vq()) to wake up the appropriate60* kernel verb handler that is blocked awaiting the verb reply.61* So handle_vq() will do a "put" on the object when it's done accessing it.62* NOTE: If we guarantee that the kernel verb handler will never bail before63* getting the reply, then we don't need these refcnts.64*65*66* VQ Request objects are freed by the kernel verbs handlers only67* after the verb has been processed, or when the adapter fails and68* does not reply.69*70*71* Verbs Reply Buffers:72*73* VQ Reply bufs are local host memory copies of a74* outstanding Verb Request reply75* message. The are always allocated by the kernel verbs handlers, and _may_ be76* freed by either the kernel verbs handler -or- the interrupt handler. The77* kernel verbs handler _must_ free the repbuf, then free the vq request object78* in that order.79*/8081int vq_init(struct c2_dev *c2dev)82{83sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",84(char) ('0' + c2dev->devnum));85c2dev->host_msg_cache =86kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,87SLAB_HWCACHE_ALIGN, NULL);88if (c2dev->host_msg_cache == NULL) {89return -ENOMEM;90}91return 0;92}9394void vq_term(struct c2_dev *c2dev)95{96kmem_cache_destroy(c2dev->host_msg_cache);97}9899/* vq_req_alloc - allocate a VQ Request Object and initialize it.100* The refcnt is set to 1.101*/102struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)103{104struct c2_vq_req *r;105106r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);107if (r) {108init_waitqueue_head(&r->wait_object);109r->reply_msg = 0;110r->event = 0;111r->cm_id = NULL;112r->qp = NULL;113atomic_set(&r->refcnt, 1);114atomic_set(&r->reply_ready, 0);115}116return r;117}118119120/* vq_req_free - free the VQ Request Object. It is assumed the verbs handler121* has already free the VQ Reply Buffer if it existed.122*/123void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)124{125r->reply_msg = 0;126if (atomic_dec_and_test(&r->refcnt)) {127kfree(r);128}129}130131/* vq_req_get - reference a VQ Request Object. Done132* only in the kernel verbs handlers.133*/134void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)135{136atomic_inc(&r->refcnt);137}138139140/* vq_req_put - dereference and potentially free a VQ Request Object.141*142* This is only called by handle_vq() on the143* interrupt when it is done processing144* a verb reply message. If the associated145* kernel verbs handler has already bailed,146* then this put will actually free the VQ147* Request object _and_ the VQ Reply Buffer148* if it exists.149*/150void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)151{152if (atomic_dec_and_test(&r->refcnt)) {153if (r->reply_msg != 0)154vq_repbuf_free(c2dev,155(void *) (unsigned long) r->reply_msg);156kfree(r);157}158}159160161/*162* vq_repbuf_alloc - allocate a VQ Reply Buffer.163*/164void *vq_repbuf_alloc(struct c2_dev *c2dev)165{166return kmem_cache_alloc(c2dev->host_msg_cache, GFP_ATOMIC);167}168169/*170* vq_send_wr - post a verbs request message to the Verbs Request Queue.171* If a message is not available in the MQ, then block until one is available.172* NOTE: handle_mq() on the interrupt context will wake up threads blocked here.173* When the adapter drains the Verbs Request Queue,174* it inserts MQ index 0 in to the175* adapter->host activity fifo and interrupts the host.176*/177int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)178{179void *msg;180wait_queue_t __wait;181182/*183* grab adapter vq lock184*/185spin_lock(&c2dev->vqlock);186187/*188* allocate msg189*/190msg = c2_mq_alloc(&c2dev->req_vq);191192/*193* If we cannot get a msg, then we'll wait194* When a messages are available, the int handler will wake_up()195* any waiters.196*/197while (msg == NULL) {198pr_debug("%s:%d no available msg in VQ, waiting...\n",199__func__, __LINE__);200init_waitqueue_entry(&__wait, current);201add_wait_queue(&c2dev->req_vq_wo, &__wait);202spin_unlock(&c2dev->vqlock);203for (;;) {204set_current_state(TASK_INTERRUPTIBLE);205if (!c2_mq_full(&c2dev->req_vq)) {206break;207}208if (!signal_pending(current)) {209schedule_timeout(1 * HZ); /* 1 second... */210continue;211}212set_current_state(TASK_RUNNING);213remove_wait_queue(&c2dev->req_vq_wo, &__wait);214return -EINTR;215}216set_current_state(TASK_RUNNING);217remove_wait_queue(&c2dev->req_vq_wo, &__wait);218spin_lock(&c2dev->vqlock);219msg = c2_mq_alloc(&c2dev->req_vq);220}221222/*223* copy wr into adapter msg224*/225memcpy(msg, wr, c2dev->req_vq.msg_size);226227/*228* post msg229*/230c2_mq_produce(&c2dev->req_vq);231232/*233* release adapter vq lock234*/235spin_unlock(&c2dev->vqlock);236return 0;237}238239240/*241* vq_wait_for_reply - block until the adapter posts a Verb Reply Message.242*/243int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)244{245if (!wait_event_timeout(req->wait_object,246atomic_read(&req->reply_ready),24760*HZ))248return -ETIMEDOUT;249250return 0;251}252253/*254* vq_repbuf_free - Free a Verbs Reply Buffer.255*/256void vq_repbuf_free(struct c2_dev *c2dev, void *reply)257{258kmem_cache_free(c2dev->host_msg_cache, reply);259}260261262