Hi Kishon, Thank you for the review. On Fri, Apr 24, 2020 at 7:13 AM Kishon Vijay Abraham I <kishon@xxxxxx> wrote: > > Hi Prabhakar, > > On 4/23/2020 11:52 PM, Lad Prabhakar wrote: > > R-Car PCIe controller has support to map multiple memory regions for > > mapping the outbound memory in local system also the controller limits > > single allocation for each region (that is, once a chunk is used from the > > region it cannot be used to allocate a new one). This features inspires to > > add support for handling multiple memory bases in endpoint framework. > > > > With this patch pci_epc_mem_init() initializes address space for endpoint > > controller which support single window and pci_epc_multi_mem_init() > > initializes multiple windows supported by endpoint controller. > > Have a couple of clean-up comments. See below. > > > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> > > --- > > .../pci/controller/dwc/pcie-designware-ep.c | 16 +- > > drivers/pci/endpoint/pci-epc-mem.c | 199 ++++++++++++------ > > include/linux/pci-epc.h | 33 ++- > > 3 files changed, 170 insertions(+), 78 deletions(-) > > > . > . > <snip> > . > . > > diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c > > index cdd1d3821249..a3466da2a16f 100644 > > --- a/drivers/pci/endpoint/pci-epc-mem.c > > +++ b/drivers/pci/endpoint/pci-epc-mem.c > > @@ -23,7 +23,7 @@ > > 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); > > + unsigned int page_shift = ilog2(mem->window.page_size); > > > > size--; > > size >>= page_shift; > > @@ -36,67 +36,95 @@ static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) > > } > > > > /** > > - * __pci_epc_mem_init() - initialize the pci_epc_mem structure > > + * pci_epc_multi_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 > > + * @windows: pointer to windows supported by the device > > + * @num_windows: number of windows device supports > > * > > * 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, > > - size_t page_size) > > +int pci_epc_multi_mem_init(struct pci_epc *epc, > > + struct pci_epc_mem_window *windows, > > + unsigned int num_windows) > > { > > - int ret; > > - struct pci_epc_mem *mem; > > - unsigned long *bitmap; > > + struct pci_epc_mem *mem = NULL; > > + unsigned long *bitmap = NULL; > > unsigned int page_shift; > > - int pages; > > + size_t page_size; > > int bitmap_size; > > + int pages; > > + int ret; > > + int i; > > > > - if (page_size < PAGE_SIZE) > > - page_size = PAGE_SIZE; > > + epc->num_windows = 0; > > > > - page_shift = ilog2(page_size); > > - pages = size >> page_shift; > > - bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); > > + if (!windows || !num_windows) > > + return -EINVAL; > > > > - mem = kzalloc(sizeof(*mem), GFP_KERNEL); > > - if (!mem) { > > - ret = -ENOMEM; > > - goto err; > > - } > > + epc->windows = kcalloc(num_windows, sizeof(*mem), GFP_KERNEL); > > + if (!epc->windows) > > + return -ENOMEM; > > > > - bitmap = kzalloc(bitmap_size, GFP_KERNEL); > > - if (!bitmap) { > > - ret = -ENOMEM; > > - goto err_mem; > > - } > > + for (i = 0; i < num_windows; i++) { > > + page_size = windows[i].page_size; > > + if (page_size < PAGE_SIZE) > > + page_size = PAGE_SIZE; > > + page_shift = ilog2(page_size); > > + pages = windows[i].size >> page_shift; > > + bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); > > > > - mem->bitmap = bitmap; > > - mem->phys_base = phys_base; > > - mem->page_size = page_size; > > - mem->pages = pages; > > - mem->size = size; > > - mutex_init(&mem->lock); > > + mem = kzalloc(sizeof(*mem), GFP_KERNEL); > > + if (!mem) { > > + ret = -ENOMEM; > > + i--; > > + goto err_mem; > > + } > > > > - epc->mem = mem; > > + bitmap = kzalloc(bitmap_size, GFP_KERNEL); > > + if (!bitmap) { > > + ret = -ENOMEM; > > + kfree(mem); > > + i--; > > + goto err_mem; > > + } > > + > > + mem->window.phys_base = windows[i].phys_base; > > + mem->window.size = windows[i].size; > > + mem->window.page_size = page_size; > > + mem->bitmap = bitmap; > > + mem->pages = pages; > > + mutex_init(&mem->lock); > > + epc->windows[i] = mem; > > + } > > + > > + epc->mem = epc->windows[0]; > > "mem" member of EPC looks unnecessary since that value is available at > epc->windows[0]. This was suggested by Shimoda-san, as most of the current controller drivers support single region this pointer would be easier to access the region instead of adding #define EPC_DEFAULT_WINDOW 0 and accessing as epc->windows[EPC_DEFAULT_WINDOW]; > > + epc->num_windows = num_windows; > > > > return 0; > > > > err_mem: > > - kfree(mem); > > + for (; i >= 0; i--) { > > + mem = epc->windows[i]; > > + kfree(mem->bitmap); > > + kfree(mem); > > + } > > + kfree(epc->windows); > > > > -err: > > -return ret; > > + return ret; > > } > > -EXPORT_SYMBOL_GPL(__pci_epc_mem_init); > > +EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init); > > > > int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base, > > size_t size, size_t page_size) > > { > > - return __pci_epc_mem_init(epc, base, size, page_size); > > + struct pci_epc_mem_window mem_window; > > + > > + mem_window.phys_base = base; > > + mem_window.size = size; > > + mem_window.page_size = page_size; > > + > > + return pci_epc_multi_mem_init(epc, &mem_window, 1); > > } > > EXPORT_SYMBOL_GPL(pci_epc_mem_init); > > > > @@ -109,11 +137,22 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_init); > > */ > > void pci_epc_mem_exit(struct pci_epc *epc) > > { > > - struct pci_epc_mem *mem = epc->mem; > > + struct pci_epc_mem *mem; > > + int i; > > > > + if (!epc->num_windows) > > + return; > > + > > + for (i = 0; i < epc->num_windows; i++) { > > + mem = epc->windows[i]; > > + kfree(mem->bitmap); > > + kfree(mem); > > + } > > + kfree(epc->windows); > > + > > + epc->windows = NULL; > > epc->mem = NULL; > > - kfree(mem->bitmap); > > - kfree(mem); > > + epc->num_windows = 0; > > } > > EXPORT_SYMBOL_GPL(pci_epc_mem_exit); > > > > @@ -129,31 +168,60 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_exit); > > void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, > > phys_addr_t *phys_addr, size_t size) > > { > > - int pageno; > > void __iomem *virt_addr = NULL; > > - struct pci_epc_mem *mem = epc->mem; > > - unsigned int page_shift = ilog2(mem->page_size); > > + struct pci_epc_mem *mem; > > + unsigned int page_shift; > > + size_t align_size; > > + int pageno; > > int order; > > + int i; > > > > - size = ALIGN(size, mem->page_size); > > - order = pci_epc_mem_get_order(mem, size); > > - > > - mutex_lock(&mem->lock); > > - pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); > > - if (pageno < 0) > > - goto ret; > > + for (i = 0; i < epc->num_windows; i++) { > > + mem = epc->windows[i]; > > + mutex_lock(&mem->lock); > > + align_size = ALIGN(size, mem->window.page_size); > > + order = pci_epc_mem_get_order(mem, align_size); > > > > - *phys_addr = mem->phys_base + ((phys_addr_t)pageno << page_shift); > > - virt_addr = ioremap(*phys_addr, size); > > - if (!virt_addr) > > - bitmap_release_region(mem->bitmap, pageno, order); > > + pageno = bitmap_find_free_region(mem->bitmap, mem->pages, > > + order); > > + if (pageno >= 0) { > > + page_shift = ilog2(mem->window.page_size); > > + *phys_addr = mem->window.phys_base + > > + ((phys_addr_t)pageno << page_shift); > > + virt_addr = ioremap(*phys_addr, align_size); > > + if (!virt_addr) { > > + bitmap_release_region(mem->bitmap, > > + pageno, order); > > + mutex_unlock(&mem->lock); > > + continue; > > + } > > + mutex_unlock(&mem->lock); > > + return virt_addr; > > + } > > + mutex_unlock(&mem->lock); > > + } > > > > -ret: > > - mutex_unlock(&mem->lock); > > return virt_addr; > > } > > EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); > > > > +struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc, > > + phys_addr_t phys_addr) > > +{ > > + struct pci_epc_mem *mem; > > + int i; > > + > > + for (i = 0; i < epc->num_windows; i++) { > > + mem = epc->windows[i]; > > + > > + if (phys_addr >= mem->window.phys_base && > > + phys_addr < (mem->window.phys_base + mem->window.size)) > > + return mem; > > + } > > + > > + return NULL; > > +} > > + > > /** > > * pci_epc_mem_free_addr() - free the allocated memory address > > * @epc: the EPC device on which memory was allocated > > @@ -166,14 +234,23 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); > > void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, > > void __iomem *virt_addr, size_t size) > > { > > + struct pci_epc_mem *mem; > > + unsigned int page_shift; > > + size_t page_size; > > int pageno; > > - struct pci_epc_mem *mem = epc->mem; > > - unsigned int page_shift = ilog2(mem->page_size); > > int order; > > > > + mem = pci_epc_get_matching_window(epc, phys_addr); > > + if (!mem) { > > + pr_err("failed to get matching window\n"); > > + return; > > + } > > + > > + page_size = mem->window.page_size; > > + page_shift = ilog2(page_size); > > iounmap(virt_addr); > > - pageno = (phys_addr - mem->phys_base) >> page_shift; > > - size = ALIGN(size, mem->page_size); > > + pageno = (phys_addr - mem->window.phys_base) >> page_shift; > > + size = ALIGN(size, page_size); > > order = pci_epc_mem_get_order(mem, size); > > mutex_lock(&mem->lock); > > bitmap_release_region(mem->bitmap, pageno, order); > > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h > > index 5bc1de65849e..cc66bec8be90 100644 > > --- a/include/linux/pci-epc.h > > +++ b/include/linux/pci-epc.h > > @@ -65,20 +65,28 @@ struct pci_epc_ops { > > struct module *owner; > > }; > > > > +/** > > + * struct pci_epc_mem_window - address window of the endpoint controller > > + * @phys_base: physical base address of the PCI address window > > + * @size: the size of the PCI address window > > + * @page_size: size of each page > > + */ > > +struct pci_epc_mem_window { > > + phys_addr_t phys_base; > > + size_t size; > > + size_t page_size; > > +}; > > + > > /** > > * struct pci_epc_mem - address space of the endpoint controller > > - * @phys_base: physical base address of the PCI address space > > - * @size: the size of the PCI address space > > + * @window: address window of the endpoint controller > > * @bitmap: bitmap to manage the PCI address space > > * @pages: number of bits representing the address region > > - * @page_size: size of each page > > * @lock: mutex to protect bitmap > > */ > > struct pci_epc_mem { > > - phys_addr_t phys_base; > > - size_t size; > > + struct pci_epc_mem_window window; > > Don't see any additional value in moving phys_base, size, page_size to a new > structure and again including it here. > Controllers supporting multiple windows create a list of supported regions (struct pci_epc_mem_window ) and pass a pointer to pci_epc_multi_mem_init(), hence this split. Cheers, --Prabhakar