linux/drivers/staging/android/ion/ion_carveout_heap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * drivers/staging/android/ion/ion_carveout_heap.c
   4 *
   5 * Copyright (C) 2011 Google, Inc.
   6 */
   7#include <linux/spinlock.h>
   8#include <linux/dma-mapping.h>
   9#include <linux/err.h>
  10#include <linux/genalloc.h>
  11#include <linux/io.h>
  12#include <linux/mm.h>
  13#include <linux/scatterlist.h>
  14#include <linux/slab.h>
  15#include <linux/vmalloc.h>
  16#include "ion.h"
  17
  18#define ION_CARVEOUT_ALLOCATE_FAIL      -1
  19
  20struct ion_carveout_heap {
  21        struct ion_heap heap;
  22        struct gen_pool *pool;
  23        phys_addr_t base;
  24};
  25
  26static phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
  27                                         unsigned long size)
  28{
  29        struct ion_carveout_heap *carveout_heap =
  30                container_of(heap, struct ion_carveout_heap, heap);
  31        unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);
  32
  33        if (!offset)
  34                return ION_CARVEOUT_ALLOCATE_FAIL;
  35
  36        return offset;
  37}
  38
  39static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr,
  40                              unsigned long size)
  41{
  42        struct ion_carveout_heap *carveout_heap =
  43                container_of(heap, struct ion_carveout_heap, heap);
  44
  45        if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
  46                return;
  47        gen_pool_free(carveout_heap->pool, addr, size);
  48}
  49
  50static int ion_carveout_heap_allocate(struct ion_heap *heap,
  51                                      struct ion_buffer *buffer,
  52                                      unsigned long size,
  53                                      unsigned long flags)
  54{
  55        struct sg_table *table;
  56        phys_addr_t paddr;
  57        int ret;
  58
  59        table = kmalloc(sizeof(*table), GFP_KERNEL);
  60        if (!table)
  61                return -ENOMEM;
  62        ret = sg_alloc_table(table, 1, GFP_KERNEL);
  63        if (ret)
  64                goto err_free;
  65
  66        paddr = ion_carveout_allocate(heap, size);
  67        if (paddr == ION_CARVEOUT_ALLOCATE_FAIL) {
  68                ret = -ENOMEM;
  69                goto err_free_table;
  70        }
  71
  72        sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
  73        buffer->sg_table = table;
  74
  75        return 0;
  76
  77err_free_table:
  78        sg_free_table(table);
  79err_free:
  80        kfree(table);
  81        return ret;
  82}
  83
  84static void ion_carveout_heap_free(struct ion_buffer *buffer)
  85{
  86        struct ion_heap *heap = buffer->heap;
  87        struct sg_table *table = buffer->sg_table;
  88        struct page *page = sg_page(table->sgl);
  89        phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
  90
  91        ion_heap_buffer_zero(buffer);
  92
  93        ion_carveout_free(heap, paddr, buffer->size);
  94        sg_free_table(table);
  95        kfree(table);
  96}
  97
  98static struct ion_heap_ops carveout_heap_ops = {
  99        .allocate = ion_carveout_heap_allocate,
 100        .free = ion_carveout_heap_free,
 101        .map_user = ion_heap_map_user,
 102        .map_kernel = ion_heap_map_kernel,
 103        .unmap_kernel = ion_heap_unmap_kernel,
 104};
 105
 106struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
 107{
 108        struct ion_carveout_heap *carveout_heap;
 109        int ret;
 110
 111        struct page *page;
 112        size_t size;
 113
 114        page = pfn_to_page(PFN_DOWN(heap_data->base));
 115        size = heap_data->size;
 116
 117        ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
 118        if (ret)
 119                return ERR_PTR(ret);
 120
 121        carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL);
 122        if (!carveout_heap)
 123                return ERR_PTR(-ENOMEM);
 124
 125        carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);
 126        if (!carveout_heap->pool) {
 127                kfree(carveout_heap);
 128                return ERR_PTR(-ENOMEM);
 129        }
 130        carveout_heap->base = heap_data->base;
 131        gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size,
 132                     -1);
 133        carveout_heap->heap.ops = &carveout_heap_ops;
 134        carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
 135        carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
 136
 137        return &carveout_heap->heap;
 138}
 139