2018-07-09 17:45:52

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 00/12] Add MSI-X support on pcitest tool

Patch series made against Lorenzo's master branch.

Fix EP link notification implementation.

Add MSI-X support on pcitest tool.

Add new callbacks methods and handlers to trigger the MSI-X interrupts
on the EP DesignWare IP driver.

Allow to set/get MSI-X EP maximum capability number.

Rework on set/get and triggering MSI methods on EP DesignWare IP driver.

Add a new input parameter (msix) to pcitest tool to test MSI-X feature.

Update the pcitest.sh script to support MSI-X feature tests.

Gustavo Pimentel (12):
PCI: dwc: Fix EP link notification implementation
PCI: endpoint: Add MSI-X interfaces
PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
PCI: dwc: Add MSI-X callbacks handler
PCI: dwc: Rework MSI callbacks handler
PCI: dwc: Add legacy interrupt callback handler
pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
pci-epf-test/pci_endpoint_test: Use irq_type module parameter
pci-epf-test/pci_endpoint_test: Add MSI-X support
pci_endpoint_test: Add 2 ioctl commands
tools: PCI: Add MSI-X support
PCI: endpoint: Add MSI set maximum restriction

Documentation/PCI/endpoint/pci-test-function.txt | 8 +-
Documentation/ioctl/ioctl-number.txt | 1 +
Documentation/misc-devices/pci-endpoint-test.txt | 6 +
drivers/misc/pci_endpoint_test.c | 260 ++++++++++++++++------
drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-ep.c | 217 ++++++++++++++++--
drivers/pci/controller/dwc/pcie-designware-plat.c | 11 +-
drivers/pci/controller/dwc/pcie-designware.h | 31 ++-
drivers/pci/controller/pcie-cadence-ep.c | 3 +-
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/functions/pci-epf-test.c | 86 +++++--
drivers/pci/endpoint/pci-ep-cfs.c | 24 ++
drivers/pci/endpoint/pci-epc-core.c | 68 +++++-
include/linux/pci-epc.h | 16 +-
include/linux/pci-epf.h | 1 +
include/uapi/linux/pcitest.h | 3 +
tools/pci/pcitest.c | 51 ++++-
tools/pci/pcitest.sh | 15 ++
19 files changed, 664 insertions(+), 143 deletions(-)

--
2.7.4




2018-07-09 17:44:55

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 02/12] PCI: endpoint: Add MSI-X interfaces

Add PCI_EPC_IRQ_MSIX type.

Add MSI-X callbacks signatures to the ops structure.

Add sysfs interface for set/get MSI-X capability maximum number.

Signed-off-by: Gustavo Pimentel <[email protected]>
Acked-by: Kishon Vijay Abraham I <[email protected]>
---
Change v1->v2:
- Nothing changed, just to follow the patch set version.
Change v2->v3:
- Moved pci_epc_raise_irq() signature changes to patch file #3.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

drivers/pci/endpoint/pci-ep-cfs.c | 24 ++++++++++++++++
drivers/pci/endpoint/pci-epc-core.c | 57 +++++++++++++++++++++++++++++++++++++
include/linux/pci-epc.h | 9 ++++++
include/linux/pci-epf.h | 1 +
4 files changed, 91 insertions(+)

diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index 018ea34..d1288a0 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -286,6 +286,28 @@ static ssize_t pci_epf_msi_interrupts_show(struct config_item *item,
to_pci_epf_group(item)->epf->msi_interrupts);
}

+static ssize_t pci_epf_msix_interrupts_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ u16 val;
+ int ret;
+
+ ret = kstrtou16(page, 0, &val);
+ if (ret)
+ return ret;
+
+ to_pci_epf_group(item)->epf->msix_interrupts = val;
+
+ return len;
+}
+
+static ssize_t pci_epf_msix_interrupts_show(struct config_item *item,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ to_pci_epf_group(item)->epf->msix_interrupts);
+}
+
PCI_EPF_HEADER_R(vendorid)
PCI_EPF_HEADER_W_u16(vendorid)

@@ -327,6 +349,7 @@ CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);
CONFIGFS_ATTR(pci_epf_, subsys_id);
CONFIGFS_ATTR(pci_epf_, interrupt_pin);
CONFIGFS_ATTR(pci_epf_, msi_interrupts);
+CONFIGFS_ATTR(pci_epf_, msix_interrupts);

static struct configfs_attribute *pci_epf_attrs[] = {
&pci_epf_attr_vendorid,
@@ -340,6 +363,7 @@ static struct configfs_attribute *pci_epf_attrs[] = {
&pci_epf_attr_subsys_id,
&pci_epf_attr_interrupt_pin,
&pci_epf_attr_msi_interrupts,
+ &pci_epf_attr_msix_interrupts,
NULL,
};

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index b0ee427..7d77bd0 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -218,6 +218,63 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
EXPORT_SYMBOL_GPL(pci_epc_set_msi);

/**
+ * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated
+ * @epc: the EPC device to which MSI-X interrupts was requested
+ * @func_no: the endpoint function number in the EPC device
+ *
+ * Invoke to get the number of MSI-X interrupts allocated by the RC
+ */
+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;
+
+ if (!epc->ops->get_msix)
+ return 0;
+
+ spin_lock_irqsave(&epc->lock, flags);
+ interrupt = epc->ops->get_msix(epc, func_no);
+ spin_unlock_irqrestore(&epc->lock, flags);
+
+ if (interrupt < 0)
+ return 0;
+
+ return interrupt + 1;
+}
+EXPORT_SYMBOL_GPL(pci_epc_get_msix);
+
+/**
+ * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required
+ * @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
+ *
+ * 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 ret;
+ unsigned long flags;
+
+ if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
+ interrupts < 1 || interrupts > 2048)
+ return -EINVAL;
+
+ if (!epc->ops->set_msix)
+ return 0;
+
+ spin_lock_irqsave(&epc->lock, flags);
+ ret = epc->ops->set_msix(epc, func_no, interrupts - 1);
+ spin_unlock_irqrestore(&epc->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_set_msix);
+
+/**
* pci_epc_unmap_addr() - unmap CPU address from PCI address
* @epc: the EPC device on which address is allocated
* @func_no: the endpoint function number in the EPC device
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 243eaa5..89f079f 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -17,6 +17,7 @@ enum pci_epc_irq_type {
PCI_EPC_IRQ_UNKNOWN,
PCI_EPC_IRQ_LEGACY,
PCI_EPC_IRQ_MSI,
+ PCI_EPC_IRQ_MSIX,
};

/**
@@ -30,6 +31,10 @@ enum pci_epc_irq_type {
* capability register
* @get_msi: ops to get the number of MSI interrupts allocated by the RC from
* the MSI capability register
+ * @set_msix: ops to set the requested number of MSI-X interrupts in the
+ * MSI-X capability register
+ * @get_msix: ops to get the number of MSI-X interrupts allocated by the RC
+ * from the MSI-X capability register
* @raise_irq: ops to raise a legacy or MSI interrupt
* @start: ops to start the PCI link
* @stop: ops to stop the PCI link
@@ -48,6 +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 (*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, u8 interrupt_num);
int (*start)(struct pci_epc *epc);
@@ -144,6 +151,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_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, u8 interrupt_num);
int pci_epc_start(struct pci_epc *epc);
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 4e77649..ec02f587 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -119,6 +119,7 @@ struct pci_epf {
struct pci_epf_header *header;
struct pci_epf_bar bar[6];
u8 msi_interrupts;
+ u16 msix_interrupts;
u8 func_no;

struct pci_epc *epc;
--
2.7.4



2018-07-09 17:45:21

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 01/12] PCI: dwc: Fix EP link notification implementation

Move specific features settings from EP shared code
(pcie-designware-ep.c) to the driver (pcie-designware-plat.c).

Previous implementation disables the EP link notification
by default for all SoCs that uses EP DesignWare IP, which affects
directly the dra7xx and artpec6 SoCs.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v8->v9:
- Created patch file.

drivers/pci/controller/dwc/pcie-designware-ep.c | 14 ++++++--------
drivers/pci/controller/dwc/pcie-designware-plat.c | 3 +++
2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 8650416..04092a7 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -386,15 +386,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
return -ENOMEM;
ep->outbound_addr = addr;

- if (ep->ops->ep_init)
- ep->ops->ep_init(ep);
-
epc = devm_pci_epc_create(dev, &epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "Failed to create epc device\n");
return PTR_ERR(epc);
}

+ ep->epc = epc;
+ epc_set_drvdata(epc, ep);
+
+ if (ep->ops->ep_init)
+ ep->ops->ep_init(ep);
+
ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
if (ret < 0)
epc->max_functions = 1;
@@ -413,11 +416,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
return -ENOMEM;
}

- epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
- EPC_FEATURE_SET_BAR(epc->features, BAR_0);
-
- ep->epc = epc;
- epc_set_drvdata(epc, ep);
dw_pcie_setup(pci);

return 0;
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 5937fed..0ce3440 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -70,10 +70,13 @@ static const struct dw_pcie_ops dw_pcie_ops = {
static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ struct pci_epc *epc = ep->epc;
enum pci_barno bar;

for (bar = BAR_0; bar <= BAR_5; bar++)
dw_pcie_ep_reset_bar(pci, bar);
+
+ epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
}

static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
--
2.7.4



2018-07-09 17:45:35

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 03/12] PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures

Change {cdns, dra7xx, artpec6, dw, rockchip}_pcie_ep_raise_irq() and
pci_epc_raise_irq() signature, namely the interrupt_num variable type
from u8 to u16 to accommodate 2048 maximum MSI-X interrupts.

Signed-off-by: Gustavo Pimentel <[email protected]>
Acked-by: Alan Douglas <[email protected]>
Acked-by: Shawn Lin <[email protected]>
Acked-by: Jesper Nilsson <[email protected]>
Acked-by: Joao Pinto <[email protected]>
---
Change v1->v2:
- Nothing changed, just to follow the patch set version.
Change v2->v3:
- Move into here the pci_epc_raise_irq() signature change from patch
file #1.
- Move into here the {dra7xx, artpec6}_pcie_ep_raise_irq() signature
changes from patch file #2.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Swap patch files position (#3 -> #2).
- Moved dw_pcie_ep_raise_irq and dw_plat_pcie_ep_raise_irq functions
signatures changes from patch file #3.
- Changed rockchip_pcie_ep_raise_irq function signature.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +-
drivers/pci/controller/dwc/pcie-designware.h | 2 +-
drivers/pci/controller/pcie-cadence-ep.c | 3 ++-
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/pci-epc-core.c | 8 ++++----
include/linux/pci-epc.h | 6 +++---
9 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index 345aab5..ce9224a 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -370,7 +370,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx,
}

static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u8 interrupt_num)
+ enum pci_epc_irq_type type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
index 321b56c..9a2474b 100644
--- a/drivers/pci/controller/dwc/pcie-artpec6.c
+++ b/drivers/pci/controller/dwc/pcie-artpec6.c
@@ -428,7 +428,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
}

static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u8 interrupt_num)
+ enum pci_epc_irq_type type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 04092a7..69d039d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -242,7 +242,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
}

static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
- enum pci_epc_irq_type type, u8 interrupt_num)
+ enum pci_epc_irq_type type, u16 interrupt_num)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);

diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 0ce3440..0efb318 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -81,7 +81,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)

static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
enum pci_epc_irq_type type,
- u8 interrupt_num)
+ u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);

diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index bee4e25..9d581c0 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -191,7 +191,7 @@ enum dw_pcie_as_type {
struct dw_pcie_ep_ops {
void (*ep_init)(struct dw_pcie_ep *ep);
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u8 interrupt_num);
+ enum pci_epc_irq_type type, u16 interrupt_num);
};

struct dw_pcie_ep {
diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
index e3fe412..208d11f 100644
--- a/drivers/pci/controller/pcie-cadence-ep.c
+++ b/drivers/pci/controller/pcie-cadence-ep.c
@@ -363,7 +363,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
}

static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
- enum pci_epc_irq_type type, u8 interrupt_num)
+ enum pci_epc_irq_type type,
+ u16 interrupt_num)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);

diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index 6beba8e..b8163c5 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -472,7 +472,7 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,

static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
enum pci_epc_irq_type type,
- u8 interrupt_num)
+ u16 interrupt_num)
{
struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 7d77bd0..c72e656 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -131,13 +131,13 @@ EXPORT_SYMBOL_GPL(pci_epc_start);
* pci_epc_raise_irq() - interrupt the host system
* @epc: the EPC device which has to interrupt the host
* @func_no: the endpoint function number in the EPC device
- * @type: specify the type of interrupt; legacy or MSI
- * @interrupt_num: the MSI interrupt number
+ * @type: specify the type of interrupt; legacy, MSI or MSI-X
+ * @interrupt_num: the MSI or MSI-X interrupt number
*
- * Invoke to raise an MSI or legacy interrupt
+ * Invoke to raise an legacy, MSI or MSI-X interrupt
*/
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
- enum pci_epc_irq_type type, u8 interrupt_num)
+ enum pci_epc_irq_type type, u16 interrupt_num)
{
int ret;
unsigned long flags;
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 89f079f..bb2395b 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -35,7 +35,7 @@ enum pci_epc_irq_type {
* MSI-X capability register
* @get_msix: ops to get the number of MSI-X interrupts allocated by the RC
* from the MSI-X capability register
- * @raise_irq: ops to raise a legacy or MSI interrupt
+ * @raise_irq: ops to raise a legacy, MSI or MSI-X interrupt
* @start: ops to start the PCI link
* @stop: ops to stop the PCI link
* @owner: the module owner containing the ops
@@ -56,7 +56,7 @@ struct pci_epc_ops {
int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts);
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, u8 interrupt_num);
+ enum pci_epc_irq_type type, u16 interrupt_num);
int (*start)(struct pci_epc *epc);
void (*stop)(struct pci_epc *epc);
struct module *owner;
@@ -154,7 +154,7 @@ 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_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, u8 interrupt_num);
+ enum pci_epc_irq_type type, u16 interrupt_num);
int pci_epc_start(struct pci_epc *epc);
void pci_epc_stop(struct pci_epc *epc);
struct pci_epc *pci_epc_get(const char *epc_name);
--
2.7.4



2018-07-09 17:45:42

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 08/12] pci-epf-test/pci_endpoint_test: Use irq_type module parameter

Add new driver parameter to allow interruption type selection.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v2->v3:
- New patch file created base on the previous patch
"misc: pci_endpoint_test: Add MSI-X support" patch file following
Kishon's suggestion.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Removed unnecessary set to zero variable.
- Removed empty line.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

drivers/misc/pci_endpoint_test.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 35fbfbd..349794c 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -82,6 +82,10 @@ static bool no_msi;
module_param(no_msi, bool, 0444);
MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");

+static int irq_type = IRQ_TYPE_MSI;
+module_param(irq_type, int, 0444);
+MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
+
enum pci_barno {
BAR_0,
BAR_1,
@@ -108,7 +112,7 @@ struct pci_endpoint_test {
struct pci_endpoint_test_data {
enum pci_barno test_reg_bar;
size_t alignment;
- bool no_msi;
+ int irq_type;
};

static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
@@ -291,8 +295,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
size);

- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
COMMAND_COPY);
@@ -361,8 +364,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
COMMAND_READ);
@@ -419,8 +421,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
COMMAND_WRITE);
@@ -505,11 +506,14 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
test->alignment = 0;
test->pdev = pdev;

+ if (no_msi)
+ irq_type = IRQ_TYPE_LEGACY;
+
data = (struct pci_endpoint_test_data *)ent->driver_data;
if (data) {
test_reg_bar = data->test_reg_bar;
test->alignment = data->alignment;
- no_msi = data->no_msi;
+ irq_type = data->irq_type;
}

init_completion(&test->irq_raised);
@@ -529,11 +533,17 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,

pci_set_master(pdev);

- if (!no_msi) {
+ switch (irq_type) {
+ case IRQ_TYPE_LEGACY:
+ break;
+ case IRQ_TYPE_MSI:
irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
if (irq < 0)
dev_err(dev, "Failed to get MSI interrupts\n");
test->num_irqs = irq;
+ break;
+ default:
+ dev_err(dev, "Invalid IRQ type selected\n");
}

err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
--
2.7.4



2018-07-09 17:46:09

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 06/12] PCI: dwc: Add legacy interrupt callback handler

Add a legacy interrupt callback handler. Currently DesignWare IP don't
allow trigger legacy interrupts.

Signed-off-by: Gustavo Pimentel <[email protected]>
Acked-by: Kishon Vijay Abraham I <[email protected]>
---
Change v1->v2:
- Nothing changed, just to follow the patch set version.
Change v2->v3:
- Nothing changed, just to follow the patch set version.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.

