Commit d45e3c1a authored by Lad Prabhakar's avatar Lad Prabhakar Committed by Lorenzo Pieralisi

PCI: endpoint: Add support to handle multiple base for mapping outbound memory

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.

Link: https://lore.kernel.org/r/1588854799-13710-6-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.comSigned-off-by: default avatarLad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 975cf23e
...@@ -412,11 +412,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -412,11 +412,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
reg = ep->msi_cap + PCI_MSI_DATA_32; reg = ep->msi_cap + PCI_MSI_DATA_32;
msg_data = dw_pcie_readw_dbi(pci, reg); msg_data = dw_pcie_readw_dbi(pci, reg);
} }
aligned_offset = msg_addr_lower & (epc->mem->page_size - 1); aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr = ((u64)msg_addr_upper) << 32 |
(msg_addr_lower & ~aligned_offset); (msg_addr_lower & ~aligned_offset);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
epc->mem->page_size); epc->mem->window.page_size);
if (ret) if (ret)
return ret; return ret;
...@@ -459,9 +459,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -459,9 +459,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return -EPERM; return -EPERM;
} }
aligned_offset = msg_addr & (epc->mem->page_size - 1); aligned_offset = msg_addr & (epc->mem->window.page_size - 1);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
epc->mem->page_size); epc->mem->window.page_size);
if (ret) if (ret)
return ret; return ret;
...@@ -477,7 +477,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) ...@@ -477,7 +477,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
struct pci_epc *epc = ep->epc; struct pci_epc *epc = ep->epc;
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->page_size); epc->mem->window.page_size);
pci_epc_mem_exit(epc); pci_epc_mem_exit(epc);
} }
...@@ -610,15 +610,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ...@@ -610,15 +610,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ret < 0) if (ret < 0)
epc->max_functions = 1; epc->max_functions = 1;
ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
ep->page_size); ep->page_size);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to initialize address space\n"); dev_err(dev, "Failed to initialize address space\n");
return ret; return ret;
} }
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
epc->mem->page_size); epc->mem->window.page_size);
if (!ep->msi_mem) { if (!ep->msi_mem) {
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
{ {
int order; int order;
unsigned int page_shift = ilog2(mem->page_size); unsigned int page_shift = ilog2(mem->window.page_size);
size--; size--;
size >>= page_shift; size >>= page_shift;
...@@ -36,67 +36,95 @@ static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) ...@@ -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 * @epc: the EPC device that invoked pci_epc_mem_init
* @phys_base: the physical address of the base * @windows: pointer to windows supported by the device
* @size: the size of the address space * @num_windows: number of windows device supports
* @page_size: size of each page
* *
* Invoke to initialize the pci_epc_mem structure used by the * Invoke to initialize the pci_epc_mem structure used by the
* endpoint functions to allocate mapped PCI address. * 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_multi_mem_init(struct pci_epc *epc,
size_t page_size) struct pci_epc_mem_window *windows,
unsigned int num_windows)
{ {
int ret; struct pci_epc_mem *mem = NULL;
struct pci_epc_mem *mem; unsigned long *bitmap = NULL;
unsigned long *bitmap;
unsigned int page_shift; unsigned int page_shift;
int pages; size_t page_size;
int bitmap_size; int bitmap_size;
int pages;
int ret;
int i;
if (page_size < PAGE_SIZE) epc->num_windows = 0;
page_size = PAGE_SIZE;
page_shift = ilog2(page_size); if (!windows || !num_windows)
pages = size >> page_shift; return -EINVAL;
bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
mem = kzalloc(sizeof(*mem), GFP_KERNEL); epc->windows = kcalloc(num_windows, sizeof(*epc->windows), GFP_KERNEL);
if (!mem) { if (!epc->windows)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
bitmap = kzalloc(bitmap_size, GFP_KERNEL); for (i = 0; i < num_windows; i++) {
if (!bitmap) { page_size = windows[i].page_size;
ret = -ENOMEM; if (page_size < PAGE_SIZE)
goto err_mem; 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 = kzalloc(sizeof(*mem), GFP_KERNEL);
mem->phys_base = phys_base; if (!mem) {
mem->page_size = page_size; ret = -ENOMEM;
mem->pages = pages; i--;
mem->size = size; goto err_mem;
mutex_init(&mem->lock); }
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];
epc->num_windows = num_windows;
return 0; return 0;
err_mem: 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, int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
size_t size, size_t page_size) 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); EXPORT_SYMBOL_GPL(pci_epc_mem_init);
...@@ -109,11 +137,22 @@ 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) 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; epc->mem = NULL;
kfree(mem->bitmap); epc->num_windows = 0;
kfree(mem);
} }
EXPORT_SYMBOL_GPL(pci_epc_mem_exit); EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
...@@ -129,31 +168,60 @@ 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, void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size) phys_addr_t *phys_addr, size_t size)
{ {
int pageno;
void __iomem *virt_addr = NULL; void __iomem *virt_addr = NULL;
struct pci_epc_mem *mem = epc->mem; struct pci_epc_mem *mem;
unsigned int page_shift = ilog2(mem->page_size); unsigned int page_shift;
size_t align_size;
int pageno;
int order; int order;
int i;
size = ALIGN(size, mem->page_size); for (i = 0; i < epc->num_windows; i++) {
order = pci_epc_mem_get_order(mem, size); mem = epc->windows[i];
mutex_lock(&mem->lock);
mutex_lock(&mem->lock); align_size = ALIGN(size, mem->window.page_size);
pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); order = pci_epc_mem_get_order(mem, align_size);
if (pageno < 0)
goto ret;
*phys_addr = mem->phys_base + ((phys_addr_t)pageno << page_shift); pageno = bitmap_find_free_region(mem->bitmap, mem->pages,
virt_addr = ioremap(*phys_addr, size); order);
if (!virt_addr) if (pageno >= 0) {
bitmap_release_region(mem->bitmap, pageno, order); 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; return virt_addr;
} }
EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
static 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 * pci_epc_mem_free_addr() - free the allocated memory address
* @epc: the EPC device on which memory was allocated * @epc: the EPC device on which memory was allocated
...@@ -166,14 +234,23 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); ...@@ -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 pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
void __iomem *virt_addr, size_t size) void __iomem *virt_addr, size_t size)
{ {
struct pci_epc_mem *mem;
unsigned int page_shift;
size_t page_size;
int pageno; int pageno;
struct pci_epc_mem *mem = epc->mem;
unsigned int page_shift = ilog2(mem->page_size);
int order; 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); iounmap(virt_addr);
pageno = (phys_addr - mem->phys_base) >> page_shift; pageno = (phys_addr - mem->window.phys_base) >> page_shift;
size = ALIGN(size, mem->page_size); size = ALIGN(size, page_size);
order = pci_epc_mem_get_order(mem, size); order = pci_epc_mem_get_order(mem, size);
mutex_lock(&mem->lock); mutex_lock(&mem->lock);
bitmap_release_region(mem->bitmap, pageno, order); bitmap_release_region(mem->bitmap, pageno, order);
......
...@@ -65,20 +65,28 @@ struct pci_epc_ops { ...@@ -65,20 +65,28 @@ struct pci_epc_ops {
struct module *owner; 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 * struct pci_epc_mem - address space of the endpoint controller
* @phys_base: physical base address of the PCI address space * @window: address window of the endpoint controller
* @size: the size of the PCI address space
* @bitmap: bitmap to manage the PCI address space * @bitmap: bitmap to manage the PCI address space
* @pages: number of bits representing the address region * @pages: number of bits representing the address region
* @page_size: size of each page
* @lock: mutex to protect bitmap * @lock: mutex to protect bitmap
*/ */
struct pci_epc_mem { struct pci_epc_mem {
phys_addr_t phys_base; struct pci_epc_mem_window window;
size_t size;
unsigned long *bitmap; unsigned long *bitmap;
size_t page_size;
int pages; int pages;
/* mutex to protect against concurrent access for memory allocation*/ /* mutex to protect against concurrent access for memory allocation*/
struct mutex lock; struct mutex lock;
...@@ -89,7 +97,11 @@ struct pci_epc_mem { ...@@ -89,7 +97,11 @@ struct pci_epc_mem {
* @dev: PCI EPC device * @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device * @pci_epf: list of endpoint functions present in this EPC device
* @ops: function pointers for performing endpoint operations * @ops: function pointers for performing endpoint operations
* @mem: address space of the endpoint controller * @windows: array of address space of the endpoint controller
* @mem: first window of the endpoint controller, which corresponds to
* default address space of the endpoint controller supporting
* single window.
* @num_windows: number of windows supported by device
* @max_functions: max number of functions that can be configured in this EPC * @max_functions: max number of functions that can be configured in this EPC
* @group: configfs group representing the PCI EPC device * @group: configfs group representing the PCI EPC device
* @lock: mutex to protect pci_epc ops * @lock: mutex to protect pci_epc ops
...@@ -100,7 +112,9 @@ struct pci_epc { ...@@ -100,7 +112,9 @@ struct pci_epc {
struct device dev; struct device dev;
struct list_head pci_epf; struct list_head pci_epf;
const struct pci_epc_ops *ops; const struct pci_epc_ops *ops;
struct pci_epc_mem **windows;
struct pci_epc_mem *mem; struct pci_epc_mem *mem;
unsigned int num_windows;
u8 max_functions; u8 max_functions;
struct config_group *group; struct config_group *group;
/* mutex to protect against concurrent access of EP controller */ /* mutex to protect against concurrent access of EP controller */
...@@ -194,8 +208,9 @@ void pci_epc_put(struct pci_epc *epc); ...@@ -194,8 +208,9 @@ void pci_epc_put(struct pci_epc *epc);
int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base, int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
size_t size, size_t page_size); size_t size, size_t page_size);
int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size, int pci_epc_multi_mem_init(struct pci_epc *epc,
size_t page_size); struct pci_epc_mem_window *window,
unsigned int num_windows);
void pci_epc_mem_exit(struct pci_epc *epc); void pci_epc_mem_exit(struct pci_epc *epc);
void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size); phys_addr_t *phys_addr, size_t size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment