GNU Linux-libre 4.14.254-gnu1
[releases.git] / drivers / infiniband / hw / qib / qib_keys.c
1 /*
2  * Copyright (c) 2006, 2007, 2009 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 "qib.h"
35
36 /**
37  * qib_alloc_lkey - allocate an lkey
38  * @mr: memory region that this lkey protects
39  * @dma_region: 0->normal key, 1->restricted DMA key
40  *
41  * Returns 0 if successful, otherwise returns -errno.
42  *
43  * Increments mr reference count as required.
44  *
45  * Sets the lkey field mr for non-dma regions.
46  *
47  */
48
49 int qib_alloc_lkey(struct rvt_mregion *mr, int dma_region)
50 {
51         unsigned long flags;
52         u32 r;
53         u32 n;
54         int ret = 0;
55         struct qib_ibdev *dev = to_idev(mr->pd->device);
56         struct rvt_lkey_table *rkt = &dev->lk_table;
57
58         spin_lock_irqsave(&rkt->lock, flags);
59
60         /* special case for dma_mr lkey == 0 */
61         if (dma_region) {
62                 struct rvt_mregion *tmr;
63
64                 tmr = rcu_access_pointer(dev->dma_mr);
65                 if (!tmr) {
66                         qib_get_mr(mr);
67                         rcu_assign_pointer(dev->dma_mr, mr);
68                         mr->lkey_published = 1;
69                 }
70                 goto success;
71         }
72
73         /* Find the next available LKEY */
74         r = rkt->next;
75         n = r;
76         for (;;) {
77                 if (rkt->table[r] == NULL)
78                         break;
79                 r = (r + 1) & (rkt->max - 1);
80                 if (r == n)
81                         goto bail;
82         }
83         rkt->next = (r + 1) & (rkt->max - 1);
84         /*
85          * Make sure lkey is never zero which is reserved to indicate an
86          * unrestricted LKEY.
87          */
88         rkt->gen++;
89         /*
90          * bits are capped in qib_verbs.c to insure enough bits
91          * for generation number
92          */
93         mr->lkey = (r << (32 - ib_rvt_lkey_table_size)) |
94                 ((((1 << (24 - ib_rvt_lkey_table_size)) - 1) & rkt->gen)
95                  << 8);
96         if (mr->lkey == 0) {
97                 mr->lkey |= 1 << 8;
98                 rkt->gen++;
99         }
100         qib_get_mr(mr);
101         rcu_assign_pointer(rkt->table[r], mr);
102         mr->lkey_published = 1;
103 success:
104         spin_unlock_irqrestore(&rkt->lock, flags);
105 out:
106         return ret;
107 bail:
108         spin_unlock_irqrestore(&rkt->lock, flags);
109         ret = -ENOMEM;
110         goto out;
111 }
112
113 /**
114  * qib_free_lkey - free an lkey
115  * @mr: mr to free from tables
116  */
117 void qib_free_lkey(struct rvt_mregion *mr)
118 {
119         unsigned long flags;
120         u32 lkey = mr->lkey;
121         u32 r;
122         struct qib_ibdev *dev = to_idev(mr->pd->device);
123         struct rvt_lkey_table *rkt = &dev->lk_table;
124
125         spin_lock_irqsave(&rkt->lock, flags);
126         if (!mr->lkey_published)
127                 goto out;
128         if (lkey == 0)
129                 RCU_INIT_POINTER(dev->dma_mr, NULL);
130         else {
131                 r = lkey >> (32 - ib_rvt_lkey_table_size);
132                 RCU_INIT_POINTER(rkt->table[r], NULL);
133         }
134         qib_put_mr(mr);
135         mr->lkey_published = 0;
136 out:
137         spin_unlock_irqrestore(&rkt->lock, flags);
138 }
139
140 /**
141  * qib_rkey_ok - check the IB virtual address, length, and RKEY
142  * @qp: qp for validation
143  * @sge: SGE state
144  * @len: length of data
145  * @vaddr: virtual address to place data
146  * @rkey: rkey to check
147  * @acc: access flags
148  *
149  * Return 1 if successful, otherwise 0.
150  *
151  * increments the reference count upon success
152  */
153 int qib_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge,
154                 u32 len, u64 vaddr, u32 rkey, int acc)
155 {
156         struct rvt_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
157         struct rvt_mregion *mr;
158         unsigned n, m;
159         size_t off;
160
161         /* We use RKEY == zero for kernel virtual addresses */
162         rcu_read_lock();
163         if (rkey == 0) {
164                 struct rvt_pd *pd = ibpd_to_rvtpd(qp->ibqp.pd);
165                 struct qib_ibdev *dev = to_idev(pd->ibpd.device);
166
167                 if (pd->user)
168                         goto bail;
169                 mr = rcu_dereference(dev->dma_mr);
170                 if (!mr)
171                         goto bail;
172                 if (unlikely(!atomic_inc_not_zero(&mr->refcount)))
173                         goto bail;
174                 rcu_read_unlock();
175
176                 sge->mr = mr;
177                 sge->vaddr = (void *) vaddr;
178                 sge->length = len;
179                 sge->sge_length = len;
180                 sge->m = 0;
181                 sge->n = 0;
182                 goto ok;
183         }
184
185         mr = rcu_dereference(
186                 rkt->table[(rkey >> (32 - ib_rvt_lkey_table_size))]);
187         if (unlikely(!mr || mr->lkey != rkey || qp->ibqp.pd != mr->pd))
188                 goto bail;
189
190         off = vaddr - mr->iova;
191         if (unlikely(vaddr < mr->iova || off + len > mr->length ||
192                      (mr->access_flags & acc) == 0))
193                 goto bail;
194         if (unlikely(!atomic_inc_not_zero(&mr->refcount)))
195                 goto bail;
196         rcu_read_unlock();
197
198         off += mr->offset;
199         if (mr->page_shift) {
200                 /*
201                 page sizes are uniform power of 2 so no loop is necessary
202                 entries_spanned_by_off is the number of times the loop below
203                 would have executed.
204                 */
205                 size_t entries_spanned_by_off;
206
207                 entries_spanned_by_off = off >> mr->page_shift;
208                 off -= (entries_spanned_by_off << mr->page_shift);
209                 m = entries_spanned_by_off / RVT_SEGSZ;
210                 n = entries_spanned_by_off % RVT_SEGSZ;
211         } else {
212                 m = 0;
213                 n = 0;
214                 while (off >= mr->map[m]->segs[n].length) {
215                         off -= mr->map[m]->segs[n].length;
216                         n++;
217                         if (n >= RVT_SEGSZ) {
218                                 m++;
219                                 n = 0;
220                         }
221                 }
222         }
223         sge->mr = mr;
224         sge->vaddr = mr->map[m]->segs[n].vaddr + off;
225         sge->length = mr->map[m]->segs[n].length - off;
226         sge->sge_length = len;
227         sge->m = m;
228         sge->n = n;
229 ok:
230         return 1;
231 bail:
232         rcu_read_unlock();
233         return 0;
234 }
235