drivers/pci/controller/dwc/pcie-designware-ep.c | 10 ++++++++++
drivers/pci/controller/dwc/pcie-designware-plat.c | 3 +--
drivers/pci/controller/dwc/pcie-designware.h | 6 ++++++
3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index afb48b5..9eec21f 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -370,6 +370,16 @@ static const struct pci_epc_ops epc_ops = {
.stop = dw_pcie_ep_stop,
};

+int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ struct device *dev = pci->dev;
+
+ dev_err(dev, "EP cannot trigger legacy IRQs\n");
+
+ return -EINVAL;
+}
+
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num)
{
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 8bb2ecb..160714d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -87,8 +87,7 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,

switch (type) {
case PCI_EPC_IRQ_LEGACY:
- dev_err(pci->dev, "EP cannot trigger legacy IRQs\n");
- return -EINVAL;
+ return dw_pcie_ep_raise_legacy_irq(ep, func_no);
case PCI_EPC_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
case PCI_EPC_IRQ_MSIX:
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index a0ab12f..69e6e17 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -350,6 +350,7 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep);
int dw_pcie_ep_init(struct dw_pcie_ep *ep);
void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
+int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no);
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num);
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
@@ -369,6 +370,11 @@ static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
{
}

+static inline int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
+{
+ return 0;
+}
+
static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num)
{
--
2.7.4



2018-07-09 17:46:41

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 10/12] pci_endpoint_test: Add 2 ioctl commands

Add MSI-X support and update driver documentation accordingly.

Add 2 new IOCTL commands:
- Allow to reconfigure driver IRQ type in runtime.
- Allow to retrieve current driver IRQ type configured.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v2->v3:
- New patch file created base on the previous patch
"misc: pci_endpoint_test: Add MSI-X support" patch file following
Kishon's suggestion.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Moved PCITEST_SET_IRQTYPE and PCITEST_GET_IRQTYPE ioctl entries
from patch #10 to here.
- Increased ioctl parameters range associated to
drivers/misc/pci_endpoint_test.c driver.
Change v6->v7:
- irq_type variable update just before returning the function.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Added a extra parameter to pci_endpoint_test_alloc_irq_vectors,
that specifies which irq type should be allocated.

Documentation/ioctl/ioctl-number.txt | 2 +-
Documentation/misc-devices/pci-endpoint-test.txt | 3 +
drivers/misc/pci_endpoint_test.c | 176 +++++++++++++++++------
include/uapi/linux/pcitest.h | 2 +
4 files changed, 136 insertions(+), 47 deletions(-)

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 65259d4..c15c4f3 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -166,7 +166,7 @@ Code Seq#(hex) Include File Comments
'P' all linux/soundcard.h conflict!
'P' 60-6F sound/sscape_ioctl.h conflict!
'P' 00-0F drivers/usb/class/usblp.c conflict!
-'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
+'P' 01-09 drivers/misc/pci_endpoint_test.c conflict!
'Q' all linux/soundcard.h
'R' 00-1F linux/random.h conflict!
'R' 01 linux/rfkill.h conflict!
diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
index fdfa0f6..58ccca4 100644
--- a/Documentation/misc-devices/pci-endpoint-test.txt
+++ b/Documentation/misc-devices/pci-endpoint-test.txt
@@ -28,6 +28,9 @@ ioctl
to be tested should be passed as argument.
PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
to be tested should be passed as argument.
+ PCITEST_SET_IRQTYPE: Changes driver IRQ type configuration. The IRQ type
+ should be passed as argument (0: Legacy, 1:MSI, 2:MSI-X).
+ PCITEST_GET_IRQTYPE: Gets driver IRQ type configuration.
PCITEST_WRITE: Perform write tests. The size of the buffer should be passed
as argument.
PCITEST_READ: Perform read tests. The size of the buffer should be passed
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index f4fef10..ce4b79a 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -157,6 +157,88 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
return IRQ_HANDLED;
}

+static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
+{
+ int i;
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+
+ for (i = 0; i < test->num_irqs; i++)
+ devm_free_irq(dev, pci_irq_vector(pdev, i), test);
+
+ test->num_irqs = 0;
+}
+
+static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
+ int type)
+{
+ int irq = -1;
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ bool res = true;
+
+ switch (type) {
+ case IRQ_TYPE_LEGACY:
+ irq = 0;
+ break;
+ case IRQ_TYPE_MSI:
+ irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
+ if (irq < 0)
+ dev_err(dev, "Failed to get MSI interrupts\n");
+ break;
+ case IRQ_TYPE_MSIX:
+ irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
+ if (irq < 0)
+ dev_err(dev, "Failed to get MSI-X interrupts\n");
+ break;
+ default:
+ dev_err(dev, "Invalid IRQ type selected\n");
+ }
+
+ if (irq < 0) {
+ irq = 0;
+ res = false;
+ }
+ test->num_irqs = irq;
+
+ return res;
+}
+
+static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test)
+{
+ struct pci_dev *pdev = test->pdev;
+
+ pci_disable_msi(pdev);
+ pci_disable_msix(pdev);
+}
+
+static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
+{
+ int i;
+ int err;
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+
+ err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
+ IRQF_SHARED, DRV_MODULE_NAME, test);
+ if (err) {
+ dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
+ return false;
+ }
+
+ for (i = 1; i < test->num_irqs; i++) {
+ err = devm_request_irq(dev, pci_irq_vector(pdev, i),
+ pci_endpoint_test_irqhandler,
+ IRQF_SHARED, DRV_MODULE_NAME, test);
+ if (err)
+ dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
+ pci_irq_vector(pdev, i),
+ irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
+ }
+
+ return true;
+}
+
static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
enum pci_barno barno)
{
@@ -440,6 +522,38 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
return ret;
}

+static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
+ int req_irq_type)
+{
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+
+ if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
+ dev_err(dev, "Invalid IRQ type option\n");
+ return false;
+ }
+
+ if (irq_type == req_irq_type)
+ return true;
+
+ pci_endpoint_test_free_irq_vectors(test);
+ pci_endpoint_test_release_irq(test);
+
+ if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type)) {
+ pci_endpoint_test_release_irq(test);
+ return false;
+ }
+
+ if (!pci_endpoint_test_request_irq(test)) {
+ pci_endpoint_test_release_irq(test);
+ return false;
+ }
+
+ irq_type = req_irq_type;
+
+ return true;
+}
+
static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -471,6 +585,12 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
case PCITEST_COPY:
ret = pci_endpoint_test_copy(test, arg);
break;
+ case PCITEST_SET_IRQTYPE:
+ ret = pci_endpoint_test_set_irq(test, arg);
+ break;
+ case PCITEST_GET_IRQTYPE:
+ ret = irq_type;
+ break;
}

ret:
@@ -486,9 +606,7 @@ static const struct file_operations pci_endpoint_test_fops = {
static int pci_endpoint_test_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i;
int err;
- int irq = 0;
int id;
char name[20];
enum pci_barno bar;
@@ -537,41 +655,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,

pci_set_master(pdev);

- switch (irq_type) {
- case IRQ_TYPE_LEGACY:
- break;
- case IRQ_TYPE_MSI:
- irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
- if (irq < 0)
- dev_err(dev, "Failed to get MSI interrupts\n");
- test->num_irqs = irq;
- break;
- case IRQ_TYPE_MSIX:
- irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
- if (irq < 0)
- dev_err(dev, "Failed to get MSI-X interrupts\n");
- test->num_irqs = irq;
- break;
- default:
- dev_err(dev, "Invalid IRQ type selected\n");
- }
-
- err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
- IRQF_SHARED, DRV_MODULE_NAME, test);
- if (err) {
- dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
- goto err_disable_msi;
- }
+ if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
+ goto err_disable_irq;

- for (i = 1; i < irq; i++) {
- err = devm_request_irq(dev, pci_irq_vector(pdev, i),
- pci_endpoint_test_irqhandler,
- IRQF_SHARED, DRV_MODULE_NAME, test);
- if (err)
- dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
- pci_irq_vector(pdev, i),
- irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
- }
+ if (!pci_endpoint_test_request_irq(test))
+ goto err_disable_irq;

for (bar = BAR_0; bar <= BAR_5; bar++) {
if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
@@ -631,12 +719,10 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
pci_iounmap(pdev, test->bar[bar]);
}

- for (i = 0; i < irq; i++)
- devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
+ pci_endpoint_test_free_irq_vectors(test);

-err_disable_msi:
- pci_disable_msi(pdev);
- pci_disable_msix(pdev);
+err_disable_irq:
+ pci_endpoint_test_release_irq(test);
pci_release_regions(pdev);

err_disable_pdev:
@@ -648,7 +734,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
static void pci_endpoint_test_remove(struct pci_dev *pdev)
{
int id;
- int i;
enum pci_barno bar;
struct pci_endpoint_test *test = pci_get_drvdata(pdev);
struct miscdevice *misc_device = &test->miscdev;
@@ -665,10 +750,9 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
if (test->bar[bar])
pci_iounmap(pdev, test->bar[bar]);
}
- for (i = 0; i < test->num_irqs; i++)
- devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
- pci_disable_msi(pdev);
- pci_disable_msix(pdev);
+ pci_endpoint_test_free_irq_vectors(test);
+
+ pci_endpoint_test_release_irq(test);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index d746fb1..cbf422e 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -17,5 +17,7 @@
#define PCITEST_READ _IOW('P', 0x5, unsigned long)
#define PCITEST_COPY _IOW('P', 0x6, unsigned long)
#define PCITEST_MSIX _IOW('P', 0x7, int)
+#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
+#define PCITEST_GET_IRQTYPE _IO('P', 0x9)

#endif /* __UAPI_LINUX_PCITEST_H */
--
2.7.4



2018-07-09 17:46:42

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 09/12] pci-epf-test/pci_endpoint_test: Add MSI-X support

Add MSI-X support and update driver documentation accordingly.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v2->v3:
- New patch file created base on the previous patch
"misc: pci_endpoint_test: Add MSI-X support" patch file following
Kishon's suggestion.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Moved PCITEST_MSIX ioctl entry from patch #10 to here.
- Documented ioctl parameter type associated to
drivers/misc/pci_endpoint_test.c driver.
Change v6->v7:
- Updated documentation.
- Added flag that enables or not the MSI-X on the EP features.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Moving the EPC_FEATURE_MSIX_AVAILABLE feature set from the
dw_pcie_ep_init() to dw_plat_pcie_ep_init().

Documentation/PCI/endpoint/pci-test-function.txt | 2 +-
Documentation/ioctl/ioctl-number.txt | 1 +
Documentation/misc-devices/pci-endpoint-test.txt | 3 +++
drivers/misc/pci_endpoint_test.c | 29 ++++++++++++++++-------
drivers/pci/controller/dwc/pcie-designware-plat.c | 1 +
drivers/pci/endpoint/functions/pci-epf-test.c | 29 +++++++++++++++++++++--
include/linux/pci-epc.h | 1 +
include/uapi/linux/pcitest.h | 1 +
8 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt
index 7ee2361..b1cbff3 100644
--- a/Documentation/PCI/endpoint/pci-test-function.txt
+++ b/Documentation/PCI/endpoint/pci-test-function.txt
@@ -34,7 +34,7 @@ that the endpoint device must perform.
Bitfield Description:
Bit 0 : raise legacy IRQ
Bit 1 : raise MSI IRQ
- Bit 2 : raise MSI-X IRQ (reserved for future implementation)
+ Bit 2 : raise MSI-X IRQ
Bit 3 : read command (read data from RC buffer)
Bit 4 : write command (write data to RC buffer)
Bit 5 : copy command (copy data from one RC buffer to another
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 480c860..65259d4 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -166,6 +166,7 @@ Code Seq#(hex) Include File Comments
'P' all linux/soundcard.h conflict!
'P' 60-6F sound/sscape_ioctl.h conflict!
'P' 00-0F drivers/usb/class/usblp.c conflict!
+'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
'Q' all linux/soundcard.h
'R' 00-1F linux/random.h conflict!
'R' 01 linux/rfkill.h conflict!
diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
index 4ebc359..fdfa0f6 100644
--- a/Documentation/misc-devices/pci-endpoint-test.txt
+++ b/Documentation/misc-devices/pci-endpoint-test.txt
@@ -10,6 +10,7 @@ The PCI driver for the test device performs the following tests
*) verifying addresses programmed in BAR
*) raise legacy IRQ
*) raise MSI IRQ
+ *) raise MSI-X IRQ
*) read data
*) write data
*) copy data
@@ -25,6 +26,8 @@ ioctl
PCITEST_LEGACY_IRQ: Tests legacy IRQ
PCITEST_MSI: Tests message signalled interrupts. The MSI number
to be tested should be passed as argument.
+ PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
+ to be tested should be passed as argument.
PCITEST_WRITE: Perform write tests. The size of the buffer should be passed
as argument.
PCITEST_READ: Perform read tests. The size of the buffer should be passed
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 349794c..f4fef10 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -39,13 +39,14 @@

#define IRQ_TYPE_LEGACY 0
#define IRQ_TYPE_MSI 1
+#define IRQ_TYPE_MSIX 2

#define PCI_ENDPOINT_TEST_MAGIC 0x0

#define PCI_ENDPOINT_TEST_COMMAND 0x4
#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
-/* BIT(2) is reserved for raising MSI-X IRQ command */
+#define COMMAND_RAISE_MSIX_IRQ BIT(2)
#define COMMAND_READ BIT(3)
#define COMMAND_WRITE BIT(4)
#define COMMAND_COPY BIT(5)
@@ -84,7 +85,7 @@ MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");

static int irq_type = IRQ_TYPE_MSI;
module_param(irq_type, int, 0444);
-MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
+MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)");

enum pci_barno {
BAR_0,
@@ -202,16 +203,18 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
}

static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
- u8 msi_num)
+ u16 msi_num, bool msix)
{
u32 val;
struct pci_dev *pdev = test->pdev;

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- IRQ_TYPE_MSI);
+ msix == false ? IRQ_TYPE_MSI :
+ IRQ_TYPE_MSIX);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- COMMAND_RAISE_MSI_IRQ);
+ msix == false ? COMMAND_RAISE_MSI_IRQ :
+ COMMAND_RAISE_MSIX_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
msecs_to_jiffies(1000));
if (!val)
@@ -456,7 +459,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
ret = pci_endpoint_test_legacy_irq(test);
break;
case PCITEST_MSI:
- ret = pci_endpoint_test_msi_irq(test, arg);
+ case PCITEST_MSIX:
+ ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX);
break;
case PCITEST_WRITE:
ret = pci_endpoint_test_write(test, arg);
@@ -542,6 +546,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
dev_err(dev, "Failed to get MSI interrupts\n");
test->num_irqs = irq;
break;
+ case IRQ_TYPE_MSIX:
+ irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
+ if (irq < 0)
+ dev_err(dev, "Failed to get MSI-X interrupts\n");
+ test->num_irqs = irq;
+ break;
default:
dev_err(dev, "Invalid IRQ type selected\n");
}
@@ -558,8 +568,9 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
pci_endpoint_test_irqhandler,
IRQF_SHARED, DRV_MODULE_NAME, test);
if (err)
- dev_err(dev, "failed to request IRQ %d for MSI %d\n",
- pci_irq_vector(pdev, i), i + 1);
+ dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
+ pci_irq_vector(pdev, i),
+ irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
}

for (bar = BAR_0; bar <= BAR_5; bar++) {
@@ -625,6 +636,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,

err_disable_msi:
pci_disable_msi(pdev);
+ pci_disable_msix(pdev);
pci_release_regions(pdev);

err_disable_pdev:
@@ -656,6 +668,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
for (i = 0; i < test->num_irqs; i++)
devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
pci_disable_msi(pdev);
+ pci_disable_msix(pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 160714d..d2dd0c7 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -77,6 +77,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
dw_pcie_ep_reset_bar(pci, bar);

epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
+ epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
}

static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index eb9cd00..123f58c 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -20,10 +20,11 @@

#define IRQ_TYPE_LEGACY 0
#define IRQ_TYPE_MSI 1
+#define IRQ_TYPE_MSIX 2

#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
-/* BIT(2) is reserved for raising MSI-X IRQ command */
+#define COMMAND_RAISE_MSIX_IRQ BIT(2)
#define COMMAND_READ BIT(3)
#define COMMAND_WRITE BIT(4)
#define COMMAND_COPY BIT(5)
@@ -47,6 +48,7 @@ struct pci_epf_test {
struct pci_epf *epf;
enum pci_barno test_reg_bar;
bool linkup_notifier;
+ bool msix_available;
struct delayed_work cmd_handler;
};

@@ -266,6 +268,9 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
case IRQ_TYPE_MSI:
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
break;
+ case IRQ_TYPE_MSIX:
+ pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq);
+ break;
default:
dev_err(dev, "Failed to raise IRQ, unknown type\n");
break;
@@ -292,7 +297,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->command = 0;
reg->status = 0;

