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