rk3188--11.android 内核下ion分配内存

一. 内核启动时保留内存
start_kernel
–> setup_arch
–>arm_memblock_init
–> rk30_reserve
在内核启动时会保留一部分内存
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中
static void __init rk30_reserve(void)
{
//保存在变量 rk30_ion_pdata.heaps[0].base 中
rk30_ion_pdata.heaps[0].base = board_mem_reserve_add(“ion”, ION_RESERVE_SIZE);
}
bank.start=0x60000000, size=0x36800000
reserved_base_end就是内存的结束地址: 0x6000000+0x36800000=0x96800000
phys_addr_t __init board_mem_reserve_add(char *name, size_t size)
{
phys_addr_t base = 0;
if(reserved_base_end == 0)
reserved_base_end = meminfo.bank[0].start + meminfo.bank[0].size;
reserved_size += size;
base = reserved_base_end - reserved_size;

return base;

}
分配内存之后base=内存结束地址-80M=0x96800000-0x5000000=0x91800000
memory reserve: Memory(base:0x91800000 size:80M) reserved for

二. ION驱动的初始化
2.1 platform_device
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中
static struct ion_platform_data rk30_ion_pdata = {
.nr = 1,
.heaps = {
{
.type = ION_HEAP_TYPE_CARVEOUT, //reserve memory:这是在保留内存块中分配内存
.id = ION_NOR_HEAP_ID,
.name = “norheap”,
.size = ION_RESERVE_SIZE,
}
},
};

static struct platform_device device_ion = {
.name = “ion-rockchip”,
.id = 0,
.dev = {
.platform_data = &rk30_ion_pdata,
},
};
2.2 platform_driver
cong@ubuntu:/rk/rk3188/kernel/drivers/gpu$ tree
├── ion
│ ├── ion.c
│ ├── ion_carveout_heap.c
│ ├── ion_heap.c
│ ├── ion_priv.h
│ ├── ion_system_heap.c
│ ├── ion_system_mapper.c
│ └── rockchip
│ └── rockchip_ion.c
└── Makefile
module_init(ion_init);
–> ion_init
static struct platform_driver ion_driver = {
.probe = rockchip_ion_probe,
.remove = rockchip_ion_remove,
.driver = { .name = “ion-rockchip” }
};

static int __init ion_init(void)
{
return platform_driver_register(&ion_driver);
}

module_init(ion_init);
–> ion_init
–> rockchip_ion_probe
static int rockchip_ion_probe(struct platform_device *pdev)
{
struct ion_device *idev;
struct ion_platform_data *pdata = pdev->dev.platform_data;

num_heaps = pdata->nr;    //num_heaps =1
heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);

idev = ion_device_create(rockchip_custom_ioctl);

for (i = 0; i < num_heaps; i++) {
    struct ion_platform_heap *heap_data = &pdata->heaps[i];
    heaps[i] = ion_heap_create(heap_data);        
    ion_device_add_heap(idev, heaps[i]);
}
platform_set_drvdata(pdev, idev);
return 0;

}

rockchip_ion_probe
–> ion_device_create
在drivers/gpu/ion/ion.c中
struct ion_device *ion_device_create(long (*custom_ioctl)(struct ion_client *client, unsigned int cmd, unsigned long arg))
{
struct ion_device *idev;
idev = kzalloc(sizeof(struct ion_device), GFP_KERNEL);
idev->dev.minor = MISC_DYNAMIC_MINOR;
idev->dev.name = “ion”;
idev->dev.fops = &ion_fops;
idev->dev.parent = NULL;
ret = misc_register(&idev->dev);

idev->debug_root = debugfs_create_dir("ion", NULL);

idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT;
mutex_init(&idev->lock);
idev->heaps = RB_ROOT;
idev->user_clients = RB_ROOT;
idev->kernel_clients = RB_ROOT;
debugfs_create_file("leak", 0664, idev->debug_root, idev, &debug_leak_fops);
return idev;

}
rockchip_ion_probe
–> ion_heap_create
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;

switch (heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:  //通过kmalloc分配内存
    heap = ion_system_contig_heap_create(heap_data);
    break;
case ION_HEAP_TYPE_SYSTEM:    //通过vmalloc分配内存
    heap = ion_system_heap_create(heap_data);
    break;
case ION_HEAP_TYPE_CARVEOUT:    //在保留内存块中(reserve memory)分配内存
    heap = ion_carveout_heap_create(heap_data);
    break;
default:
    pr_err("%s: Invalid heap type %d\n", __func__, heap_data->type);
    return ERR_PTR(-EINVAL);
}
heap->name = heap_data->name;
heap->id = heap_data->id;
return heap;

}

rockchip_ion_probe
–> ion_heap_create
–> ion_carveout_heap_create
在drivers/gpu/ion/ion_heap.c中
struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_carveout_heap *carveout_heap;

carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL);

carveout_heap->pool = gen_pool_create(12, -1);
carveout_heap->base = heap_data->base;               //系统保留的物理地址base=0x91800000 
// 向内存池中加入内存块,起始地址base=0x918000000,size=0x50000000=80M
gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size, -1);
carveout_heap->heap.ops = &carveout_heap_ops;
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->heap.allocated_size = 0;
carveout_heap->heap.max_allocated = 0;
carveout_heap->heap.total_size = heap_data->size;    // size=0x5000000=80M
//内存的映射位图: 每个bit代表1个PAGE
carveout_heap->bit_nr = heap_data->size/(PAGE_SIZE * sizeof(unsigned long) * 8);  
carveout_heap->bits =  (unsigned long *)kzalloc(carveout_heap->bit_nr * sizeof(unsigned long), GFP_KERNEL);

return &carveout_heap->heap;

}
rockchip_ion_probe
–> ion_device_add_heap
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
{
struct rb_node **p = &dev->heaps.rb_node;
struct rb_node *parent = NULL;
struct ion_heap *entry;

heap->dev = dev;
mutex_lock(&dev->lock);
while (*p) {
    parent = *p;
    entry = rb_entry(parent, struct ion_heap, node);

    if (heap->id < entry->id) {
        p = &(*p)->rb_left;
    } else if (heap->id > entry->id ) {
        p = &(*p)->rb_right;
    } else {
        pr_err("%s: can not insert multiple heaps with id %d\n", __func__, heap->id);
        goto end;
    }
}

rb_link_node(&heap->node, parent, p);
rb_insert_color(&heap->node, &dev->heaps);
debugfs_create_file(heap->name, 0664, dev->debug_root, heap, &debug_heap_fops);

end:
mutex_unlock(&dev->lock);
}

三. ION分配内存的过程
drivers/gpu/ion/ion.c –> ion_ioctl //cmd=0xc0104900 接收到命令:ION_IOC_ALLOC
–> ion_alloc
–> ion_carveout_heap_allocate
–> drivers/gpu/ion/ion_carveout_heap.c 调用 ion_carveout_allocate[47]:
static int ion_carveout_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer, unsigned long size, unsigned long align, unsigned long flags)
{
buffer->priv_phys = ion_carveout_allocate(heap, size, align); //buffer->priv_phy=0x91a00000是物理地址
return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0;
}
ion_carveout_heap_allocate
–> ion_carveout_allocate
在drivers/gpu/ion/ion_carverout_heap.c中
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size, unsigned long align)
{
struct ion_carveout_heap *carveout_heap = container_of(heap, struct ion_carveout_heap, heap);
unsigned long offset = gen_pool_alloc(carveout_heap->pool, size); //offset=0x91a00000,是物理地址

heap->allocated_size += size;     //统计己分配的大小
//防止越界
if((offset + size - carveout_heap->base) > heap->max_allocated)
    heap->max_allocated = offset + size - carveout_heap->base;
//填充位图
bitmap_set(carveout_heap->bits, (offset - carveout_heap->base)/PAGE_SIZE , size/PAGE_SIZE);
return offset;

}
原理很简单:
就是在位图中查找适合的大小,然后把位图所代表的地址返回 (怎么有点表达不清楚了??? 反正就这个意思,呵呵)
ion_carveout_heap_allocate
–> ion_carveout_allocate
–> gen_pool_alloc
在lib/genalloc.c中
unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
{
struct list_head *_chunk;
struct gen_pool_chunk *chunk;
unsigned long addr, flags;
int order = pool->min_alloc_order;
int nbits, start_bit, end_bit;

if (size == 0)
    return 0;

nbits = (size + (1UL << order) - 1) >> order;  //由字节转成块,转成位图所代表的大小

read_lock(&pool->lock);
list_for_each(_chunk, &pool->chunks) {
    chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);

    end_bit = (chunk->end_addr - chunk->start_addr) >> order;  

    spin_lock_irqsave(&chunk->lock, flags);
    //在这个内存位图中查找足够大的内存
    start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, 0, nbits, 0);
    if (start_bit >= end_bit) { 
        spin_unlock_irqrestore(&chunk->lock, flags);
        continue;
    }
    //由位图映射到实际的地址
    addr = chunk->start_addr + ((unsigned long)start_bit << order);
    //填充位图,说明这块内存地方己分配
    bitmap_set(chunk->bits, start_bit, nbits);
    spin_unlock_irqrestore(&chunk->lock, flags);
    read_unlock(&pool->lock);
    return addr;   //返回地址
}
read_unlock(&pool->lock);
return 0;

}
EXPORT_SYMBOL(gen_pool_alloc);

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值