- if (reg->irq_type > IRQ_TYPE_MSI) {
+ if (reg->irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Failed to detect IRQ type\n");
goto reset_handler;
}
@@ -346,6 +351,16 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
goto reset_handler;
}

+ if (command & COMMAND_RAISE_MSIX_IRQ) {
+ count = pci_epc_get_msix(epc, epf->func_no);
+ if (reg->irq_number > count || count <= 0)
+ goto reset_handler;
+ reg->status = STATUS_IRQ_RAISED;
+ pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX,
+ reg->irq_number);
+ goto reset_handler;
+ }
+
reset_handler:
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
msecs_to_jiffies(1));
@@ -459,6 +474,8 @@ static int pci_epf_test_bind(struct pci_epf *epf)
else
epf_test->linkup_notifier = true;

+ epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE;
+
epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features);

ret = pci_epc_write_header(epc, epf->func_no, header);
@@ -481,6 +498,14 @@ static int pci_epf_test_bind(struct pci_epf *epf)
return ret;
}

+ if (epf_test->msix_available) {
+ ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
+ if (ret) {
+ dev_err(dev, "MSI-X configuration failed\n");
+ return ret;
+ }
+ }
+
if (!epf_test->linkup_notifier)
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);

diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index bb2395b..37dab81 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -102,6 +102,7 @@ struct pci_epc {

#define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0)
#define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3))
+#define EPC_FEATURE_MSIX_AVAILABLE BIT(4)
#define EPC_FEATURE_SET_BAR(features, bar) \
(features |= (EPC_FEATURE_BAR_MASK & (bar << 1)))
#define EPC_FEATURE_GET_BAR(features) \
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index 953cf03..d746fb1 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -16,5 +16,6 @@
#define PCITEST_WRITE _IOW('P', 0x4, unsigned long)
#define PCITEST_READ _IOW('P', 0x5, unsigned long)
#define PCITEST_COPY _IOW('P', 0x6, unsigned long)
+#define PCITEST_MSIX _IOW('P', 0x7, int)

#endif /* __UAPI_LINUX_PCITEST_H */
--
2.7.4



2018-07-09 17:46:46

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 11/12] tools: PCI: Add MSI-X support

Add MSI-X support to pcitest tool.

Modify pcitest.sh script to accommodate MSI-X interrupt tests.

Signed-off-by: Gustavo Pimentel <[email protected]>
Acked-by: Kishon Vijay Abraham I <[email protected]>
---
Change v1->v2:
- Allow IRQ type driver reconfiguring in runtime, follwing Kishon's
suggestion.
Change v2->v3:
- Nothing changed, just to follow the patch set version.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Nothing changed, just to follow the patch set version.
Change v5->v6:
- Moved PCITEST_MSIX ioctl entry to patch #8.
- Moved PCITEST_SET_IRQTYPE and PCITEST_GET_IRQTYPE ioctl entries
to patch #9.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

tools/pci/pcitest.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
tools/pci/pcitest.sh | 15 +++++++++++++++
2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c
index 9074b47..af146bb 100644
--- a/tools/pci/pcitest.c
+++ b/tools/pci/pcitest.c
@@ -31,12 +31,17 @@
#define BILLION 1E9

static char *result[] = { "NOT OKAY", "OKAY" };
+static char *irq[] = { "LEGACY", "MSI", "MSI-X" };

struct pci_test {
char *device;
char barnum;
bool legacyirq;
unsigned int msinum;
+ unsigned int msixnum;
+ int irqtype;
+ bool set_irqtype;
+ bool get_irqtype;
bool read;
bool write;
bool copy;
@@ -65,6 +70,24 @@ static int run_test(struct pci_test *test)
fprintf(stdout, "%s\n", result[ret]);
}

+ if (test->set_irqtype) {
+ ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype);
+ fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]);
+ if (ret < 0)
+ fprintf(stdout, "FAILED\n");
+ else
+ fprintf(stdout, "%s\n", result[ret]);
+ }
+
+ if (test->get_irqtype) {
+ ret = ioctl(fd, PCITEST_GET_IRQTYPE);
+ fprintf(stdout, "GET IRQ TYPE:\t\t");
+ if (ret < 0)
+ fprintf(stdout, "FAILED\n");
+ else
+ fprintf(stdout, "%s\n", irq[ret]);
+ }
+
if (test->legacyirq) {
ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0);
fprintf(stdout, "LEGACY IRQ:\t");
@@ -83,6 +106,15 @@ static int run_test(struct pci_test *test)
fprintf(stdout, "%s\n", result[ret]);
}

+ if (test->msixnum > 0 && test->msixnum <= 2048) {
+ ret = ioctl(fd, PCITEST_MSIX, test->msixnum);
+ fprintf(stdout, "MSI-X%d:\t\t", test->msixnum);
+ if (ret < 0)
+ fprintf(stdout, "TEST FAILED\n");
+ else
+ fprintf(stdout, "%s\n", result[ret]);
+ }
+
if (test->write) {
ret = ioctl(fd, PCITEST_WRITE, test->size);
fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size);
@@ -133,7 +165,7 @@ int main(int argc, char **argv)
/* set default endpoint device */
test->device = "/dev/pci-endpoint-test.0";

- while ((c = getopt(argc, argv, "D:b:m:lrwcs:")) != EOF)
+ while ((c = getopt(argc, argv, "D:b:m:x:i:Ilrwcs:")) != EOF)
switch (c) {
case 'D':
test->device = optarg;
@@ -151,6 +183,20 @@ int main(int argc, char **argv)
if (test->msinum < 1 || test->msinum > 32)
goto usage;
continue;
+ case 'x':
+ test->msixnum = atoi(optarg);
+ if (test->msixnum < 1 || test->msixnum > 2048)
+ goto usage;
+ continue;
+ case 'i':
+ test->irqtype = atoi(optarg);
+ if (test->irqtype < 0 || test->irqtype > 2)
+ goto usage;
+ test->set_irqtype = true;
+ continue;
+ case 'I':
+ test->get_irqtype = true;
+ continue;
case 'r':
test->read = true;
continue;
@@ -173,6 +219,9 @@ int main(int argc, char **argv)
"\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n"
"\t-b <bar num> BAR test (bar number between 0..5)\n"
"\t-m <msi num> MSI test (msi number between 1..32)\n"
+ "\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n"
+ "\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n"
+ "\t-I Get current IRQ type configured\n"
"\t-l Legacy IRQ test\n"
"\t-r Read buffer test\n"
"\t-w Write buffer test\n"
diff --git a/tools/pci/pcitest.sh b/tools/pci/pcitest.sh
index 77e8c85..75ed48f 100644
--- a/tools/pci/pcitest.sh
+++ b/tools/pci/pcitest.sh
@@ -16,7 +16,10 @@ echo
echo "Interrupt tests"
echo

+pcitest -i 0
pcitest -l
+
+pcitest -i 1
msi=1

while [ $msi -lt 33 ]
@@ -26,9 +29,21 @@ do
done
echo

+pcitest -i 2
+msix=1
+
+while [ $msix -lt 2049 ]
+do
+ pcitest -x $msix
+ msix=`expr $msix + 1`
+done
+echo
+
echo "Read Tests"
echo

+pcitest -i 1
+
pcitest -r -s 1
pcitest -r -s 1024
pcitest -r -s 1025
--
2.7.4



2018-07-09 17:47:04

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 12/12] PCI: endpoint: Add MSI set maximum restriction

Add pci_epc_set_msi() maximum 32 interrupts validation.

Signed-off-by: Gustavo Pimentel <[email protected]>
Acked-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/endpoint/pci-epc-core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index c72e656..094dcc3 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -201,7 +201,8 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
u8 encode_int;
unsigned long flags;

- if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
+ if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions ||
+ interrupts > 32)
return -EINVAL;

if (!epc->ops->set_msi)
--
2.7.4



2018-07-09 17:47:14

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 07/12] pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace

Cleanup PCI_ENDPOINT_TEST memspace (by moving the interrupt number away
from command section).

Update documentation accordingly.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v2->v3:
- New patch file created base on the previous patch
"misc: pci_endpoint_test: Add MSI-X support" patch file following
Kishon's suggestion.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Reverted irq_num rename to msi_num.
- Added comment about the MSI-X bit reservation for future implementation.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Updated documentation.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

Documentation/PCI/endpoint/pci-test-function.txt | 8 +--
drivers/misc/pci_endpoint_test.c | 81 +++++++++++++++---------
drivers/pci/endpoint/functions/pci-epf-test.c | 61 ++++++++++++------
3 files changed, 95 insertions(+), 55 deletions(-)

diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt
index 0c519c9..7ee2361 100644
--- a/Documentation/PCI/endpoint/pci-test-function.txt
+++ b/Documentation/PCI/endpoint/pci-test-function.txt
@@ -34,10 +34,10 @@ that the endpoint device must perform.
Bitfield Description:
Bit 0 : raise legacy IRQ
Bit 1 : raise MSI IRQ
- Bit 2 - 7 : MSI interrupt number
- Bit 8 : read command (read data from RC buffer)
- Bit 9 : write command (write data to RC buffer)
- Bit 10 : copy command (copy data from one RC buffer to another
+ Bit 2 : raise MSI-X IRQ (reserved for future implementation)
+ Bit 3 : read command (read data from RC buffer)
+ Bit 4 : write command (write data to RC buffer)
+ Bit 5 : copy command (copy data from one RC buffer to another
RC buffer)

*) PCI_ENDPOINT_TEST_STATUS
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 7b37046..35fbfbd 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -35,38 +35,43 @@

#include <uapi/linux/pcitest.h>

-#define DRV_MODULE_NAME "pci-endpoint-test"
-
-#define PCI_ENDPOINT_TEST_MAGIC 0x0
-
-#define PCI_ENDPOINT_TEST_COMMAND 0x4
-#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
-#define COMMAND_RAISE_MSI_IRQ BIT(1)
-#define MSI_NUMBER_SHIFT 2
-/* 6 bits for MSI number */
-#define COMMAND_READ BIT(8)
-#define COMMAND_WRITE BIT(9)
-#define COMMAND_COPY BIT(10)
-
-#define PCI_ENDPOINT_TEST_STATUS 0x8
-#define STATUS_READ_SUCCESS BIT(0)
-#define STATUS_READ_FAIL BIT(1)
-#define STATUS_WRITE_SUCCESS BIT(2)
-#define STATUS_WRITE_FAIL BIT(3)
-#define STATUS_COPY_SUCCESS BIT(4)
-#define STATUS_COPY_FAIL BIT(5)
-#define STATUS_IRQ_RAISED BIT(6)
-#define STATUS_SRC_ADDR_INVALID BIT(7)
-#define STATUS_DST_ADDR_INVALID BIT(8)
-
-#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc
+#define DRV_MODULE_NAME "pci-endpoint-test"
+
+#define IRQ_TYPE_LEGACY 0
+#define IRQ_TYPE_MSI 1
+
+#define PCI_ENDPOINT_TEST_MAGIC 0x0
+
+#define PCI_ENDPOINT_TEST_COMMAND 0x4
+#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
+#define COMMAND_RAISE_MSI_IRQ BIT(1)
+/* BIT(2) is reserved for raising MSI-X IRQ command */
+#define COMMAND_READ BIT(3)
+#define COMMAND_WRITE BIT(4)
+#define COMMAND_COPY BIT(5)
+
+#define PCI_ENDPOINT_TEST_STATUS 0x8
+#define STATUS_READ_SUCCESS BIT(0)
+#define STATUS_READ_FAIL BIT(1)
+#define STATUS_WRITE_SUCCESS BIT(2)
+#define STATUS_WRITE_FAIL BIT(3)
+#define STATUS_COPY_SUCCESS BIT(4)
+#define STATUS_COPY_FAIL BIT(5)
+#define STATUS_IRQ_RAISED BIT(6)
+#define STATUS_SRC_ADDR_INVALID BIT(7)
+#define STATUS_DST_ADDR_INVALID BIT(8)
+
+#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10

#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18

-#define PCI_ENDPOINT_TEST_SIZE 0x1c
-#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
+#define PCI_ENDPOINT_TEST_SIZE 0x1c
+#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
+
+#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
+#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28

static DEFINE_IDA(pci_endpoint_test_ida);

@@ -179,6 +184,9 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
{
u32 val;

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
+ IRQ_TYPE_LEGACY);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
COMMAND_RAISE_LEGACY_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
@@ -195,8 +203,10 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
u32 val;
struct pci_dev *pdev = test->pdev;

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
+ IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- msi_num << MSI_NUMBER_SHIFT |
COMMAND_RAISE_MSI_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
msecs_to_jiffies(1000));
@@ -281,8 +291,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
+ no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- 1 << MSI_NUMBER_SHIFT | COMMAND_COPY);
+ COMMAND_COPY);

wait_for_completion(&test->irq_raised);

@@ -348,8 +361,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
+ no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- 1 << MSI_NUMBER_SHIFT | COMMAND_READ);
+ COMMAND_READ);

wait_for_completion(&test->irq_raised);

@@ -403,8 +419,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
+ no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- 1 << MSI_NUMBER_SHIFT | COMMAND_WRITE);
+ COMMAND_WRITE);

wait_for_completion(&test->irq_raised);

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 63ed706..eb9cd00 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -18,13 +18,15 @@
#include <linux/pci-epf.h>
#include <linux/pci_regs.h>

+#define IRQ_TYPE_LEGACY 0
+#define IRQ_TYPE_MSI 1
+
#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
-#define MSI_NUMBER_SHIFT 2
-#define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT)
-#define COMMAND_READ BIT(8)
-#define COMMAND_WRITE BIT(9)
-#define COMMAND_COPY BIT(10)
+/* BIT(2) is reserved for raising MSI-X IRQ command */
+#define COMMAND_READ BIT(3)
+#define COMMAND_WRITE BIT(4)
+#define COMMAND_COPY BIT(5)

#define STATUS_READ_SUCCESS BIT(0)
#define STATUS_READ_FAIL BIT(1)
@@ -56,6 +58,8 @@ struct pci_epf_test_reg {
u64 dst_addr;
u32 size;
u32 checksum;
+ u32 irq_type;
+ u32 irq_number;
} __packed;

static struct pci_epf_header test_header = {
@@ -244,31 +248,39 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
return ret;
}

-static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq)
+static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
+ u16 irq)
{
- u8 msi_count;
struct pci_epf *epf = epf_test->epf;
+ struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];

reg->status |= STATUS_IRQ_RAISED;
- msi_count = pci_epc_get_msi(epc, epf->func_no);
- if (irq > msi_count || msi_count <= 0)
+
+ switch (irq_type) {
+ case IRQ_TYPE_LEGACY:
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
- else
+ break;
+ case IRQ_TYPE_MSI:
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
+ break;
+ default:
+ dev_err(dev, "Failed to raise IRQ, unknown type\n");
+ break;
+ }
}

static void pci_epf_test_cmd_handler(struct work_struct *work)
{
int ret;
- u8 irq;
- u8 msi_count;
+ u16 count;
u32 command;
struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
cmd_handler.work);
struct pci_epf *epf = epf_test->epf;
+ struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
@@ -280,7 +292,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->command = 0;
reg->status = 0;

- irq = (command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
+ if (reg->irq_type > IRQ_TYPE_MSI) {
+ dev_err(dev, "Failed to detect IRQ type\n");
+ goto reset_handler;
+ }

if (command & COMMAND_RAISE_LEGACY_IRQ) {
reg->status = STATUS_IRQ_RAISED;
@@ -294,7 +309,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_WRITE_FAIL;
else
reg->status |= STATUS_WRITE_SUCCESS;
- pci_epf_test_raise_irq(epf_test, irq);
+ pci_epf_test_raise_irq(epf_test, reg->irq_type,
+ reg->irq_number);
goto reset_handler;
}

@@ -304,7 +320,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_READ_SUCCESS;
else
reg->status |= STATUS_READ_FAIL;
- pci_epf_test_raise_irq(epf_test, irq);
+ pci_epf_test_raise_irq(epf_test, reg->irq_type,
+ reg->irq_number);
goto reset_handler;
}

@@ -314,16 +331,18 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_COPY_SUCCESS;
else
reg->status |= STATUS_COPY_FAIL;
- pci_epf_test_raise_irq(epf_test, irq);
+ pci_epf_test_raise_irq(epf_test, reg->irq_type,
+ reg->irq_number);
goto reset_handler;
}

