brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · a9c028f Raw
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