Path: blob/master/drivers/infiniband/hw/ipath/ipath_keys.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 <asm/io.h>3435#include "ipath_verbs.h"36#include "ipath_kernel.h"3738/**39* ipath_alloc_lkey - allocate an lkey40* @rkt: lkey table in which to allocate the lkey41* @mr: memory region that this lkey protects42*43* Returns 1 if successful, otherwise returns 0.44*/4546int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr)47{48unsigned long flags;49u32 r;50u32 n;51int ret;5253spin_lock_irqsave(&rkt->lock, flags);5455/* Find the next available LKEY */56r = n = rkt->next;57for (;;) {58if (rkt->table[r] == NULL)59break;60r = (r + 1) & (rkt->max - 1);61if (r == n) {62spin_unlock_irqrestore(&rkt->lock, flags);63ipath_dbg("LKEY table full\n");64ret = 0;65goto bail;66}67}68rkt->next = (r + 1) & (rkt->max - 1);69/*70* Make sure lkey is never zero which is reserved to indicate an71* unrestricted LKEY.72*/73rkt->gen++;74mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) |75((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen)76<< 8);77if (mr->lkey == 0) {78mr->lkey |= 1 << 8;79rkt->gen++;80}81rkt->table[r] = mr;82spin_unlock_irqrestore(&rkt->lock, flags);8384ret = 1;8586bail:87return ret;88}8990/**91* ipath_free_lkey - free an lkey92* @rkt: table from which to free the lkey93* @lkey: lkey id to free94*/95void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey)96{97unsigned long flags;98u32 r;99100if (lkey == 0)101return;102r = lkey >> (32 - ib_ipath_lkey_table_size);103spin_lock_irqsave(&rkt->lock, flags);104rkt->table[r] = NULL;105spin_unlock_irqrestore(&rkt->lock, flags);106}107108/**109* ipath_lkey_ok - check IB SGE for validity and initialize110* @rkt: table containing lkey to check SGE against111* @isge: outgoing internal SGE112* @sge: SGE to check113* @acc: access flags114*115* Return 1 if valid and successful, otherwise returns 0.116*117* Check the IB SGE for validity and initialize our internal version118* of it.119*/120int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,121struct ib_sge *sge, int acc)122{123struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;124struct ipath_mregion *mr;125unsigned n, m;126size_t off;127int ret;128129/*130* We use LKEY == zero for kernel virtual addresses131* (see ipath_get_dma_mr and ipath_dma.c).132*/133if (sge->lkey == 0) {134/* always a kernel port, no locking needed */135struct ipath_pd *pd = to_ipd(qp->ibqp.pd);136137if (pd->user) {138ret = 0;139goto bail;140}141isge->mr = NULL;142isge->vaddr = (void *) sge->addr;143isge->length = sge->length;144isge->sge_length = sge->length;145ret = 1;146goto bail;147}148mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];149if (unlikely(mr == NULL || mr->lkey != sge->lkey ||150qp->ibqp.pd != mr->pd)) {151ret = 0;152goto bail;153}154155off = sge->addr - mr->user_base;156if (unlikely(sge->addr < mr->user_base ||157off + sge->length > mr->length ||158(mr->access_flags & acc) != acc)) {159ret = 0;160goto bail;161}162163off += mr->offset;164m = 0;165n = 0;166while (off >= mr->map[m]->segs[n].length) {167off -= mr->map[m]->segs[n].length;168n++;169if (n >= IPATH_SEGSZ) {170m++;171n = 0;172}173}174isge->mr = mr;175isge->vaddr = mr->map[m]->segs[n].vaddr + off;176isge->length = mr->map[m]->segs[n].length - off;177isge->sge_length = sge->length;178isge->m = m;179isge->n = n;180181ret = 1;182183bail:184return ret;185}186187/**188* ipath_rkey_ok - check the IB virtual address, length, and RKEY189* @dev: infiniband device190* @ss: SGE state191* @len: length of data192* @vaddr: virtual address to place data193* @rkey: rkey to check194* @acc: access flags195*196* Return 1 if successful, otherwise 0.197*/198int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,199u32 len, u64 vaddr, u32 rkey, int acc)200{201struct ipath_ibdev *dev = to_idev(qp->ibqp.device);202struct ipath_lkey_table *rkt = &dev->lk_table;203struct ipath_sge *sge = &ss->sge;204struct ipath_mregion *mr;205unsigned n, m;206size_t off;207int ret;208209/*210* We use RKEY == zero for kernel virtual addresses211* (see ipath_get_dma_mr and ipath_dma.c).212*/213if (rkey == 0) {214/* always a kernel port, no locking needed */215struct ipath_pd *pd = to_ipd(qp->ibqp.pd);216217if (pd->user) {218ret = 0;219goto bail;220}221sge->mr = NULL;222sge->vaddr = (void *) vaddr;223sge->length = len;224sge->sge_length = len;225ss->sg_list = NULL;226ss->num_sge = 1;227ret = 1;228goto bail;229}230231mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];232if (unlikely(mr == NULL || mr->lkey != rkey ||233qp->ibqp.pd != mr->pd)) {234ret = 0;235goto bail;236}237238off = vaddr - mr->iova;239if (unlikely(vaddr < mr->iova || off + len > mr->length ||240(mr->access_flags & acc) == 0)) {241ret = 0;242goto bail;243}244245off += mr->offset;246m = 0;247n = 0;248while (off >= mr->map[m]->segs[n].length) {249off -= mr->map[m]->segs[n].length;250n++;251if (n >= IPATH_SEGSZ) {252m++;253n = 0;254}255}256sge->mr = mr;257sge->vaddr = mr->map[m]->segs[n].vaddr + off;258sge->length = mr->map[m]->segs[n].length - off;259sge->sge_length = len;260sge->m = m;261sge->n = n;262ss->sg_list = NULL;263ss->num_sge = 1;264265ret = 1;266267bail:268return ret;269}270271272