if (command & COMMAND_RAISE_MSI_IRQ) {
- msi_count = pci_epc_get_msi(epc, epf->func_no);
- if (irq > msi_count || msi_count <= 0)
+ count = pci_epc_get_msi(epc, epf->func_no);
+ if (reg->irq_number > count || count <= 0)
goto reset_handler;
reg->status = STATUS_IRQ_RAISED;
- pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
+ pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI,
+ reg->irq_number);
goto reset_handler;
}

@@ -457,8 +476,10 @@ static int pci_epf_test_bind(struct pci_epf *epf)
return ret;

ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
- if (ret)
+ if (ret) {
+ dev_err(dev, "MSI configuration failed\n");
return ret;
+ }

if (!epf_test->linkup_notifier)
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
--
2.7.4



2018-07-09 17:48:34

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 04/12] PCI: dwc: Add MSI-X callbacks handler

Add PCIe config space capability search function.

Add sysfs set/get interface to allow the change of EP MSI-X maximum number.

Add EP MSI-X callback for triggering interruptions.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v1->v2:
- Nothing changed, just to follow the patch set version.
Change v2->v3:
- Moved dra7xx_pcie_raise_irq() signature change to patch file #3.
- Moved artpec6_pcie_raise_irq() signature change to patch file #3.
- Replaced wrong return value 0 to -EINVAL.
- Removed an else if by code refactoring.
- Reduced the size of ioremap_nocache mapping from ep->addr_size to
PCI_MSIX_ENTRY_SIZE.
- Fixed a small bug. If the MSI-X vector bit has been set, the function
would return without executing the proper unmap.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
- Added static prefix to __dw_pcie_ep_find_next_cap function.
Change v4->v5:
- Added static prefix to dw_pcie_ep_find_capability function.
- Swap patch files position (#2 <-> #3).
- Moved dw_pcie_ep_raise_irq and dw_plat_pcie_ep_raise_irq functions
signatures change to patch file #2.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

drivers/pci/controller/dwc/pcie-designware-ep.c | 144 ++++++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +
drivers/pci/controller/dwc/pcie-designware.h | 12 ++
3 files changed, 158 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 69d039d..72c4188 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
__dw_pcie_ep_reset_bar(pci, bar, 0);
}

+static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
+ u8 cap)
+{
+ u8 cap_id, next_cap_ptr;
+ u16 reg;
+
+ reg = dw_pcie_readw_dbi(pci, cap_ptr);
+ next_cap_ptr = (reg & 0xff00) >> 8;
+ cap_id = (reg & 0x00ff);
+
+ if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX)
+ return 0;
+
+ if (cap_id == cap)
+ return cap_ptr;
+
+ return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
+}
+
+static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
+{
+ u8 next_cap_ptr;
+ u16 reg;
+
+ reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
+ next_cap_ptr = (reg & 0x00ff);
+
+ if (!next_cap_ptr)
+ return 0;
+
+ return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
+}
+
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
struct pci_epf_header *hdr)
{
@@ -241,6 +274,45 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
return 0;
}

+static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+ struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 val, reg;
+
+ if (!ep->msix_cap)
+ return -EINVAL;
+
+ reg = ep->msix_cap + PCI_MSIX_FLAGS;
+ val = dw_pcie_readw_dbi(pci, reg);
+ if (!(val & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ val &= PCI_MSIX_FLAGS_QSIZE;
+
+ return val;
+}
+
+static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
+{
+ struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 val, reg;
+
+ if (!ep->msix_cap)
+ return -EINVAL;
+
+ 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);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ return 0;
+}
+
static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
enum pci_epc_irq_type type, u16 interrupt_num)
{
@@ -282,6 +354,8 @@ static const struct pci_epc_ops epc_ops = {
.unmap_addr = dw_pcie_ep_unmap_addr,
.set_msi = dw_pcie_ep_set_msi,
.get_msi = dw_pcie_ep_get_msi,
+ .set_msix = dw_pcie_ep_set_msix,
+ .get_msix = dw_pcie_ep_get_msix,
.raise_irq = dw_pcie_ep_raise_irq,
.start = dw_pcie_ep_start,
.stop = dw_pcie_ep_stop,
@@ -322,6 +396,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
return 0;
}

+int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
+ u16 interrupt_num)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ struct pci_epc *epc = ep->epc;
+ u16 tbl_offset, bir;
+ u32 bar_addr_upper, bar_addr_lower;
+ u32 msg_addr_upper, msg_addr_lower;
+ u32 reg, msg_data, vec_ctrl;
+ u64 tbl_addr, msg_addr, reg_u64;
+ void __iomem *msix_tbl;
+ int ret;
+
+ reg = ep->msix_cap + PCI_MSIX_TABLE;
+ tbl_offset = dw_pcie_readl_dbi(pci, reg);
+ bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
+ tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+ tbl_offset >>= 3;
+
+ reg = PCI_BASE_ADDRESS_0 + (4 * bir);
+ bar_addr_upper = 0;
+ bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
+ reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
+ if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
+
+ tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
+ tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
+ tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr,
+ PCI_MSIX_ENTRY_SIZE);
+ if (!msix_tbl)
+ return -EINVAL;
+
+ msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
+ msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
+ msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
+ msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
+ vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
+
+ iounmap(msix_tbl);
+
+ if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)
+ return -EPERM;
+
+ ret = dw_pcie_ep_map_addr(epc, func_no, ep->msix_mem_phys, msg_addr,
+ epc->mem->page_size);
+ if (ret)
+ return ret;
+
+ writel(msg_data, ep->msix_mem);
+
+ dw_pcie_ep_unmap_addr(epc, func_no, ep->msix_mem_phys);
+
+ return 0;
+}
+
void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
{
struct pci_epc *epc = ep->epc;
@@ -329,6 +461,9 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->page_size);

+ pci_epc_mem_free_addr(epc, ep->msix_mem_phys, ep->msix_mem,
+ epc->mem->page_size);
+
pci_epc_mem_exit(epc);
}

@@ -415,6 +550,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
dev_err(dev, "Failed to reserve memory for MSI\n");
return -ENOMEM;
}
+ ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI);
+
+ ep->msix_mem = pci_epc_mem_alloc_addr(epc, &ep->msix_mem_phys,
+ epc->mem->page_size);
+ if (!ep->msix_mem) {
+ dev_err(dev, "Failed to reserve memory for MSI-X\n");
+ return -ENOMEM;
+ }
+ ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);

dw_pcie_setup(pci);

diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 0efb318..8bb2ecb 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -91,6 +91,8 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
return -EINVAL;
case PCI_EPC_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
+ case PCI_EPC_IRQ_MSIX:
+ return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "UNKNOWN IRQ type\n");
}
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 9d581c0..b22c5bb 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -208,6 +208,10 @@ struct dw_pcie_ep {
u32 num_ob_windows;
void __iomem *msi_mem;
phys_addr_t msi_mem_phys;
+ void __iomem *msix_mem;
+ phys_addr_t msix_mem_phys;
+ u8 msi_cap; /* MSI capability offset */
+ u8 msix_cap; /* MSI-X capability offset */
};

struct dw_pcie_ops {
@@ -359,6 +363,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep);
void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num);
+int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
+ u16 interrupt_num);
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
#else
static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
@@ -380,6 +386,12 @@ static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
return 0;
}

+static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
+ u16 interrupt_num)
+{
+ return 0;
+}
+
static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
{
}
--
2.7.4



2018-07-09 17:48:42

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v9 05/12] PCI: dwc: Rework MSI callbacks handler

Remove duplicate defines located on pcie-designware.h file already
available on /include/uapi/linux/pci-regs.h file.

Signed-off-by: Gustavo Pimentel <[email protected]>
---
Change v1->v2:
- Nothing changed, just to follow the patch set version.
Change v2->v3:
- Replaced wrong return value 0 to -EINVAL.
Change v3->v4:
- Rebased to Lorenzo's master branch v4.18-rc1.
Change v4->v5:
- Moved pci_epc_set_msi maximum interrupts validation into a new patch
file #11.
Change v5->v6:
- Nothing changed, just to follow the patch set version.
Change v6->v7:
- Nothing changed, just to follow the patch set version.
Change v7->v8:
- Re-sending the patch series.
Change v8->v9:
- Nothing changed, just to follow the patch set version.

drivers/pci/controller/dwc/pcie-designware-ep.c | 49 +++++++++++++++++--------
drivers/pci/controller/dwc/pcie-designware.h | 11 ------
2 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 72c4188..afb48b5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -246,29 +246,38 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,

static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
{
- int val;
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 val, reg;
+
+ if (!ep->msi_cap)
+ return -EINVAL;

- val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
- if (!(val & MSI_CAP_MSI_EN_MASK))
+ reg = ep->msi_cap + PCI_MSI_FLAGS;
+ val = dw_pcie_readw_dbi(pci, reg);
+ if (!(val & PCI_MSI_FLAGS_ENABLE))
return -EINVAL;

- val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT;
+ val = (val & PCI_MSI_FLAGS_QSIZE) >> 4;
+
return val;
}

-static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
+static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
{
- int val;
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 val, reg;

- val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
- val &= ~MSI_CAP_MMC_MASK;
- val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK;
+ if (!ep->msi_cap)
+ return -EINVAL;
+
+ reg = ep->msi_cap + PCI_MSI_FLAGS;
+ val = dw_pcie_readw_dbi(pci, reg);
+ val &= ~PCI_MSI_FLAGS_QMASK;
+ val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val);
+ dw_pcie_writew_dbi(pci, reg, val);
dw_pcie_dbi_ro_wr_dis(pci);

return 0;
@@ -367,21 +376,29 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct pci_epc *epc = ep->epc;
u16 msg_ctrl, msg_data;
- u32 msg_addr_lower, msg_addr_upper;
+ u32 msg_addr_lower, msg_addr_upper, reg;
u64 msg_addr;
bool has_upper;
int ret;

