Date   

[PATCH 4.19.y-cip 10/13] PCI: endpoint: Add support to handle multiple base for mapping outbound memory

Lad Prabhakar
 

commit d45e3c1a5979efd40dbbac9a5c3586f4fa41f734 upstream.

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.com
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...>
Acked-by: Kishon Vijay Abraham I <kishon@...>
[PL: manually applied changes to pcie-designware-ep.c]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
.../pci/controller/dwc/pcie-designware-ep.c | 12 +-
drivers/pci/endpoint/pci-epc-mem.c | 199 ++++++++++++------
include/linux/pci-epc.h | 33 ++-
3 files changed, 168 insertions(+), 76 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 667763fd868f..471855feab03 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -434,11 +434,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
reg = ep->msi_cap + PCI_MSI_DATA_32;
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_lower & ~aligned_offset);
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)
return ret;

@@ -495,7 +495,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return -EPERM;

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)
return ret;

@@ -511,7 +511,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
struct pci_epc *epc = ep->epc;

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);
}
@@ -586,7 +586,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ret < 0)
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);
if (ret < 0) {
dev_err(dev, "Failed to initialize address space\n");
@@ -594,7 +594,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
}

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) {
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
return -ENOMEM;
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c
index cdd1d3821249..80c46f3a4590 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(*epc->windows), 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];
+ 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);

+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
* @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 e5f6ca8c36a8..5adb881bbcd7 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;
unsigned long *bitmap;
- size_t page_size;
int pages;
/* mutex to protect against concurrent access for memory allocation*/
struct mutex lock;
@@ -89,7 +97,11 @@ struct pci_epc_mem {
* @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device
* @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
* @group: configfs group representing the PCI EPC device
* @lock: mutex to protect pci_epc ops
@@ -100,7 +112,9 @@ struct pci_epc {
struct device dev;
struct list_head pci_epf;
const struct pci_epc_ops *ops;
+ struct pci_epc_mem **windows;
struct pci_epc_mem *mem;
+ unsigned int num_windows;
u8 max_functions;
struct config_group *group;
/* mutex to protect against concurrent access of EP controller */
@@ -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,
size_t size, size_t page_size);
-int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size,
- size_t page_size);
+int pci_epc_multi_mem_init(struct pci_epc *epc,
+ struct pci_epc_mem_window *window,
+ unsigned int num_windows);
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);
--
2.17.1


[PATCH 4.19.y-cip 09/13] PCI: endpoint: Pass page size as argument to pci_epc_mem_init()

Lad Prabhakar
 

commit 975cf23e3aa89588cbfc9ad6f2b23bd32af4edc7 upstream.

pci_epc_mem_init() internally used page size equal to *PAGE_SIZE* to
manage the address space so instead just pass the page size as a
argument to pci_epc_mem_init().

Also make pci_epc_mem_init() as a C function instead of a macro function
in preparation for adding support for pci-epc-mem core to handle multiple
windows.

Link: https://lore.kernel.org/r/1588854799-13710-5-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...>
Acked-by: Kishon Vijay Abraham I <kishon@...>
[PL: Manually applied changes to pcie-cadence-ep.c]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/controller/pcie-cadence-ep.c | 2 +-
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/pci-epc-mem.c | 7 +++++++
include/linux/pci-epc.h | 5 ++---
4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
index def7820cb824..3575c8e3e398 100644
--- a/drivers/pci/controller/pcie-cadence-ep.c
+++ b/drivers/pci/controller/pcie-cadence-ep.c
@@ -503,7 +503,7 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
epc->max_functions = 1;

ret = pci_epc_mem_init(epc, pcie->mem_res->start,
- resource_size(pcie->mem_res));
+ resource_size(pcie->mem_res), PAGE_SIZE);
if (ret < 0) {
dev_err(dev, "failed to initialize the memory space\n");
goto err_init;
diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index d743b0a48988..5eaf36629a75 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -615,7 +615,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);

err = pci_epc_mem_init(epc, rockchip->mem_res->start,
- resource_size(rockchip->mem_res));
+ resource_size(rockchip->mem_res), PAGE_SIZE);
if (err < 0) {
dev_err(dev, "failed to initialize the memory space\n");
goto err_uninit_port;
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c
index abfac1109a13..cdd1d3821249 100644
--- a/drivers/pci/endpoint/pci-epc-mem.c
+++ b/drivers/pci/endpoint/pci-epc-mem.c
@@ -93,6 +93,13 @@ return ret;
}
EXPORT_SYMBOL_GPL(__pci_epc_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);
+}
+EXPORT_SYMBOL_GPL(pci_epc_mem_init);
+
/**
* pci_epc_mem_exit() - cleanup the pci_epc_mem structure
* @epc: the EPC device that invoked pci_epc_mem_exit
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 8c86841fcdaf..e5f6ca8c36a8 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -137,9 +137,6 @@ struct pci_epc_features {
#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);
@@ -195,6 +192,8 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
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 base,
+ size_t size, size_t page_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);
--
2.17.1


[PATCH 4.19.y-cip 08/13] PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments

Lad Prabhakar
 

From: Kishon Vijay Abraham I <kishon@...>

commit 83153d9f36e24978c6211d246cb6f532bf54e5dc upstream.

commit 8963106eabdc ("PCI: endpoint: Add MSI-X interfaces") while
adding support to raise MSI-X interrupts from endpoint didn't include
BAR Indicator register (BIR) configuration and MSI-X table offset as
arguments in pci_epc_set_msix(). This would result in endpoint
controller register using random BAR indicator register, the memory
for which might not be allocated by the endpoint function driver.
Add BAR indicator register and MSI-X table offset as arguments in
pci_epc_set_msix() and allocate space for MSI-X table and pending
bit array (PBA) in pci-epf-test endpoint function driver.

Fixes: 8963106eabdc ("PCI: endpoint: Add MSI-X interfaces")
Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
.../pci/controller/dwc/pcie-designware-ep.c | 15 +++++++--
drivers/pci/endpoint/functions/pci-epf-test.c | 32 +++++++++++++++----
drivers/pci/endpoint/pci-epc-core.c | 7 ++--
include/linux/pci-epc.h | 6 ++--
4 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index d1bb4b852b6c..667763fd868f 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -302,7 +302,8 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
return val;
}

-static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
+static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
+ enum pci_barno bir, u32 offset)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@@ -311,12 +312,22 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
if (!ep->msix_cap)
return -EINVAL;

+ dw_pcie_dbi_ro_wr_en(pci);
+
reg = ep->msix_cap + PCI_MSIX_FLAGS;
val = dw_pcie_readw_dbi(pci, reg);
val &= ~PCI_MSIX_FLAGS_QSIZE;
val |= interrupts;
- dw_pcie_dbi_ro_wr_en(pci);
dw_pcie_writew_dbi(pci, reg, val);
+
+ reg = ep->msix_cap + PCI_MSIX_TABLE;
+ val = offset | bir;
+ dw_pcie_writel_dbi(pci, reg, val);
+
+ reg = ep->msix_cap + PCI_MSIX_PBA;
+ val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
+ dw_pcie_writel_dbi(pci, reg, val);
+
dw_pcie_dbi_ro_wr_dis(pci);

return 0;
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 865a09d583df..f6905c242194 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -47,6 +47,7 @@ struct pci_epf_test {
void *reg[6];
struct pci_epf *epf;
enum pci_barno test_reg_bar;
+ size_t msix_table_offset;
struct delayed_work cmd_handler;
const struct pci_epc_features *epc_features;
};
@@ -418,6 +419,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)

static int pci_epf_test_core_init(struct pci_epf *epf)
{
+ struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct pci_epf_header *header = epf->header;
const struct pci_epc_features *epc_features;
struct pci_epc *epc = epf->epc;
@@ -451,7 +453,9 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
}

if (msix_capable) {
- ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
+ ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts,
+ epf_test->test_reg_bar,
+ epf_test->msix_table_offset);
if (ret) {
dev_err(dev, "MSI-X configuration failed\n");
return ret;
@@ -493,6 +497,10 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct device *dev = &epf->dev;
struct pci_epf_bar *epf_bar;
+ size_t msix_table_size = 0;
+ size_t test_reg_bar_size;
+ size_t pba_size = 0;
+ bool msix_capable;
void *base;
int bar, add;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
@@ -501,13 +509,25 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)

epc_features = epf_test->epc_features;

- if (epc_features->bar_fixed_size[test_reg_bar])
+ test_reg_bar_size = ALIGN(sizeof(struct pci_epf_test_reg), 128);
+
+ msix_capable = epc_features->msix_capable;
+ if (msix_capable) {
+ msix_table_size = PCI_MSIX_ENTRY_SIZE * epf->msix_interrupts;
+ epf_test->msix_table_offset = test_reg_bar_size;
+ /* Align to QWORD or 8 Bytes */
+ pba_size = ALIGN(DIV_ROUND_UP(epf->msix_interrupts, 8), 8);
+ }
+ test_reg_size = test_reg_bar_size + msix_table_size + pba_size;
+
+ if (epc_features->bar_fixed_size[test_reg_bar]) {
+ if (test_reg_size > bar_size[test_reg_bar])
+ return -ENOMEM;
test_reg_size = bar_size[test_reg_bar];
- else
- test_reg_size = sizeof(struct pci_epf_test_reg);
+ }

