diff options
author | Michael S. Tsirkin <mst@mellanox.co.il> | 2005-04-16 18:26:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:26:26 -0400 |
commit | 9095e208d84c349193fa19245cd5a8bc1a9774b8 (patch) | |
tree | cdef394c9e01b44d59125b8a4e299e4a7d984384 | |
parent | 8df8a34de60f8e51c87e5c145679f1a896133199 (diff) |
[PATCH] IB/mthca: encapsulate MTT buddy allocator
Encapsulate the buddy allocator used for MTT segments. This cleans up the
code and also gets us ready to add FMR support.
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <roland@topspin.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_dev.h | 9 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_mr.c | 160 |
2 files changed, 95 insertions, 74 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index d4bd9aa232b1..1faaf542a4e1 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h | |||
@@ -170,10 +170,15 @@ struct mthca_pd_table { | |||
170 | struct mthca_alloc alloc; | 170 | struct mthca_alloc alloc; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | struct mthca_buddy { | ||
174 | unsigned long **bits; | ||
175 | int max_order; | ||
176 | spinlock_t lock; | ||
177 | }; | ||
178 | |||
173 | struct mthca_mr_table { | 179 | struct mthca_mr_table { |
174 | struct mthca_alloc mpt_alloc; | 180 | struct mthca_alloc mpt_alloc; |
175 | int max_mtt_order; | 181 | struct mthca_buddy mtt_buddy; |
176 | unsigned long **mtt_buddy; | ||
177 | u64 mtt_base; | 182 | u64 mtt_base; |
178 | struct mthca_icm_table *mtt_table; | 183 | struct mthca_icm_table *mtt_table; |
179 | struct mthca_icm_table *mpt_table; | 184 | struct mthca_icm_table *mpt_table; |
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 5cde296b4065..6a127a7aca57 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c | |||
@@ -72,60 +72,108 @@ struct mthca_mpt_entry { | |||
72 | * through the bitmaps) | 72 | * through the bitmaps) |
73 | */ | 73 | */ |
74 | 74 | ||
75 | static u32 __mthca_alloc_mtt(struct mthca_dev *dev, int order) | 75 | static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order) |
76 | { | 76 | { |
77 | int o; | 77 | int o; |
78 | int m; | 78 | int m; |
79 | u32 seg; | 79 | u32 seg; |
80 | 80 | ||
81 | spin_lock(&dev->mr_table.mpt_alloc.lock); | 81 | spin_lock(&buddy->lock); |
82 | 82 | ||
83 | for (o = order; o <= dev->mr_table.max_mtt_order; ++o) { | 83 | for (o = order; o <= buddy->max_order; ++o) { |
84 | m = 1 << (dev->mr_table.max_mtt_order - o); | 84 | m = 1 << (buddy->max_order - o); |
85 | seg = find_first_bit(dev->mr_table.mtt_buddy[o], m); | 85 | seg = find_first_bit(buddy->bits[o], m); |
86 | if (seg < m) | 86 | if (seg < m) |
87 | goto found; | 87 | goto found; |
88 | } | 88 | } |
89 | 89 | ||
90 | spin_unlock(&dev->mr_table.mpt_alloc.lock); | 90 | spin_unlock(&buddy->lock); |
91 | return -1; | 91 | return -1; |
92 | 92 | ||
93 | found: | 93 | found: |
94 | clear_bit(seg, dev->mr_table.mtt_buddy[o]); | 94 | clear_bit(seg, buddy->bits[o]); |
95 | 95 | ||
96 | while (o > order) { | 96 | while (o > order) { |
97 | --o; | 97 | --o; |
98 | seg <<= 1; | 98 | seg <<= 1; |
99 | set_bit(seg ^ 1, dev->mr_table.mtt_buddy[o]); | 99 | set_bit(seg ^ 1, buddy->bits[o]); |
100 | } | 100 | } |
101 | 101 | ||
102 | spin_unlock(&dev->mr_table.mpt_alloc.lock); | 102 | spin_unlock(&buddy->lock); |
103 | 103 | ||
104 | seg <<= order; | 104 | seg <<= order; |
105 | 105 | ||
106 | return seg; | 106 | return seg; |
107 | } | 107 | } |
108 | 108 | ||
109 | static void __mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order) | 109 | static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order) |
110 | { | 110 | { |
111 | seg >>= order; | 111 | seg >>= order; |
112 | 112 | ||
113 | spin_lock(&dev->mr_table.mpt_alloc.lock); | 113 | spin_lock(&buddy->lock); |
114 | 114 | ||
115 | while (test_bit(seg ^ 1, dev->mr_table.mtt_buddy[order])) { | 115 | while (test_bit(seg ^ 1, buddy->bits[order])) { |
116 | clear_bit(seg ^ 1, dev->mr_table.mtt_buddy[order]); | 116 | clear_bit(seg ^ 1, buddy->bits[order]); |
117 | seg >>= 1; | 117 | seg >>= 1; |
118 | ++order; | 118 | ++order; |
119 | } | 119 | } |
120 | 120 | ||
121 | set_bit(seg, dev->mr_table.mtt_buddy[order]); | 121 | set_bit(seg, buddy->bits[order]); |
122 | 122 | ||
123 | spin_unlock(&dev->mr_table.mpt_alloc.lock); | 123 | spin_unlock(&buddy->lock); |
124 | } | 124 | } |
125 | 125 | ||
126 | static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order) | 126 | static int __devinit mthca_buddy_init(struct mthca_buddy *buddy, int max_order) |
127 | { | 127 | { |
128 | u32 seg = __mthca_alloc_mtt(dev, order); | 128 | int i, s; |
129 | |||
130 | buddy->max_order = max_order; | ||
131 | spin_lock_init(&buddy->lock); | ||
132 | |||
133 | buddy->bits = kmalloc((buddy->max_order + 1) * sizeof (long *), | ||
134 | GFP_KERNEL); | ||
135 | if (!buddy->bits) | ||
136 | goto err_out; | ||
137 | |||
138 | memset(buddy->bits, 0, (buddy->max_order + 1) * sizeof (long *)); | ||
139 | |||
140 | for (i = 0; i <= buddy->max_order; ++i) { | ||
141 | s = BITS_TO_LONGS(1 << (buddy->max_order - i)); | ||
142 | buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); | ||
143 | if (!buddy->bits[i]) | ||
144 | goto err_out_free; | ||
145 | bitmap_zero(buddy->bits[i], | ||
146 | 1 << (buddy->max_order - i)); | ||
147 | } | ||
148 | |||
149 | set_bit(0, buddy->bits[buddy->max_order]); | ||
150 | |||
151 | return 0; | ||
152 | |||
153 | err_out_free: | ||
154 | for (i = 0; i <= buddy->max_order; ++i) | ||
155 | kfree(buddy->bits[i]); | ||
156 | |||
157 | kfree(buddy->bits); | ||
158 | |||
159 | err_out: | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | |||
163 | static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy) | ||
164 | { | ||
165 | int i; | ||
166 | |||
167 | for (i = 0; i <= buddy->max_order; ++i) | ||
168 | kfree(buddy->bits[i]); | ||
169 | |||
170 | kfree(buddy->bits); | ||
171 | } | ||
172 | |||
173 | static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order, | ||
174 | struct mthca_buddy *buddy) | ||
175 | { | ||
176 | u32 seg = mthca_buddy_alloc(buddy, order); | ||
129 | 177 | ||
130 | if (seg == -1) | 178 | if (seg == -1) |
131 | return -1; | 179 | return -1; |
@@ -133,16 +181,17 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order) | |||
133 | if (dev->hca_type == ARBEL_NATIVE) | 181 | if (dev->hca_type == ARBEL_NATIVE) |
134 | if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg, | 182 | if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg, |
135 | seg + (1 << order) - 1)) { | 183 | seg + (1 << order) - 1)) { |
136 | __mthca_free_mtt(dev, seg, order); | 184 | mthca_buddy_free(buddy, seg, order); |
137 | seg = -1; | 185 | seg = -1; |
138 | } | 186 | } |
139 | 187 | ||
140 | return seg; | 188 | return seg; |
141 | } | 189 | } |
142 | 190 | ||
143 | static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order) | 191 | static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order, |
192 | struct mthca_buddy* buddy) | ||
144 | { | 193 | { |
145 | __mthca_free_mtt(dev, seg, order); | 194 | mthca_buddy_free(buddy, seg, order); |
146 | 195 | ||
147 | if (dev->hca_type == ARBEL_NATIVE) | 196 | if (dev->hca_type == ARBEL_NATIVE) |
148 | mthca_table_put_range(dev, dev->mr_table.mtt_table, seg, | 197 | mthca_table_put_range(dev, dev->mr_table.mtt_table, seg, |
@@ -268,7 +317,8 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, | |||
268 | i <<= 1, ++mr->order) | 317 | i <<= 1, ++mr->order) |
269 | ; /* nothing */ | 318 | ; /* nothing */ |
270 | 319 | ||
271 | mr->first_seg = mthca_alloc_mtt(dev, mr->order); | 320 | mr->first_seg = mthca_alloc_mtt(dev, mr->order, |
321 | &dev->mr_table.mtt_buddy); | ||
272 | if (mr->first_seg == -1) | 322 | if (mr->first_seg == -1) |
273 | goto err_out_table; | 323 | goto err_out_table; |
274 | 324 | ||
@@ -361,7 +411,7 @@ err_out_mailbox_free: | |||
361 | kfree(mailbox); | 411 | kfree(mailbox); |
362 | 412 | ||
363 | err_out_free_mtt: | 413 | err_out_free_mtt: |
364 | mthca_free_mtt(dev, mr->first_seg, mr->order); | 414 | mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy); |
365 | 415 | ||
366 | err_out_table: | 416 | err_out_table: |
367 | if (dev->hca_type == ARBEL_NATIVE) | 417 | if (dev->hca_type == ARBEL_NATIVE) |
@@ -390,7 +440,7 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) | |||
390 | status); | 440 | status); |
391 | 441 | ||
392 | if (mr->order >= 0) | 442 | if (mr->order >= 0) |
393 | mthca_free_mtt(dev, mr->first_seg, mr->order); | 443 | mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy); |
394 | 444 | ||
395 | if (dev->hca_type == ARBEL_NATIVE) | 445 | if (dev->hca_type == ARBEL_NATIVE) |
396 | mthca_table_put(dev, dev->mr_table.mpt_table, | 446 | mthca_table_put(dev, dev->mr_table.mpt_table, |
@@ -401,7 +451,6 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) | |||
401 | int __devinit mthca_init_mr_table(struct mthca_dev *dev) | 451 | int __devinit mthca_init_mr_table(struct mthca_dev *dev) |
402 | { | 452 | { |
403 | int err; | 453 | int err; |
404 | int i, s; | ||
405 | 454 | ||
406 | err = mthca_alloc_init(&dev->mr_table.mpt_alloc, | 455 | err = mthca_alloc_init(&dev->mr_table.mpt_alloc, |
407 | dev->limits.num_mpts, | 456 | dev->limits.num_mpts, |
@@ -409,53 +458,24 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) | |||
409 | if (err) | 458 | if (err) |
410 | return err; | 459 | return err; |
411 | 460 | ||
412 | err = -ENOMEM; | 461 | err = mthca_buddy_init(&dev->mr_table.mtt_buddy, |
413 | 462 | fls(dev->limits.num_mtt_segs - 1)); | |
414 | for (i = 1, dev->mr_table.max_mtt_order = 0; | 463 | if (err) |
415 | i < dev->limits.num_mtt_segs; | 464 | goto err_mtt_buddy; |
416 | i <<= 1, ++dev->mr_table.max_mtt_order) | 465 | |
417 | ; /* nothing */ | 466 | if (dev->limits.reserved_mtts) { |
418 | 467 | if (mthca_alloc_mtt(dev, fls(dev->limits.reserved_mtts - 1), | |
419 | dev->mr_table.mtt_buddy = kmalloc((dev->mr_table.max_mtt_order + 1) * | 468 | &dev->mr_table.mtt_buddy) == -1) { |
420 | sizeof (long *), | 469 | mthca_warn(dev, "MTT table of order %d is too small.\n", |
421 | GFP_KERNEL); | 470 | dev->mr_table.mtt_buddy.max_order); |
422 | if (!dev->mr_table.mtt_buddy) | 471 | err = -ENOMEM; |
423 | goto err_out; | 472 | goto err_mtt_buddy; |
424 | 473 | } | |
425 | for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) | ||
426 | dev->mr_table.mtt_buddy[i] = NULL; | ||
427 | |||
428 | for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) { | ||
429 | s = BITS_TO_LONGS(1 << (dev->mr_table.max_mtt_order - i)); | ||
430 | dev->mr_table.mtt_buddy[i] = kmalloc(s * sizeof (long), | ||
431 | GFP_KERNEL); | ||
432 | if (!dev->mr_table.mtt_buddy[i]) | ||
433 | goto err_out_free; | ||
434 | bitmap_zero(dev->mr_table.mtt_buddy[i], | ||
435 | 1 << (dev->mr_table.max_mtt_order - i)); | ||
436 | } | ||
437 | |||
438 | set_bit(0, dev->mr_table.mtt_buddy[dev->mr_table.max_mtt_order]); | ||
439 | |||
440 | for (i = 0; i < dev->mr_table.max_mtt_order; ++i) | ||
441 | if (1 << i >= dev->limits.reserved_mtts) | ||
442 | break; | ||
443 | |||
444 | if (i == dev->mr_table.max_mtt_order) { | ||
445 | mthca_err(dev, "MTT table of order %d is " | ||
446 | "too small.\n", i); | ||
447 | goto err_out_free; | ||
448 | } | 474 | } |
449 | 475 | ||
450 | (void) mthca_alloc_mtt(dev, i); | ||
451 | |||
452 | return 0; | 476 | return 0; |
453 | 477 | ||
454 | err_out_free: | 478 | err_mtt_buddy: |
455 | for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) | ||
456 | kfree(dev->mr_table.mtt_buddy[i]); | ||
457 | |||
458 | err_out: | ||
459 | mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); | 479 | mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); |
460 | 480 | ||
461 | return err; | 481 | return err; |
@@ -463,11 +483,7 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) | |||
463 | 483 | ||
464 | void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev) | 484 | void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev) |
465 | { | 485 | { |
466 | int i; | ||
467 | |||
468 | /* XXX check if any MRs are still allocated? */ | 486 | /* XXX check if any MRs are still allocated? */ |
469 | for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) | 487 | mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); |
470 | kfree(dev->mr_table.mtt_buddy[i]); | ||
471 | kfree(dev->mr_table.mtt_buddy); | ||
472 | mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); | 488 | mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); |
473 | } | 489 | } |