diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2017-08-18 17:57:56 +0300 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-08-30 00:00:37 +0300 |
commit | 52c9285d47459cf241e144c7d8ef15941ba1b181 (patch) | |
tree | 2fb522bf05fb3227b9fba950ad9f31844afce158 /drivers/pci/endpoint | |
parent | 28daeff66990db85022c6a8b410e5b78dc78ff6a (diff) | |
download | linux-52c9285d47459cf241e144c7d8ef15941ba1b181.tar.xz |
PCI: endpoint: Add support for configurable page size
pci-epc-mem uses a page size equal to *PAGE_SIZE* (usually 4KB) to manage
the address space. However certain platforms like TI's K2G have a
restriction that this address space should be either divided into
1MB/2MB/4MB or 8MB sizes (Ref: 11.14.4.9.1 Outbound Address Translation in
K2G TRM SPRUHY8F January 2016 – Revised May 2017). Add support to handle
different page sizes here.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/endpoint')
-rw-r--r-- | drivers/pci/endpoint/pci-epc-mem.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index 3a94cc1caf22..83b7d5d3fc3e 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -24,21 +24,54 @@ #include <linux/pci-epc.h> /** - * pci_epc_mem_init() - initialize the pci_epc_mem structure + * pci_epc_mem_get_order() - determine the allocation order of a memory size + * @mem: address space of the endpoint controller + * @size: the size for which to get the order + * + * Reimplement get_order() for mem->page_size since the generic get_order + * always gets order with a constant PAGE_SIZE. + */ +static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) +{ + int order; + unsigned int page_shift = ilog2(mem->page_size); + + size--; + size >>= page_shift; +#if BITS_PER_LONG == 32 + order = fls(size); +#else + order = fls64(size); +#endif + return order; +} + +/** + * __pci_epc_mem_init() - initialize the pci_epc_mem structure * @epc: the EPC device that invoked pci_epc_mem_init * @phys_base: the physical address of the base * @size: the size of the address space + * @page_size: size of each page * * Invoke to initialize the pci_epc_mem structure used by the * endpoint functions to allocate mapped PCI address. */ -int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size) +int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size, + size_t page_size) { int ret; struct pci_epc_mem *mem; unsigned long *bitmap; - int pages = size >> PAGE_SHIFT; - int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); + unsigned int page_shift; + int pages; + int bitmap_size; + + if (page_size < PAGE_SIZE) + page_size = PAGE_SIZE; + + page_shift = ilog2(page_size); + pages = size >> page_shift; + bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) { @@ -54,6 +87,7 @@ int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size) mem->bitmap = bitmap; mem->phys_base = phys_base; + mem->page_size = page_size; mem->pages = pages; mem->size = size; @@ -67,7 +101,7 @@ err_mem: err: return ret; } -EXPORT_SYMBOL_GPL(pci_epc_mem_init); +EXPORT_SYMBOL_GPL(__pci_epc_mem_init); /** * pci_epc_mem_exit() - cleanup the pci_epc_mem structure @@ -101,13 +135,17 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, int pageno; void __iomem *virt_addr; struct pci_epc_mem *mem = epc->mem; - int order = get_order(size); + unsigned int page_shift = ilog2(mem->page_size); + int order; + + size = ALIGN(size, mem->page_size); + order = pci_epc_mem_get_order(mem, size); pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); if (pageno < 0) return NULL; - *phys_addr = mem->phys_base + (pageno << PAGE_SHIFT); + *phys_addr = mem->phys_base + (pageno << page_shift); virt_addr = ioremap(*phys_addr, size); if (!virt_addr) bitmap_release_region(mem->bitmap, pageno, order); @@ -129,11 +167,14 @@ void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, void __iomem *virt_addr, size_t size) { int pageno; - int order = get_order(size); struct pci_epc_mem *mem = epc->mem; + unsigned int page_shift = ilog2(mem->page_size); + int order; iounmap(virt_addr); - pageno = (phys_addr - mem->phys_base) >> PAGE_SHIFT; + pageno = (phys_addr - mem->phys_base) >> page_shift; + size = ALIGN(size, mem->page_size); + order = pci_epc_mem_get_order(mem, size); bitmap_release_region(mem->bitmap, pageno, order); } EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr); |