- base = pci_epf_alloc_space(epf, test_reg_size,
- test_reg_bar, epc_features->align);
+ base = pci_epf_alloc_space(epf, test_reg_size, test_reg_bar,
+ epc_features->align);
if (!base) {
dev_err(dev, "Failed to allocated register space\n");
return -ENOMEM;
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 0d22a377a0cf..82ba0dc7f2f5 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -297,10 +297,13 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix);
* @epc: the EPC device on which MSI-X has to be configured
* @func_no: the endpoint function number in the EPC device
* @interrupts: number of MSI-X interrupts required by the EPF
+ * @bir: BAR where the MSI-X table resides
+ * @offset: Offset pointing to the start of MSI-X table
*
* Invoke to set the required number of MSI-X interrupts.
*/
-int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
+int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
+ enum pci_barno bir, u32 offset)
{
int ret;

@@ -312,7 +315,7 @@ int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
return 0;

mutex_lock(&epc->lock);
- ret = epc->ops->set_msix(epc, func_no, interrupts - 1);
+ ret = epc->ops->set_msix(epc, func_no, interrupts - 1, bir, offset);
mutex_unlock(&epc->lock);

return ret;
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 77e04ee1fe05..8c86841fcdaf 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -53,7 +53,8 @@ struct pci_epc_ops {
phys_addr_t addr);
int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 interrupts);
int (*get_msi)(struct pci_epc *epc, u8 func_no);
- int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts);
+ int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts,
+ enum pci_barno, u32 offset);
int (*get_msix)(struct pci_epc *epc, u8 func_no);
int (*raise_irq)(struct pci_epc *epc, u8 func_no,
enum pci_epc_irq_type type, u16 interrupt_num);
@@ -180,7 +181,8 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no,
phys_addr_t phys_addr);
int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts);
int pci_epc_get_msi(struct pci_epc *epc, u8 func_no);
-int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts);
+int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
+ enum pci_barno, u32 offset);
int pci_epc_get_msix(struct pci_epc *epc, u8 func_no);
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
enum pci_epc_irq_type type, u16 interrupt_num);
--
2.17.1


[PATCH 4.19.y-cip 07/13] PCI: pci-epf-test: Add support to defer core initialization

Lad Prabhakar
 

From: Vidya Sagar <vidyas@...>

commit 5e50ee27d4a52a817ab152128c48690ec7c5cdf1 upstream.

Add support to defer core initialization for the endpoint mode of
operation.

This would enable support for implementations where the core
initialization needs to be deferred until the PCIe reference clock is
available from the host system.

Signed-off-by: Vidya Sagar <vidyas@...>
[lorenzo.pieralisi@...: commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Acked-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 118 ++++++++++++------
1 file changed, 77 insertions(+), 41 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 7dd40ab8b5d2..865a09d583df 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -360,18 +360,6 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
msecs_to_jiffies(1));
}

-static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
- struct pci_epf_test *epf_test = epf_get_drvdata(epf);
-
- queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
- msecs_to_jiffies(1));
-
- return NOTIFY_OK;
-}
-
static void pci_epf_test_unbind(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@@ -428,6 +416,78 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
return 0;
}