+ if (!ep->msi_cap)
+ return -EINVAL;
+
/* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
- msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
+ reg = ep->msi_cap + PCI_MSI_FLAGS;
+ msg_ctrl = dw_pcie_readw_dbi(pci, reg);
has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
- msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32);
+ reg = ep->msi_cap + PCI_MSI_ADDRESS_LO;
+ msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
if (has_upper) {
- msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32);
- msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64);
+ reg = ep->msi_cap + PCI_MSI_ADDRESS_HI;
+ msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
+ reg = ep->msi_cap + PCI_MSI_DATA_64;
+ msg_data = dw_pcie_readw_dbi(pci, reg);
} else {
msg_addr_upper = 0;
- msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32);
+ reg = ep->msi_cap + PCI_MSI_DATA_32;
+ msg_data = dw_pcie_readw_dbi(pci, reg);
}
msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index b22c5bb..a0ab12f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -96,17 +96,6 @@
#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
((0x3 << 20) | ((region) << 9) | (0x1 << 8))

-#define MSI_MESSAGE_CONTROL 0x52
-#define MSI_CAP_MMC_SHIFT 1
-#define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT)
-#define MSI_CAP_MME_SHIFT 4
-#define MSI_CAP_MSI_EN_MASK 0x1
-#define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT)
-#define MSI_MESSAGE_ADDR_L32 0x54
-#define MSI_MESSAGE_ADDR_U32 0x58
-#define MSI_MESSAGE_DATA_32 0x58
-#define MSI_MESSAGE_DATA_64 0x5C
-
#define MAX_MSI_IRQS 256
#define MAX_MSI_IRQS_PER_CTRL 32
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
--
2.7.4



2018-07-10 10:11:35

by Alan Douglas

[permalink] [raw]
Subject: RE: [PATCH v9 10/12] pci_endpoint_test: Add 2 ioctl commands

On 09 July 2018 18:43 Gustavo Pimentel wrote:
> Add MSI-X support and update driver documentation accordingly.
>
> Add 2 new IOCTL commands:
> - Allow to reconfigure driver IRQ type in runtime.
> - Allow to retrieve current driver IRQ type configured.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>
> ---
> Change v2->v3:
> - New patch file created base on the previous patch
> "misc: pci_endpoint_test: Add MSI-X support" patch file following
> Kishon's suggestion.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Nothing changed, just to follow the patch set version.
> Change v5->v6:
> - Moved PCITEST_SET_IRQTYPE and PCITEST_GET_IRQTYPE ioctl entries
> from patch #10 to here.
> - Increased ioctl parameters range associated to
> drivers/misc/pci_endpoint_test.c driver.
> Change v6->v7:
> - irq_type variable update just before returning the function.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Added a extra parameter to pci_endpoint_test_alloc_irq_vectors,
> that specifies which irq type should be allocated.
>
> Documentation/ioctl/ioctl-number.txt | 2 +-
> Documentation/misc-devices/pci-endpoint-test.txt | 3 +
> drivers/misc/pci_endpoint_test.c | 176 +++++++++++++++++------
> include/uapi/linux/pcitest.h | 2 +
> 4 files changed, 136 insertions(+), 47 deletions(-)
>
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index 65259d4..c15c4f3 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -166,7 +166,7 @@ Code Seq#(hex) Include File Comments
> 'P' all linux/soundcard.h conflict!
> 'P' 60-6F sound/sscape_ioctl.h conflict!
> 'P' 00-0F drivers/usb/class/usblp.c conflict!
> -'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
> +'P' 01-09 drivers/misc/pci_endpoint_test.c conflict!
> 'Q' all linux/soundcard.h
> 'R' 00-1F linux/random.h conflict!
> 'R' 01 linux/rfkill.h conflict!
> diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
> index fdfa0f6..58ccca4 100644
> --- a/Documentation/misc-devices/pci-endpoint-test.txt
> +++ b/Documentation/misc-devices/pci-endpoint-test.txt
> @@ -28,6 +28,9 @@ ioctl
> to be tested should be passed as argument.
> PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
> to be tested should be passed as argument.
> + PCITEST_SET_IRQTYPE: Changes driver IRQ type configuration. The IRQ type
> + should be passed as argument (0: Legacy, 1:MSI, 2:MSI-X).
> + PCITEST_GET_IRQTYPE: Gets driver IRQ type configuration.
I've tested this latest set of patches with the cadence ep driver, which
does not yet support MSI-X, and can confirm that setting, getting and using
legacy and MSI IRQ type IRQs is working correctly. Setting MSI-X fails, as
expected.

2018-07-10 10:39:14

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v9 10/12] pci_endpoint_test: Add 2 ioctl commands

Hi Alan,

On 10/07/2018 11:10, Alan Douglas wrote:
> On 09 July 2018 18:43 Gustavo Pimentel wrote:
>> Add MSI-X support and update driver documentation accordingly.
>>
>> Add 2 new IOCTL commands:
>> - Allow to reconfigure driver IRQ type in runtime.
>> - Allow to retrieve current driver IRQ type configured.
>>
>> Signed-off-by: Gustavo Pimentel <[email protected]>
>> ---
>> Change v2->v3:
>> - New patch file created base on the previous patch
>> "misc: pci_endpoint_test: Add MSI-X support" patch file following
>> Kishon's suggestion.
>> Change v3->v4:
>> - Rebased to Lorenzo's master branch v4.18-rc1.
>> Change v4->v5:
>> - Nothing changed, just to follow the patch set version.
>> Change v5->v6:
>> - Moved PCITEST_SET_IRQTYPE and PCITEST_GET_IRQTYPE ioctl entries
>> from patch #10 to here.
>> - Increased ioctl parameters range associated to
>> drivers/misc/pci_endpoint_test.c driver.
>> Change v6->v7:
>> - irq_type variable update just before returning the function.
>> Change v7->v8:
>> - Re-sending the patch series.
>> Change v8->v9:
>> - Added a extra parameter to pci_endpoint_test_alloc_irq_vectors,
>> that specifies which irq type should be allocated.
>>
>> Documentation/ioctl/ioctl-number.txt | 2 +-
>> Documentation/misc-devices/pci-endpoint-test.txt | 3 +
>> drivers/misc/pci_endpoint_test.c | 176 +++++++++++++++++------
>> include/uapi/linux/pcitest.h | 2 +
>> 4 files changed, 136 insertions(+), 47 deletions(-)
>>
>> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
>> index 65259d4..c15c4f3 100644
>> --- a/Documentation/ioctl/ioctl-number.txt
>> +++ b/Documentation/ioctl/ioctl-number.txt
>> @@ -166,7 +166,7 @@ Code Seq#(hex) Include File Comments
>> 'P' all linux/soundcard.h conflict!
>> 'P' 60-6F sound/sscape_ioctl.h conflict!
>> 'P' 00-0F drivers/usb/class/usblp.c conflict!
>> -'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
>> +'P' 01-09 drivers/misc/pci_endpoint_test.c conflict!
>> 'Q' all linux/soundcard.h
>> 'R' 00-1F linux/random.h conflict!
>> 'R' 01 linux/rfkill.h conflict!
>> diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
>> index fdfa0f6..58ccca4 100644
>> --- a/Documentation/misc-devices/pci-endpoint-test.txt
>> +++ b/Documentation/misc-devices/pci-endpoint-test.txt
>> @@ -28,6 +28,9 @@ ioctl
>> to be tested should be passed as argument.
>> PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
>> to be tested should be passed as argument.
>> + PCITEST_SET_IRQTYPE: Changes driver IRQ type configuration. The IRQ type
>> + should be passed as argument (0: Legacy, 1:MSI, 2:MSI-X).
>> + PCITEST_GET_IRQTYPE: Gets driver IRQ type configuration.
> I've tested this latest set of patches with the cadence ep driver, which
> does not yet support MSI-X, and can confirm that setting, getting and using
> legacy and MSI IRQ type IRQs is working correctly. Setting MSI-X fails, as
> expected.

Great, thanks for testing!

Regards,
Gustavo

>


2018-07-13 07:49:24

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 01/12] PCI: dwc: Fix EP link notification implementation



On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Move specific features settings from EP shared code
> (pcie-designware-ep.c) to the driver (pcie-designware-plat.c).
>
> Previous implementation disables the EP link notification
> by default for all SoCs that uses EP DesignWare IP, which affects
> directly the dra7xx and artpec6 SoCs.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>

Acked-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Change v8->v9:
> - Created patch file.
>
> drivers/pci/controller/dwc/pcie-designware-ep.c | 14 ++++++--------
> drivers/pci/controller/dwc/pcie-designware-plat.c | 3 +++
> 2 files changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 8650416..04092a7 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -386,15 +386,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> return -ENOMEM;
> ep->outbound_addr = addr;
>
> - if (ep->ops->ep_init)
> - ep->ops->ep_init(ep);
> -
> epc = devm_pci_epc_create(dev, &epc_ops);
> if (IS_ERR(epc)) {
> dev_err(dev, "Failed to create epc device\n");
> return PTR_ERR(epc);
> }
>
> + ep->epc = epc;
> + epc_set_drvdata(epc, ep);
> +
> + if (ep->ops->ep_init)
> + ep->ops->ep_init(ep);
> +
> ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
> if (ret < 0)
> epc->max_functions = 1;
> @@ -413,11 +416,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> return -ENOMEM;
> }
>
> - epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
> - EPC_FEATURE_SET_BAR(epc->features, BAR_0);
> -
> - ep->epc = epc;
> - epc_set_drvdata(epc, ep);
> dw_pcie_setup(pci);
>
> return 0;
> diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
> index 5937fed..0ce3440 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-plat.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
> @@ -70,10 +70,13 @@ static const struct dw_pcie_ops dw_pcie_ops = {
> static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + struct pci_epc *epc = ep->epc;
> enum pci_barno bar;
>
> for (bar = BAR_0; bar <= BAR_5; bar++)
> dw_pcie_ep_reset_bar(pci, bar);
> +
> + epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
> }
>
> static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
>

2018-07-13 07:50:36

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 03/12] PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures



On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Change {cdns, dra7xx, artpec6, dw, rockchip}_pcie_ep_raise_irq() and
> pci_epc_raise_irq() signature, namely the interrupt_num variable type
> from u8 to u16 to accommodate 2048 maximum MSI-X interrupts.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>
> Acked-by: Alan Douglas <[email protected]>
> Acked-by: Shawn Lin <[email protected]>
> Acked-by: Jesper Nilsson <[email protected]>
> Acked-by: Joao Pinto <[email protected]>

Acked-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Change v1->v2:
> - Nothing changed, just to follow the patch set version.
> Change v2->v3:
> - Move into here the pci_epc_raise_irq() signature change from patch
> file #1.
> - Move into here the {dra7xx, artpec6}_pcie_ep_raise_irq() signature
> changes from patch file #2.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Swap patch files position (#3 -> #2).
> - Moved dw_pcie_ep_raise_irq and dw_plat_pcie_ep_raise_irq functions
> signatures changes from patch file #3.
> - Changed rockchip_pcie_ep_raise_irq function signature.
> Change v5->v6:
> - Nothing changed, just to follow the patch set version.
> Change v6->v7:
> - Nothing changed, just to follow the patch set version.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Nothing changed, just to follow the patch set version.
>
> drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
> drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
> drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +-
> drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +-
> drivers/pci/controller/dwc/pcie-designware.h | 2 +-
> drivers/pci/controller/pcie-cadence-ep.c | 3 ++-
> drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
> drivers/pci/endpoint/pci-epc-core.c | 8 ++++----
> include/linux/pci-epc.h | 6 +++---
> 9 files changed, 15 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
> index 345aab5..ce9224a 100644
> --- a/drivers/pci/controller/dwc/pci-dra7xx.c
> +++ b/drivers/pci/controller/dwc/pci-dra7xx.c
> @@ -370,7 +370,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx,
> }
>
> static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
> - enum pci_epc_irq_type type, u8 interrupt_num)
> + enum pci_epc_irq_type type, u16 interrupt_num)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
> diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
> index 321b56c..9a2474b 100644
> --- a/drivers/pci/controller/dwc/pcie-artpec6.c
> +++ b/drivers/pci/controller/dwc/pcie-artpec6.c
> @@ -428,7 +428,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
> }
>
> static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
> - enum pci_epc_irq_type type, u8 interrupt_num)
> + enum pci_epc_irq_type type, u16 interrupt_num)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 04092a7..69d039d 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -242,7 +242,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
> }
>
> static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
> - enum pci_epc_irq_type type, u8 interrupt_num)
> + enum pci_epc_irq_type type, u16 interrupt_num)
> {
> struct dw_pcie_ep *ep = epc_get_drvdata(epc);
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
> index 0ce3440..0efb318 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-plat.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
> @@ -81,7 +81,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
>
> static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
> enum pci_epc_irq_type type,
> - u8 interrupt_num)
> + u16 interrupt_num)
> {
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index bee4e25..9d581c0 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -191,7 +191,7 @@ enum dw_pcie_as_type {
> struct dw_pcie_ep_ops {
> void (*ep_init)(struct dw_pcie_ep *ep);
> int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
> - enum pci_epc_irq_type type, u8 interrupt_num);
> + enum pci_epc_irq_type type, u16 interrupt_num);
> };
>
> struct dw_pcie_ep {
> diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
> index e3fe412..208d11f 100644
> --- a/drivers/pci/controller/pcie-cadence-ep.c
> +++ b/drivers/pci/controller/pcie-cadence-ep.c
> @@ -363,7 +363,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
> }
>
> static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
> - enum pci_epc_irq_type type, u8 interrupt_num)
> + enum pci_epc_irq_type type,
> + u16 interrupt_num)
> {
> struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
>
> diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
> index 6beba8e..b8163c5 100644
> --- a/drivers/pci/controller/pcie-rockchip-ep.c
> +++ b/drivers/pci/controller/pcie-rockchip-ep.c
> @@ -472,7 +472,7 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
>
> static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
> enum pci_epc_irq_type type,
> - u8 interrupt_num)
> + u16 interrupt_num)
> {
> struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
>
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index 7d77bd0..c72e656 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -131,13 +131,13 @@ EXPORT_SYMBOL_GPL(pci_epc_start);
> * pci_epc_raise_irq() - interrupt the host system
> * @epc: the EPC device which has to interrupt the host
> * @func_no: the endpoint function number in the EPC device
> - * @type: specify the type of interrupt; legacy or MSI
> - * @interrupt_num: the MSI interrupt number
> + * @type: specify the type of interrupt; legacy, MSI or MSI-X
> + * @interrupt_num: the MSI or MSI-X interrupt number
> *
> - * Invoke to raise an MSI or legacy interrupt
> + * Invoke to raise an legacy, MSI or MSI-X interrupt
> */
> int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
> - enum pci_epc_irq_type type, u8 interrupt_num)
> + enum pci_epc_irq_type type, u16 interrupt_num)
> {
> int ret;
> unsigned long flags;
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index 89f079f..bb2395b 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -35,7 +35,7 @@ enum pci_epc_irq_type {
> * MSI-X capability register
> * @get_msix: ops to get the number of MSI-X interrupts allocated by the RC
> * from the MSI-X capability register
> - * @raise_irq: ops to raise a legacy or MSI interrupt
> + * @raise_irq: ops to raise a legacy, MSI or MSI-X interrupt
> * @start: ops to start the PCI link
> * @stop: ops to stop the PCI link
> * @owner: the module owner containing the ops
> @@ -56,7 +56,7 @@ struct pci_epc_ops {
> int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts);
> 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, u8 interrupt_num);
> + enum pci_epc_irq_type type, u16 interrupt_num);
> int (*start)(struct pci_epc *epc);
> void (*stop)(struct pci_epc *epc);
> struct module *owner;
> @@ -154,7 +154,7 @@ 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_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, u8 interrupt_num);
> + enum pci_epc_irq_type type, u16 interrupt_num);
> int pci_epc_start(struct pci_epc *epc);
> void pci_epc_stop(struct pci_epc *epc);
> struct pci_epc *pci_epc_get(const char *epc_name);
>

2018-07-13 07:57:16

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 04/12] PCI: dwc: Add MSI-X callbacks handler

Hi,

On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Add PCIe config space capability search function.
>
> Add sysfs set/get interface to allow the change of EP MSI-X maximum number.
>
> Add EP MSI-X callback for triggering interruptions.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>
> ---
> Change v1->v2:
> - Nothing changed, just to follow the patch set version.
> Change v2->v3:
> - Moved dra7xx_pcie_raise_irq() signature change to patch file #3.
> - Moved artpec6_pcie_raise_irq() signature change to patch file #3.
> - Replaced wrong return value 0 to -EINVAL.
> - Removed an else if by code refactoring.
> - Reduced the size of ioremap_nocache mapping from ep->addr_size to
> PCI_MSIX_ENTRY_SIZE.
> - Fixed a small bug. If the MSI-X vector bit has been set, the function
> would return without executing the proper unmap.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> - Added static prefix to __dw_pcie_ep_find_next_cap function.
> Change v4->v5:
> - Added static prefix to dw_pcie_ep_find_capability function.
> - Swap patch files position (#2 <-> #3).
> - Moved dw_pcie_ep_raise_irq and dw_plat_pcie_ep_raise_irq functions
> signatures change to patch file #2.
> Change v5->v6:
> - Nothing changed, just to follow the patch set version.
> Change v6->v7:
> - Nothing changed, just to follow the patch set version.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Nothing changed, just to follow the patch set version.
>
> drivers/pci/controller/dwc/pcie-designware-ep.c | 144 ++++++++++++++++++++++
> drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +
> drivers/pci/controller/dwc/pcie-designware.h | 12 ++
> 3 files changed, 158 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 69d039d..72c4188 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
> __dw_pcie_ep_reset_bar(pci, bar, 0);
> }
>
> +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
> + u8 cap)
> +{
> + u8 cap_id, next_cap_ptr;
> + u16 reg;
> +
> + reg = dw_pcie_readw_dbi(pci, cap_ptr);
> + next_cap_ptr = (reg & 0xff00) >> 8;
> + cap_id = (reg & 0x00ff);
> +
> + if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX)
> + return 0;
> +
> + if (cap_id == cap)
> + return cap_ptr;
> +
> + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
> +}
> +
> +static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
> +{
> + u8 next_cap_ptr;
> + u16 reg;
> +
> + reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
> + next_cap_ptr = (reg & 0x00ff);
> +
> + if (!next_cap_ptr)
> + return 0;
> +
> + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
> +}
> +
> static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
> struct pci_epf_header *hdr)
> {
> @@ -241,6 +274,45 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
> return 0;
> }
>
> +static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
> +{
> + struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + u32 val, reg;
> +
> + if (!ep->msix_cap)
> + return -EINVAL;
> +
> + reg = ep->msix_cap + PCI_MSIX_FLAGS;
> + val = dw_pcie_readw_dbi(pci, reg);
> + if (!(val & PCI_MSIX_FLAGS_ENABLE))
> + return -EINVAL;
> +
> + val &= PCI_MSIX_FLAGS_QSIZE;
> +
> + return val;
> +}
> +
> +static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
> +{
> + struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + u32 val, reg;
> +
> + if (!ep->msix_cap)
> + return -EINVAL;
> +
> + 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);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + return 0;
> +}
> +
> static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
> enum pci_epc_irq_type type, u16 interrupt_num)
> {
> @@ -282,6 +354,8 @@ static const struct pci_epc_ops epc_ops = {
> .unmap_addr = dw_pcie_ep_unmap_addr,
> .set_msi = dw_pcie_ep_set_msi,
> .get_msi = dw_pcie_ep_get_msi,
> + .set_msix = dw_pcie_ep_set_msix,
> + .get_msix = dw_pcie_ep_get_msix,
> .raise_irq = dw_pcie_ep_raise_irq,
> .start = dw_pcie_ep_start,
> .stop = dw_pcie_ep_stop,
> @@ -322,6 +396,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> return 0;
> }
>
> +int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
> + u16 interrupt_num)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + struct pci_epc *epc = ep->epc;
> + u16 tbl_offset, bir;
> + u32 bar_addr_upper, bar_addr_lower;
> + u32 msg_addr_upper, msg_addr_lower;
> + u32 reg, msg_data, vec_ctrl;
> + u64 tbl_addr, msg_addr, reg_u64;
> + void __iomem *msix_tbl;
> + int ret;
> +
> + reg = ep->msix_cap + PCI_MSIX_TABLE;
> + tbl_offset = dw_pcie_readl_dbi(pci, reg);
> + bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
> + tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> + tbl_offset >>= 3;
> +
> + reg = PCI_BASE_ADDRESS_0 + (4 * bir);
> + bar_addr_upper = 0;
> + bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
> + reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
> + if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
> + bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
> +
> + tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
> + tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
> + tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
> +
> + msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr,
> + PCI_MSIX_ENTRY_SIZE);
> + if (!msix_tbl)
> + return -EINVAL;
> +
> + msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
> + msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
> + msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
> + msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
> + vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
> +
> + iounmap(msix_tbl);
> +
> + if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)
> + return -EPERM;
> +
> + ret = dw_pcie_ep_map_addr(epc, func_no, ep->msix_mem_phys, msg_addr,
> + epc->mem->page_size);
> + if (ret)
> + return ret;
> +
> + writel(msg_data, ep->msix_mem);
> +
> + dw_pcie_ep_unmap_addr(epc, func_no, ep->msix_mem_phys);
> +
> + return 0;
> +}
> +
> void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
> {
> struct pci_epc *epc = ep->epc;
> @@ -329,6 +461,9 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
> pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
> epc->mem->page_size);
>
> + pci_epc_mem_free_addr(epc, ep->msix_mem_phys, ep->msix_mem,
> + epc->mem->page_size);
> +
> pci_epc_mem_exit(epc);
> }
>
> @@ -415,6 +550,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> dev_err(dev, "Failed to reserve memory for MSI\n");
> return -ENOMEM;
> }
> + ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI);
> +
> + ep->msix_mem = pci_epc_mem_alloc_addr(epc, &ep->msix_mem_phys,
> + epc->mem->page_size);
> + if (!ep->msix_mem) {
> + dev_err(dev, "Failed to reserve memory for MSI-X\n");
> + return -ENOMEM;

Do we have to allocate memory for MSIX memory separately? I think we can reuse
msi_mem. That's also because we shouldn't fail if a platform doesn't support
MSIX and fails to allocate msix_mem.

Thanks
Kishon

2018-07-13 07:57:34

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 05/12] PCI: dwc: Rework MSI callbacks handler



On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Remove duplicate defines located on pcie-designware.h file already
> available on /include/uapi/linux/pci-regs.h file.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>

