linux/drivers/pci/endpoint/pci-epc-mem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/**
   3 * PCI Endpoint *Controller* Address Space Management
   4 *
   5 * Copyright (C) 2017 Texas Instruments
   6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
   7 */
   8
   9#include <linux/io.h>
  10#include <linux/module.h>
  11#include <linux/slab.h>
  12
  13#include <linux/pci-epc.h>
  14
  15/**
  16 * pci_epc_mem_get_order() - determine the allocation order of a memory size
  17 * @mem: address space of the endpoint controller
  18 * @size: the size for which to get the order
  19 *
  20 * Reimplement get_order() for mem->page_size since the generic get_order
  21 * always gets order with a constant PAGE_SIZE.
  22 */
  23static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
  24{
  25        int order;
  26        unsigned int page_shift = ilog2(mem->page_size);
  27
  28        size--;
  29        size >>= page_shift;
  30#if BITS_PER_LONG == 32
  31        order = fls(size);
  32#else
  33        order = fls64(size);
  34#endif
  35        return order;
  36}
  37
  38/**
  39 * __pci_epc_mem_init() - initialize the pci_epc_mem structure
  40 * @epc: the EPC device that invoked pci_epc_mem_init
  41 * @phys_base: the physical address of the base
  42 * @size: the size of the address space
  43 * @page_size: size of each page
  44 *
  45 * Invoke to initialize the pci_epc_mem structure used by the
  46 * endpoint functions to allocate mapped PCI address.
  47 */
  48int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size,
  49                       size_t page_size)
  50{
  51        int ret;
  52        struct pci_epc_mem *mem;
  53        unsigned long *bitmap;
  54        unsigned int page_shift;
  55        int pages;
  56        int bitmap_size;
  57
  58        if (page_size < PAGE_SIZE)
  59                page_size = PAGE_SIZE;
  60
  61        page_shift = ilog2(page_size);
  62        pages = size >> page_shift;
  63        bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
  64
  65        mem = kzalloc(sizeof(*mem), GFP_KERNEL);
  66        if (!mem) {
  67                ret = -ENOMEM;
  68                goto err;
  69        }
  70
  71        bitmap = kzalloc(bitmap_size, GFP_KERNEL);
  72        if (!bitmap) {
  73                ret = -ENOMEM;
  74                goto err_mem;
  75        }
  76
  77        mem->bitmap = bitmap;
  78        mem->phys_base = phys_base;
  79        mem->page_size = page_size;
  80        mem->pages = pages;
  81        mem->size = size;
  82
  83        epc->mem = mem;
  84
  85        return 0;
  86
  87err_mem:
  88        kfree(mem);
  89
  90err:
  91return ret;
  92}
  93EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
  94
  95/**
  96 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
  97 * @epc: the EPC device that invoked pci_epc_mem_exit
  98 *
  99 * Invoke to cleanup the pci_epc_mem structure allocated in
 100 * pci_epc_mem_init().
 101 */
 102void pci_epc_mem_exit(struct pci_epc *epc)
 103{
 104        struct pci_epc_mem *mem = epc->mem;
 105
 106        epc->mem = NULL;
 107        kfree(mem->bitmap);
 108        kfree(mem);
 109}
 110EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
 111
 112/**
 113 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
 114 * @epc: the EPC device on which memory has to be allocated
 115 * @phys_addr: populate the allocated physical address here
 116 * @size: the size of the address space that has to be allocated
 117 *
 118 * Invoke to allocate memory address from the EPC address space. This
 119 * is usually done to map the remote RC address into the local system.
 120 */
 121void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 122                                     phys_addr_t *phys_addr, size_t size)
 123{
 124        int pageno;
 125        void __iomem *virt_addr;
 126        struct pci_epc_mem *mem = epc->mem;
 127        unsigned int page_shift = ilog2(mem->page_size);
 128        int order;
 129
 130        size = ALIGN(size, mem->page_size);
 131        order = pci_epc_mem_get_order(mem, size);
 132
 133        pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
 134        if (pageno < 0)
 135                return NULL;
 136
 137        *phys_addr = mem->phys_base + (pageno << page_shift);
 138        virt_addr = ioremap(*phys_addr, size);
 139        if (!virt_addr)
 140                bitmap_release_region(mem->bitmap, pageno, order);
 141
 142        return virt_addr;
 143}
 144EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
 145
 146/**
 147 * pci_epc_mem_free_addr() - free the allocated memory address
 148 * @epc: the EPC device on which memory was allocated
 149 * @phys_addr: the allocated physical address
 150 * @virt_addr: virtual address of the allocated mem space
 151 * @size: the size of the allocated address space
 152 *
 153 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
 154 */
 155void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 156                           void __iomem *virt_addr, size_t size)
 157{
 158        int pageno;
 159        struct pci_epc_mem *mem = epc->mem;
 160        unsigned int page_shift = ilog2(mem->page_size);
 161        int order;
 162
 163        iounmap(virt_addr);
 164        pageno = (phys_addr - mem->phys_base) >> page_shift;
 165        size = ALIGN(size, mem->page_size);
 166        order = pci_epc_mem_get_order(mem, size);
 167        bitmap_release_region(mem->bitmap, pageno, order);
 168}
 169EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
 170
 171MODULE_DESCRIPTION("PCI EPC Address Space Management");
 172MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
 173MODULE_LICENSE("GPL v2");
 174