+static int pci_epf_test_core_init(struct pci_epf *epf)
+{
+ struct pci_epf_header *header = epf->header;
+ const struct pci_epc_features *epc_features;
+ struct pci_epc *epc = epf->epc;
+ struct device *dev = &epf->dev;
+ bool msix_capable = false;
+ bool msi_capable = true;
+ int ret;
+
+ epc_features = pci_epc_get_features(epc, epf->func_no);
+ if (epc_features) {
+ msix_capable = epc_features->msix_capable;
+ msi_capable = epc_features->msi_capable;
+ }
+
+ ret = pci_epc_write_header(epc, epf->func_no, header);
+ if (ret) {
+ dev_err(dev, "Configuration header write failed\n");
+ return ret;
+ }
+
+ ret = pci_epf_test_set_bar(epf);
+ if (ret)
+ return ret;
+
+ if (msi_capable) {
+ ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
+ if (ret) {
+ dev_err(dev, "MSI configuration failed\n");
+ return ret;
+ }
+ }
+
+ if (msix_capable) {
+ ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
+ if (ret) {
+ dev_err(dev, "MSI-X configuration failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
+ struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+ int ret;
+
+ switch (val) {
+ case CORE_INIT:
+ ret = pci_epf_test_core_init(epf);
+ if (ret)
+ return NOTIFY_BAD;
+ break;
+
+ case LINK_UP:
+ queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
+ msecs_to_jiffies(1));
+ break;
+
+ default:
+ dev_err(&epf->dev, "Invalid EPF test notifier event\n");
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_OK;
+}
+
static int pci_epf_test_alloc_space(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@@ -496,14 +556,11 @@ static int pci_epf_test_bind(struct pci_epf *epf)
{
int ret;
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
- struct pci_epf_header *header = epf->header;
const struct pci_epc_features *epc_features;
enum pci_barno test_reg_bar = BAR_0;
struct pci_epc *epc = epf->epc;
- struct device *dev = &epf->dev;
bool linkup_notifier = false;
- bool msix_capable = false;
- bool msi_capable = true;
+ bool core_init_notifier = false;

if (WARN_ON_ONCE(!epc))
return -EINVAL;
@@ -511,8 +568,7 @@ static int pci_epf_test_bind(struct pci_epf *epf)
epc_features = pci_epc_get_features(epc, epf->func_no);
if (epc_features) {
linkup_notifier = epc_features->linkup_notifier;
- msix_capable = epc_features->msix_capable;
- msi_capable = epc_features->msi_capable;
+ core_init_notifier = epc_features->core_init_notifier;
test_reg_bar = pci_epc_get_first_free_bar(epc_features);
pci_epf_configure_bar(epf, epc_features);
}
@@ -520,34 +576,14 @@ static int pci_epf_test_bind(struct pci_epf *epf)
epf_test->test_reg_bar = test_reg_bar;
epf_test->epc_features = epc_features;

- ret = pci_epc_write_header(epc, epf->func_no, header);
- if (ret) {
- dev_err(dev, "Configuration header write failed\n");
- return ret;
- }
-
ret = pci_epf_test_alloc_space(epf);
if (ret)
return ret;

- ret = pci_epf_test_set_bar(epf);
- if (ret)
- return ret;
-
- if (msi_capable) {
- ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
- if (ret) {
- dev_err(dev, "MSI configuration failed\n");
- return ret;
- }
- }
-
- if (msix_capable) {
- ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
- if (ret) {
- dev_err(dev, "MSI-X configuration failed\n");
+ if (!core_init_notifier) {
+ ret = pci_epf_test_core_init(epf);
+ if (ret)
return ret;
- }
}

if (linkup_notifier) {
--
2.17.1


[PATCH 4.19.y-cip 06/13] PCI: endpoint: Add notification for core init completion

Lad Prabhakar
 

From: Vidya Sagar <vidyas@...>

commit 0ef22dcf0c1871888c4c0ee46a9d9c494f2fe997 upstream.

Add support to send notifications to EPF from EPC once the core
registers initialization is complete.

Signed-off-by: Vidya Sagar <vidyas@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Acked-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/pci-epc-core.c | 19 ++++++++++++++++++-
include/linux/pci-epc.h | 1 +
include/linux/pci-epf.h | 5 +++++
3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index dc1c673534e0..0d22a377a0cf 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -540,10 +540,27 @@ void pci_epc_linkup(struct pci_epc *epc)
if (!epc || IS_ERR(epc))
return;

- atomic_notifier_call_chain(&epc->notifier, 0, NULL);
+ atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL);
}
EXPORT_SYMBOL_GPL(pci_epc_linkup);

+/**
+ * pci_epc_init_notify() - Notify the EPF device that EPC device's core
+ * initialization is completed.
+ * @epc: the EPC device whose core initialization is completeds
+ *
+ * Invoke to Notify the EPF device that the EPC device's initialization
+ * is completed.
+ */
+void pci_epc_init_notify(struct pci_epc *epc)
+{
+ if (!epc || IS_ERR(epc))
+ return;
+
+ atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_epc_init_notify);
+
/**
* pci_epc_destroy() - destroy the EPC device
* @epc: the EPC device that has to be destroyed
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 8f9bbc4b7ad1..77e04ee1fe05 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -165,6 +165,7 @@ void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc);
void pci_epc_destroy(struct pci_epc *epc);
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf);
void pci_epc_linkup(struct pci_epc *epc);
+void pci_epc_init_notify(struct pci_epc *epc);
void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf);
int pci_epc_write_header(struct pci_epc *epc, u8 func_no,
struct pci_epf_header *hdr);
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index efbc08a153ff..6644ff3b0702 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -15,6 +15,11 @@

struct pci_epf;

+enum pci_notify_event {
+ CORE_INIT,
+ LINK_UP,
+};
+
enum pci_barno {
BAR_0,
BAR_1,
--
2.17.1


[PATCH 4.19.y-cip 05/13] PCI: endpoint: Add core init notifying feature

Lad Prabhakar
 

From: Vidya Sagar <vidyas@...>

commit 3d5f7d9f6a38ddcc105ebfb23b640630bbabba65 upstream.

Add a new feature core_init_notifier for cores that can notify about
their availability for initialization.

Signed-off-by: Vidya Sagar <vidyas@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Acked-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
include/linux/pci-epc.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 44bfbeb480bb..8f9bbc4b7ad1 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -120,6 +120,7 @@ struct pci_epc {
*/
struct pci_epc_features {
unsigned int linkup_notifier : 1;
+ unsigned int core_init_notifier : 1;
unsigned int msi_capable : 1;
unsigned int msix_capable : 1;
u8 reserved_bar;
--
2.17.1


[PATCH 4.19.y-cip 04/13] PCI: endpoint: Assign function number for each PF in EPC core

Lad Prabhakar
 

From: Kishon Vijay Abraham I <kishon@...>

commit 2499ee84e02774a8573b7b4c76c8f2ea38669313 upstream.

The PCIe endpoint core relies on the drivers that invoke the
pci_epc_add_epf() API to allocate and assign a function number
to each physical function (PF). Since endpoint function device can
be created by multiple mechanisms (configfs, devicetree, etc..),
allowing each of these mechanisms to assign a function number
would result in mutliple endpoint function devices having the
same function number. In order to avoid this, let EPC core assign
a function number to the endpoint device.

Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/pci-ep-cfs.c | 27 +++++----------------------
drivers/pci/endpoint/pci-epc-core.c | 26 ++++++++++++++++++++++----
include/linux/pci-epc.h | 2 ++
3 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index 4fead88257bb..55edce50be96 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -29,7 +29,6 @@ struct pci_epc_group {
struct config_group group;
struct pci_epc *epc;
bool start;
- unsigned long function_num_map;
};

static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
@@ -90,37 +89,22 @@ static int pci_epc_epf_link(struct config_item *epc_item,
struct config_item *epf_item)
{
int ret;
- u32 func_no = 0;
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
struct pci_epc *epc = epc_group->epc;
struct pci_epf *epf = epf_group->epf;

- func_no = find_first_zero_bit(&epc_group->function_num_map,
- BITS_PER_LONG);
- if (func_no >= BITS_PER_LONG)
- return -EINVAL;
-
- set_bit(func_no, &epc_group->function_num_map);
- epf->func_no = func_no;
-
ret = pci_epc_add_epf(epc, epf);
if (ret)
- goto err_add_epf;
+ return ret;

ret = pci_epf_bind(epf);
- if (ret)
- goto err_epf_bind;
+ if (ret) {
+ pci_epc_remove_epf(epc, epf);
+ return ret;
+ }

return 0;
-
-err_epf_bind:
- pci_epc_remove_epf(epc, epf);
-
-err_add_epf:
- clear_bit(func_no, &epc_group->function_num_map);
-
- return ret;
}

static void pci_epc_epf_unlink(struct config_item *epc_item,
@@ -135,7 +119,6 @@ static void pci_epc_epf_unlink(struct config_item *epc_item,

epc = epc_group->epc;
epf = epf_group->epf;
- clear_bit(epf->func_no, &epc_group->function_num_map);
pci_epf_unbind(epf);
pci_epc_remove_epf(epc, epf);
}
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index e51a12ed85bb..dc1c673534e0 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -471,22 +471,39 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
*/
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
{
+ u32 func_no;
+ int ret = 0;
+
if (epf->epc)
return -EBUSY;

if (IS_ERR(epc))
return -EINVAL;

- if (epf->func_no > epc->max_functions - 1)
- return -EINVAL;
+ mutex_lock(&epc->lock);
+ func_no = find_first_zero_bit(&epc->function_num_map,
+ BITS_PER_LONG);
+ if (func_no >= BITS_PER_LONG) {
+ ret = -EINVAL;
+ goto ret;
+ }
+
+ if (func_no > epc->max_functions - 1) {
+ dev_err(&epc->dev, "Exceeding max supported Function Number\n");
+ ret = -EINVAL;
+ goto ret;
+ }

+ set_bit(func_no, &epc->function_num_map);
+ epf->func_no = func_no;
epf->epc = epc;

- mutex_lock(&epc->lock);
list_add_tail(&epf->list, &epc->pci_epf);
+
+ret:
mutex_unlock(&epc->lock);

- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(pci_epc_add_epf);

@@ -503,6 +520,7 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf)
return;

mutex_lock(&epc->lock);
+ clear_bit(epf->func_no, &epc->function_num_map);
list_del(&epf->list);
epf->epc = NULL;
mutex_unlock(&epc->lock);
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 9b21692bc2e4..44bfbeb480bb 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -92,6 +92,7 @@ struct pci_epc_mem {
* @max_functions: max number of functions that can be configured in this EPC
* @group: configfs group representing the PCI EPC device
* @lock: mutex to protect pci_epc ops
+ * @function_num_map: bitmap to manage physical function number
* @notifier: used to notify EPF of any EPC events (like linkup)
*/
struct pci_epc {
@@ -103,6 +104,7 @@ struct pci_epc {
struct config_group *group;
/* mutex to protect against concurrent access of EP controller */
struct mutex lock;
+ unsigned long function_num_map;
struct atomic_notifier_head notifier;
};

--
2.17.1


[PATCH 4.19.y-cip 03/13] PCI: endpoint: Protect concurrent access to pci_epf_ops with mutex

Lad Prabhakar
 

From: Kishon Vijay Abraham I <kishon@...>

commit 07301c982643a432212840a4b648b5d3f5a061fa upstream.

Protect concurrent access to pci_epf_ops with a mutex.

Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/pci-epf-core.c | 11 ++++++++++-
include/linux/pci-epf.h | 3 +++
2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 642f233efcaf..244e00f48c5c 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -35,7 +35,9 @@ void pci_epf_unbind(struct pci_epf *epf)
return;
}

+ mutex_lock(&epf->lock);
epf->driver->ops->unbind(epf);
+ mutex_unlock(&epf->lock);
module_put(epf->driver->owner);
}
EXPORT_SYMBOL_GPL(pci_epf_unbind);
@@ -49,6 +51,8 @@ EXPORT_SYMBOL_GPL(pci_epf_unbind);
*/
int pci_epf_bind(struct pci_epf *epf)
{
+ int ret;
+
if (!epf->driver) {
dev_WARN(&epf->dev, "epf device not bound to driver\n");
return -EINVAL;
@@ -57,7 +61,11 @@ int pci_epf_bind(struct pci_epf *epf)
if (!try_module_get(epf->driver->owner))
return -EAGAIN;

- return epf->driver->ops->bind(epf);
+ mutex_lock(&epf->lock);
+ ret = epf->driver->ops->bind(epf);
+ mutex_unlock(&epf->lock);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(pci_epf_bind);

@@ -254,6 +262,7 @@ struct pci_epf *pci_epf_create(const char *name)
device_initialize(dev);
dev->bus = &pci_epf_bus_type;
dev->type = &pci_epf_type;
+ mutex_init(&epf->lock);

ret = dev_set_name(dev, "%s", name);
if (ret) {
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 75aa1003646b..efbc08a153ff 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -112,6 +112,7 @@ struct pci_epf_bar {
* @driver: the EPF driver to which this EPF device is bound
* @list: to add pci_epf as a list of PCI endpoint functions to pci_epc
* @nb: notifier block to notify EPF of any EPC events (like linkup)
+ * @lock: mutex to protect pci_epf_ops
*/
struct pci_epf {
struct device dev;
@@ -126,6 +127,8 @@ struct pci_epf {
struct pci_epf_driver *driver;
struct list_head list;
struct notifier_block nb;
+ /* mutex to protect against concurrent access of pci_epf_ops */
+ struct mutex lock;
};

/**
--
2.17.1


[PATCH 4.19.y-cip 02/13] PCI: endpoint: Replace spinlock with mutex

Lad Prabhakar
 

From: Kishon Vijay Abraham I <kishon@...>

commit 3d3248dbd018502f654064c78efcd2e165ab3486 upstream.

The pci_epc_ops is not intended to be invoked from interrupt context.
Hence replace spin_lock_irqsave and spin_unlock_irqrestore with
mutex_lock and mutex_unlock respectively.

Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/pci-epc-core.c | 82 +++++++++++------------------
include/linux/pci-epc.h | 6 +--
2 files changed, 34 insertions(+), 54 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 2f6436599fcb..e51a12ed85bb 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -120,7 +120,6 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
u8 func_no)
{
const struct pci_epc_features *epc_features;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return NULL;
@@ -128,9 +127,9 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
if (!epc->ops->get_features)
return NULL;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
epc_features = epc->ops->get_features(epc, func_no);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return epc_features;
}
@@ -144,14 +143,12 @@ EXPORT_SYMBOL_GPL(pci_epc_get_features);
*/
void pci_epc_stop(struct pci_epc *epc)
{
- unsigned long flags;
-
if (IS_ERR(epc) || !epc->ops->stop)
return;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
epc->ops->stop(epc);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);
}
EXPORT_SYMBOL_GPL(pci_epc_stop);

@@ -164,7 +161,6 @@ EXPORT_SYMBOL_GPL(pci_epc_stop);
int pci_epc_start(struct pci_epc *epc)
{
int ret;
- unsigned long flags;

if (IS_ERR(epc))
return -EINVAL;
@@ -172,9 +168,9 @@ int pci_epc_start(struct pci_epc *epc)
if (!epc->ops->start)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->start(epc);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -193,7 +189,6 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
enum pci_epc_irq_type type, u16 interrupt_num)
{
int ret;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return -EINVAL;
@@ -201,9 +196,9 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
if (!epc->ops->raise_irq)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->raise_irq(epc, func_no, type, interrupt_num);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -219,7 +214,6 @@ EXPORT_SYMBOL_GPL(pci_epc_raise_irq);
int pci_epc_get_msi(struct pci_epc *epc, u8 func_no)
{
int interrupt;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return 0;
@@ -227,9 +221,9 @@ int pci_epc_get_msi(struct pci_epc *epc, u8 func_no)
if (!epc->ops->get_msi)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
interrupt = epc->ops->get_msi(epc, func_no);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

if (interrupt < 0)
return 0;
@@ -252,7 +246,6 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
{
int ret;
u8 encode_int;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
interrupts > 32)
@@ -263,9 +256,9 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)

encode_int = order_base_2(interrupts);

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->set_msi(epc, func_no, encode_int);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -281,7 +274,6 @@ EXPORT_SYMBOL_GPL(pci_epc_set_msi);
int pci_epc_get_msix(struct pci_epc *epc, u8 func_no)
{
int interrupt;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return 0;
@@ -289,9 +281,9 @@ int pci_epc_get_msix(struct pci_epc *epc, u8 func_no)
if (!epc->ops->get_msix)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
interrupt = epc->ops->get_msix(epc, func_no);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

if (interrupt < 0)
return 0;
@@ -311,7 +303,6 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix);
int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
{
int ret;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
interrupts < 1 || interrupts > 2048)
@@ -320,9 +311,9 @@ int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
if (!epc->ops->set_msix)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->set_msix(epc, func_no, interrupts - 1);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -339,17 +330,15 @@ EXPORT_SYMBOL_GPL(pci_epc_set_msix);
void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no,
phys_addr_t phys_addr)
{
- unsigned long flags;
-
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return;

if (!epc->ops->unmap_addr)
return;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
epc->ops->unmap_addr(epc, func_no, phys_addr);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);
}
EXPORT_SYMBOL_GPL(pci_epc_unmap_addr);

@@ -367,7 +356,6 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no,
phys_addr_t phys_addr, u64 pci_addr, size_t size)
{
int ret;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return -EINVAL;
@@ -375,9 +363,9 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no,
if (!epc->ops->map_addr)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->map_addr(epc, func_no, phys_addr, pci_addr, size);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -394,8 +382,6 @@ EXPORT_SYMBOL_GPL(pci_epc_map_addr);
void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no,
struct pci_epf_bar *epf_bar)
{
- unsigned long flags;
-
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
(epf_bar->barno == BAR_5 &&
epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64))
@@ -404,9 +390,9 @@ void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no,
if (!epc->ops->clear_bar)
return;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
epc->ops->clear_bar(epc, func_no, epf_bar);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);
}
EXPORT_SYMBOL_GPL(pci_epc_clear_bar);

@@ -422,7 +408,6 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no,
struct pci_epf_bar *epf_bar)
{
int ret;
- unsigned long irq_flags;
int flags = epf_bar->flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
@@ -437,9 +422,9 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no,
if (!epc->ops->set_bar)
return 0;

- spin_lock_irqsave(&epc->lock, irq_flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->set_bar(epc, func_no, epf_bar);
- spin_unlock_irqrestore(&epc->lock, irq_flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -460,7 +445,6 @@ int pci_epc_write_header(struct pci_epc *epc, u8 func_no,
struct pci_epf_header *header)
{
int ret;
- unsigned long flags;

if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
return -EINVAL;
@@ -468,9 +452,9 @@ int pci_epc_write_header(struct pci_epc *epc, u8 func_no,
if (!epc->ops->write_header)
return 0;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
ret = epc->ops->write_header(epc, func_no, header);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return ret;
}
@@ -487,8 +471,6 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
*/
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
{
- unsigned long flags;
-
if (epf->epc)
return -EBUSY;

@@ -500,9 +482,9 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)

epf->epc = epc;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
list_add_tail(&epf->list, &epc->pci_epf);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);

return 0;
}
@@ -517,15 +499,13 @@ EXPORT_SYMBOL_GPL(pci_epc_add_epf);
*/
void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf)
{
- unsigned long flags;
-
if (!epc || IS_ERR(epc) || !epf)
return;

- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->lock);
list_del(&epf->list);
epf->epc = NULL;
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->lock);
}
EXPORT_SYMBOL_GPL(pci_epc_remove_epf);

@@ -604,7 +584,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
goto err_ret;
}

- spin_lock_init(&epc->lock);
+ mutex_init(&epc->lock);
INIT_LIST_HEAD(&epc->pci_epf);
ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);

diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 8c61908d2c41..9b21692bc2e4 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -91,7 +91,7 @@ struct pci_epc_mem {
* @mem: address space of the endpoint controller
* @max_functions: max number of functions that can be configured in this EPC
* @group: configfs group representing the PCI EPC device
- * @lock: spinlock to protect pci_epc ops
+ * @lock: mutex to protect pci_epc ops
* @notifier: used to notify EPF of any EPC events (like linkup)
*/
struct pci_epc {
@@ -101,8 +101,8 @@ struct pci_epc {
struct pci_epc_mem *mem;
u8 max_functions;
struct config_group *group;
- /* spinlock to protect against concurrent access of EP controller */
- spinlock_t lock;
+ /* mutex to protect against concurrent access of EP controller */
+ struct mutex lock;
struct atomic_notifier_head notifier;
};

--
2.17.1


[PATCH 4.19.y-cip 01/13] PCI: endpoint: Use notification chain mechanism to notify EPC events to EPF

Lad Prabhakar
 

From: Kishon Vijay Abraham I <kishon@...>

commit 5779dd0a7dbd71e82478fb0bf125cc6cd3c43266 upstream.

Use atomic_notifier_call_chain() to notify EPC events like linkup to EPF
driver instead of using linkup ops in EPF driver. This is in preparation
for adding proper locking mechanism to EPF ops. This will also enable to
add more events (in addition to linkup) in the future.

Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Tested-by: Vidya Sagar <vidyas@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 13 ++++++++---
drivers/pci/endpoint/pci-epc-core.c | 9 ++------
drivers/pci/endpoint/pci-epf-core.c | 22 +------------------
include/linux/pci-epc.h | 8 +++++++
include/linux/pci-epf.h | 6 ++---
5 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 1cfe3687a211..7dd40ab8b5d2 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -360,12 +360,16 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
msecs_to_jiffies(1));
}

-static void pci_epf_test_linkup(struct pci_epf *epf)
+static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
{
+ struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
struct pci_epf_test *epf_test = epf_get_drvdata(epf);

queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
msecs_to_jiffies(1));
+
+ return NOTIFY_OK;
}

static void pci_epf_test_unbind(struct pci_epf *epf)
@@ -546,8 +550,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
}
}