Acked-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Change v1->v2:
> - Nothing changed, just to follow the patch set version.
> Change v2->v3:
> - Replaced wrong return value 0 to -EINVAL.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Moved pci_epc_set_msi maximum interrupts validation into a new patch
> file #11.
> Change v5->v6:
> - Nothing changed, just to follow the patch set version.
> Change v6->v7:
> - Nothing changed, just to follow the patch set version.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Nothing changed, just to follow the patch set version.
>
> drivers/pci/controller/dwc/pcie-designware-ep.c | 49 +++++++++++++++++--------
> drivers/pci/controller/dwc/pcie-designware.h | 11 ------
> 2 files changed, 33 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 72c4188..afb48b5 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -246,29 +246,38 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
>
> static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
> {
> - int val;
> struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + u32 val, reg;
> +
> + if (!ep->msi_cap)
> + return -EINVAL;
>
> - val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
> - if (!(val & MSI_CAP_MSI_EN_MASK))
> + reg = ep->msi_cap + PCI_MSI_FLAGS;
> + val = dw_pcie_readw_dbi(pci, reg);
> + if (!(val & PCI_MSI_FLAGS_ENABLE))
> return -EINVAL;
>
> - val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT;
> + val = (val & PCI_MSI_FLAGS_QSIZE) >> 4;
> +
> return val;
> }
>
> -static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
> +static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
> {
> - int val;
> struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + u32 val, reg;
>
> - val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
> - val &= ~MSI_CAP_MMC_MASK;
> - val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK;
> + if (!ep->msi_cap)
> + return -EINVAL;
> +
> + reg = ep->msi_cap + PCI_MSI_FLAGS;
> + val = dw_pcie_readw_dbi(pci, reg);
> + val &= ~PCI_MSI_FLAGS_QMASK;
> + val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
> dw_pcie_dbi_ro_wr_en(pci);
> - dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val);
> + dw_pcie_writew_dbi(pci, reg, val);
> dw_pcie_dbi_ro_wr_dis(pci);
>
> return 0;
> @@ -367,21 +376,29 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> struct pci_epc *epc = ep->epc;
> u16 msg_ctrl, msg_data;
> - u32 msg_addr_lower, msg_addr_upper;
> + u32 msg_addr_lower, msg_addr_upper, reg;
> u64 msg_addr;
> bool has_upper;
> int ret;
>
> + if (!ep->msi_cap)
> + return -EINVAL;
> +
> /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
> - msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
> + reg = ep->msi_cap + PCI_MSI_FLAGS;
> + msg_ctrl = dw_pcie_readw_dbi(pci, reg);
> has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
> - msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32);
> + reg = ep->msi_cap + PCI_MSI_ADDRESS_LO;
> + msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
> if (has_upper) {
> - msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32);
> - msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64);
> + reg = ep->msi_cap + PCI_MSI_ADDRESS_HI;
> + msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
> + reg = ep->msi_cap + PCI_MSI_DATA_64;
> + msg_data = dw_pcie_readw_dbi(pci, reg);
> } else {
> msg_addr_upper = 0;
> - msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32);
> + reg = ep->msi_cap + PCI_MSI_DATA_32;
> + msg_data = dw_pcie_readw_dbi(pci, reg);
> }
> msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
> ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index b22c5bb..a0ab12f 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -96,17 +96,6 @@
> #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
> ((0x3 << 20) | ((region) << 9) | (0x1 << 8))
>
> -#define MSI_MESSAGE_CONTROL 0x52
> -#define MSI_CAP_MMC_SHIFT 1
> -#define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT)
> -#define MSI_CAP_MME_SHIFT 4
> -#define MSI_CAP_MSI_EN_MASK 0x1
> -#define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT)
> -#define MSI_MESSAGE_ADDR_L32 0x54
> -#define MSI_MESSAGE_ADDR_U32 0x58
> -#define MSI_MESSAGE_DATA_32 0x58
> -#define MSI_MESSAGE_DATA_64 0x5C
> -
> #define MAX_MSI_IRQS 256
> #define MAX_MSI_IRQS_PER_CTRL 32
> #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
>

2018-07-13 08:01:27

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 07/12] pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace

Hi,

On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Cleanup PCI_ENDPOINT_TEST memspace (by moving the interrupt number away
> from command section).
>
> Update documentation accordingly.

you are also adding IRQ_TYPE register. It has to be mentioned why you added
IRQ_TYPE register in the commit message and should also be documented in
pci-test-function.txt

Thanks
Kishon

>
> Signed-off-by: Gustavo Pimentel <[email protected]>
> ---
> Change v2->v3:
> - New patch file created base on the previous patch
> "misc: pci_endpoint_test: Add MSI-X support" patch file following
> Kishon's suggestion.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Reverted irq_num rename to msi_num.
> - Added comment about the MSI-X bit reservation for future implementation.
> Change v5->v6:
> - Nothing changed, just to follow the patch set version.
> Change v6->v7:
> - Updated documentation.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Nothing changed, just to follow the patch set version.
>
> Documentation/PCI/endpoint/pci-test-function.txt | 8 +--
> drivers/misc/pci_endpoint_test.c | 81 +++++++++++++++---------
> drivers/pci/endpoint/functions/pci-epf-test.c | 61 ++++++++++++------
> 3 files changed, 95 insertions(+), 55 deletions(-)
>
> diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt
> index 0c519c9..7ee2361 100644
> --- a/Documentation/PCI/endpoint/pci-test-function.txt
> +++ b/Documentation/PCI/endpoint/pci-test-function.txt
> @@ -34,10 +34,10 @@ that the endpoint device must perform.
> Bitfield Description:
> Bit 0 : raise legacy IRQ
> Bit 1 : raise MSI IRQ
> - Bit 2 - 7 : MSI interrupt number
> - Bit 8 : read command (read data from RC buffer)
> - Bit 9 : write command (write data to RC buffer)
> - Bit 10 : copy command (copy data from one RC buffer to another
> + Bit 2 : raise MSI-X IRQ (reserved for future implementation)
> + Bit 3 : read command (read data from RC buffer)
> + Bit 4 : write command (write data to RC buffer)
> + Bit 5 : copy command (copy data from one RC buffer to another
> RC buffer)
>
> *) PCI_ENDPOINT_TEST_STATUS
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index 7b37046..35fbfbd 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -35,38 +35,43 @@
>
> #include <uapi/linux/pcitest.h>
>
> -#define DRV_MODULE_NAME "pci-endpoint-test"
> -
> -#define PCI_ENDPOINT_TEST_MAGIC 0x0
> -
> -#define PCI_ENDPOINT_TEST_COMMAND 0x4
> -#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> -#define COMMAND_RAISE_MSI_IRQ BIT(1)
> -#define MSI_NUMBER_SHIFT 2
> -/* 6 bits for MSI number */
> -#define COMMAND_READ BIT(8)
> -#define COMMAND_WRITE BIT(9)
> -#define COMMAND_COPY BIT(10)
> -
> -#define PCI_ENDPOINT_TEST_STATUS 0x8
> -#define STATUS_READ_SUCCESS BIT(0)
> -#define STATUS_READ_FAIL BIT(1)
> -#define STATUS_WRITE_SUCCESS BIT(2)
> -#define STATUS_WRITE_FAIL BIT(3)
> -#define STATUS_COPY_SUCCESS BIT(4)
> -#define STATUS_COPY_FAIL BIT(5)
> -#define STATUS_IRQ_RAISED BIT(6)
> -#define STATUS_SRC_ADDR_INVALID BIT(7)
> -#define STATUS_DST_ADDR_INVALID BIT(8)
> -
> -#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc
> +#define DRV_MODULE_NAME "pci-endpoint-test"
> +
> +#define IRQ_TYPE_LEGACY 0
> +#define IRQ_TYPE_MSI 1
> +
> +#define PCI_ENDPOINT_TEST_MAGIC 0x0
> +
> +#define PCI_ENDPOINT_TEST_COMMAND 0x4
> +#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> +#define COMMAND_RAISE_MSI_IRQ BIT(1)
> +/* BIT(2) is reserved for raising MSI-X IRQ command */
> +#define COMMAND_READ BIT(3)
> +#define COMMAND_WRITE BIT(4)
> +#define COMMAND_COPY BIT(5)
> +
> +#define PCI_ENDPOINT_TEST_STATUS 0x8
> +#define STATUS_READ_SUCCESS BIT(0)
> +#define STATUS_READ_FAIL BIT(1)
> +#define STATUS_WRITE_SUCCESS BIT(2)
> +#define STATUS_WRITE_FAIL BIT(3)
> +#define STATUS_COPY_SUCCESS BIT(4)
> +#define STATUS_COPY_FAIL BIT(5)
> +#define STATUS_IRQ_RAISED BIT(6)
> +#define STATUS_SRC_ADDR_INVALID BIT(7)
> +#define STATUS_DST_ADDR_INVALID BIT(8)
> +
> +#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
> #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
>
> #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
> #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
>
> -#define PCI_ENDPOINT_TEST_SIZE 0x1c
> -#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
> +#define PCI_ENDPOINT_TEST_SIZE 0x1c
> +#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
> +
> +#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
> +#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
>
> static DEFINE_IDA(pci_endpoint_test_ida);
>
> @@ -179,6 +184,9 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
> {
> u32 val;
>
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> + IRQ_TYPE_LEGACY);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> COMMAND_RAISE_LEGACY_IRQ);
> val = wait_for_completion_timeout(&test->irq_raised,
> @@ -195,8 +203,10 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
> u32 val;
> struct pci_dev *pdev = test->pdev;
>
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> + IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> - msi_num << MSI_NUMBER_SHIFT |
> COMMAND_RAISE_MSI_IRQ);
> val = wait_for_completion_timeout(&test->irq_raised,
> msecs_to_jiffies(1000));
> @@ -281,8 +291,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
> size);
>
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> + no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> - 1 << MSI_NUMBER_SHIFT | COMMAND_COPY);
> + COMMAND_COPY);
>
> wait_for_completion(&test->irq_raised);
>
> @@ -348,8 +361,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
>
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
>
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> + no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> - 1 << MSI_NUMBER_SHIFT | COMMAND_READ);
> + COMMAND_READ);
>
> wait_for_completion(&test->irq_raised);
>
> @@ -403,8 +419,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
>
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
>
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> + no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> - 1 << MSI_NUMBER_SHIFT | COMMAND_WRITE);
> + COMMAND_WRITE);
>
> wait_for_completion(&test->irq_raised);
>
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 63ed706..eb9cd00 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -18,13 +18,15 @@
> #include <linux/pci-epf.h>
> #include <linux/pci_regs.h>
>
> +#define IRQ_TYPE_LEGACY 0
> +#define IRQ_TYPE_MSI 1
> +
> #define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> #define COMMAND_RAISE_MSI_IRQ BIT(1)
> -#define MSI_NUMBER_SHIFT 2
> -#define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT)
> -#define COMMAND_READ BIT(8)
> -#define COMMAND_WRITE BIT(9)
> -#define COMMAND_COPY BIT(10)
> +/* BIT(2) is reserved for raising MSI-X IRQ command */
> +#define COMMAND_READ BIT(3)
> +#define COMMAND_WRITE BIT(4)
> +#define COMMAND_COPY BIT(5)
>
> #define STATUS_READ_SUCCESS BIT(0)
> #define STATUS_READ_FAIL BIT(1)
> @@ -56,6 +58,8 @@ struct pci_epf_test_reg {
> u64 dst_addr;
> u32 size;
> u32 checksum;
> + u32 irq_type;
> + u32 irq_number;
> } __packed;
>
> static struct pci_epf_header test_header = {
> @@ -244,31 +248,39 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
> return ret;
> }
>
> -static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq)
> +static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
> + u16 irq)
> {
> - u8 msi_count;
> struct pci_epf *epf = epf_test->epf;
> + struct device *dev = &epf->dev;
> struct pci_epc *epc = epf->epc;
> enum pci_barno test_reg_bar = epf_test->test_reg_bar;
> struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
>
> reg->status |= STATUS_IRQ_RAISED;
> - msi_count = pci_epc_get_msi(epc, epf->func_no);
> - if (irq > msi_count || msi_count <= 0)
> +
> + switch (irq_type) {
> + case IRQ_TYPE_LEGACY:
> pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
> - else
> + break;
> + case IRQ_TYPE_MSI:
> pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
> + break;
> + default:
> + dev_err(dev, "Failed to raise IRQ, unknown type\n");
> + break;
> + }
> }
>
> static void pci_epf_test_cmd_handler(struct work_struct *work)
> {
> int ret;
> - u8 irq;
> - u8 msi_count;
> + u16 count;
> u32 command;
> struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
> cmd_handler.work);
> struct pci_epf *epf = epf_test->epf;
> + struct device *dev = &epf->dev;
> struct pci_epc *epc = epf->epc;
> enum pci_barno test_reg_bar = epf_test->test_reg_bar;
> struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
> @@ -280,7 +292,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> reg->command = 0;
> reg->status = 0;
>
> - irq = (command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
> + if (reg->irq_type > IRQ_TYPE_MSI) {
> + dev_err(dev, "Failed to detect IRQ type\n");
> + goto reset_handler;
> + }
>
> if (command & COMMAND_RAISE_LEGACY_IRQ) {
> reg->status = STATUS_IRQ_RAISED;
> @@ -294,7 +309,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> reg->status |= STATUS_WRITE_FAIL;
> else
> reg->status |= STATUS_WRITE_SUCCESS;
> - pci_epf_test_raise_irq(epf_test, irq);
> + pci_epf_test_raise_irq(epf_test, reg->irq_type,
> + reg->irq_number);
> goto reset_handler;
> }
>
> @@ -304,7 +320,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> reg->status |= STATUS_READ_SUCCESS;
> else
> reg->status |= STATUS_READ_FAIL;
> - pci_epf_test_raise_irq(epf_test, irq);
> + pci_epf_test_raise_irq(epf_test, reg->irq_type,
> + reg->irq_number);
> goto reset_handler;
> }
>
> @@ -314,16 +331,18 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> reg->status |= STATUS_COPY_SUCCESS;
> else
> reg->status |= STATUS_COPY_FAIL;
> - pci_epf_test_raise_irq(epf_test, irq);
> + pci_epf_test_raise_irq(epf_test, reg->irq_type,
> + reg->irq_number);
> goto reset_handler;
> }
>
> if (command & COMMAND_RAISE_MSI_IRQ) {
> - msi_count = pci_epc_get_msi(epc, epf->func_no);
> - if (irq > msi_count || msi_count <= 0)
> + count = pci_epc_get_msi(epc, epf->func_no);
> + if (reg->irq_number > count || count <= 0)
> goto reset_handler;
> reg->status = STATUS_IRQ_RAISED;
> - pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
> + pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI,
> + reg->irq_number);
> goto reset_handler;
> }
>
> @@ -457,8 +476,10 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> return ret;
>
> ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
> - if (ret)
> + if (ret) {
> + dev_err(dev, "MSI configuration failed\n");
> return ret;
> + }
>
> if (!epf_test->linkup_notifier)
> queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
>

2018-07-13 08:01:45

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 08/12] pci-epf-test/pci_endpoint_test: Use irq_type module parameter



On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Add new driver parameter to allow interruption type selection.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>

Acked-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Change v2->v3:
> - New patch file created base on the previous patch
> "misc: pci_endpoint_test: Add MSI-X support" patch file following
> Kishon's suggestion.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Nothing changed, just to follow the patch set version.
> Change v5->v6:
> - Nothing changed, just to follow the patch set version.
> Change v6->v7:
> - Removed unnecessary set to zero variable.
> - Removed empty line.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Nothing changed, just to follow the patch set version.
>
> drivers/misc/pci_endpoint_test.c | 28 +++++++++++++++++++---------
> 1 file changed, 19 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index 35fbfbd..349794c 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -82,6 +82,10 @@ static bool no_msi;
> module_param(no_msi, bool, 0444);
> MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
>
> +static int irq_type = IRQ_TYPE_MSI;
> +module_param(irq_type, int, 0444);
> +MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
> +
> enum pci_barno {
> BAR_0,
> BAR_1,
> @@ -108,7 +112,7 @@ struct pci_endpoint_test {
> struct pci_endpoint_test_data {
> enum pci_barno test_reg_bar;
> size_t alignment;
> - bool no_msi;
> + int irq_type;
> };
>
> static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
> @@ -291,8 +295,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
> size);
>
> - pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> - no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> COMMAND_COPY);
> @@ -361,8 +364,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
>
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
>
> - pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> - no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> COMMAND_READ);
> @@ -419,8 +421,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
>
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
>
> - pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> - no_msi ? IRQ_TYPE_LEGACY : IRQ_TYPE_MSI);
> + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> COMMAND_WRITE);
> @@ -505,11 +506,14 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
> test->alignment = 0;
> test->pdev = pdev;
>
> + if (no_msi)
> + irq_type = IRQ_TYPE_LEGACY;
> +
> data = (struct pci_endpoint_test_data *)ent->driver_data;
> if (data) {
> test_reg_bar = data->test_reg_bar;
> test->alignment = data->alignment;
> - no_msi = data->no_msi;
> + irq_type = data->irq_type;
> }
>
> init_completion(&test->irq_raised);
> @@ -529,11 +533,17 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
>
> pci_set_master(pdev);
>
> - if (!no_msi) {
> + switch (irq_type) {
> + case IRQ_TYPE_LEGACY:
> + break;
> + case IRQ_TYPE_MSI:
> irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
> if (irq < 0)
> dev_err(dev, "Failed to get MSI interrupts\n");
> test->num_irqs = irq;
> + break;
> + default:
> + dev_err(dev, "Invalid IRQ type selected\n");
> }
>
> err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
>

2018-07-13 08:10:06

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 09/12] pci-epf-test/pci_endpoint_test: Add MSI-X support



