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