- if (!linkup_notifier)
+ if (linkup_notifier) {
+ epf->nb.notifier_call = pci_epf_test_notifier;
+ pci_epc_register_notifier(epc, &epf->nb);
+ } else {
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
+ }

return 0;
}
@@ -580,7 +588,6 @@ static int pci_epf_test_probe(struct pci_epf *epf)
static struct pci_epf_ops ops = {
.unbind = pci_epf_test_unbind,
.bind = pci_epf_test_bind,
- .linkup = pci_epf_test_linkup,
};

static struct pci_epf_driver test_driver = {
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 2091508c1620..2f6436599fcb 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -539,16 +539,10 @@ EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
*/
void pci_epc_linkup(struct pci_epc *epc)
{
- unsigned long flags;
- struct pci_epf *epf;
-
if (!epc || IS_ERR(epc))
return;

- spin_lock_irqsave(&epc->lock, flags);
- list_for_each_entry(epf, &epc->pci_epf, list)
- pci_epf_linkup(epf);
- spin_unlock_irqrestore(&epc->lock, flags);
+ atomic_notifier_call_chain(&epc->notifier, 0, NULL);
}
EXPORT_SYMBOL_GPL(pci_epc_linkup);

@@ -612,6 +606,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,

spin_lock_init(&epc->lock);
INIT_LIST_HEAD(&epc->pci_epf);
+ ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);