On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
> Add MSI-X support and update driver documentation accordingly.
>
> Signed-off-by: Gustavo Pimentel <[email protected]>

Acked-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Change v2->v3:
> - New patch file created base on the previous patch
> "misc: pci_endpoint_test: Add MSI-X support" patch file following
> Kishon's suggestion.
> Change v3->v4:
> - Rebased to Lorenzo's master branch v4.18-rc1.
> Change v4->v5:
> - Nothing changed, just to follow the patch set version.
> Change v5->v6:
> - Moved PCITEST_MSIX ioctl entry from patch #10 to here.
> - Documented ioctl parameter type associated to
> drivers/misc/pci_endpoint_test.c driver.
> Change v6->v7:
> - Updated documentation.
> - Added flag that enables or not the MSI-X on the EP features.
> Change v7->v8:
> - Re-sending the patch series.
> Change v8->v9:
> - Moving the EPC_FEATURE_MSIX_AVAILABLE feature set from the
> dw_pcie_ep_init() to dw_plat_pcie_ep_init().
>
> Documentation/PCI/endpoint/pci-test-function.txt | 2 +-
> Documentation/ioctl/ioctl-number.txt | 1 +
> Documentation/misc-devices/pci-endpoint-test.txt | 3 +++
> drivers/misc/pci_endpoint_test.c | 29 ++++++++++++++++-------
> drivers/pci/controller/dwc/pcie-designware-plat.c | 1 +
> drivers/pci/endpoint/functions/pci-epf-test.c | 29 +++++++++++++++++++++--
> include/linux/pci-epc.h | 1 +
> include/uapi/linux/pcitest.h | 1 +
> 8 files changed, 56 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt
> index 7ee2361..b1cbff3 100644
> --- a/Documentation/PCI/endpoint/pci-test-function.txt
> +++ b/Documentation/PCI/endpoint/pci-test-function.txt
> @@ -34,7 +34,7 @@ that the endpoint device must perform.
> Bitfield Description:
> Bit 0 : raise legacy IRQ
> Bit 1 : raise MSI IRQ
> - Bit 2 : raise MSI-X IRQ (reserved for future implementation)
> + Bit 2 : raise MSI-X IRQ
> Bit 3 : read command (read data from RC buffer)
> Bit 4 : write command (write data to RC buffer)
> Bit 5 : copy command (copy data from one RC buffer to another
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index 480c860..65259d4 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -166,6 +166,7 @@ Code Seq#(hex) Include File Comments
> 'P' all linux/soundcard.h conflict!
> 'P' 60-6F sound/sscape_ioctl.h conflict!
> 'P' 00-0F drivers/usb/class/usblp.c conflict!
> +'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
> 'Q' all linux/soundcard.h
> 'R' 00-1F linux/random.h conflict!
> 'R' 01 linux/rfkill.h conflict!
> diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt
> index 4ebc359..fdfa0f6 100644
> --- a/Documentation/misc-devices/pci-endpoint-test.txt
> +++ b/Documentation/misc-devices/pci-endpoint-test.txt
> @@ -10,6 +10,7 @@ The PCI driver for the test device performs the following tests
> *) verifying addresses programmed in BAR
> *) raise legacy IRQ
> *) raise MSI IRQ
> + *) raise MSI-X IRQ
> *) read data
> *) write data
> *) copy data
> @@ -25,6 +26,8 @@ ioctl
> PCITEST_LEGACY_IRQ: Tests legacy IRQ
> PCITEST_MSI: Tests message signalled interrupts. The MSI number
> to be tested should be passed as argument.
> + PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
> + to be tested should be passed as argument.
> PCITEST_WRITE: Perform write tests. The size of the buffer should be passed
> as argument.
> PCITEST_READ: Perform read tests. The size of the buffer should be passed
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index 349794c..f4fef10 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -39,13 +39,14 @@
>
> #define IRQ_TYPE_LEGACY 0
> #define IRQ_TYPE_MSI 1
> +#define IRQ_TYPE_MSIX 2
>
> #define PCI_ENDPOINT_TEST_MAGIC 0x0
>
> #define PCI_ENDPOINT_TEST_COMMAND 0x4
> #define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> #define COMMAND_RAISE_MSI_IRQ BIT(1)
> -/* BIT(2) is reserved for raising MSI-X IRQ command */
> +#define COMMAND_RAISE_MSIX_IRQ BIT(2)
> #define COMMAND_READ BIT(3)
> #define COMMAND_WRITE BIT(4)
> #define COMMAND_COPY BIT(5)
> @@ -84,7 +85,7 @@ MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
>
> static int irq_type = IRQ_TYPE_MSI;
> module_param(irq_type, int, 0444);
> -MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
> +MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)");
>
> enum pci_barno {
> BAR_0,
> @@ -202,16 +203,18 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
> }
>
> static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
> - u8 msi_num)
> + u16 msi_num, bool msix)
> {
> u32 val;
> struct pci_dev *pdev = test->pdev;
>
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
> - IRQ_TYPE_MSI);
> + msix == false ? IRQ_TYPE_MSI :
> + IRQ_TYPE_MSIX);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
> pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
> - COMMAND_RAISE_MSI_IRQ);
> + msix == false ? COMMAND_RAISE_MSI_IRQ :
> + COMMAND_RAISE_MSIX_IRQ);
> val = wait_for_completion_timeout(&test->irq_raised,
> msecs_to_jiffies(1000));
> if (!val)
> @@ -456,7 +459,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
> ret = pci_endpoint_test_legacy_irq(test);
> break;
> case PCITEST_MSI:
> - ret = pci_endpoint_test_msi_irq(test, arg);
> + case PCITEST_MSIX:
> + ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX);
> break;
> case PCITEST_WRITE:
> ret = pci_endpoint_test_write(test, arg);
> @@ -542,6 +546,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
> dev_err(dev, "Failed to get MSI interrupts\n");
> test->num_irqs = irq;
> break;
> + case IRQ_TYPE_MSIX:
> + irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
> + if (irq < 0)
> + dev_err(dev, "Failed to get MSI-X interrupts\n");
> + test->num_irqs = irq;
> + break;
> default:
> dev_err(dev, "Invalid IRQ type selected\n");
> }
> @@ -558,8 +568,9 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
> pci_endpoint_test_irqhandler,
> IRQF_SHARED, DRV_MODULE_NAME, test);
> if (err)
> - dev_err(dev, "failed to request IRQ %d for MSI %d\n",
> - pci_irq_vector(pdev, i), i + 1);
> + dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
> + pci_irq_vector(pdev, i),
> + irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
> }
>
> for (bar = BAR_0; bar <= BAR_5; bar++) {
> @@ -625,6 +636,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
>
> err_disable_msi:
> pci_disable_msi(pdev);
> + pci_disable_msix(pdev);
> pci_release_regions(pdev);
>
> err_disable_pdev:
> @@ -656,6 +668,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
> for (i = 0; i < test->num_irqs; i++)
> devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
> pci_disable_msi(pdev);
> + pci_disable_msix(pdev);
> pci_release_regions(pdev);
> pci_disable_device(pdev);
> }
> diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
> index 160714d..d2dd0c7 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-plat.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
> @@ -77,6 +77,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
> dw_pcie_ep_reset_bar(pci, bar);
>
> epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
> + epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
> }
>
> static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index eb9cd00..123f58c 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -20,10 +20,11 @@
>
> #define IRQ_TYPE_LEGACY 0
> #define IRQ_TYPE_MSI 1
> +#define IRQ_TYPE_MSIX 2
>
> #define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> #define COMMAND_RAISE_MSI_IRQ BIT(1)
> -/* BIT(2) is reserved for raising MSI-X IRQ command */
> +#define COMMAND_RAISE_MSIX_IRQ BIT(2)
> #define COMMAND_READ BIT(3)
> #define COMMAND_WRITE BIT(4)
> #define COMMAND_COPY BIT(5)
> @@ -47,6 +48,7 @@ struct pci_epf_test {
> struct pci_epf *epf;
> enum pci_barno test_reg_bar;
> bool linkup_notifier;
> + bool msix_available;
> struct delayed_work cmd_handler;
> };
>
> @@ -266,6 +268,9 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
> case IRQ_TYPE_MSI:
> pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
> break;
> + case IRQ_TYPE_MSIX:
> + pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq);
> + break;
> default:
> dev_err(dev, "Failed to raise IRQ, unknown type\n");
> break;
> @@ -292,7 +297,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> reg->command = 0;
> reg->status = 0;
>
> - if (reg->irq_type > IRQ_TYPE_MSI) {
> + if (reg->irq_type > IRQ_TYPE_MSIX) {
> dev_err(dev, "Failed to detect IRQ type\n");
> goto reset_handler;
> }
> @@ -346,6 +351,16 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> goto reset_handler;
> }
>
> + if (command & COMMAND_RAISE_MSIX_IRQ) {
> + count = pci_epc_get_msix(epc, epf->func_no);
> + if (reg->irq_number > count || count <= 0)
> + goto reset_handler;
> + reg->status = STATUS_IRQ_RAISED;
> + pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX,
> + reg->irq_number);
> + goto reset_handler;
> + }
> +
> reset_handler:
> queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
> msecs_to_jiffies(1));
> @@ -459,6 +474,8 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> else
> epf_test->linkup_notifier = true;
>
> + epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE;
> +
> epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features);
>
> ret = pci_epc_write_header(epc, epf->func_no, header);
> @@ -481,6 +498,14 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> return ret;
> }
>
> + if (epf_test->msix_available) {
> + ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
> + if (ret) {
> + dev_err(dev, "MSI-X configuration failed\n");
> + return ret;
> + }
> + }
> +
> if (!epf_test->linkup_notifier)
> queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
>
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index bb2395b..37dab81 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -102,6 +102,7 @@ struct pci_epc {
>
> #define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0)
> #define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3))
> +#define EPC_FEATURE_MSIX_AVAILABLE BIT(4)
> #define EPC_FEATURE_SET_BAR(features, bar) \
> (features |= (EPC_FEATURE_BAR_MASK & (bar << 1)))
> #define EPC_FEATURE_GET_BAR(features) \
> diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
> index 953cf03..d746fb1 100644
> --- a/include/uapi/linux/pcitest.h
> +++ b/include/uapi/linux/pcitest.h
> @@ -16,5 +16,6 @@
> #define PCITEST_WRITE _IOW('P', 0x4, unsigned long)
> #define PCITEST_READ _IOW('P', 0x5, unsigned long)
> #define PCITEST_COPY _IOW('P', 0x6, unsigned long)
> +#define PCITEST_MSIX _IOW('P', 0x7, int)
>
> #endif /* __UAPI_LINUX_PCITEST_H */
>

2018-07-13 13:24:09

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH v9 00/12] Add MSI-X support on pcitest tool

On Mon, Jul 09, 2018 at 06:42:38PM +0100, Gustavo Pimentel wrote:
> Patch series made against Lorenzo's master branch.
>
> Fix EP link notification implementation.
>
> Add MSI-X support on pcitest tool.
>
> Add new callbacks methods and handlers to trigger the MSI-X interrupts
> on the EP DesignWare IP driver.
>
> Allow to set/get MSI-X EP maximum capability number.
>
> Rework on set/get and triggering MSI methods on EP DesignWare IP driver.
>
> Add a new input parameter (msix) to pcitest tool to test MSI-X feature.
>
> Update the pcitest.sh script to support MSI-X feature tests.
>
> Gustavo Pimentel (12):
> PCI: dwc: Fix EP link notification implementation
> PCI: endpoint: Add MSI-X interfaces
> PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
> PCI: dwc: Add MSI-X callbacks handler
> PCI: dwc: Rework MSI callbacks handler
> PCI: dwc: Add legacy interrupt callback handler
> pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
> pci-epf-test/pci_endpoint_test: Use irq_type module parameter
> pci-epf-test/pci_endpoint_test: Add MSI-X support
> pci_endpoint_test: Add 2 ioctl commands
> tools: PCI: Add MSI-X support
> PCI: endpoint: Add MSI set maximum restriction
>
> Documentation/PCI/endpoint/pci-test-function.txt | 8 +-
> Documentation/ioctl/ioctl-number.txt | 1 +
> Documentation/misc-devices/pci-endpoint-test.txt | 6 +
> drivers/misc/pci_endpoint_test.c | 260 ++++++++++++++++------
> drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
> drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
> drivers/pci/controller/dwc/pcie-designware-ep.c | 217 ++++++++++++++++--
> drivers/pci/controller/dwc/pcie-designware-plat.c | 11 +-
> drivers/pci/controller/dwc/pcie-designware.h | 31 ++-
> drivers/pci/controller/pcie-cadence-ep.c | 3 +-
> drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
> drivers/pci/endpoint/functions/pci-epf-test.c | 86 +++++--
> drivers/pci/endpoint/pci-ep-cfs.c | 24 ++
> drivers/pci/endpoint/pci-epc-core.c | 68 +++++-
> include/linux/pci-epc.h | 16 +-
> include/linux/pci-epf.h | 1 +
> include/uapi/linux/pcitest.h | 3 +
> tools/pci/pcitest.c | 51 ++++-
> tools/pci/pcitest.sh | 15 ++
> 19 files changed, 664 insertions(+), 143 deletions(-)

Gustavo, Kishon,

it seems like this series has been thoroughly reviewed and it is
ready to go, please let me know if there is any pending change.

Lorenzo

2018-07-13 15:58:53

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v9 04/12] PCI: dwc: Add MSI-X callbacks handler

Hi Kishon,

