root/drivers/pci/endpoint/pci-epc-mem.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pci_epc_mem_get_order
  2. __pci_epc_mem_init
  3. pci_epc_mem_exit
  4. pci_epc_mem_alloc_addr
  5. pci_epc_mem_free_addr

   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  */
  23 static 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  */
  48 int __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         mutex_init(&mem->lock);
  83 
  84         epc->mem = mem;
  85 
  86         return 0;
  87 
  88 err_mem:
  89         kfree(mem);
  90 
  91 err:
  92 return ret;
  93 }
  94 EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
  95 
  96 /**
  97  * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
  98  * @epc: the EPC device that invoked pci_epc_mem_exit
  99  *
 100  * Invoke to cleanup the pci_epc_mem structure allocated in
 101  * pci_epc_mem_init().
 102  */
 103 void pci_epc_mem_exit(struct pci_epc *epc)
 104 {
 105         struct pci_epc_mem *mem = epc->mem;
 106 
 107         epc->mem = NULL;
 108         kfree(mem->bitmap);
 109         kfree(mem);
 110 }
 111 EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
 112 
 113 /**
 114  * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
 115  * @epc: the EPC device on which memory has to be allocated
 116  * @phys_addr: populate the allocated physical address here
 117  * @size: the size of the address space that has to be allocated
 118  *
 119  * Invoke to allocate memory address from the EPC address space. This
 120  * is usually done to map the remote RC address into the local system.
 121  */
 122 void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 123                                      phys_addr_t *phys_addr, size_t size)
 124 {
 125         int pageno;
 126         void __iomem *virt_addr = NULL;
 127         struct pci_epc_mem *mem = epc->mem;
 128         unsigned int page_shift = ilog2(mem->page_size);
 129         int order;
 130 
 131         size = ALIGN(size, mem->page_size);
 132         order = pci_epc_mem_get_order(mem, size);
 133 
 134         mutex_lock(&mem->lock);
 135         pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
 136         if (pageno < 0)
 137                 goto ret;
 138 
 139         *phys_addr = mem->phys_base + (pageno << page_shift);
 140         virt_addr = ioremap(*phys_addr, size);
 141         if (!virt_addr)
 142                 bitmap_release_region(mem->bitmap, pageno, order);
 143 
 144 ret:
 145         mutex_unlock(&mem->lock);
 146         return virt_addr;
 147 }
 148 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
 149 
 150 /**
 151  * pci_epc_mem_free_addr() - free the allocated memory address
 152  * @epc: the EPC device on which memory was allocated
 153  * @phys_addr: the allocated physical address
 154  * @virt_addr: virtual address of the allocated mem space
 155  * @size: the size of the allocated address space
 156  *
 157  * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
 158  */
 159 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 160                            void __iomem *virt_addr, size_t size)
 161 {
 162         int pageno;
 163         struct pci_epc_mem *mem = epc->mem;
 164         unsigned int page_shift = ilog2(mem->page_size);
 165         int order;
 166 
 167         iounmap(virt_addr);
 168         pageno = (phys_addr - mem->phys_base) >> page_shift;
 169         size = ALIGN(size, mem->page_size);
 170         order = pci_epc_mem_get_order(mem, size);
 171         mutex_lock(&mem->lock);
 172         bitmap_release_region(mem->bitmap, pageno, order);
 173         mutex_unlock(&mem->lock);
 174 }
 175 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
 176 
 177 MODULE_DESCRIPTION("PCI EPC Address Space Management");
 178 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
 179 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */