[MTHCA, IBAL] added FMR support; [MTHCA] 1. fixed (and now works) "livefish" support;
[mirror/winof/.git] / hw / mthca / kernel / mthca_mr.c
1 /*
2  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2005 Mellanox Technologies. 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  * $Id: mthca_mr.c 2905 2005-07-25 18:26:52Z roland $
34  */
35
36 #include "mthca_dev.h"
37 #if defined(EVENT_TRACING)
38 #ifdef offsetof
39 #undef offsetof
40 #endif
41 #include "mthca_mr.tmh"
42 #endif
43 #include "mthca_cmd.h"
44 #include "mthca_memfree.h"
45
46 static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order);
47 static void mthca_buddy_cleanup(struct mthca_buddy *buddy);
48
49 #ifdef ALLOC_PRAGMA
50 #pragma alloc_text (PAGE, mthca_buddy_init)
51 #pragma alloc_text (PAGE, mthca_buddy_cleanup)
52 #pragma alloc_text (PAGE, mthca_init_mr_table)
53 #pragma alloc_text (PAGE, mthca_cleanup_mr_table)
54 #endif
55
56 struct mthca_mtt {
57         struct mthca_buddy *buddy;
58         int                 order;
59         u32                 first_seg;
60 };
61
62 /*
63  * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
64  */
65 #pragma pack(push,1)
66 struct mthca_mpt_entry {
67         __be32 flags;
68         __be32 page_size;
69         __be32 key;
70         __be32 pd;
71         __be64 start;
72         __be64 length;
73         __be32 lkey;
74         __be32 window_count;
75         __be32 window_count_limit;
76         __be64 mtt_seg;
77         __be32 mtt_sz;          /* Arbel only */
78         u32    reserved[2];
79 } ;
80 #pragma pack(pop)
81
82 #define MTHCA_MPT_FLAG_SW_OWNS       (0xfUL << 28)
83 #define MTHCA_MPT_FLAG_MIO           (1 << 17)
84 #define MTHCA_MPT_FLAG_BIND_ENABLE   (1 << 15)
85 #define MTHCA_MPT_FLAG_PHYSICAL      (1 <<  9)
86 #define MTHCA_MPT_FLAG_REGION        (1 <<  8)
87
88 #define MTHCA_MTT_FLAG_PRESENT       1
89
90 #define MTHCA_MPT_STATUS_SW 0xF0
91 #define MTHCA_MPT_STATUS_HW 0x00
92
93 #define SINAI_FMR_KEY_INC 0x1000000
94
95 static void dump_mtt(u32 print_lvl, __be64 *mtt_entry ,int list_len)
96 {
97         int i;
98         UNREFERENCED_PARAMETER(mtt_entry);              // for release version
99         HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("Dumping MTT entry len %d :\n",list_len));
100         for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; i=i+4) {
101                 HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("[%02x]  %016I64x %016I64x %016I64x %016I64x\n",i,
102                         cl_ntoh64(mtt_entry[i]),
103                         cl_ntoh64(mtt_entry[i+1]),
104                         cl_ntoh64(mtt_entry[i+2]),
105                         cl_ntoh64(mtt_entry[i+3])));
106         }
107 }
108
109
110 static void dump_mpt(u32 print_lvl, struct mthca_mpt_entry *mpt_entry )
111 {
112         int i;
113         UNREFERENCED_PARAMETER(mpt_entry);              // for release version
114         HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("Dumping MPT entry %08x :\n", mpt_entry->key));
115         for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; i=i+4) {
116         HCA_PRINT(print_lvl ,HCA_DBG_MEMORY ,("[%02x]  %08x %08x %08x %08x \n",i,
117                         cl_ntoh32(((__be32 *) mpt_entry)[i]),
118                         cl_ntoh32(((__be32 *) mpt_entry)[i+1]),
119                         cl_ntoh32(((__be32 *) mpt_entry)[i+2]),
120                         cl_ntoh32(((__be32 *) mpt_entry)[i+3])));
121         }
122 }
123
124
125
126
127
128
129
130
131 /*
132  * Buddy allocator for MTT segments (currently not very efficient
133  * since it doesn't keep a free list and just searches linearly
134  * through the bitmaps)
135  */
136
137 static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order)
138 {
139         int o;
140         u32 m;
141         u32 seg;
142         SPIN_LOCK_PREP(lh);
143
144         spin_lock(&buddy->lock, &lh);
145
146         for (o = order; o <= buddy->max_order; ++o) {
147                 m = 1 << (buddy->max_order - o);
148                 seg = find_first_bit(buddy->bits[o], m);
149                 if (seg < m)
150                         goto found;
151         }
152
153         spin_unlock(&lh);
154         return (u32)-1;
155
156  found:
157         clear_bit(seg, (long*)buddy->bits[o]);
158
159         while (o > order) {
160                 --o;
161                 seg <<= 1;
162                 set_bit(seg ^ 1, (long*)buddy->bits[o]);
163         }
164
165         spin_unlock(&lh);
166
167         seg <<= order;
168
169         return seg;
170 }
171
172 static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order)
173 {
174         SPIN_LOCK_PREP(lh);
175
176         seg >>= order;
177
178         spin_lock(&buddy->lock, &lh);
179
180         while (test_bit(seg ^ 1, buddy->bits[order])) {
181                 clear_bit(seg ^ 1, (long*)buddy->bits[order]);
182                 seg >>= 1;
183                 ++order;
184         }
185
186         set_bit(seg, (long*)buddy->bits[order]);
187
188         spin_unlock(&lh);
189 }
190
191 static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order)
192 {
193         int i, s;
194
195         buddy->max_order = max_order;
196         spin_lock_init(&buddy->lock);
197
198         buddy->bits = kmalloc((buddy->max_order + 1) * sizeof (long *),
199                               GFP_KERNEL);
200         if (!buddy->bits)
201                 goto err_out;
202
203         RtlZeroMemory(buddy->bits, (buddy->max_order + 1) * sizeof (long *));
204
205         for (i = 0; i <= buddy->max_order; ++i) {
206                 s = BITS_TO_LONGS(1 << (buddy->max_order - i));
207                 buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
208                 if (!buddy->bits[i])
209                         goto err_out_free;
210                 bitmap_zero(buddy->bits[i],
211                             1 << (buddy->max_order - i));
212         }
213
214         set_bit(0, (long*)buddy->bits[buddy->max_order]);
215
216         return 0;
217
218 err_out_free:
219         for (i = 0; i <= buddy->max_order; ++i)
220                 kfree(buddy->bits[i]);
221
222         kfree(buddy->bits);
223
224 err_out:
225         return -ENOMEM;
226 }
227
228 static void mthca_buddy_cleanup(struct mthca_buddy *buddy)
229 {
230         int i;
231
232         for (i = 0; i <= buddy->max_order; ++i)
233                 kfree(buddy->bits[i]);
234
235         kfree(buddy->bits);
236 }
237
238 static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
239                                  struct mthca_buddy *buddy)
240 {
241         u32 seg = mthca_buddy_alloc(buddy, order);
242
243         if (seg == -1)
244                 return (u32)-1;
245
246         if (mthca_is_memfree(dev))
247                 if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg,
248                                           seg + (1 << order) - 1)) {
249                         mthca_buddy_free(buddy, seg, order);
250                         seg = (u32)-1;
251                 }
252
253         return seg;
254 }
255
256 static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
257                                            struct mthca_buddy *buddy)
258 {
259         struct mthca_mtt *mtt;
260         int i;
261         HCA_ENTER(HCA_DBG_MEMORY);
262         if (size <= 0)
263                 return ERR_PTR(-EINVAL);
264
265         mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
266         if (!mtt)
267                 return ERR_PTR(-ENOMEM);
268
269         mtt->buddy = buddy;
270         mtt->order = 0;
271         for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
272                 ++mtt->order;
273
274         mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
275         if (mtt->first_seg == -1) {
276                 kfree(mtt);
277                 return ERR_PTR(-ENOMEM);
278         }
279         HCA_EXIT(HCA_DBG_MEMORY);
280         return mtt;
281 }
282
283 struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
284 {
285         return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
286 }
287
288 void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
289 {
290         if (!mtt)
291                 return;
292
293         mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
294
295         mthca_table_put_range(dev, dev->mr_table.mtt_table,
296                               mtt->first_seg,
297                               mtt->first_seg + (1 << mtt->order) - 1);
298
299         kfree(mtt);
300 }
301
302 int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
303                     int start_index, u64 *buffer_list, int list_len)
304 {
305         struct mthca_mailbox *mailbox;
306         __be64 *mtt_entry;
307         int err = 0;
308         u8 status;
309         int i;
310         u64 val = 1;
311
312         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
313         if (IS_ERR(mailbox))
314                 return PTR_ERR(mailbox);
315         mtt_entry = mailbox->buf;
316
317         while (list_len > 0) {
318                 val = dev->mr_table.mtt_base +
319                         mtt->first_seg * MTHCA_MTT_SEG_SIZE + start_index * 8;
320                 //TODO: a workaround of bug in _byteswap_uint64
321                 // in release version optimizer puts the above expression into the function call and generates incorrect code
322                 // so we call the macro to work around that
323                 mtt_entry[0] = CL_HTON64(val); 
324                 mtt_entry[1] = 0;
325                 for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i) {
326                         val = buffer_list[i];
327                         // BUG in compiler:  it can't perform OR on u64 !!! We perform OR on the low dword
328                         *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT;
329                         mtt_entry[i + 2] = cl_hton64(val);
330                 }
331
332                 /*
333                  * If we have an odd number of entries to write, add
334                  * one more dummy entry for firmware efficiency.
335                  */
336                 if (i & 1)
337                         mtt_entry[i + 2] = 0;
338                 
339                 dump_mtt(TRACE_LEVEL_VERBOSE, mtt_entry ,i);
340                 
341                 err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
342                 if (err) {
343                         HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("WRITE_MTT failed (%d)\n", err));
344                         goto out;
345                 }
346                 if (status) {
347                         HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("WRITE_MTT returned status 0x%02x\n",
348                                    status));
349                         err = -EINVAL;
350                         goto out;
351                 }
352
353                 list_len    -= i;
354                 start_index += i;
355                 buffer_list += i;
356         }
357
358 out:
359         mthca_free_mailbox(dev, mailbox);
360         return err;
361 }
362
363 static inline u32 tavor_hw_index_to_key(u32 ind)
364 {
365         return ind;
366 }
367
368 static inline u32 tavor_key_to_hw_index(u32 key)
369 {
370         return key;
371 }
372
373 static inline u32 arbel_hw_index_to_key(u32 ind)
374 {
375         return (ind >> 24) | (ind << 8);
376 }
377
378 static inline u32 arbel_key_to_hw_index(u32 key)
379 {
380         return (key << 24) | (key >> 8);
381 }
382
383 static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind)
384 {
385         if (mthca_is_memfree(dev))
386                 return arbel_hw_index_to_key(ind);
387         else
388                 return tavor_hw_index_to_key(ind);
389 }
390
391 static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
392 {
393         if (mthca_is_memfree(dev))
394                 return arbel_key_to_hw_index(key);
395         else
396                 return tavor_key_to_hw_index(key);
397 }
398
399
400 static inline u32 adjust_key(struct mthca_dev *dev, u32 key)
401 {
402         if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
403                 return ((key << 20) & 0x800000) | (key & 0x7fffff);
404         else
405                 return key;
406 }
407
408 int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
409                    u64 iova, u64 total_size, mthca_mpt_access_t access, struct mthca_mr *mr)
410 {
411         struct mthca_mailbox *mailbox;
412         struct mthca_mpt_entry *mpt_entry;
413         u32 key;
414         int err;
415         u8 status;
416         CPU_2_BE64_PREP;
417
418         WARN_ON(buffer_size_shift >= 32);
419
420         key = mthca_alloc(&dev->mr_table.mpt_alloc);
421         if (key == -1)
422                 return -ENOMEM;
423         mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
424
425         if (mthca_is_memfree(dev)) {
426                 err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
427                 if (err)
428                         goto err_out_mpt_free;
429         }
430
431         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
432         if (IS_ERR(mailbox)) {
433                 err = PTR_ERR(mailbox);
434                 goto err_out_table;
435         }
436         mpt_entry = mailbox->buf;
437
438         mpt_entry->flags = cl_hton32(MTHCA_MPT_FLAG_SW_OWNS     |
439                                        MTHCA_MPT_FLAG_MIO         |
440                                        MTHCA_MPT_FLAG_REGION      |
441                                        access);
442         if (!mr->mtt)
443                 mpt_entry->flags |= cl_hton32(MTHCA_MPT_FLAG_PHYSICAL);
444
445         mpt_entry->page_size = cl_hton32(buffer_size_shift - 12);
446         mpt_entry->key       = cl_hton32(key);
447         mpt_entry->pd        = cl_hton32(pd);
448         mpt_entry->start     = cl_hton64(iova);
449         mpt_entry->length    = cl_hton64(total_size);
450
451         RtlZeroMemory(&mpt_entry->lkey, 
452                 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
453
454         if (mr->mtt)
455                 mpt_entry->mtt_seg =
456                         CPU_2_BE64(dev->mr_table.mtt_base +
457                                     mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
458
459         {
460                 dump_mpt(TRACE_LEVEL_VERBOSE, mpt_entry);
461         }
462
463         err = mthca_SW2HW_MPT(dev, mailbox,
464                               key & (dev->limits.num_mpts - 1),
465                               &status);
466         if (err) {
467                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("SW2HW_MPT failed (%d)\n", err));
468                 goto err_out_mailbox;
469         } else if (status) {
470                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("SW2HW_MPT returned status 0x%02x\n",
471                            status));
472                 err = -EINVAL;
473                 goto err_out_mailbox;
474         }
475
476         mthca_free_mailbox(dev, mailbox);
477         return err;
478
479 err_out_mailbox:
480         mthca_free_mailbox(dev, mailbox);
481
482 err_out_table:
483         mthca_table_put(dev, dev->mr_table.mpt_table, key);
484
485 err_out_mpt_free:
486         mthca_free(&dev->mr_table.mpt_alloc, key);
487         return err;
488 }
489
490 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
491                            mthca_mpt_access_t access, struct mthca_mr *mr)
492 {
493         mr->mtt = NULL;
494         return mthca_mr_alloc(dev, pd, 12, 0, ~0Ui64, access, mr);
495 }
496
497 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
498                         u64 *buffer_list, int buffer_size_shift,
499                         int list_len, u64 iova, u64 total_size,
500                         mthca_mpt_access_t access, struct mthca_mr *mr)
501 {
502         int err;
503         HCA_ENTER(HCA_DBG_MEMORY);
504         mr->mtt = mthca_alloc_mtt(dev, list_len);
505         if (IS_ERR(mr->mtt)){
506                 err= PTR_ERR(mr->mtt);
507                 goto out;
508         }
509
510         err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
511         if (err) {
512                 mthca_free_mtt(dev, mr->mtt);
513                 goto out;
514         }
515
516         err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
517                              total_size, access, mr);
518         if (err)
519                 mthca_free_mtt(dev, mr->mtt);
520
521 out:
522         HCA_EXIT(HCA_DBG_MEMORY);
523         return err;
524 }
525
526 /* Free mr or fmr */
527 static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
528 {
529         mthca_table_put(dev, dev->mr_table.mpt_table,   key_to_hw_index(dev, lkey));
530         mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
531 }
532
533 void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
534 {
535         int err;
536         u8 status;
537
538         err = mthca_HW2SW_MPT(dev, NULL,
539                               key_to_hw_index(dev, mr->ibmr.lkey) &
540                               (dev->limits.num_mpts - 1),
541                               &status);
542         if (err){
543                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("HW2SW_MPT failed (%d)\n", err));
544         }else if (status){
545                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("HW2SW_MPT returned status 0x%02x\n",
546                            status));
547         }
548
549         mthca_free_region(dev, mr->ibmr.lkey);
550         mthca_free_mtt(dev, mr->mtt);
551 }
552
553 int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
554                     mthca_mpt_access_t access, struct mthca_fmr *mr)
555 {
556         struct mthca_mpt_entry *mpt_entry;
557         struct mthca_mailbox *mailbox;
558         u64 mtt_seg;
559         u32 key, idx;
560         u8 status;
561         int list_len = mr->attr.max_pages;
562         int err = -ENOMEM;
563         int i;
564         CPU_2_BE64_PREP;
565         
566         if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)
567                 return -EINVAL;
568
569         /* For Arbel, all MTTs must fit in the same page. */
570         if (mthca_is_memfree(dev) &&
571             mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE)
572                 return -EINVAL;
573
574         mr->maps = 0;
575
576         key = mthca_alloc(&dev->mr_table.mpt_alloc);
577         if (key == -1)
578                 return -ENOMEM;
579         key = adjust_key(dev, key);
580
581         idx = key & (dev->limits.num_mpts - 1);
582         mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
583
584         if (mthca_is_memfree(dev)) {
585                 err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
586                 if (err)
587                         goto err_out_mpt_free;
588
589                 mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key);
590                 BUG_ON(!mr->mem.arbel.mpt);
591         } else
592                 mr->mem.tavor.mpt = (struct mthca_mpt_entry*)((u8*)dev->mr_table.tavor_fmr.mpt_base +
593                         sizeof *(mr->mem.tavor.mpt) * idx);
594
595         mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
596         if (IS_ERR(mr->mtt))
597                 goto err_out_table;
598
599         mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
600
601         if (mthca_is_memfree(dev)) {
602                 mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
603                                                       mr->mtt->first_seg);
604                 BUG_ON(!mr->mem.arbel.mtts);
605         } else
606                 mr->mem.tavor.mtts = (u64*)((u8*)dev->mr_table.tavor_fmr.mtt_base + mtt_seg);
607
608         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
609         if (IS_ERR(mailbox))
610                 goto err_out_free_mtt;
611
612         mpt_entry = mailbox->buf;
613
614         mpt_entry->flags = cl_hton32(MTHCA_MPT_FLAG_SW_OWNS     |
615                                        MTHCA_MPT_FLAG_MIO         |
616                                        MTHCA_MPT_FLAG_REGION      |
617                                        access);
618
619         mpt_entry->page_size = cl_hton32(mr->attr.page_shift - 12);
620         mpt_entry->key       = cl_hton32(key);
621         mpt_entry->pd        = cl_hton32(pd);
622         RtlZeroMemory(&mpt_entry->start, 
623                 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start));
624         mpt_entry->mtt_seg   = CPU_2_BE64(dev->mr_table.mtt_base + mtt_seg);
625
626         {
627                 HCA_PRINT(TRACE_LEVEL_INFORMATION  ,HCA_DBG_MEMORY  ,("Dumping MPT entry %08x:\n", mr->ibmr.lkey));
628                 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; i=i+4) {
629                                 HCA_PRINT(TRACE_LEVEL_INFORMATION   ,HCA_DBG_MEMORY   ,("[%02x]  %08x %08x %08x %08x \n",i,
630                                         cl_ntoh32(((__be32 *) mpt_entry)[i]),
631                                         cl_ntoh32(((__be32 *) mpt_entry)[i+1]),
632                                         cl_ntoh32(((__be32 *) mpt_entry)[i+2]),
633                                         cl_ntoh32(((__be32 *) mpt_entry)[i+3])));
634                 }
635         }
636
637         err = mthca_SW2HW_MPT(dev, mailbox,
638                               key & (dev->limits.num_mpts - 1),
639                               &status);
640
641         if (err) {
642                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("SW2HW_MPT failed (%d)\n", err));
643                 goto err_out_mailbox_free;
644         }
645         if (status) {
646                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("SW2HW_MPT returned status 0x%02x\n",
647                            status));
648                 err = -EINVAL;
649                 goto err_out_mailbox_free;
650         }
651
652         mthca_free_mailbox(dev, mailbox);
653         return 0;
654
655 err_out_mailbox_free:
656         mthca_free_mailbox(dev, mailbox);
657
658 err_out_free_mtt:
659         mthca_free_mtt(dev, mr->mtt);
660
661 err_out_table:
662         mthca_table_put(dev, dev->mr_table.mpt_table, key);
663
664 err_out_mpt_free:
665         mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
666         return err;
667 }
668
669
670 int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
671 {
672         if (fmr->maps)
673                 return -EBUSY;
674
675         mthca_free_region(dev, fmr->ibmr.lkey);
676         mthca_free_mtt(dev, fmr->mtt);
677
678         return 0;
679 }
680
681
682 static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list,
683                                   int list_len, u64 iova)
684 {
685         int page_mask;
686         UNREFERENCED_PARAMETER(page_list);
687
688         if (list_len > fmr->attr.max_pages)
689                 return -EINVAL;
690
691         page_mask = (1 << fmr->attr.page_shift) - 1;
692
693         /* We are getting page lists, so va must be page aligned. */
694         if (iova & page_mask)
695                 return -EINVAL;
696
697         /* Trust the user not to pass misaligned data in page_list */
698         #if 0
699                 for (i = 0; i < list_len; ++i) {
700                         if (page_list[i] & ~page_mask)
701                                 return -EINVAL;
702                 }
703         #endif  
704
705         if (fmr->maps >= fmr->attr.max_maps)
706                 return -EINVAL;
707
708         return 0;
709 }
710
711
712 int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
713                              int list_len, u64 iova)
714 {
715         struct mthca_fmr *fmr = to_mfmr(ibfmr);
716         struct mthca_dev *dev = to_mdev(ibfmr->device);
717         struct mthca_mpt_entry mpt_entry;
718         u32 key;
719         int i, err;
720         CPU_2_BE64_PREP;
721
722         err = mthca_check_fmr(fmr, page_list, list_len, iova);
723         if (err)
724                 return err;
725
726         ++fmr->maps;
727
728         key = tavor_key_to_hw_index(fmr->ibmr.lkey);
729         key += dev->limits.num_mpts;
730         fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
731
732         writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
733
734         for (i = 0; i < list_len; ++i) {
735                 __be64 mtt_entry;
736                 u64 val = page_list[i];
737                 // BUG in compiler:  it can't perform OR on u64 !!! We perform OR on the low dword
738                 *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT;
739                 mtt_entry = cl_hton64(val);
740                 mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i);
741         }
742
743         mpt_entry.lkey   = cl_hton32(key);
744         mpt_entry.length = CPU_2_BE64(list_len * (1Ui64 << fmr->attr.page_shift));
745         mpt_entry.start  = cl_hton64(iova);
746
747         __raw_writel((u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
748         memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start,
749                     offsetof(struct mthca_mpt_entry, window_count) -
750                     offsetof(struct mthca_mpt_entry, start));
751
752         writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt);
753
754         return 0;
755 }
756
757 int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
758                              int list_len, u64 iova)
759 {
760         struct mthca_fmr *fmr = to_mfmr(ibfmr);
761         struct mthca_dev *dev = to_mdev(ibfmr->device);
762         u32 key;
763         int i, err;
764         CPU_2_BE64_PREP;
765
766         err = mthca_check_fmr(fmr, page_list, list_len, iova);
767         if (err)
768                 return err;
769
770         ++fmr->maps;
771
772         key = arbel_key_to_hw_index(fmr->ibmr.lkey);
773         if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
774                 key += SINAI_FMR_KEY_INC;
775         else
776                 key += dev->limits.num_mpts;
777         fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
778
779         *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
780
781         wmb();
782
783         for (i = 0; i < list_len; ++i) {
784                 // BUG in compiler:  it can't perform OR on u64 !!! We perform OR on the low dword
785                 u64 val = page_list[i];
786                 *(PULONG)&val |= MTHCA_MTT_FLAG_PRESENT;
787                 fmr->mem.arbel.mtts[i] = cl_hton64(val);
788         }
789
790         fmr->mem.arbel.mpt->key    = cl_hton32(key);
791         fmr->mem.arbel.mpt->lkey   = cl_hton32(key);
792         fmr->mem.arbel.mpt->length = CPU_2_BE64(list_len * (1Ui64 << fmr->attr.page_shift));
793         fmr->mem.arbel.mpt->start  = cl_hton64(iova);
794
795         wmb();
796
797         *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW;
798
799         wmb();
800
801         return 0;
802 }
803
804
805 void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
806 {
807         u32 key;
808
809         if (!fmr->maps)
810                 return;
811
812         key = tavor_key_to_hw_index(fmr->ibmr.lkey);
813         key &= dev->limits.num_mpts - 1;
814         fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
815
816         fmr->maps = 0;
817
818         writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
819 }
820
821
822 void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
823 {
824         u32 key;
825
826         if (!fmr->maps)
827                 return;
828
829         key = arbel_key_to_hw_index(fmr->ibmr.lkey);
830         key &= dev->limits.num_mpts - 1;
831         fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
832
833         fmr->maps = 0;
834
835         *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
836 }
837
838 int mthca_init_mr_table(struct mthca_dev *dev)
839 {
840         int err, i;
841
842         err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
843                                (u32)dev->limits.num_mpts,
844                                (u32)~0, (u32)dev->limits.reserved_mrws);
845         if (err)
846                 return err;
847
848         if (!mthca_is_memfree(dev) &&
849             (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN))
850                 dev->limits.fmr_reserved_mtts = 0;
851         else
852                 dev->mthca_flags |= MTHCA_FLAG_FMR;
853
854         if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
855                 HCA_PRINT(TRACE_LEVEL_INFORMATION  ,HCA_DBG_MEMORY      ,("Memory key throughput optimization activated.\n"));
856
857         err = mthca_buddy_init(&dev->mr_table.mtt_buddy,
858                                fls(dev->limits.num_mtt_segs - 1));
859
860         if (err)
861                 goto err_mtt_buddy;
862
863         dev->mr_table.tavor_fmr.mpt_base = NULL;
864         dev->mr_table.tavor_fmr.mtt_base = NULL;
865
866         if (dev->limits.fmr_reserved_mtts) {
867                 i = fls(dev->limits.fmr_reserved_mtts - 1);
868
869                 if (i >= 31) {
870                         HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("Unable to reserve 2^31 FMR MTTs.\n"));
871                         err = -EINVAL;
872                         goto err_fmr_mpt;
873                 }
874
875                 dev->mr_table.tavor_fmr.mpt_base =
876                         ioremap(dev->mr_table.mpt_base,
877                                 (1 << i) * sizeof (struct mthca_mpt_entry), 
878                                 &dev->mr_table.tavor_fmr.mpt_base_size);
879
880                 if (!dev->mr_table.tavor_fmr.mpt_base) {
881                         HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("MPT ioremap for FMR failed.\n"));
882                         err = -ENOMEM;
883                         goto err_fmr_mpt;
884                 }
885
886                 dev->mr_table.tavor_fmr.mtt_base =
887                         ioremap(dev->mr_table.mtt_base,
888                                 (1 << i) * MTHCA_MTT_SEG_SIZE,
889                                 &dev->mr_table.tavor_fmr.mtt_base_size );
890
891                 if (!dev->mr_table.tavor_fmr.mtt_base) {
892                         HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_MEMORY  ,("MTT ioremap for FMR failed.\n"));
893                         err = -ENOMEM;
894                         goto err_fmr_mtt;
895                 }
896
897                 err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, i);
898                 if (err)
899                         goto err_fmr_mtt_buddy;
900
901                 /* Prevent regular MRs from using FMR keys */
902                 err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, i);
903                 if (err)
904                         goto err_reserve_fmr;
905
906                 dev->mr_table.fmr_mtt_buddy =
907                         &dev->mr_table.tavor_fmr.mtt_buddy;
908         } else
909                 dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
910
911         /* FMR table is always the first, take reserved MTTs out of there */
912         if (dev->limits.reserved_mtts) {
913                 i = fls(dev->limits.reserved_mtts - 1);
914
915                 if (mthca_alloc_mtt_range(dev, i,
916                                           dev->mr_table.fmr_mtt_buddy) == -1) {
917                         HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_MEMORY,("MTT table of order %d is too small.\n",
918                                   dev->mr_table.fmr_mtt_buddy->max_order));
919                         err = -ENOMEM;
920                         goto err_reserve_mtts;
921                 }
922         }
923
924         return 0;
925
926 err_reserve_mtts:
927 err_reserve_fmr:
928         if (dev->limits.fmr_reserved_mtts)
929                 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);
930
931 err_fmr_mtt_buddy:
932         if (dev->mr_table.tavor_fmr.mtt_base)
933                 iounmap(dev->mr_table.tavor_fmr.mtt_base,
934                         dev->mr_table.tavor_fmr.mtt_base_size);
935
936 err_fmr_mtt:
937         if (dev->mr_table.tavor_fmr.mpt_base)
938                 iounmap(dev->mr_table.tavor_fmr.mpt_base,
939                         dev->mr_table.tavor_fmr.mpt_base_size);
940
941 err_fmr_mpt:
942         mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);
943
944 err_mtt_buddy:
945         mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
946
947         return err;
948 }
949
950 void mthca_cleanup_mr_table(struct mthca_dev *dev)
951 {
952         /* XXX check if any MRs are still allocated? */
953         if (dev->limits.fmr_reserved_mtts)
954                 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);
955
956         mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);
957
958         if (dev->mr_table.tavor_fmr.mtt_base)
959                 iounmap(dev->mr_table.tavor_fmr.mtt_base,
960                         dev->mr_table.tavor_fmr.mtt_base_size);
961         if (dev->mr_table.tavor_fmr.mpt_base)
962                 iounmap(dev->mr_table.tavor_fmr.mpt_base,
963                         dev->mr_table.tavor_fmr.mpt_base_size);
964
965         mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);
966 }
967