device_initialize(&epc->dev);
epc->dev.class = pci_epc_class;
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 93ebe916949e..642f233efcaf 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -20,26 +20,6 @@ static DEFINE_MUTEX(pci_epf_mutex);
static struct bus_type pci_epf_bus_type;
static const struct device_type pci_epf_type;

-/**
- * pci_epf_linkup() - Notify the function driver that EPC device has
- * established a connection with the Root Complex.
- * @epf: the EPF device bound to the EPC device which has established
- * the connection with the host
- *
- * Invoke to notify the function driver that EPC device has established
- * a connection with the Root Complex.
- */
-void pci_epf_linkup(struct pci_epf *epf)
-{
- if (!epf->driver) {
- dev_WARN(&epf->dev, "epf device not bound to driver\n");
- return;
- }
-
- epf->driver->ops->linkup(epf);
-}
-EXPORT_SYMBOL_GPL(pci_epf_linkup);
-
/**
* pci_epf_unbind() - Notify the function driver that the binding between the
* EPF device and EPC device has been lost
@@ -216,7 +196,7 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
if (!driver->ops)
return -EINVAL;

- if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup)
+ if (!driver->ops->bind || !driver->ops->unbind)
return -EINVAL;

driver->driver.bus = &pci_epf_bus_type;
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 0c12d69dde92..8c61908d2c41 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -92,6 +92,7 @@ struct pci_epc_mem {
* @max_functions: max number of functions that can be configured in this EPC
* @group: configfs group representing the PCI EPC device
* @lock: spinlock to protect pci_epc ops
+ * @notifier: used to notify EPF of any EPC events (like linkup)
*/
struct pci_epc {
struct device dev;
@@ -102,6 +103,7 @@ struct pci_epc {
struct config_group *group;
/* spinlock to protect against concurrent access of EP controller */
spinlock_t lock;
+ struct atomic_notifier_head notifier;
};

/**
@@ -144,6 +146,12 @@ static inline void *epc_get_drvdata(struct pci_epc *epc)
return dev_get_drvdata(&epc->dev);
}

+static inline int
+pci_epc_register_notifier(struct pci_epc *epc, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&epc->notifier, nb);
+}
+
struct pci_epc *
__devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
struct module *owner);
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index bc5ce7afd79a..75aa1003646b 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -55,13 +55,10 @@ struct pci_epf_header {
* @bind: ops to perform when a EPC device has been bound to EPF device
* @unbind: ops to perform when a binding has been lost between a EPC device
* and EPF device
- * @linkup: ops to perform when the EPC device has established a connection with
- * a host system
*/
struct pci_epf_ops {
int (*bind)(struct pci_epf *epf);
void (*unbind)(struct pci_epf *epf);
- void (*linkup)(struct pci_epf *epf);
};

/**
@@ -114,6 +111,7 @@ struct pci_epf_bar {
* @epc: the EPC device to which this EPF device is bound
* @driver: the EPF driver to which this EPF device is bound
* @list: to add pci_epf as a list of PCI endpoint functions to pci_epc
+ * @nb: notifier block to notify EPF of any EPC events (like linkup)
*/
struct pci_epf {
struct device dev;
@@ -127,6 +125,7 @@ struct pci_epf {
struct pci_epc *epc;
struct pci_epf_driver *driver;
struct list_head list;
+ struct notifier_block nb;
};

/**
@@ -169,5 +168,4 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
int pci_epf_bind(struct pci_epf *epf);
void pci_epf_unbind(struct pci_epf *epf);
-void pci_epf_linkup(struct pci_epf *epf);
#endif /* __LINUX_PCI_EPF_H */
--
2.17.1


[PATCH 4.19.y-cip 00/13] Enhancements to PCIe EPF

Lad Prabhakar
 

Hi All,

This patch series is part of RFC series [1] ("Add PCIe EP support for
Renesas R-Car Gen3 and RZ/G2x"). For making it more cleaner and easier
to review series [1] is split up as suggested by Pavel, patches 23-29,
31, 33-37 are included in this set from [1].

This adds following features to EPF
* Deferred core initialization
* Support for notification after core init
* Replace spinlock with mutex
* Support to handle multiple base for mapping outbound memory

[1] https://patchwork.kernel.org/project/cip-dev/list/?series=363279&state=*

Cheers,
Prabhakar


Kishon Vijay Abraham I (6):
PCI: endpoint: Use notification chain mechanism to notify EPC events
to EPF
PCI: endpoint: Replace spinlock with mutex
PCI: endpoint: Protect concurrent access to pci_epf_ops with mutex
PCI: endpoint: Assign function number for each PF in EPC core
PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments
PCI: endpoint: functions/pci-epf-test: Print throughput information

Lad Prabhakar (4):
PCI: endpoint: Pass page size as argument to pci_epc_mem_init()
PCI: endpoint: Add support to handle multiple base for mapping
outbound memory
PCI: rcar: Rename pcie-rcar.c to pcie-rcar-host.c
arm64: defconfig: Enable CONFIG_PCIE_RCAR_HOST

Vidya Sagar (3):
PCI: endpoint: Add core init notifying feature
PCI: endpoint: Add notification for core init completion
PCI: pci-epf-test: Add support to defer core initialization

arch/arm64/configs/defconfig | 2 +-
drivers/pci/controller/Kconfig | 10 +
drivers/pci/controller/Makefile | 2 +-
.../pci/controller/dwc/pcie-designware-ep.c | 27 ++-
drivers/pci/controller/pcie-cadence-ep.c | 2 +-
.../{pcie-rcar.c => pcie-rcar-host.c} | 0
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/functions/pci-epf-test.c | 195 +++++++++++++----
drivers/pci/endpoint/pci-ep-cfs.c | 27 +--
drivers/pci/endpoint/pci-epc-core.c | 137 ++++++------
drivers/pci/endpoint/pci-epc-mem.c | 204 ++++++++++++------
drivers/pci/endpoint/pci-epf-core.c | 33 +--
include/linux/pci-epc.h | 62 ++++--
include/linux/pci-epf.h | 14 +-
14 files changed, 474 insertions(+), 243 deletions(-)
rename drivers/pci/controller/{pcie-rcar.c => pcie-rcar-host.c} (100%)

--
2.17.1


Direct Pushes for cip-kernel-sec

Chen-Yu Tsai (Moxa) <wens@...>
 

Hi,

After today's CIP weekly meeting, Pavel proposed the idea of skipping
merge requests for the cip-kernel-sec repository:

17:25 < pave1> wens: I see that currently merges to cip-kernel-sec are
approved, etc... which adds a delay.
17:25 < pave1> wens: Would it be possible to direct pushes, so we can
colaborate in the repository?
17:25 < wens> pave1: I don't have push access to cip-kernel-sec
17:26 < pave1> wens: Who can I talk to to get you one?
17:26 < pave1> wens: Because repository that is delayed like this... is not too
useful.
17:28 < wens> not sure who has admin access, maybe szlin would know.
17:28 < iwamatsu> wens: I can add permisson, maybe
17:28 < pave1> iwamatsu: That would be nice. cip-kernel-sec is kind of
dashboard, not a code repository.
17:28 < pave1> iwamatsu: So approving commits only delays stuff...
17:29 < wens> right, we are mostly pulling in data from other projects.
17:29 < pave1> wens: Right. Plus, you announce CVEs here, and it would be very
nice to be able to git pull and have the information available.
17:29 < wens> occasionally we have to fill in data ourselves, but maybe we
could do those separately with review, while having the automated
scripts just push directly?
17:30 < iwamatsu> wens: I just send invite.
17:30 < pave1> wens: I'd prefer not to do reviews. It is our internal status,
it does not go into product.
17:30 < wens> iwamatsu: thanks. looks like I can merge stuff now.
17:30 < pave1> wens: if we make mistake, we fix a mistake.
17:31 < pave1> iwamatsu: Thanks a lot!
17:31 < wens> pave1: so, auditing instead of reviewing
17:31 < pave1> wens: Yes, I guess.
17:32 < wens> bwh isn't around right now. we should let him know.
17:32 < pave1> Yes, I guess we need to discuss that.
17:32 < wens> I am in favor of pushing directly.
17:33 < iwamatsu> +1
17:33 < pave1> +1 :-)

Ben, could you share your thoughts on this?


Regards
ChenYu
Moxa


CIP IRC weekly meeting today

masashi.kudo@cybertrust.co.jp <masashi.kudo@...>
 

Hi all,

Kindly be reminded to attend the weekly meeting through IRC to discuss technical topics with CIP kernel today.

*Please note that the IRC meeting was rescheduled to UTC (GMT) 09:00 starting from the first week of Apr. according to TSC meeting*
https://www.timeanddate.com/worldclock/meetingdetails.html?year=2020&month=10&day=22&hour=9&min=0&sec=0&p1=224&p2=179&p3=136&p4=37&p5=241&p6=248

USWest USEast UK DE TW JP
02:00 05:00 10:00 11:00 17:00 18:00

Channel:
* irc:chat.freenode.net:6667/cip

Last meeting minutes:
https://irclogs.baserock.org/meetings/cip/2020/10/cip.2020-10-15-09.00.log.html

Agenda:

* Action item
1. Combine root filesystem with kselftest binary - iwamatsu
2. Check whether CVE-2019-0145, CVE-2019-0147, CVE-2019-0148 needs to be backported to 4.4 - masashi910

* Kernel maintenance updates
* Kernel testing
* CIP Security
* AOB

The meeting will take 30 min, although it can be extended to an hour if it makes sense and those involved in the topics can stay. Otherwise, the topic will be taken offline or in the next meeting.

Best regards,
--
M. Kudo
Cybertrust Japan Co., Ltd.


Re: [RFC PATCH 4.19.y-cip 38/50] PCI: rcar: Move shareable code to a common file

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 21 October 2020 20:07
To: Prabhakar Mahadev Lad <prabhakar.mahadev-lad.rj@...>
Cc: cip-dev@...; Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>; Pavel Machek <pavel@...>; Biju Das
<biju.das.jz@...>
Subject: Re: [RFC PATCH 4.19.y-cip 38/50] PCI: rcar: Move shareable code to a common file

Hi!

commit 78a0d7f2f5a31357bce68012d886507b4cf33598 upstream.

Move shareable code to common file pcie-rcar.c and the #defines to
pcie-rcar.h so that the common code can be reused with endpoint driver.
There are no functional changes with this patch for the host controller
driver.
Whoa.

So... original patch _moved_ shared code to new place.

This version creates another copy of shared code, probably subtly
different from the other one.

Is that good idea? Won't two copies cause problems depending on
.config? Could we share code, as the mainline does?
My main concern was this produces a big diff which would make it difficult for review. And CONFIG_PCIE_RCAR_HOST by default selects CONFIG_PCIE_RCAR which builds the host driver.
pcie-rcar.c is the same as mainline only that pcie-rcar-host.c is untouched here.

If you are OK ill post the similar changes to pcie-rcar-host.c as done in the actual upstream patch.

Anyway, patches up to previous one -- [37/50] arm64: defconfig: Enable
CONFIG_PCIE_RCAR_HOST look okay to me, so if you can send them as
non-RFC version, I cal likely apply them.
I shall get on posting the 2nd bunch of non-RFC.

Cheers,
Prabhakar

Best regards,
Pavel

--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [RFC PATCH 4.19.y-cip 28/50] PCI: endpoint: Add notification for core init completion

Lad Prabhakar
 

Hi Pavel,

Thank you for the review.

-----Original Message-----
From: Pavel Machek <pavel@...>
Sent: 21 October 2020 20:01
To: Prabhakar Mahadev Lad <prabhakar.mahadev-lad.rj@...>
Cc: cip-dev@...; Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@...>; Pavel Machek <pavel@...>; Biju Das
<biju.das.jz@...>
Subject: Re: [RFC PATCH 4.19.y-cip 28/50] PCI: endpoint: Add notification for core init completion

Hi!

From: Vidya Sagar <vidyas@...>

commit 0ef22dcf0c1871888c4c0ee46a9d9c494f2fe997 upstream.

Add support to send notifications to EPF from EPC once the core
registers initialization is complete.

+/**
+ * pci_epc_init_notify() - Notify the EPF device that EPC device's core
+ * initialization is completed.
+ * @epc: the EPC device whose core initialization is completeds
+ *
+ * Invoke to Notify the EPF device that the EPC device's initialization
+ * is completed.
+ */
+void pci_epc_init_notify(struct pci_epc *epc)
+{
+ if (!epc || IS_ERR(epc))
+ return;
+
+ atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_epc_init_notify);
Is this used somewhere? This adds symbol but noone calls this, and
AFAICT it is not used in the rest of the series, either.
Yep none users (only dwc uses it mainline).

We can merge it, anyway, I guess, but... explanation would be welcome.
Ill post it as part of non-RFC feel free to drop it.

Cheers,
Prabhakar

Best regards,
Pavel

--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [RFC PATCH 4.19.y-cip 38/50] PCI: rcar: Move shareable code to a common file

Pavel Machek
 

Hi!

commit 78a0d7f2f5a31357bce68012d886507b4cf33598 upstream.

Move shareable code to common file pcie-rcar.c and the #defines to
pcie-rcar.h so that the common code can be reused with endpoint driver.
There are no functional changes with this patch for the host controller
driver.
Whoa.

So... original patch _moved_ shared code to new place.

This version creates another copy of shared code, probably subtly
different from the other one.

Is that good idea? Won't two copies cause problems depending on
.config? Could we share code, as the mainline does?

Anyway, patches up to previous one -- [37/50] arm64: defconfig: Enable
CONFIG_PCIE_RCAR_HOST look okay to me, so if you can send them as
non-RFC version, I cal likely apply them.

Best regards,
Pavel

--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [RFC PATCH 4.19.y-cip 28/50] PCI: endpoint: Add notification for core init completion

Pavel Machek
 

Hi!

From: Vidya Sagar <vidyas@...>

commit 0ef22dcf0c1871888c4c0ee46a9d9c494f2fe997 upstream.

Add support to send notifications to EPF from EPC once the core
registers initialization is complete.

+/**
+ * pci_epc_init_notify() - Notify the EPF device that EPC device's core
+ * initialization is completed.
+ * @epc: the EPC device whose core initialization is completeds
+ *
+ * Invoke to Notify the EPF device that the EPC device's initialization
+ * is completed.
+ */
+void pci_epc_init_notify(struct pci_epc *epc)
+{
+ if (!epc || IS_ERR(epc))
+ return;
+
+ atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_epc_init_notify);
Is this used somewhere? This adds symbol but noone calls this, and
AFAICT it is not used in the rest of the series, either.

We can merge it, anyway, I guess, but... explanation would be welcome.

Best regards,
Pavel

--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: [RFC PATCH 4.19.y-cip 24/50] PCI: endpoint: Replace spinlock with mutex

Pavel Machek
 

Hi!

commit 3d3248dbd018502f654064c78efcd2e165ab3486 upstream.

The pci_epc_ops is not intended to be invoked from interrupt context.
Hence replace spin_lock_irqsave and spin_unlock_irqrestore with
mutex_lock and mutex_unlock respectively.
Could I get some kind of explanation why this is good idea?
Apart of one mentioned above other point I would add is on a single core machine mutex_lock/unlock would be good choice.

Also to add the callbacks in controller driver might sleep. For example in raise_irq callback [1], [2].

As long as code protected by the locks does not sleep, spinlocks are
okay... (but they should not need "_irqsave" variants).

They are likely to have better performance, too, when protected code
is small and fast.
I do agree with the above two points *if the code isn't sleeping*.
Okay, we can't really protect sleeping code with a mutex.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip.git/tree/drivers/pci/controller/pcie-rockchip-ep.c?h=linux-4.19.y-cip#n410
But this one is not sleeping. It is mdelay(), not msleep().

[2] https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip.git/tree/drivers/pci/controller/pcie-cadence-ep.c?h=linux-4.19.y-cip#n310
And same here.

If there's a place which does sleep with the spinlock held, I'd still
be curious.

OTOH, 1 msec is already threshold where mutex makes sense, so... this
is okay.

Thanks,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Re: Request for Camera CSI support for IMX

Lakshmi Natarajan <lakshmi.natarajan@...>
 

Hello Jan,

Thanks for the details. This gives us an idea on what we could do next.
Thanks for your immediate support. We will get in touch with NXP for this.

Regards,
Lakshmi


On Wed, Oct 21, 2020 at 4:27 PM Jan Kiszka <jan.kiszka@...> wrote:
Hi Lakshmi,

On 21.10.20 11:50, Lakshmi Natarajan wrote:
> Hello Jan,
>
> This is regarding requests for CSI support in the IMX processor.
> We were using Yocto + NXP provided kernel to use the CSI peripheral of
> the IMX6 processor. We have complete support from NXP for their kernel
> along with the Yocto framework.
> We want to move to CIP 4.19 + ISAR framework.
> When we checked CIP kernel 4.19 - there was no support for CSI interface
> as well as there were some differences in the arch support too.
> After study of the NXP provided framework, we found that they use the
> kernel from https://source.codeaurora.org/external/imx/linux-imxand
> commit ID 0f9917c56d5995e1dc3bde5658e2d7bc865464de.
> Even linux kernel 5.9 doesn't have the imx specific support.

That's unfortunate.

> Can you guide us on how we should proceed with the same - will it be
> possible for CIP to add IMX support (or) should we request NXP to add
> the patch for CIP kernel 4.19

Yes, please reach out to NXP and ask what their answer for upstream is,
today or at least for the future. It's their issue in the first place.
Also for that, you should prepare with naming the kernel interfaces or
drivers you need in more details.

If NXP cannot or do not want to answer this appropriately, plan B) will
be identifying the patches they provide on top of the upstream kernel,
optimally 4.19. Those patches then needs to be applied on top of the CIP
kernel but, as they are unfortunately downstream only, you will then
have to maintain them for your product and can't propose them for the
CIP kernel.

Best regards,
Jan

>
> Regards,
> Lakshmi
>
>
> On Tue, Oct 20, 2020 at 5:48 PM Rajashree Sankar
> <rajashree.sankar@... <mailto:rajashree.sankar@...>> wrote:
>
>     Hello Jan,
>     We have used Yocto Framework provided by NXP from the following link
>     <https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/evaluation-kit-for-the-i-mx-6ull-and-6ulz-applications-processor:MCIMX6ULL-EVK?fpsp=1#documentsandsoftware>.Refer
>     to the Document
>
>
>           L4.19.35_1.1.0_LINUX_DOCS
>           <https://www.nxp.com/webapp/Download?colCode=L4.19.35_1.1.0_LINUX_DOCS>
>           in the above mentioned link.
>
>     The DT-bindings and the IMX Camera capture information will be
>     available by following the steps mentioned in the document
>     i.MX_Yocto_Project_User's_Guide from the above link.
>     The Kernel which we are using is fetched from the bitbake files
>     attached below( linux-yocto_4.19.bb <http://linux-yocto_4.19.bb> and
>     its append).Could you please let us know whether CSI  Camera capture
>     supported in this kernel be included in the Linux CIP?
>
>     Thanks and Regards,
>     Rajashree Sankar
>
>
>
> CONFIDENTIALITY
> This e-mail message and any attachments thereto, is intended only for
> use by the addressee(s) named herein and may contain legally privileged
> and/or confidential information. If you are not the intended recipient
> of this e-mail message, you are hereby notified that any dissemination,
> distribution or copying of this e-mail message, and any attachments
> thereto, is strictly prohibited. If you have received this e-mail
> message in error, please immediately notify the sender and permanently
> delete the original and any copies of this email and any prints thereof.
> ABSENT AN EXPRESS STATEMENT TO THE CONTRARY HEREINABOVE, THIS E-MAIL IS
> NOT INTENDED AS A SUBSTITUTE FOR A WRITING. Notwithstanding the Uniform
> Electronic Transactions Act or the applicability of any other law of
> similar substance and effect, absent an express statement to the
> contrary hereinabove, this e-mail message its contents, and any
> attachments hereto are not intended to represent an offer or acceptance
> to enter into a contract and are not otherwise intended to bind the
> sender, Sanmina Corporation (or any of its subsidiaries), or any other
> person or entity.

--
Siemens AG, T RDA IOT
Corporate Competence Center Embedded Linux

CONFIDENTIALITY
This e-mail message and any attachments thereto, is intended only for use by the addressee(s) named herein and may contain legally privileged and/or confidential information. If you are not the intended recipient of this e-mail message, you are hereby notified that any dissemination, distribution or copying of this e-mail message, and any attachments thereto, is strictly prohibited. If you have received this e-mail message in error, please immediately notify the sender and permanently delete the original and any copies of this email and any prints thereof.
ABSENT AN EXPRESS STATEMENT TO THE CONTRARY HEREINABOVE, THIS E-MAIL IS NOT INTENDED AS A SUBSTITUTE FOR A WRITING. Notwithstanding the Uniform Electronic Transactions Act or the applicability of any other law of similar substance and effect, absent an express statement to the contrary hereinabove, this e-mail message its contents, and any attachments hereto are not intended to represent an offer or acceptance to enter into a contract and are not otherwise intended to bind the sender, Sanmina Corporation (or any of its subsidiaries), or any other person or entity.


Re: Request for Camera CSI support for IMX

Jan Kiszka
 

Hi Lakshmi,

On 21.10.20 11:50, Lakshmi Natarajan wrote:
Hello Jan,
This is regarding requests for CSI support in the IMX processor.
We were using Yocto + NXP provided kernel to use the CSI peripheral of the IMX6 processor. We have complete support from NXP for their kernel along with the Yocto framework.
We want to move to CIP 4.19 + ISAR framework.
When we checked CIP kernel 4.19 - there was no support for CSI interface as well as there were some differences in the arch support too.
After study of the NXP provided framework, we found that they use the kernel from https://source.codeaurora.org/external/imx/linux-imxand commit ID 0f9917c56d5995e1dc3bde5658e2d7bc865464de.
Even linux kernel 5.9 doesn't have the imx specific support.
That's unfortunate.

Can you guide us on how we should proceed with the same - will it be possible for CIP to add IMX support (or) should we request NXP to add the patch for CIP kernel 4.19
Yes, please reach out to NXP and ask what their answer for upstream is, today or at least for the future. It's their issue in the first place. Also for that, you should prepare with naming the kernel interfaces or drivers you need in more details.

If NXP cannot or do not want to answer this appropriately, plan B) will be identifying the patches they provide on top of the upstream kernel, optimally 4.19. Those patches then needs to be applied on top of the CIP kernel but, as they are unfortunately downstream only, you will then have to maintain them for your product and can't propose them for the CIP kernel.

