]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/net/mlx4/alloc.c
f9d6b4dca180e49f6d16fc4ebfe594831cc0cf29
[linux-2.6-omap-h63xx.git] / drivers / net / mlx4 / alloc.c
1 /*
2  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  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
33 #include <linux/errno.h>
34 #include <linux/slab.h>
35 #include <linux/bitmap.h>
36 #include <linux/dma-mapping.h>
37 #include <linux/vmalloc.h>
38
39 #include "mlx4.h"
40
41 u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
42 {
43         u32 obj;
44
45         spin_lock(&bitmap->lock);
46
47         obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
48         if (obj >= bitmap->max) {
49                 bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
50                 obj = find_first_zero_bit(bitmap->table, bitmap->max);
51         }
52
53         if (obj < bitmap->max) {
54                 set_bit(obj, bitmap->table);
55                 bitmap->last = (obj + 1) & (bitmap->max - 1);
56                 obj |= bitmap->top;
57         } else
58                 obj = -1;
59
60         spin_unlock(&bitmap->lock);
61
62         return obj;
63 }
64
65 void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
66 {
67         obj &= bitmap->max - 1;
68
69         spin_lock(&bitmap->lock);
70         clear_bit(obj, bitmap->table);
71         bitmap->last = min(bitmap->last, obj);
72         bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
73         spin_unlock(&bitmap->lock);
74 }
75
76 int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved)
77 {
78         int i;
79
80         /* num must be a power of 2 */
81         if (num != roundup_pow_of_two(num))
82                 return -EINVAL;
83
84         bitmap->last = 0;
85         bitmap->top  = 0;
86         bitmap->max  = num;
87         bitmap->mask = mask;
88         spin_lock_init(&bitmap->lock);
89         bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL);
90         if (!bitmap->table)
91                 return -ENOMEM;
92
93         for (i = 0; i < reserved; ++i)
94                 set_bit(i, bitmap->table);
95
96         return 0;
97 }
98
99 void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
100 {
101         kfree(bitmap->table);
102 }
103
104 /*
105  * Handling for queue buffers -- we allocate a bunch of memory and
106  * register it in a memory region at HCA virtual address 0.  If the
107  * requested size is > max_direct, we split the allocation into
108  * multiple pages, so we don't require too much contiguous memory.
109  */
110
111 int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
112                    struct mlx4_buf *buf)
113 {
114         dma_addr_t t;
115
116         if (size <= max_direct) {
117                 buf->nbufs        = 1;
118                 buf->npages       = 1;
119                 buf->page_shift   = get_order(size) + PAGE_SHIFT;
120                 buf->direct.buf   = dma_alloc_coherent(&dev->pdev->dev,
121                                                        size, &t, GFP_KERNEL);
122                 if (!buf->direct.buf)
123                         return -ENOMEM;
124
125                 buf->direct.map = t;
126
127                 while (t & ((1 << buf->page_shift) - 1)) {
128                         --buf->page_shift;
129                         buf->npages *= 2;
130                 }
131
132                 memset(buf->direct.buf, 0, size);
133         } else {
134                 int i;
135
136                 buf->nbufs       = (size + PAGE_SIZE - 1) / PAGE_SIZE;
137                 buf->npages      = buf->nbufs;
138                 buf->page_shift  = PAGE_SHIFT;
139                 buf->page_list   = kzalloc(buf->nbufs * sizeof *buf->page_list,
140                                            GFP_KERNEL);
141                 if (!buf->page_list)
142                         return -ENOMEM;
143
144                 for (i = 0; i < buf->nbufs; ++i) {
145                         buf->page_list[i].buf =
146                                 dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
147                                                    &t, GFP_KERNEL);
148                         if (!buf->page_list[i].buf)
149                                 goto err_free;
150
151                         buf->page_list[i].map = t;
152
153                         memset(buf->page_list[i].buf, 0, PAGE_SIZE);
154                 }
155
156                 if (BITS_PER_LONG == 64) {
157                         struct page **pages;
158                         pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL);
159                         if (!pages)
160                                 goto err_free;
161                         for (i = 0; i < buf->nbufs; ++i)
162                                 pages[i] = virt_to_page(buf->page_list[i].buf);
163                         buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
164                         kfree(pages);
165                         if (!buf->direct.buf)
166                                 goto err_free;
167                 }
168         }
169
170         return 0;
171
172 err_free:
173         mlx4_buf_free(dev, size, buf);
174
175         return -ENOMEM;
176 }
177 EXPORT_SYMBOL_GPL(mlx4_buf_alloc);
178
179 void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
180 {
181         int i;
182
183         if (buf->nbufs == 1)
184                 dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf,
185                                   buf->direct.map);
186         else {
187                 if (BITS_PER_LONG == 64)
188                         vunmap(buf->direct.buf);
189
190                 for (i = 0; i < buf->nbufs; ++i)
191                         if (buf->page_list[i].buf)
192                                 dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
193                                                   buf->page_list[i].buf,
194                                                   buf->page_list[i].map);
195                 kfree(buf->page_list);
196         }
197 }
198 EXPORT_SYMBOL_GPL(mlx4_buf_free);
199
200 static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
201 {
202         struct mlx4_db_pgdir *pgdir;
203
204         pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL);
205         if (!pgdir)
206                 return NULL;
207
208         bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2);
209         pgdir->bits[0] = pgdir->order0;
210         pgdir->bits[1] = pgdir->order1;
211         pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
212                                             &pgdir->db_dma, GFP_KERNEL);
213         if (!pgdir->db_page) {
214                 kfree(pgdir);
215                 return NULL;
216         }
217
218         return pgdir;
219 }
220
221 static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
222                                     struct mlx4_db *db, int order)
223 {
224         int o;
225         int i;
226
227         for (o = order; o <= 1; ++o) {
228                 i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o);
229                 if (i < MLX4_DB_PER_PAGE >> o)
230                         goto found;
231         }
232
233         return -ENOMEM;
234
235 found:
236         clear_bit(i, pgdir->bits[o]);
237
238         i <<= o;
239
240         if (o > order)
241                 set_bit(i ^ 1, pgdir->bits[order]);
242
243         db->u.pgdir = pgdir;
244         db->index   = i;
245         db->db      = pgdir->db_page + db->index;
246         db->dma     = pgdir->db_dma  + db->index * 4;
247         db->order   = order;
248
249         return 0;
250 }
251
252 int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
253 {
254         struct mlx4_priv *priv = mlx4_priv(dev);
255         struct mlx4_db_pgdir *pgdir;
256         int ret = 0;
257
258         mutex_lock(&priv->pgdir_mutex);
259
260         list_for_each_entry(pgdir, &priv->pgdir_list, list)
261                 if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
262                         goto out;
263
264         pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev));
265         if (!pgdir) {
266                 ret = -ENOMEM;
267                 goto out;
268         }
269
270         list_add(&pgdir->list, &priv->pgdir_list);
271
272         /* This should never fail -- we just allocated an empty page: */
273         WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order));
274
275 out:
276         mutex_unlock(&priv->pgdir_mutex);
277
278         return ret;
279 }
280 EXPORT_SYMBOL_GPL(mlx4_db_alloc);
281
282 void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db)
283 {
284         struct mlx4_priv *priv = mlx4_priv(dev);
285         int o;
286         int i;
287
288         mutex_lock(&priv->pgdir_mutex);
289
290         o = db->order;
291         i = db->index;
292
293         if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
294                 clear_bit(i ^ 1, db->u.pgdir->order0);
295                 ++o;
296         }
297         i >>= o;
298         set_bit(i, db->u.pgdir->bits[o]);
299
300         if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) {
301                 dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
302                                   db->u.pgdir->db_page, db->u.pgdir->db_dma);
303                 list_del(&db->u.pgdir->list);
304                 kfree(db->u.pgdir);
305         }
306
307         mutex_unlock(&priv->pgdir_mutex);
308 }
309 EXPORT_SYMBOL_GPL(mlx4_db_free);
310
311 int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
312                        int size, int max_direct)
313 {
314         int err;
315
316         err = mlx4_db_alloc(dev, &wqres->db, 1);
317         if (err)
318                 return err;
319
320         *wqres->db.db = 0;
321
322         err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf);
323         if (err)
324                 goto err_db;
325
326         err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift,
327                             &wqres->mtt);
328         if (err)
329                 goto err_buf;
330
331         err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf);
332         if (err)
333                 goto err_mtt;
334
335         return 0;
336
337 err_mtt:
338         mlx4_mtt_cleanup(dev, &wqres->mtt);
339 err_buf:
340         mlx4_buf_free(dev, size, &wqres->buf);
341 err_db:
342         mlx4_db_free(dev, &wqres->db);
343
344         return err;
345 }
346 EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res);
347
348 void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
349                        int size)
350 {
351         mlx4_mtt_cleanup(dev, &wqres->mtt);
352         mlx4_buf_free(dev, size, &wqres->buf);
353         mlx4_db_free(dev, &wqres->db);
354 }
355 EXPORT_SYMBOL_GPL(mlx4_free_hwq_res);