Path: blob/master/drivers/infiniband/hw/ipath/ipath_cq.c
15112 views
/*1* Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.2* Copyright (c) 2005, 2006 PathScale, 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*/3233#include <linux/err.h>34#include <linux/slab.h>35#include <linux/vmalloc.h>3637#include "ipath_verbs.h"3839/**40* ipath_cq_enter - add a new entry to the completion queue41* @cq: completion queue42* @entry: work completion entry to add43* @sig: true if @entry is a solicitated entry44*45* This may be called with qp->s_lock held.46*/47void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)48{49struct ipath_cq_wc *wc;50unsigned long flags;51u32 head;52u32 next;5354spin_lock_irqsave(&cq->lock, flags);5556/*57* Note that the head pointer might be writable by user processes.58* Take care to verify it is a sane value.59*/60wc = cq->queue;61head = wc->head;62if (head >= (unsigned) cq->ibcq.cqe) {63head = cq->ibcq.cqe;64next = 0;65} else66next = head + 1;67if (unlikely(next == wc->tail)) {68spin_unlock_irqrestore(&cq->lock, flags);69if (cq->ibcq.event_handler) {70struct ib_event ev;7172ev.device = cq->ibcq.device;73ev.element.cq = &cq->ibcq;74ev.event = IB_EVENT_CQ_ERR;75cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);76}77return;78}79if (cq->ip) {80wc->uqueue[head].wr_id = entry->wr_id;81wc->uqueue[head].status = entry->status;82wc->uqueue[head].opcode = entry->opcode;83wc->uqueue[head].vendor_err = entry->vendor_err;84wc->uqueue[head].byte_len = entry->byte_len;85wc->uqueue[head].ex.imm_data = (__u32 __force) entry->ex.imm_data;86wc->uqueue[head].qp_num = entry->qp->qp_num;87wc->uqueue[head].src_qp = entry->src_qp;88wc->uqueue[head].wc_flags = entry->wc_flags;89wc->uqueue[head].pkey_index = entry->pkey_index;90wc->uqueue[head].slid = entry->slid;91wc->uqueue[head].sl = entry->sl;92wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;93wc->uqueue[head].port_num = entry->port_num;94/* Make sure entry is written before the head index. */95smp_wmb();96} else97wc->kqueue[head] = *entry;98wc->head = next;99100if (cq->notify == IB_CQ_NEXT_COMP ||101(cq->notify == IB_CQ_SOLICITED && solicited)) {102cq->notify = IB_CQ_NONE;103cq->triggered++;104/*105* This will cause send_complete() to be called in106* another thread.107*/108tasklet_hi_schedule(&cq->comptask);109}110111spin_unlock_irqrestore(&cq->lock, flags);112113if (entry->status != IB_WC_SUCCESS)114to_idev(cq->ibcq.device)->n_wqe_errs++;115}116117/**118* ipath_poll_cq - poll for work completion entries119* @ibcq: the completion queue to poll120* @num_entries: the maximum number of entries to return121* @entry: pointer to array where work completions are placed122*123* Returns the number of completion entries polled.124*125* This may be called from interrupt context. Also called by ib_poll_cq()126* in the generic verbs code.127*/128int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)129{130struct ipath_cq *cq = to_icq(ibcq);131struct ipath_cq_wc *wc;132unsigned long flags;133int npolled;134u32 tail;135136/* The kernel can only poll a kernel completion queue */137if (cq->ip) {138npolled = -EINVAL;139goto bail;140}141142spin_lock_irqsave(&cq->lock, flags);143144wc = cq->queue;145tail = wc->tail;146if (tail > (u32) cq->ibcq.cqe)147tail = (u32) cq->ibcq.cqe;148for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {149if (tail == wc->head)150break;151/* The kernel doesn't need a RMB since it has the lock. */152*entry = wc->kqueue[tail];153if (tail >= cq->ibcq.cqe)154tail = 0;155else156tail++;157}158wc->tail = tail;159160spin_unlock_irqrestore(&cq->lock, flags);161162bail:163return npolled;164}165166static void send_complete(unsigned long data)167{168struct ipath_cq *cq = (struct ipath_cq *)data;169170/*171* The completion handler will most likely rearm the notification172* and poll for all pending entries. If a new completion entry173* is added while we are in this routine, tasklet_hi_schedule()174* won't call us again until we return so we check triggered to175* see if we need to call the handler again.176*/177for (;;) {178u8 triggered = cq->triggered;179180cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);181182if (cq->triggered == triggered)183return;184}185}186187/**188* ipath_create_cq - create a completion queue189* @ibdev: the device this completion queue is attached to190* @entries: the minimum size of the completion queue191* @context: unused by the InfiniPath driver192* @udata: unused by the InfiniPath driver193*194* Returns a pointer to the completion queue or negative errno values195* for failure.196*197* Called by ib_create_cq() in the generic verbs code.198*/199struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,200struct ib_ucontext *context,201struct ib_udata *udata)202{203struct ipath_ibdev *dev = to_idev(ibdev);204struct ipath_cq *cq;205struct ipath_cq_wc *wc;206struct ib_cq *ret;207u32 sz;208209if (entries < 1 || entries > ib_ipath_max_cqes) {210ret = ERR_PTR(-EINVAL);211goto done;212}213214/* Allocate the completion queue structure. */215cq = kmalloc(sizeof(*cq), GFP_KERNEL);216if (!cq) {217ret = ERR_PTR(-ENOMEM);218goto done;219}220221/*222* Allocate the completion queue entries and head/tail pointers.223* This is allocated separately so that it can be resized and224* also mapped into user space.225* We need to use vmalloc() in order to support mmap and large226* numbers of entries.227*/228sz = sizeof(*wc);229if (udata && udata->outlen >= sizeof(__u64))230sz += sizeof(struct ib_uverbs_wc) * (entries + 1);231else232sz += sizeof(struct ib_wc) * (entries + 1);233wc = vmalloc_user(sz);234if (!wc) {235ret = ERR_PTR(-ENOMEM);236goto bail_cq;237}238239/*240* Return the address of the WC as the offset to mmap.241* See ipath_mmap() for details.242*/243if (udata && udata->outlen >= sizeof(__u64)) {244int err;245246cq->ip = ipath_create_mmap_info(dev, sz, context, wc);247if (!cq->ip) {248ret = ERR_PTR(-ENOMEM);249goto bail_wc;250}251252err = ib_copy_to_udata(udata, &cq->ip->offset,253sizeof(cq->ip->offset));254if (err) {255ret = ERR_PTR(err);256goto bail_ip;257}258} else259cq->ip = NULL;260261spin_lock(&dev->n_cqs_lock);262if (dev->n_cqs_allocated == ib_ipath_max_cqs) {263spin_unlock(&dev->n_cqs_lock);264ret = ERR_PTR(-ENOMEM);265goto bail_ip;266}267268dev->n_cqs_allocated++;269spin_unlock(&dev->n_cqs_lock);270271if (cq->ip) {272spin_lock_irq(&dev->pending_lock);273list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);274spin_unlock_irq(&dev->pending_lock);275}276277/*278* ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.279* The number of entries should be >= the number requested or return280* an error.281*/282cq->ibcq.cqe = entries;283cq->notify = IB_CQ_NONE;284cq->triggered = 0;285spin_lock_init(&cq->lock);286tasklet_init(&cq->comptask, send_complete, (unsigned long)cq);287wc->head = 0;288wc->tail = 0;289cq->queue = wc;290291ret = &cq->ibcq;292293goto done;294295bail_ip:296kfree(cq->ip);297bail_wc:298vfree(wc);299bail_cq:300kfree(cq);301done:302return ret;303}304305/**306* ipath_destroy_cq - destroy a completion queue307* @ibcq: the completion queue to destroy.308*309* Returns 0 for success.310*311* Called by ib_destroy_cq() in the generic verbs code.312*/313int ipath_destroy_cq(struct ib_cq *ibcq)314{315struct ipath_ibdev *dev = to_idev(ibcq->device);316struct ipath_cq *cq = to_icq(ibcq);317318tasklet_kill(&cq->comptask);319spin_lock(&dev->n_cqs_lock);320dev->n_cqs_allocated--;321spin_unlock(&dev->n_cqs_lock);322if (cq->ip)323kref_put(&cq->ip->ref, ipath_release_mmap_info);324else325vfree(cq->queue);326kfree(cq);327328return 0;329}330331/**332* ipath_req_notify_cq - change the notification type for a completion queue333* @ibcq: the completion queue334* @notify_flags: the type of notification to request335*336* Returns 0 for success.337*338* This may be called from interrupt context. Also called by339* ib_req_notify_cq() in the generic verbs code.340*/341int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)342{343struct ipath_cq *cq = to_icq(ibcq);344unsigned long flags;345int ret = 0;346347spin_lock_irqsave(&cq->lock, flags);348/*349* Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow350* any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).351*/352if (cq->notify != IB_CQ_NEXT_COMP)353cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;354355if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&356cq->queue->head != cq->queue->tail)357ret = 1;358359spin_unlock_irqrestore(&cq->lock, flags);360361return ret;362}363364/**365* ipath_resize_cq - change the size of the CQ366* @ibcq: the completion queue367*368* Returns 0 for success.369*/370int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)371{372struct ipath_cq *cq = to_icq(ibcq);373struct ipath_cq_wc *old_wc;374struct ipath_cq_wc *wc;375u32 head, tail, n;376int ret;377u32 sz;378379if (cqe < 1 || cqe > ib_ipath_max_cqes) {380ret = -EINVAL;381goto bail;382}383384/*385* Need to use vmalloc() if we want to support large #s of entries.386*/387sz = sizeof(*wc);388if (udata && udata->outlen >= sizeof(__u64))389sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);390else391sz += sizeof(struct ib_wc) * (cqe + 1);392wc = vmalloc_user(sz);393if (!wc) {394ret = -ENOMEM;395goto bail;396}397398/* Check that we can write the offset to mmap. */399if (udata && udata->outlen >= sizeof(__u64)) {400__u64 offset = 0;401402ret = ib_copy_to_udata(udata, &offset, sizeof(offset));403if (ret)404goto bail_free;405}406407spin_lock_irq(&cq->lock);408/*409* Make sure head and tail are sane since they410* might be user writable.411*/412old_wc = cq->queue;413head = old_wc->head;414if (head > (u32) cq->ibcq.cqe)415head = (u32) cq->ibcq.cqe;416tail = old_wc->tail;417if (tail > (u32) cq->ibcq.cqe)418tail = (u32) cq->ibcq.cqe;419if (head < tail)420n = cq->ibcq.cqe + 1 + head - tail;421else422n = head - tail;423if (unlikely((u32)cqe < n)) {424ret = -EINVAL;425goto bail_unlock;426}427for (n = 0; tail != head; n++) {428if (cq->ip)429wc->uqueue[n] = old_wc->uqueue[tail];430else431wc->kqueue[n] = old_wc->kqueue[tail];432if (tail == (u32) cq->ibcq.cqe)433tail = 0;434else435tail++;436}437cq->ibcq.cqe = cqe;438wc->head = n;439wc->tail = 0;440cq->queue = wc;441spin_unlock_irq(&cq->lock);442443vfree(old_wc);444445if (cq->ip) {446struct ipath_ibdev *dev = to_idev(ibcq->device);447struct ipath_mmap_info *ip = cq->ip;448449ipath_update_mmap_info(dev, ip, sz, wc);450451/*452* Return the offset to mmap.453* See ipath_mmap() for details.454*/455if (udata && udata->outlen >= sizeof(__u64)) {456ret = ib_copy_to_udata(udata, &ip->offset,457sizeof(ip->offset));458if (ret)459goto bail;460}461462spin_lock_irq(&dev->pending_lock);463if (list_empty(&ip->pending_mmaps))464list_add(&ip->pending_mmaps, &dev->pending_mmaps);465spin_unlock_irq(&dev->pending_lock);466}467468ret = 0;469goto bail;470471bail_unlock:472spin_unlock_irq(&cq->lock);473bail_free:474vfree(wc);475bail:476return ret;477}478479480