On 13/07/2018 08:55, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Monday 09 July 2018 11:12 PM, Gustavo Pimentel wrote:
>> Add PCIe config space capability search function.
>>
>> Add sysfs set/get interface to allow the change of EP MSI-X maximum number.
>>
>> Add EP MSI-X callback for triggering interruptions.
>>
>> Signed-off-by: Gustavo Pimentel <[email protected]>
>> ---
>> Change v1->v2:
>> - Nothing changed, just to follow the patch set version.
>> Change v2->v3:
>> - Moved dra7xx_pcie_raise_irq() signature change to patch file #3.
>> - Moved artpec6_pcie_raise_irq() signature change to patch file #3.
>> - Replaced wrong return value 0 to -EINVAL.
>> - Removed an else if by code refactoring.
>> - Reduced the size of ioremap_nocache mapping from ep->addr_size to
>> PCI_MSIX_ENTRY_SIZE.
>> - Fixed a small bug. If the MSI-X vector bit has been set, the function
>> would return without executing the proper unmap.
>> Change v3->v4:
>> - Rebased to Lorenzo's master branch v4.18-rc1.
>> - Added static prefix to __dw_pcie_ep_find_next_cap function.
>> Change v4->v5:
>> - Added static prefix to dw_pcie_ep_find_capability function.
>> - Swap patch files position (#2 <-> #3).
>> - Moved dw_pcie_ep_raise_irq and dw_plat_pcie_ep_raise_irq functions
>> signatures change to patch file #2.
>> Change v5->v6:
>> - Nothing changed, just to follow the patch set version.
>> Change v6->v7:
>> - Nothing changed, just to follow the patch set version.
>> Change v7->v8:
>> - Re-sending the patch series.
>> Change v8->v9:
>> - Nothing changed, just to follow the patch set version.
>>
>> drivers/pci/controller/dwc/pcie-designware-ep.c | 144 ++++++++++++++++++++++
>> drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +
>> drivers/pci/controller/dwc/pcie-designware.h | 12 ++
>> 3 files changed, 158 insertions(+)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
>> index 69d039d..72c4188 100644
>> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
>> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
>> @@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
>> __dw_pcie_ep_reset_bar(pci, bar, 0);
>> }
>>
>> +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
>> + u8 cap)
>> +{
>> + u8 cap_id, next_cap_ptr;
>> + u16 reg;
>> +
>> + reg = dw_pcie_readw_dbi(pci, cap_ptr);
>> + next_cap_ptr = (reg & 0xff00) >> 8;
>> + cap_id = (reg & 0x00ff);
>> +
>> + if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX)
>> + return 0;
>> +
>> + if (cap_id == cap)
>> + return cap_ptr;
>> +
>> + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
>> +}
>> +
>> +static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
>> +{
>> + u8 next_cap_ptr;
>> + u16 reg;
>> +
>> + reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
>> + next_cap_ptr = (reg & 0x00ff);
>> +
>> + if (!next_cap_ptr)
>> + return 0;
>> +
>> + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
>> +}
>> +
>> static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
>> struct pci_epf_header *hdr)
>> {
>> @@ -241,6 +274,45 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
>> return 0;
>> }
>>
>> +static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
>> +{
>> + struct dw_pcie_ep *ep = epc_get_drvdata(epc);
>> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
>> + u32 val, reg;
>> +
>> + if (!ep->msix_cap)
>> + return -EINVAL;
>> +
>> + reg = ep->msix_cap + PCI_MSIX_FLAGS;
>> + val = dw_pcie_readw_dbi(pci, reg);
>> + if (!(val & PCI_MSIX_FLAGS_ENABLE))
>> + return -EINVAL;
>> +
>> + val &= PCI_MSIX_FLAGS_QSIZE;
>> +
>> + return val;
>> +}
>> +
>> +static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
>> +{
>> + struct dw_pcie_ep *ep = epc_get_drvdata(epc);
>> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
>> + u32 val, reg;
>> +
>> + if (!ep->msix_cap)
>> + return -EINVAL;
>> +
>> + 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);
>> + dw_pcie_dbi_ro_wr_dis(pci);
>> +
>> + return 0;
>> +}
>> +
>> static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
>> enum pci_epc_irq_type type, u16 interrupt_num)
>> {
>> @@ -282,6 +354,8 @@ static const struct pci_epc_ops epc_ops = {
>> .unmap_addr = dw_pcie_ep_unmap_addr,
>> .set_msi = dw_pcie_ep_set_msi,
>> .get_msi = dw_pcie_ep_get_msi,
>> + .set_msix = dw_pcie_ep_set_msix,
>> + .get_msix = dw_pcie_ep_get_msix,
>> .raise_irq = dw_pcie_ep_raise_irq,
>> .start = dw_pcie_ep_start,
>> .stop = dw_pcie_ep_stop,
>> @@ -322,6 +396,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
>> return 0;
>> }
>>
>> +int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
>> + u16 interrupt_num)
>> +{
>> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
>> + struct pci_epc *epc = ep->epc;
>> + u16 tbl_offset, bir;
>> + u32 bar_addr_upper, bar_addr_lower;
>> + u32 msg_addr_upper, msg_addr_lower;
>> + u32 reg, msg_data, vec_ctrl;
>> + u64 tbl_addr, msg_addr, reg_u64;
>> + void __iomem *msix_tbl;
>> + int ret;
>> +
>> + reg = ep->msix_cap + PCI_MSIX_TABLE;
>> + tbl_offset = dw_pcie_readl_dbi(pci, reg);
>> + bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
>> + tbl_offset &= PCI_MSIX_TABLE_OFFSET;
>> + tbl_offset >>= 3;
>> +
>> + reg = PCI_BASE_ADDRESS_0 + (4 * bir);
>> + bar_addr_upper = 0;
>> + bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
>> + reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
>> + if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
>> + bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
>> +
>> + tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
>> + tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
>> + tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
>> +
>> + msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr,
>> + PCI_MSIX_ENTRY_SIZE);
>> + if (!msix_tbl)
>> + return -EINVAL;
>> +
>> + msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
>> + msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
>> + msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
>> + msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
>> + vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
>> +
>> + iounmap(msix_tbl);
>> +
>> + if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)
>> + return -EPERM;
>> +
>> + ret = dw_pcie_ep_map_addr(epc, func_no, ep->msix_mem_phys, msg_addr,
>> + epc->mem->page_size);
>> + if (ret)
>> + return ret;
>> +
>> + writel(msg_data, ep->msix_mem);
>> +
>> + dw_pcie_ep_unmap_addr(epc, func_no, ep->msix_mem_phys);
>> +
>> + return 0;
>> +}
>> +
>> void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
>> {
>> struct pci_epc *epc = ep->epc;
>> @@ -329,6 +461,9 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
>> pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
>> epc->mem->page_size);
>>
>> + pci_epc_mem_free_addr(epc, ep->msix_mem_phys, ep->msix_mem,
>> + epc->mem->page_size);
>> +
>> pci_epc_mem_exit(epc);
>> }
>>
>> @@ -415,6 +550,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
>> dev_err(dev, "Failed to reserve memory for MSI\n");
>> return -ENOMEM;
>> }
>> + ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI);
>> +
>> + ep->msix_mem = pci_epc_mem_alloc_addr(epc, &ep->msix_mem_phys,
>> + epc->mem->page_size);
>> + if (!ep->msix_mem) {
>> + dev_err(dev, "Failed to reserve memory for MSI-X\n");
>> + return -ENOMEM;
>
> Do we have to allocate memory for MSIX memory separately? I think we can reuse
> msi_mem. That's also because we shouldn't fail if a platform doesn't support
> MSIX and fails to allocate msix_mem.

Ok.

>
> Thanks
> Kishon
>

Regards,
Gustavo

2018-07-13 16:03:16

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v9 00/12] Add MSI-X support on pcitest tool

Hi Lorenzo,

On 13/07/2018 14:25, Lorenzo Pieralisi wrote:
> On Mon, Jul 09, 2018 at 06:42:38PM +0100, Gustavo Pimentel wrote:
>> Patch series made against Lorenzo's master branch.
>>
>> Fix EP link notification implementation.
>>
>> Add MSI-X support on pcitest tool.
>>
>> Add new callbacks methods and handlers to trigger the MSI-X interrupts
>> on the EP DesignWare IP driver.
>>
>> Allow to set/get MSI-X EP maximum capability number.
>>
>> Rework on set/get and triggering MSI methods on EP DesignWare IP driver.
>>
>> Add a new input parameter (msix) to pcitest tool to test MSI-X feature.
>>
>> Update the pcitest.sh script to support MSI-X feature tests.
>>
>> Gustavo Pimentel (12):
>> PCI: dwc: Fix EP link notification implementation
>> PCI: endpoint: Add MSI-X interfaces
>> PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
>> PCI: dwc: Add MSI-X callbacks handler
>> PCI: dwc: Rework MSI callbacks handler
>> PCI: dwc: Add legacy interrupt callback handler
>> pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
>> pci-epf-test/pci_endpoint_test: Use irq_type module parameter
>> pci-epf-test/pci_endpoint_test: Add MSI-X support
>> pci_endpoint_test: Add 2 ioctl commands
>> tools: PCI: Add MSI-X support
>> PCI: endpoint: Add MSI set maximum restriction
>>
>> Documentation/PCI/endpoint/pci-test-function.txt | 8 +-
>> Documentation/ioctl/ioctl-number.txt | 1 +
>> Documentation/misc-devices/pci-endpoint-test.txt | 6 +
>> drivers/misc/pci_endpoint_test.c | 260 ++++++++++++++++------
>> drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
>> drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
>> drivers/pci/controller/dwc/pcie-designware-ep.c | 217 ++++++++++++++++--
>> drivers/pci/controller/dwc/pcie-designware-plat.c | 11 +-
>> drivers/pci/controller/dwc/pcie-designware.h | 31 ++-
>> drivers/pci/controller/pcie-cadence-ep.c | 3 +-
>> drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
>> drivers/pci/endpoint/functions/pci-epf-test.c | 86 +++++--
>> drivers/pci/endpoint/pci-ep-cfs.c | 24 ++
>> drivers/pci/endpoint/pci-epc-core.c | 68 +++++-
>> include/linux/pci-epc.h | 16 +-
>> include/linux/pci-epf.h | 1 +
>> include/uapi/linux/pcitest.h | 3 +
>> tools/pci/pcitest.c | 51 ++++-
>> tools/pci/pcitest.sh | 15 ++
>> 19 files changed, 664 insertions(+), 143 deletions(-)
>
> Gustavo, Kishon,
>
> it seems like this series has been thoroughly reviewed and it is
> ready to go, please let me know if there is any pending change.

I just sent the patch # 10 based on Kishon's latest review.
For me it's nearly perfect. :)

Gustavo

>
> Lorenzo
>


2018-07-16 04:08:44

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v9 00/12] Add MSI-X support on pcitest tool

Hi,

On Friday 13 July 2018 09:29 PM, Gustavo Pimentel wrote:
> Hi Lorenzo,
>
> On 13/07/2018 14:25, Lorenzo Pieralisi wrote:
>> On Mon, Jul 09, 2018 at 06:42:38PM +0100, Gustavo Pimentel wrote:
>>> Patch series made against Lorenzo's master branch.
>>>
>>> Fix EP link notification implementation.
>>>
>>> Add MSI-X support on pcitest tool.
>>>
>>> Add new callbacks methods and handlers to trigger the MSI-X interrupts
>>> on the EP DesignWare IP driver.
>>>
>>> Allow to set/get MSI-X EP maximum capability number.
>>>
>>> Rework on set/get and triggering MSI methods on EP DesignWare IP driver.
>>>
>>> Add a new input parameter (msix) to pcitest tool to test MSI-X feature.
>>>
>>> Update the pcitest.sh script to support MSI-X feature tests.
>>>
>>> Gustavo Pimentel (12):
>>> PCI: dwc: Fix EP link notification implementation
>>> PCI: endpoint: Add MSI-X interfaces
>>> PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
>>> PCI: dwc: Add MSI-X callbacks handler
>>> PCI: dwc: Rework MSI callbacks handler
>>> PCI: dwc: Add legacy interrupt callback handler
>>> pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
>>> pci-epf-test/pci_endpoint_test: Use irq_type module parameter
>>> pci-epf-test/pci_endpoint_test: Add MSI-X support
>>> pci_endpoint_test: Add 2 ioctl commands
>>> tools: PCI: Add MSI-X support
>>> PCI: endpoint: Add MSI set maximum restriction
>>>
>>> Documentation/PCI/endpoint/pci-test-function.txt | 8 +-
>>> Documentation/ioctl/ioctl-number.txt | 1 +
>>> Documentation/misc-devices/pci-endpoint-test.txt | 6 +
>>> drivers/misc/pci_endpoint_test.c | 260 ++++++++++++++++------
>>> drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
>>> drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
>>> drivers/pci/controller/dwc/pcie-designware-ep.c | 217 ++++++++++++++++--
>>> drivers/pci/controller/dwc/pcie-designware-plat.c | 11 +-
>>> drivers/pci/controller/dwc/pcie-designware.h | 31 ++-
>>> drivers/pci/controller/pcie-cadence-ep.c | 3 +-
>>> drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
>>> drivers/pci/endpoint/functions/pci-epf-test.c | 86 +++++--
>>> drivers/pci/endpoint/pci-ep-cfs.c | 24 ++
>>> drivers/pci/endpoint/pci-epc-core.c | 68 +++++-
>>> include/linux/pci-epc.h | 16 +-
>>> include/linux/pci-epf.h | 1 +
>>> include/uapi/linux/pcitest.h | 3 +
>>> tools/pci/pcitest.c | 51 ++++-
>>> tools/pci/pcitest.sh | 15 ++
>>> 19 files changed, 664 insertions(+), 143 deletions(-)
>>
>> Gustavo, Kishon,
>>
>> it seems like this series has been thoroughly reviewed and it is
>> ready to go, please let me know if there is any pending change.
>
> I just sent the patch # 10 based on Kishon's latest review.
> For me it's nearly perfect. :)

I got to test this series today and I found one issue.

use this sequence:
1) pcitest -i 2 /* change to MSIX irq type */
For platforms that doesn't support MSIX, get the following message
pci-endpoint-test 0000:01:00.0: Failed to get MSI-X interrupts
SET IRQ TYPE TO MSI-X: NOT OKAY

However after this, pci_endpoint_test_set_irq() will invoke
pci_endpoint_test_free_irq_vectors() and pci_endpoint_test_release_irq().
This will free previously allocated MSI irq vectors.

2) pcitest -i 1 /* change to MSI irq type */

This will not invoke pci_endpoint_test_alloc_irq_vectors() and
pci_endpoint_test_request_irq() since now "if (irq_type == req_irq_type)"
will return true.

After this MSI tests will fail.

Other than this failing sequence, the series looks good to me.

Thanks
Kishon

2018-07-16 14:52:52

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v9 00/12] Add MSI-X support on pcitest tool

Hi Kishon,

On 16/07/2018 05:07, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Friday 13 July 2018 09:29 PM, Gustavo Pimentel wrote:
>> Hi Lorenzo,
>>
>> On 13/07/2018 14:25, Lorenzo Pieralisi wrote:
>>> On Mon, Jul 09, 2018 at 06:42:38PM +0100, Gustavo Pimentel wrote:
>>>> Patch series made against Lorenzo's master branch.
>>>>
>>>> Fix EP link notification implementation.
>>>>
>>>> Add MSI-X support on pcitest tool.
>>>>
>>>> Add new callbacks methods and handlers to trigger the MSI-X interrupts
>>>> on the EP DesignWare IP driver.
>>>>
>>>> Allow to set/get MSI-X EP maximum capability number.
>>>>
>>>> Rework on set/get and triggering MSI methods on EP DesignWare IP driver.
>>>>
>>>> Add a new input parameter (msix) to pcitest tool to test MSI-X feature.
>>>>
>>>> Update the pcitest.sh script to support MSI-X feature tests.
>>>>
>>>> Gustavo Pimentel (12):
>>>> PCI: dwc: Fix EP link notification implementation
>>>> PCI: endpoint: Add MSI-X interfaces
>>>> PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures
>>>> PCI: dwc: Add MSI-X callbacks handler
>>>> PCI: dwc: Rework MSI callbacks handler
>>>> PCI: dwc: Add legacy interrupt callback handler
>>>> pci-epf-test/pci_endpoint_test: Cleanup PCI_ENDPOINT_TEST memspace
>>>> pci-epf-test/pci_endpoint_test: Use irq_type module parameter
>>>> pci-epf-test/pci_endpoint_test: Add MSI-X support
>>>> pci_endpoint_test: Add 2 ioctl commands
>>>> tools: PCI: Add MSI-X support
>>>> PCI: endpoint: Add MSI set maximum restriction
>>>>
>>>> Documentation/PCI/endpoint/pci-test-function.txt | 8 +-
>>>> Documentation/ioctl/ioctl-number.txt | 1 +
>>>> Documentation/misc-devices/pci-endpoint-test.txt | 6 +
>>>> drivers/misc/pci_endpoint_test.c | 260 ++++++++++++++++------
>>>> drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
>>>> drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
>>>> drivers/pci/controller/dwc/pcie-designware-ep.c | 217 ++++++++++++++++--
>>>> drivers/pci/controller/dwc/pcie-designware-plat.c | 11 +-
>>>> drivers/pci/controller/dwc/pcie-designware.h | 31 ++-
>>>> drivers/pci/controller/pcie-cadence-ep.c | 3 +-
>>>> drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
>>>> drivers/pci/endpoint/functions/pci-epf-test.c | 86 +++++--
>>>> drivers/pci/endpoint/pci-ep-cfs.c | 24 ++
>>>> drivers/pci/endpoint/pci-epc-core.c | 68 +++++-
>>>> include/linux/pci-epc.h | 16 +-
>>>> include/linux/pci-epf.h | 1 +
>>>> include/uapi/linux/pcitest.h | 3 +
>>>> tools/pci/pcitest.c | 51 ++++-
>>>> tools/pci/pcitest.sh | 15 ++
>>>> 19 files changed, 664 insertions(+), 143 deletions(-)
>>>
>>> Gustavo, Kishon,
>>>
>>> it seems like this series has been thoroughly reviewed and it is
>>> ready to go, please let me know if there is any pending change.
>>
>> I just sent the patch # 10 based on Kishon's latest review.
>> For me it's nearly perfect. :)
>
> I got to test this series today and I found one issue.
>
> use this sequence:
> 1) pcitest -i 2 /* change to MSIX irq type */
> For platforms that doesn't support MSIX, get the following message
> pci-endpoint-test 0000:01:00.0: Failed to get MSI-X interrupts
> SET IRQ TYPE TO MSI-X: NOT OKAY
>
> However after this, pci_endpoint_test_set_irq() will invoke
> pci_endpoint_test_free_irq_vectors() and pci_endpoint_test_release_irq().
> This will free previously allocated MSI irq vectors.
>
> 2) pcitest -i 1 /* change to MSI irq type */
>
> This will not invoke pci_endpoint_test_alloc_irq_vectors() and
> pci_endpoint_test_request_irq() since now "if (irq_type == req_irq_type)"
> will return true.
>
> After this MSI tests will fail.
>
> Other than this failing sequence, the series looks good to me.

It's fixed on the patch series v11 (see patch
#10-pci_endpoint_test-Add-2-ioctl-commands.patch file).
Thanks!

>
> Thanks
> Kishon
>

Regards,
Gustavo