Skip to content
Snippets Groups Projects
Select Git revision
  • 313abe55a87bc10e55d00f337d609e17ad5f8c9a
  • vme-testing default
  • ci-test
  • master
  • remoteproc
  • am625-sk-ov5640
  • pcal6534-upstreaming
  • lps22df-upstreaming
  • msc-upstreaming
  • imx8mp
  • iio/noa1305
  • vme-next
  • vme-next-4.14-rc4
  • v4.14-rc4
  • v4.14-rc3
  • v4.14-rc2
  • v4.14-rc1
  • v4.13
  • vme-next-4.13-rc7
  • v4.13-rc7
  • v4.13-rc6
  • v4.13-rc5
  • v4.13-rc4
  • v4.13-rc3
  • v4.13-rc2
  • v4.13-rc1
  • v4.12
  • v4.12-rc7
  • v4.12-rc6
  • v4.12-rc5
  • v4.12-rc4
  • v4.12-rc3
32 results

alloc.c

Blame
  • alloc.c 5.15 KiB
    /*
     * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
     *
     * This software is available to you under a choice of one of two
     * licenses.  You may choose to be licensed under the terms of the GNU
     * General Public License (GPL) Version 2, available from the file
     * COPYING in the main directory of this source tree, or the
     * OpenIB.org BSD license below:
     *
     *     Redistribution and use in source and binary forms, with or
     *     without modification, are permitted provided that the following
     *     conditions are met:
     *
     *      - Redistributions of source code must retain the above
     *        copyright notice, this list of conditions and the following
     *        disclaimer.
     *
     *      - Redistributions in binary form must reproduce the above
     *        copyright notice, this list of conditions and the following
     *        disclaimer in the documentation and/or other materials
     *        provided with the distribution.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */
    
    #include <linux/errno.h>
    #include <linux/slab.h>
    #include <linux/bitmap.h>
    #include <linux/dma-mapping.h>
    
    #include "mlx4.h"
    
    u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
    {
    	u32 obj;
    
    	spin_lock(&bitmap->lock);
    
    	obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
    	if (obj >= bitmap->max) {
    		bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
    		obj = find_first_zero_bit(bitmap->table, bitmap->max);
    	}
    
    	if (obj < bitmap->max) {
    		set_bit(obj, bitmap->table);
    		bitmap->last = (obj + 1) & (bitmap->max - 1);
    		obj |= bitmap->top;
    	} else
    		obj = -1;
    
    	spin_unlock(&bitmap->lock);
    
    	return obj;
    }
    
    void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
    {
    	obj &= bitmap->max - 1;
    
    	spin_lock(&bitmap->lock);
    	clear_bit(obj, bitmap->table);
    	bitmap->last = min(bitmap->last, obj);
    	bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
    	spin_unlock(&bitmap->lock);
    }
    
    int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved)
    {
    	int i;
    
    	/* num must be a power of 2 */
    	if (num != roundup_pow_of_two(num))
    		return -EINVAL;
    
    	bitmap->last = 0;
    	bitmap->top  = 0;
    	bitmap->max  = num;
    	bitmap->mask = mask;
    	spin_lock_init(&bitmap->lock);
    	bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL);
    	if (!bitmap->table)
    		return -ENOMEM;
    
    	for (i = 0; i < reserved; ++i)
    		set_bit(i, bitmap->table);
    
    	return 0;
    }
    
    void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
    {
    	kfree(bitmap->table);
    }
    
    /*
     * Handling for queue buffers -- we allocate a bunch of memory and
     * register it in a memory region at HCA virtual address 0.  If the
     * requested size is > max_direct, we split the allocation into
     * multiple pages, so we don't require too much contiguous memory.
     */
    
    int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
    		   struct mlx4_buf *buf)
    {
    	dma_addr_t t;
    
    	if (size <= max_direct) {
    		buf->nbufs        = 1;
    		buf->npages       = 1;
    		buf->page_shift   = get_order(size) + PAGE_SHIFT;
    		buf->u.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
    						       size, &t, GFP_KERNEL);
    		if (!buf->u.direct.buf)
    			return -ENOMEM;
    
    		buf->u.direct.map = t;
    
    		while (t & ((1 << buf->page_shift) - 1)) {
    			--buf->page_shift;
    			buf->npages *= 2;
    		}
    
    		memset(buf->u.direct.buf, 0, size);
    	} else {
    		int i;
    
    		buf->nbufs       = (size + PAGE_SIZE - 1) / PAGE_SIZE;
    		buf->npages      = buf->nbufs;
    		buf->page_shift  = PAGE_SHIFT;
    		buf->u.page_list = kzalloc(buf->nbufs * sizeof *buf->u.page_list,
    					   GFP_KERNEL);
    		if (!buf->u.page_list)
    			return -ENOMEM;
    
    		for (i = 0; i < buf->nbufs; ++i) {
    			buf->u.page_list[i].buf =
    				dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
    						   &t, GFP_KERNEL);
    			if (!buf->u.page_list[i].buf)
    				goto err_free;
    
    			buf->u.page_list[i].map = t;
    
    			memset(buf->u.page_list[i].buf, 0, PAGE_SIZE);
    		}
    
    		if (BITS_PER_LONG == 64) {
    			struct page **pages;
    			pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL);
    			if (!pages)
    				goto err_free;
    			for (i = 0; i < buf->nbufs; ++i)
    				pages[i] = virt_to_page(buf->u.page_list[i].buf);
    			buf->u.direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
    			kfree(pages);
    			if (!buf->u.direct.buf)
    				goto err_free;
    		}
    	}
    
    	return 0;
    
    err_free:
    	mlx4_buf_free(dev, size, buf);
    
    	return -ENOMEM;
    }
    EXPORT_SYMBOL_GPL(mlx4_buf_alloc);
    
    void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
    {
    	int i;
    
    	if (buf->nbufs == 1)
    		dma_free_coherent(&dev->pdev->dev, size, buf->u.direct.buf,
    				  buf->u.direct.map);
    	else {
    		if (BITS_PER_LONG == 64)
    			vunmap(buf->u.direct.buf);
    
    		for (i = 0; i < buf->nbufs; ++i)
    			if (buf->u.page_list[i].buf)
    				dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
    						  buf->u.page_list[i].buf,
    						  buf->u.page_list[i].map);
    		kfree(buf->u.page_list);
    	}
    }
    EXPORT_SYMBOL_GPL(mlx4_buf_free);