PCI: endpoint: Add support for configurable page size
authorKishon Vijay Abraham I <kishon@ti.com>
Fri, 18 Aug 2017 14:57:56 +0000 (20:27 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 29 Aug 2017 21:00:37 +0000 (16:00 -0500)
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>
drivers/pci/endpoint/pci-epc-mem.c
include/linux/pci-epc.h

index 3a94cc1..83b7d5d 100644 (file)
 #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);
index af5edbf..f7a04e1 100644 (file)
@@ -62,11 +62,13 @@ struct pci_epc_ops {
  * @size: the size of the PCI address space
  * @bitmap: bitmap to manage the PCI address space
  * @pages: number of bits representing the address region
+ * @page_size: size of each page
  */
 struct pci_epc_mem {
        phys_addr_t     phys_base;
        size_t          size;
        unsigned long   *bitmap;
+       size_t          page_size;
        int             pages;
 };
 
@@ -98,6 +100,9 @@ struct pci_epc {
 #define devm_pci_epc_create(dev, ops)    \
                __devm_pci_epc_create((dev), (ops), THIS_MODULE)
 
+#define pci_epc_mem_init(epc, phys_addr, size) \
+               __pci_epc_mem_init((epc), (phys_addr), (size), PAGE_SIZE)
+
 static inline void epc_set_drvdata(struct pci_epc *epc, void *data)
 {
        dev_set_drvdata(&epc->dev, data);
@@ -135,7 +140,8 @@ void pci_epc_stop(struct pci_epc *epc);
 struct pci_epc *pci_epc_get(const char *epc_name);
 void pci_epc_put(struct pci_epc *epc);
 
-int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size);
+int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size,
+                      size_t page_size);
 void pci_epc_mem_exit(struct pci_epc *epc);
 void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
                                     phys_addr_t *phys_addr, size_t size);