1/* 2 * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. 3 * Copyright (c) 2005, 2006 PathScale, 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 34#include <asm/io.h> 35 36#include "ipath_verbs.h" 37#include "ipath_kernel.h" 38 39/** 40 * ipath_alloc_lkey - allocate an lkey 41 * @rkt: lkey table in which to allocate the lkey 42 * @mr: memory region that this lkey protects 43 * 44 * Returns 1 if successful, otherwise returns 0. 45 */ 46 47int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr) 48{ 49 unsigned long flags; 50 u32 r; 51 u32 n; 52 int ret; 53 54 spin_lock_irqsave(&rkt->lock, flags); 55 56 /* Find the next available LKEY */ 57 r = n = rkt->next; 58 for (;;) { 59 if (rkt->table[r] == NULL) 60 break; 61 r = (r + 1) & (rkt->max - 1); 62 if (r == n) { 63 spin_unlock_irqrestore(&rkt->lock, flags); 64 ipath_dbg("LKEY table full\n"); 65 ret = 0; 66 goto bail; 67 } 68 } 69 rkt->next = (r + 1) & (rkt->max - 1); 70 /* 71 * Make sure lkey is never zero which is reserved to indicate an 72 * unrestricted LKEY. 73 */ 74 rkt->gen++; 75 mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) | 76 ((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen) 77 << 8); 78 if (mr->lkey == 0) { 79 mr->lkey |= 1 << 8; 80 rkt->gen++; 81 } 82 rkt->table[r] = mr; 83 spin_unlock_irqrestore(&rkt->lock, flags); 84 85 ret = 1; 86 87bail: 88 return ret; 89} 90 91/** 92 * ipath_free_lkey - free an lkey 93 * @rkt: table from which to free the lkey 94 * @lkey: lkey id to free 95 */ 96void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey) 97{ 98 unsigned long flags; 99 u32 r; 100 101 if (lkey == 0) 102 return; 103 r = lkey >> (32 - ib_ipath_lkey_table_size); 104 spin_lock_irqsave(&rkt->lock, flags); 105 rkt->table[r] = NULL; 106 spin_unlock_irqrestore(&rkt->lock, flags); 107} 108 109/** 110 * ipath_lkey_ok - check IB SGE for validity and initialize 111 * @rkt: table containing lkey to check SGE against 112 * @isge: outgoing internal SGE 113 * @sge: SGE to check 114 * @acc: access flags 115 * 116 * Return 1 if valid and successful, otherwise returns 0. 117 * 118 * Check the IB SGE for validity and initialize our internal version 119 * of it. 120 */ 121int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, 122 struct ib_sge *sge, int acc) 123{ 124 struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table; 125 struct ipath_mregion *mr; 126 unsigned n, m; 127 size_t off; 128 int ret; 129 130 /* 131 * We use LKEY == zero for kernel virtual addresses 132 * (see ipath_get_dma_mr and ipath_dma.c). 133 */ 134 if (sge->lkey == 0) { 135 /* always a kernel port, no locking needed */ 136 struct ipath_pd *pd = to_ipd(qp->ibqp.pd); 137 138 if (pd->user) { 139 ret = 0; 140 goto bail; 141 } 142 isge->mr = NULL; 143 isge->vaddr = (void *) sge->addr; 144 isge->length = sge->length; 145 isge->sge_length = sge->length; 146 ret = 1; 147 goto bail; 148 } 149 mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))]; 150 if (unlikely(mr == NULL || mr->lkey != sge->lkey || 151 qp->ibqp.pd != mr->pd)) { 152 ret = 0; 153 goto bail; 154 } 155 156 off = sge->addr - mr->user_base; 157 if (unlikely(sge->addr < mr->user_base || 158 off + sge->length > mr->length || 159 (mr->access_flags & acc) != acc)) { 160 ret = 0; 161 goto bail; 162 } 163 164 off += mr->offset; 165 m = 0; 166 n = 0; 167 while (off >= mr->map[m]->segs[n].length) { 168 off -= mr->map[m]->segs[n].length; 169 n++; 170 if (n >= IPATH_SEGSZ) { 171 m++; 172 n = 0; 173 } 174 } 175 isge->mr = mr; 176 isge->vaddr = mr->map[m]->segs[n].vaddr + off; 177 isge->length = mr->map[m]->segs[n].length - off; 178 isge->sge_length = sge->length; 179 isge->m = m; 180 isge->n = n; 181 182 ret = 1; 183 184bail: 185 return ret; 186} 187 188/** 189 * ipath_rkey_ok - check the IB virtual address, length, and RKEY 190 * @dev: infiniband device 191 * @ss: SGE state 192 * @len: length of data 193 * @vaddr: virtual address to place data 194 * @rkey: rkey to check 195 * @acc: access flags 196 * 197 * Return 1 if successful, otherwise 0. 198 */ 199int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss, 200 u32 len, u64 vaddr, u32 rkey, int acc) 201{ 202 struct ipath_ibdev *dev = to_idev(qp->ibqp.device); 203 struct ipath_lkey_table *rkt = &dev->lk_table; 204 struct ipath_sge *sge = &ss->sge; 205 struct ipath_mregion *mr; 206 unsigned n, m; 207 size_t off; 208 int ret; 209 210 /* 211 * We use RKEY == zero for kernel virtual addresses 212 * (see ipath_get_dma_mr and ipath_dma.c). 213 */ 214 if (rkey == 0) { 215 /* always a kernel port, no locking needed */ 216 struct ipath_pd *pd = to_ipd(qp->ibqp.pd); 217 218 if (pd->user) { 219 ret = 0; 220 goto bail; 221 } 222 sge->mr = NULL; 223 sge->vaddr = (void *) vaddr; 224 sge->length = len; 225 sge->sge_length = len; 226 ss->sg_list = NULL; 227 ss->num_sge = 1; 228 ret = 1; 229 goto bail; 230 } 231 232 mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))]; 233 if (unlikely(mr == NULL || mr->lkey != rkey || 234 qp->ibqp.pd != mr->pd)) { 235 ret = 0; 236 goto bail; 237 } 238 239 off = vaddr - mr->iova; 240 if (unlikely(vaddr < mr->iova || off + len > mr->length || 241 (mr->access_flags & acc) == 0)) { 242 ret = 0; 243 goto bail; 244 } 245 246 off += mr->offset; 247 m = 0; 248 n = 0; 249 while (off >= mr->map[m]->segs[n].length) { 250 off -= mr->map[m]->segs[n].length; 251 n++; 252 if (n >= IPATH_SEGSZ) { 253 m++; 254 n = 0; 255 } 256 } 257 sge->mr = mr; 258 sge->vaddr = mr->map[m]->segs[n].vaddr + off; 259 sge->length = mr->map[m]->segs[n].length - off; 260 sge->sge_length = len; 261 sge->m = m; 262 sge->n = n; 263 ss->sg_list = NULL; 264 ss->num_sge = 1; 265 266 ret = 1; 267 268bail: 269 return ret; 270} 271