Best regards,
Jan

Regards,
Lakshmi
On Tue, Oct 20, 2020 at 5:48 PM Rajashree Sankar <rajashree.sankar@... <mailto:rajashree.sankar@...>> wrote:
Hello Jan,
We have used Yocto Framework provided by NXP from the following link
<https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/evaluation-kit-for-the-i-mx-6ull-and-6ulz-applications-processor:MCIMX6ULL-EVK?fpsp=1#documentsandsoftware>.Refer
to the Document
L4.19.35_1.1.0_LINUX_DOCS
<https://www.nxp.com/webapp/Download?colCode=L4.19.35_1.1.0_LINUX_DOCS> in the above mentioned link.
The DT-bindings and the IMX Camera capture information will be
available by following the steps mentioned in the document
i.MX_Yocto_Project_User's_Guide from the above link.
The Kernel which we are using is fetched from the bitbake files
attached below( linux-yocto_4.19.bb <http://linux-yocto_4.19.bb> and
its append).Could you please let us know whether CSI  Camera capture
supported in this kernel be included in the Linux CIP?
Thanks and Regards,
Rajashree Sankar
CONFIDENTIALITY
This e-mail message and any attachments thereto, is intended only for use by the addressee(s) named herein and may contain legally privileged and/or confidential information. If you are not the intended recipient of this e-mail message, you are hereby notified that any dissemination, distribution or copying of this e-mail message, and any attachments thereto, is strictly prohibited. If you have received this e-mail message in error, please immediately notify the sender and permanently delete the original and any copies of this email and any prints thereof.
ABSENT AN EXPRESS STATEMENT TO THE CONTRARY HEREINABOVE, THIS E-MAIL IS NOT INTENDED AS A SUBSTITUTE FOR A WRITING. Notwithstanding the Uniform Electronic Transactions Act or the applicability of any other law of similar substance and effect, absent an express statement to the contrary hereinabove, this e-mail message its contents, and any attachments hereto are not intended to represent an offer or acceptance to enter into a contract and are not otherwise intended to bind the sender, Sanmina Corporation (or any of its subsidiaries), or any other person or entity.
--
Siemens AG, T RDA IOT
Corporate Competence Center Embedded Linux

3501 - 3520 of 9150