Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCI Endpoint *Controller* Address Space Management
0004  *
0005  * Copyright (C) 2017 Texas Instruments
0006  * Author: Kishon Vijay Abraham I <kishon@ti.com>
0007  */
0008 
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 
0013 #include <linux/pci-epc.h>
0014 
0015 /**
0016  * pci_epc_mem_get_order() - determine the allocation order of a memory size
0017  * @mem: address space of the endpoint controller
0018  * @size: the size for which to get the order
0019  *
0020  * Reimplement get_order() for mem->page_size since the generic get_order
0021  * always gets order with a constant PAGE_SIZE.
0022  */
0023 static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
0024 {
0025     int order;
0026     unsigned int page_shift = ilog2(mem->window.page_size);
0027 
0028     size--;
0029     size >>= page_shift;
0030 #if BITS_PER_LONG == 32
0031     order = fls(size);
0032 #else
0033     order = fls64(size);
0034 #endif
0035     return order;
0036 }
0037 
0038 /**
0039  * pci_epc_multi_mem_init() - initialize the pci_epc_mem structure
0040  * @epc: the EPC device that invoked pci_epc_mem_init
0041  * @windows: pointer to windows supported by the device
0042  * @num_windows: number of windows device supports
0043  *
0044  * Invoke to initialize the pci_epc_mem structure used by the
0045  * endpoint functions to allocate mapped PCI address.
0046  */
0047 int pci_epc_multi_mem_init(struct pci_epc *epc,
0048                struct pci_epc_mem_window *windows,
0049                unsigned int num_windows)
0050 {
0051     struct pci_epc_mem *mem = NULL;
0052     unsigned long *bitmap = NULL;
0053     unsigned int page_shift;
0054     size_t page_size;
0055     int bitmap_size;
0056     int pages;
0057     int ret;
0058     int i;
0059 
0060     epc->num_windows = 0;
0061 
0062     if (!windows || !num_windows)
0063         return -EINVAL;
0064 
0065     epc->windows = kcalloc(num_windows, sizeof(*epc->windows), GFP_KERNEL);
0066     if (!epc->windows)
0067         return -ENOMEM;
0068 
0069     for (i = 0; i < num_windows; i++) {
0070         page_size = windows[i].page_size;
0071         if (page_size < PAGE_SIZE)
0072             page_size = PAGE_SIZE;
0073         page_shift = ilog2(page_size);
0074         pages = windows[i].size >> page_shift;
0075         bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
0076 
0077         mem = kzalloc(sizeof(*mem), GFP_KERNEL);
0078         if (!mem) {
0079             ret = -ENOMEM;
0080             i--;
0081             goto err_mem;
0082         }
0083 
0084         bitmap = kzalloc(bitmap_size, GFP_KERNEL);
0085         if (!bitmap) {
0086             ret = -ENOMEM;
0087             kfree(mem);
0088             i--;
0089             goto err_mem;
0090         }
0091 
0092         mem->window.phys_base = windows[i].phys_base;
0093         mem->window.size = windows[i].size;
0094         mem->window.page_size = page_size;
0095         mem->bitmap = bitmap;
0096         mem->pages = pages;
0097         mutex_init(&mem->lock);
0098         epc->windows[i] = mem;
0099     }
0100 
0101     epc->mem = epc->windows[0];
0102     epc->num_windows = num_windows;
0103 
0104     return 0;
0105 
0106 err_mem:
0107     for (; i >= 0; i--) {
0108         mem = epc->windows[i];
0109         kfree(mem->bitmap);
0110         kfree(mem);
0111     }
0112     kfree(epc->windows);
0113 
0114     return ret;
0115 }
0116 EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init);
0117 
0118 int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
0119              size_t size, size_t page_size)
0120 {
0121     struct pci_epc_mem_window mem_window;
0122 
0123     mem_window.phys_base = base;
0124     mem_window.size = size;
0125     mem_window.page_size = page_size;
0126 
0127     return pci_epc_multi_mem_init(epc, &mem_window, 1);
0128 }
0129 EXPORT_SYMBOL_GPL(pci_epc_mem_init);
0130 
0131 /**
0132  * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
0133  * @epc: the EPC device that invoked pci_epc_mem_exit
0134  *
0135  * Invoke to cleanup the pci_epc_mem structure allocated in
0136  * pci_epc_mem_init().
0137  */
0138 void pci_epc_mem_exit(struct pci_epc *epc)
0139 {
0140     struct pci_epc_mem *mem;
0141     int i;
0142 
0143     if (!epc->num_windows)
0144         return;
0145 
0146     for (i = 0; i < epc->num_windows; i++) {
0147         mem = epc->windows[i];
0148         kfree(mem->bitmap);
0149         kfree(mem);
0150     }
0151     kfree(epc->windows);
0152 
0153     epc->windows = NULL;
0154     epc->mem = NULL;
0155     epc->num_windows = 0;
0156 }
0157 EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
0158 
0159 /**
0160  * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space
0161  * @epc: the EPC device on which memory has to be allocated
0162  * @phys_addr: populate the allocated physical address here
0163  * @size: the size of the address space that has to be allocated
0164  *
0165  * Invoke to allocate memory address from the EPC address space. This
0166  * is usually done to map the remote RC address into the local system.
0167  */
0168 void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
0169                      phys_addr_t *phys_addr, size_t size)
0170 {
0171     void __iomem *virt_addr = NULL;
0172     struct pci_epc_mem *mem;
0173     unsigned int page_shift;
0174     size_t align_size;
0175     int pageno;
0176     int order;
0177     int i;
0178 
0179     for (i = 0; i < epc->num_windows; i++) {
0180         mem = epc->windows[i];
0181         mutex_lock(&mem->lock);
0182         align_size = ALIGN(size, mem->window.page_size);
0183         order = pci_epc_mem_get_order(mem, align_size);
0184 
0185         pageno = bitmap_find_free_region(mem->bitmap, mem->pages,
0186                          order);
0187         if (pageno >= 0) {
0188             page_shift = ilog2(mem->window.page_size);
0189             *phys_addr = mem->window.phys_base +
0190                 ((phys_addr_t)pageno << page_shift);
0191             virt_addr = ioremap(*phys_addr, align_size);
0192             if (!virt_addr) {
0193                 bitmap_release_region(mem->bitmap,
0194                               pageno, order);
0195                 mutex_unlock(&mem->lock);
0196                 continue;
0197             }
0198             mutex_unlock(&mem->lock);
0199             return virt_addr;
0200         }
0201         mutex_unlock(&mem->lock);
0202     }
0203 
0204     return virt_addr;
0205 }
0206 EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
0207 
0208 static struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc,
0209                                phys_addr_t phys_addr)
0210 {
0211     struct pci_epc_mem *mem;
0212     int i;
0213 
0214     for (i = 0; i < epc->num_windows; i++) {
0215         mem = epc->windows[i];
0216 
0217         if (phys_addr >= mem->window.phys_base &&
0218             phys_addr < (mem->window.phys_base + mem->window.size))
0219             return mem;
0220     }
0221 
0222     return NULL;
0223 }
0224 
0225 /**
0226  * pci_epc_mem_free_addr() - free the allocated memory address
0227  * @epc: the EPC device on which memory was allocated
0228  * @phys_addr: the allocated physical address
0229  * @virt_addr: virtual address of the allocated mem space
0230  * @size: the size of the allocated address space
0231  *
0232  * Invoke to free the memory allocated using pci_epc_mem_alloc_addr.
0233  */
0234 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
0235                void __iomem *virt_addr, size_t size)
0236 {
0237     struct pci_epc_mem *mem;
0238     unsigned int page_shift;
0239     size_t page_size;
0240     int pageno;
0241     int order;
0242 
0243     mem = pci_epc_get_matching_window(epc, phys_addr);
0244     if (!mem) {
0245         pr_err("failed to get matching window\n");
0246         return;
0247     }
0248 
0249     page_size = mem->window.page_size;
0250     page_shift = ilog2(page_size);
0251     iounmap(virt_addr);
0252     pageno = (phys_addr - mem->window.phys_base) >> page_shift;
0253     size = ALIGN(size, page_size);
0254     order = pci_epc_mem_get_order(mem, size);
0255     mutex_lock(&mem->lock);
0256     bitmap_release_region(mem->bitmap, pageno, order);
0257     mutex_unlock(&mem->lock);
0258 }
0259 EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
0260 
0261 MODULE_DESCRIPTION("PCI EPC Address Space Management");
0262 MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
0263 MODULE_LICENSE("GPL v2");