pci-epc-mem.c (6503B)
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");