cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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");