273 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCI Endpoint *Controller* Address Space Management4 *5 * Copyright (C) 2017 Texas Instruments6 * 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 size17 * @mem: address space of the endpoint controller18 * @size: the size for which to get the order19 *20 * Reimplement get_order() for mem->page_size since the generic get_order21 * 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 == 3231 order = fls(size);32#else33 order = fls64(size);34#endif35 return order;36}37 38/**39 * pci_epc_multi_mem_init() - initialize the pci_epc_mem structure40 * @epc: the EPC device that invoked pci_epc_mem_init41 * @windows: pointer to windows supported by the device42 * @num_windows: number of windows device supports43 *44 * Invoke to initialize the pci_epc_mem structure used by the45 * 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 118/**119 * pci_epc_mem_init() - Initialize the pci_epc_mem structure120 * @epc: the EPC device that invoked pci_epc_mem_init121 * @base: Physical address of the window region122 * @size: Total Size of the window region123 * @page_size: Page size of the window region124 *125 * Invoke to initialize a single pci_epc_mem structure used by the126 * endpoint functions to allocate memory for mapping the PCI host memory127 */128int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,129 size_t size, size_t page_size)130{131 struct pci_epc_mem_window mem_window;132 133 mem_window.phys_base = base;134 mem_window.size = size;135 mem_window.page_size = page_size;136 137 return pci_epc_multi_mem_init(epc, &mem_window, 1);138}139EXPORT_SYMBOL_GPL(pci_epc_mem_init);140 141/**142 * pci_epc_mem_exit() - cleanup the pci_epc_mem structure143 * @epc: the EPC device that invoked pci_epc_mem_exit144 *145 * Invoke to cleanup the pci_epc_mem structure allocated in146 * pci_epc_mem_init().147 */148void pci_epc_mem_exit(struct pci_epc *epc)149{150 struct pci_epc_mem *mem;151 int i;152 153 if (!epc->num_windows)154 return;155 156 for (i = 0; i < epc->num_windows; i++) {157 mem = epc->windows[i];158 kfree(mem->bitmap);159 kfree(mem);160 }161 kfree(epc->windows);162 163 epc->windows = NULL;164 epc->mem = NULL;165 epc->num_windows = 0;166}167EXPORT_SYMBOL_GPL(pci_epc_mem_exit);168 169/**170 * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space171 * @epc: the EPC device on which memory has to be allocated172 * @phys_addr: populate the allocated physical address here173 * @size: the size of the address space that has to be allocated174 *175 * Invoke to allocate memory address from the EPC address space. This176 * is usually done to map the remote RC address into the local system.177 */178void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,179 phys_addr_t *phys_addr, size_t size)180{181 void __iomem *virt_addr = NULL;182 struct pci_epc_mem *mem;183 unsigned int page_shift;184 size_t align_size;185 int pageno;186 int order;187 int i;188 189 for (i = 0; i < epc->num_windows; i++) {190 mem = epc->windows[i];191 mutex_lock(&mem->lock);192 align_size = ALIGN(size, mem->window.page_size);193 order = pci_epc_mem_get_order(mem, align_size);194 195 pageno = bitmap_find_free_region(mem->bitmap, mem->pages,196 order);197 if (pageno >= 0) {198 page_shift = ilog2(mem->window.page_size);199 *phys_addr = mem->window.phys_base +200 ((phys_addr_t)pageno << page_shift);201 virt_addr = ioremap(*phys_addr, align_size);202 if (!virt_addr) {203 bitmap_release_region(mem->bitmap,204 pageno, order);205 mutex_unlock(&mem->lock);206 continue;207 }208 mutex_unlock(&mem->lock);209 return virt_addr;210 }211 mutex_unlock(&mem->lock);212 }213 214 return virt_addr;215}216EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);217 218static struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc,219 phys_addr_t phys_addr)220{221 struct pci_epc_mem *mem;222 int i;223 224 for (i = 0; i < epc->num_windows; i++) {225 mem = epc->windows[i];226 227 if (phys_addr >= mem->window.phys_base &&228 phys_addr < (mem->window.phys_base + mem->window.size))229 return mem;230 }231 232 return NULL;233}234 235/**236 * pci_epc_mem_free_addr() - free the allocated memory address237 * @epc: the EPC device on which memory was allocated238 * @phys_addr: the allocated physical address239 * @virt_addr: virtual address of the allocated mem space240 * @size: the size of the allocated address space241 *242 * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.243 */244void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,245 void __iomem *virt_addr, size_t size)246{247 struct pci_epc_mem *mem;248 unsigned int page_shift;249 size_t page_size;250 int pageno;251 int order;252 253 mem = pci_epc_get_matching_window(epc, phys_addr);254 if (!mem) {255 pr_err("failed to get matching window\n");256 return;257 }258 259 page_size = mem->window.page_size;260 page_shift = ilog2(page_size);261 iounmap(virt_addr);262 pageno = (phys_addr - mem->window.phys_base) >> page_shift;263 size = ALIGN(size, page_size);264 order = pci_epc_mem_get_order(mem, size);265 mutex_lock(&mem->lock);266 bitmap_release_region(mem->bitmap, pageno, order);267 mutex_unlock(&mem->lock);268}269EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);270 271MODULE_DESCRIPTION("PCI EPC Address Space Management");272MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");273