This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_mr.c
1 /*
2  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        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 OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  * $Id: mthca_mr.c 1349 2004-12-16 21:09:43Z roland $
33  */
34
35 #include <linux/slab.h>
36 #include <linux/init.h>
37 #include <linux/errno.h>
38
39 #include "mthca_dev.h"
40 #include "mthca_cmd.h"
41
42 /*
43  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
44  */
45 struct mthca_mpt_entry {
46         u32 flags;
47         u32 page_size;
48         u32 key;
49         u32 pd;
50         u64 start;
51         u64 length;
52         u32 lkey;
53         u32 window_count;
54         u32 window_count_limit;
55         u64 mtt_seg;
56         u32 reserved[3];
57 } __attribute__((packed));
58
59 #define MTHCA_MPT_FLAG_SW_OWNS       (0xfUL << 28)
60 #define MTHCA_MPT_FLAG_MIO           (1 << 17)
61 #define MTHCA_MPT_FLAG_BIND_ENABLE   (1 << 15)
62 #define MTHCA_MPT_FLAG_PHYSICAL      (1 <<  9)
63 #define MTHCA_MPT_FLAG_REGION        (1 <<  8)
64
65 #define MTHCA_MTT_FLAG_PRESENT       1
66
67 /*
68  * Buddy allocator for MTT segments (currently not very efficient
69  * since it doesn't keep a free list and just searches linearly
70  * through the bitmaps)
71  */
72
73 static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order)
74 {
75         int o;
76         int m;
77         u32 seg;
78
79         spin_lock(&dev->mr_table.mpt_alloc.lock);
80
81         for (o = order; o <= dev->mr_table.max_mtt_order; ++o) {
82                 m = 1 << (dev->mr_table.max_mtt_order - o);
83                 seg = find_first_bit(dev->mr_table.mtt_buddy[o], m);
84                 if (seg < m)
85                         goto found;
86         }
87
88         spin_unlock(&dev->mr_table.mpt_alloc.lock);
89         return -1;
90
91  found:
92         clear_bit(seg, dev->mr_table.mtt_buddy[o]);
93
94         while (o > order) {
95                 --o;
96                 seg <<= 1;
97                 set_bit(seg ^ 1, dev->mr_table.mtt_buddy[o]);
98         }
99
100         spin_unlock(&dev->mr_table.mpt_alloc.lock);
101
102         seg <<= order;
103
104         return seg;
105 }
106
107 static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order)
108 {
109         seg >>= order;
110
111         spin_lock(&dev->mr_table.mpt_alloc.lock);
112
113         while (test_bit(seg ^ 1, dev->mr_table.mtt_buddy[order])) {
114                 clear_bit(seg ^ 1, dev->mr_table.mtt_buddy[order]);
115                 seg >>= 1;
116                 ++order;
117         }
118
119         set_bit(seg, dev->mr_table.mtt_buddy[order]);
120
121         spin_unlock(&dev->mr_table.mpt_alloc.lock);
122 }
123
124 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
125                            u32 access, struct mthca_mr *mr)
126 {
127         void *mailbox;
128         struct mthca_mpt_entry *mpt_entry;
129         int err;
130         u8 status;
131
132         might_sleep();
133
134         mr->order = -1;
135         mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);
136         if (mr->ibmr.lkey == -1)
137                 return -ENOMEM;
138         mr->ibmr.rkey = mr->ibmr.lkey;
139
140         mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
141                           GFP_KERNEL);
142         if (!mailbox) {
143                 mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
144                 return -ENOMEM;
145         }
146         mpt_entry = MAILBOX_ALIGN(mailbox);
147
148         mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
149                                        MTHCA_MPT_FLAG_MIO         |
150                                        MTHCA_MPT_FLAG_PHYSICAL    |
151                                        MTHCA_MPT_FLAG_REGION      |
152                                        access);
153         mpt_entry->page_size = 0;
154         mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);
155         mpt_entry->pd        = cpu_to_be32(pd);
156         mpt_entry->start     = 0;
157         mpt_entry->length    = ~0ULL;
158
159         memset(&mpt_entry->lkey, 0,
160                sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
161
162         err = mthca_SW2HW_MPT(dev, mpt_entry,
163                               mr->ibmr.lkey & (dev->limits.num_mpts - 1),
164                               &status);
165         if (err)
166                 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
167         else if (status) {
168                 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
169                            status);
170                 err = -EINVAL;
171         }
172
173         kfree(mailbox);
174         return err;
175 }
176
177 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
178                         u64 *buffer_list, int buffer_size_shift,
179                         int list_len, u64 iova, u64 total_size,
180                         u32 access, struct mthca_mr *mr)
181 {
182         void *mailbox;
183         u64 *mtt_entry;
184         struct mthca_mpt_entry *mpt_entry;
185         int err = -ENOMEM;
186         u8 status;
187         int i;
188
189         might_sleep();
190         WARN_ON(buffer_size_shift >= 32);
191
192         mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);
193         if (mr->ibmr.lkey == -1)
194                 return -ENOMEM;
195         mr->ibmr.rkey = mr->ibmr.lkey;
196
197         for (i = dev->limits.mtt_seg_size / 8, mr->order = 0;
198              i < list_len;
199              i <<= 1, ++mr->order)
200                 ; /* nothing */
201
202         mr->first_seg = mthca_alloc_mtt(dev, mr->order);
203         if (mr->first_seg == -1)
204                 goto err_out_mpt_free;
205
206         /*
207          * If list_len is odd, we add one more dummy entry for
208          * firmware efficiency.
209          */
210         mailbox = kmalloc(max(sizeof *mpt_entry,
211                               (size_t) 8 * (list_len + (list_len & 1) + 2)) +
212                           MTHCA_CMD_MAILBOX_EXTRA,
213                           GFP_KERNEL);
214         if (!mailbox)
215                 goto err_out_free_mtt;
216
217         mtt_entry = MAILBOX_ALIGN(mailbox);
218
219         mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
220                                    mr->first_seg * dev->limits.mtt_seg_size);
221         mtt_entry[1] = 0;
222         for (i = 0; i < list_len; ++i)
223                 mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
224                                                MTHCA_MTT_FLAG_PRESENT);
225         if (list_len & 1) {
226                 mtt_entry[i + 2] = 0;
227                 ++list_len;
228         }
229
230         if (0) {
231                 mthca_dbg(dev, "Dumping MPT entry\n");
232                 for (i = 0; i < list_len + 2; ++i)
233                         printk(KERN_ERR "[%2d] %016llx\n",
234                                i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
235         }
236
237         err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
238         if (err) {
239                 mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
240                 goto err_out_mailbox_free;
241         }
242         if (status) {
243                 mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
244                            status);
245                 err = -EINVAL;
246                 goto err_out_mailbox_free;
247         }
248
249         mpt_entry = MAILBOX_ALIGN(mailbox);
250
251         mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
252                                        MTHCA_MPT_FLAG_MIO         |
253                                        MTHCA_MPT_FLAG_REGION      |
254                                        access);
255
256         mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
257         mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);
258         mpt_entry->pd        = cpu_to_be32(pd);
259         mpt_entry->start     = cpu_to_be64(iova);
260         mpt_entry->length    = cpu_to_be64(total_size);
261         memset(&mpt_entry->lkey, 0,
262                sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
263         mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
264                                            mr->first_seg * dev->limits.mtt_seg_size);
265
266         if (0) {
267                 mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
268                 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) {
269                         if (i % 4 == 0)
270                                 printk("[%02x] ", i * 4);
271                         printk(" %08x", be32_to_cpu(((u32 *) mpt_entry)[i]));
272                         if ((i + 1) % 4 == 0)
273                                 printk("\n");
274                 }
275         }
276
277         err = mthca_SW2HW_MPT(dev, mpt_entry,
278                               mr->ibmr.lkey & (dev->limits.num_mpts - 1),
279                               &status);
280         if (err)
281                 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
282         else if (status) {
283                 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
284                            status);
285                 err = -EINVAL;
286         }
287
288         kfree(mailbox);
289         return err;
290
291  err_out_mailbox_free:
292         kfree(mailbox);
293
294  err_out_free_mtt:
295         mthca_free_mtt(dev, mr->first_seg, mr->order);
296
297  err_out_mpt_free:
298         mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
299         return err;
300 }
301
302 void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
303 {
304         int err;
305         u8 status;
306
307         might_sleep();
308
309         err = mthca_HW2SW_MPT(dev, NULL,
310                               mr->ibmr.lkey & (dev->limits.num_mpts - 1),
311                               &status);
312         if (err)
313                 mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err);
314         else if (status)
315                 mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
316                            status);
317
318         if (mr->order >= 0)
319                 mthca_free_mtt(dev, mr->first_seg, mr->order);
320
321         mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
322 }
323
324 int __devinit mthca_init_mr_table(struct mthca_dev *dev)
325 {
326         int err;
327         int i, s;
328
329         err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
330                                dev->limits.num_mpts,
331                                ~0, dev->limits.reserved_mrws);
332         if (err)
333                 return err;
334
335         err = -ENOMEM;
336
337         for (i = 1, dev->mr_table.max_mtt_order = 0;
338              i < dev->limits.num_mtt_segs;
339              i <<= 1, ++dev->mr_table.max_mtt_order)
340                 ; /* nothing */
341
342         dev->mr_table.mtt_buddy = kmalloc((dev->mr_table.max_mtt_order + 1) *
343                                           sizeof (long *),
344                                           GFP_KERNEL);
345         if (!dev->mr_table.mtt_buddy)
346                 goto err_out;
347
348         for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
349                 dev->mr_table.mtt_buddy[i] = NULL;
350
351         for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) {
352                 s = BITS_TO_LONGS(1 << (dev->mr_table.max_mtt_order - i));
353                 dev->mr_table.mtt_buddy[i] = kmalloc(s * sizeof (long),
354                                                      GFP_KERNEL);
355                 if (!dev->mr_table.mtt_buddy[i])
356                         goto err_out_free;
357                 bitmap_zero(dev->mr_table.mtt_buddy[i],
358                             1 << (dev->mr_table.max_mtt_order - i));
359         }
360
361         set_bit(0, dev->mr_table.mtt_buddy[dev->mr_table.max_mtt_order]);
362
363         for (i = 0; i < dev->mr_table.max_mtt_order; ++i)
364                 if (1 << i >= dev->limits.reserved_mtts)
365                         break;
366
367         if (i == dev->mr_table.max_mtt_order) {
368                 mthca_err(dev, "MTT table of order %d is "
369                           "too small.\n", i);
370                 goto err_out_free;
371         }
372
373         (void) mthca_alloc_mtt(dev, i);
374
375         return 0;
376
377  err_out_free:
378         for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
379                 kfree(dev->mr_table.mtt_buddy[i]);
380
381  err_out:
382         mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
383
384         return err;
385 }
386
387 void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev)
388 {
389         int i;
390
391         /* XXX check if any MRs are still allocated? */
392         for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)
393                 kfree(dev->mr_table.mtt_buddy[i]);
394         kfree(dev->mr_table.mtt_buddy);
395         mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
396 }