Date   

[PATCH 4.19.y-cip 12/13] PCI: rcar: Rename pcie-rcar.c to pcie-rcar-host.c

Lad Prabhakar
 

commit a18f4b6ea50b81e28bd05381883a531ab345f753 upstream.

This commit renames pcie-rcar.c to pcie-rcar-host.c in preparation for
adding support for endpoint mode. CONFIG_PCIE_RCAR is kept so that arm64
defconfig change can be a separate patch.

With this patch both config options PCIE_RCAR and PCIE_RCAR_HOST will be
available but PCIE_RCAR internally selects PCIE_RCAR_HOST so that bisect
builds wont be affected.

Link: https://lore.kernel.org/r/1588854799-13710-2-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@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/controller/Kconfig | 10 ++++++++++
drivers/pci/controller/Makefile | 2 +-
.../pci/controller/{pcie-rcar.c => pcie-rcar-host.c} | 0
3 files changed, 11 insertions(+), 1 deletion(-)
rename drivers/pci/controller/{pcie-rcar.c => pcie-rcar-host.c} (100%)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287466fb..6a80ee98aab9 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -84,8 +84,18 @@ config PCIE_RCAR
bool "Renesas R-Car PCIe controller"
depends on ARCH_RENESAS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_RCAR_HOST
help
Say Y here if you want PCIe controller support on R-Car SoCs.
+ This option will be removed after arm64 defconfig is updated.
+
+config PCIE_RCAR_HOST
+ bool "Renesas R-Car PCIe host controller"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on PCI_MSI_IRQ_DOMAIN
+ help
+ Say Y here if you want PCIe controller support on R-Car SoCs in host
+ mode.

config PCI_HOST_COMMON
bool
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index d56a507495c5..ad0112741d6b 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
-obj-$(CONFIG_PCIE_RCAR) += pcie-rcar.o
+obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar-host.o
obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar-host.c
similarity index 100%
rename from drivers/pci/controller/pcie-rcar.c
rename to drivers/pci/controller/pcie-rcar-host.c
--
2.17.1


[PATCH 4.19.y-cip 11/13] PCI: endpoint: functions/pci-epf-test: Print throughput information

Lad Prabhakar
 

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

commit 5893c2e5353bb9a723d862d8b6ba8028a8f6a6eb upstream.

Print throughput information in KB/s after every completed transfer,
including information on whether DMA is used or not.

Signed-off-by: Kishon Vijay Abraham I <kishon@...>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@...>
Tested-by: Alan Mikhak <alan.mikhak@...>
[PL: Applied changes to pci-epf-test.c manually, always pass dma variable
to pci_epf_test_print_rate() function as false since streaming DMA support
is missing in EPF]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index f6905c242194..8d9b5521ed50 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -73,6 +73,36 @@ static struct pci_epf_header test_header = {

static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };

+static void pci_epf_test_print_rate(const char *ops, u64 size,
+ struct timespec64 *start,
+ struct timespec64 *end, bool dma)
+{
+ struct timespec64 ts;
+ u64 rate, ns;
+
+ ts = timespec64_sub(*end, *start);
+
+ /* convert both size (stored in 'rate') and time in terms of 'ns' */
+ ns = timespec64_to_ns(&ts);
+ rate = size * NSEC_PER_SEC;
+
+ /* Divide both size (stored in 'rate') and ns by a common factor */
+ while (ns > UINT_MAX) {
+ rate >>= 1;
+ ns >>= 1;
+ }
+
+ if (!ns)
+ return;
+
+ /* calculate the rate */
+ do_div(rate, (uint32_t)ns);
+
+ pr_info("\n%s => Size: %llu bytes\t DMA: %s\t Time: %llu.%09u seconds\t"
+ "Rate: %llu KB/s\n", ops, size, dma ? "YES" : "NO",
+ (u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
+}
+
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
{
int ret;
@@ -80,6 +110,7 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
void __iomem *dst_addr;
phys_addr_t src_phys_addr;
phys_addr_t dst_phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -118,7 +149,10 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
goto err_dst_addr;
}

+ ktime_get_ts64(&start);
memcpy(dst_addr, src_addr, reg->size);
+ ktime_get_ts64(&end);
+ pci_epf_test_print_rate("COPY", reg->size, &start, &end, false);

pci_epc_unmap_addr(epc, epf->func_no, dst_phys_addr);

@@ -142,6 +176,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
void *buf;
u32 crc32;
phys_addr_t phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -170,7 +205,11 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
goto err_map_addr;
}

+ ktime_get_ts64(&start);
memcpy_fromio(buf, src_addr, reg->size);
+ ktime_get_ts64(&end);
+
+ pci_epf_test_print_rate("READ", reg->size, &start, &end, false);

crc32 = crc32_le(~0, buf, reg->size);
if (crc32 != reg->checksum)
@@ -194,6 +233,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
void __iomem *dst_addr;
void *buf;
phys_addr_t phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -225,7 +265,11 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
get_random_bytes(buf, reg->size);
reg->checksum = crc32_le(~0, buf, reg->size);

+ ktime_get_ts64(&start);
memcpy_toio(dst_addr, buf, reg->size);
+ ktime_get_ts64(&end);
+
+ pci_epf_test_print_rate("WRITE", reg->size, &start, &end, false);

/*
* wait 1ms inorder for the write to complete. Without this delay L3
--
2.17.1


[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

3501 - 3520 of 9152