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->window.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_multi_mem_init() - initialize the pci_epc_mem structure
  40 * @epc: the EPC device that invoked pci_epc_mem_init
  41 * @windows: pointer to windows supported by the device
  42 * @num_windows: number of windows device supports
  43 *
  44 * Invoke to initialize the pci_epc_mem structure used by the
  45 * endpoint functions to allocate mapped PCI address.
  46 */
  47int pci_epc_multi_mem_init(struct pci_epc *epc,
  48                           struct pci_epc_mem_window *windows,
  49                           unsigned int num_windows)
  50{
  51        struct pci_epc_mem *mem = NULL;
  52        unsigned long *bitmap = NULL;
  53        unsigned int page_shift;
  54        size_t page_size;
  55        int bitmap_size;
  56        int pages;
  57        int ret;
  58        int i;
  59
  60        epc->num_windows = 0;
  61
  62        if (!windows || !num_windows)
  63                return -EINVAL;
  64
  65        epc->windows = kcalloc(num_windows, sizeof(*epc->windows), GFP_KERNEL);
  66        if (!epc->windows)
  67                return -ENOMEM;
  68
  69        for (i = 0; i < num_windows; i++) {
  70                page_size = windows[i].page_size;
  71                if (page_size < PAGE_SIZE)
  72                        page_size = PAGE_SIZE;
  73                page_shift = ilog2(page_size);
  74                pages = windows[i].size >> page_shift;
  75                bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
  76
  77                mem = kzalloc(sizeof(*mem), GFP_KERNEL);
  78                if (!mem) {
  79                        ret = -ENOMEM;
  80                        i--;
  81                        goto err_mem;
  82                }
  83
  84                bitmap = kzalloc(bitmap_size, GFP_KERNEL);
  85                if (!bitmap) {
  86                        ret = -ENOMEM;
  87                        kfree(mem);
  88                        i--;
  89                        goto err_mem;
  90                }
  91
  92                mem->window.phys_base = windows[i].phys_base;
  93                mem->window.size = windows[i].size;
  94                mem->window.page_size = page_size;
  95                mem->bitmap = bitmap;
  96                mem->pages = pages;
  97                mutex_init(&mem->lock);
  98                epc->windows[i] = mem;
  99        }
 100
 101        epc->mem = epc->windows[0];
 102        epc->num_windows = num_windows;
 103
 104        return 0;
 105
 106err_mem:
 107        for (; i >= 0; i--) {
 108                mem = epc->windows[i];
 109                kfree(mem->bitmap);
 110                kfree(mem);
 111        }
 112        kfree(epc->windows);
 113
 114        return ret;
 115}
 116EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init);
 117
 118int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
 119                     size_t size, size_t page_size)
 120{
 121        struct pci_epc_mem_window mem_window;
 122
 123        mem_window.phys_base = base;
 124        mem_window.size = size;
 125        mem_window.page_size = page_size;
 126
 127        return pci_epc_multi_mem_init(epc, &mem_window, 1);
 128}
 129EXPORT_SYMBOL_GPL(pci_epc_mem_init);
 130
 131/**
 132 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
 133 * @epc: the EPC device that invoked pci_epc_mem_exit
 134 *
 135 * Invoke to cleanup the pci_epc_mem structure allocated in
 136 * pci_epc_mem_init().
 137 */
 138void pci_epc_mem_exit(struct pci_epc *epc)
 139{
 140        struct pci_epc_mem *mem;
 141        int i;
 142
 143        if (!epc->num_windows)
 144                return;
 145
 146        for (i = 0; i < epc->num_windows; i++) {
 147                mem = epc->windows[i];
 148                kfree(mem->bitmap);
 149                kfree(mem);
 150        }
 151        kfree(epc->windows);
 152
 153        epc->windows = NULL;
 154        epc->mem = NULL;
 155        epc->num_windows = 0;
 156}
 157EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
 158
 159/**
 160 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
 161 * @epc: the EPC device on which memory has to be allocated
 162 * @phys_addr: populate the allocated physical address here
 163 * @size: the size of the address space that has to be allocated
 164 *
 165 * Invoke to allocate memory address from the EPC address space. This
 166 * is usually done to map the remote RC address into the local system.
 167 */
 168void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 169                                     phys_addr_t *phys_addr, size_t size)
 170{
 171        void __iomem *virt_addr = NULL;
 172        struct pci_epc_mem *mem;
 173        unsigned int page_shift;
 174        size_t align_size;
 175        int pageno;
 176        int order;
 177        int i;
 178
 179        for (i = 0; i < epc->num_windows; i++) {
 180                mem = epc->windows[i];
 181                mutex_lock(&mem->lock);
 182                align_size = ALIGN(size, mem->window.page_size);
 183                order = pci_epc_mem_get_order(mem, align_size);
 184
 185                pageno = bitmap_find_free_region(mem->bitmap, mem->pages,
 186                                                 order);
 187                if (pageno >= 0) {
 188                        page_shift = ilog2(mem->window.page_size);
 189                        *phys_addr = mem->window.phys_base +
 190                                ((phys_addr_t)pageno << page_shift);
 191                        virt_addr = ioremap(*phys_addr, align_size);
 192                        if (!virt_addr) {
 193                                bitmap_release_region(mem->bitmap,
 194                                                      pageno, order);
 195                                mutex_unlock(&mem->lock);
 196                                continue;
 197                        }
 198                        mutex_unlock(&mem->lock);
 199                        return virt_addr;
 200                }
 201                mutex_unlock(&mem->lock);
 202        }
 203
 204        return virt_addr;
 205}
 206EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
 207
 208static struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc,
 209                                                       phys_addr_t phys_addr)
 210{
 211        struct pci_epc_mem *mem;
 212        int i;
 213
 214        for (i = 0; i < epc->num_windows; i++) {
 215                mem = epc->windows[i];
 216
 217                if (phys_addr >= mem->window.phys_base &&
 218                    phys_addr < (mem->window.phys_base + mem->window.size))
 219                        return mem;
 220        }
 221
 222        return NULL;
 223}
 224
 225/**
 226 * pci_epc_mem_free_addr() - free the allocated memory address
 227 * @epc: the EPC device on which memory was allocated
 228 * @phys_addr: the allocated physical address
 229 * @virt_addr: virtual address of the allocated mem space
 230 * @size: the size of the allocated address space
 231 *
 232 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
 233 */
 234void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 235                           void __iomem *virt_addr, size_t size)
 236{
 237        struct pci_epc_mem *mem;
 238        unsigned int page_shift;
 239        size_t page_size;
 240        int pageno;
 241        int order;
 242
 243        mem = pci_epc_get_matching_window(epc, phys_addr);
 244        if (!mem) {
 245                pr_err("failed to get matching window\n");
 246                return;
 247        }
 248
 249        page_size = mem->window.page_size;
 250        page_shift = ilog2(page_size);
 251        iounmap(virt_addr);
 252        pageno = (phys_addr - mem->window.phys_base) >> page_shift;
 253        size = ALIGN(size, page_size);
 254        order = pci_epc_mem_get_order(mem, size);
 255        mutex_lock(&mem->lock);
 256        bitmap_release_region(mem->bitmap, pageno, order);
 257        mutex_unlock(&mem->lock);
 258}
 259EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
 260
 261MODULE_DESCRIPTION("PCI EPC Address Space Management");
 262MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
 263MODULE_LICENSE("GPL v2");
 264