2018-07-06 15:54:36

by Gustavo Pimentel

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

Patch series made against Lorenzo's master branch.

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 (11):
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 | 259 ++++++++++++++++------
drivers/pci/controller/dwc/pci-dra7xx.c | 2 +-
drivers/pci/controller/dwc/pcie-artpec6.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-ep.c | 206 +++++++++++++++--
drivers/pci/controller/dwc/pcie-designware-plat.c | 7 +-
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, 655 insertions(+), 136 deletions(-)

--
2.7.4




2018-07-06 15:53:09

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 02/11] 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.

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 8650416..b86cb99 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 5937fed..14b6b4b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -78,7 +78,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-06 15:53:29

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 01/11] 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.

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-06 15:53:51

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 04/11] 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.

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 bbe75d7..1f98db3 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-06 15:54:30

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 06/11] 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.

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-06 15:54:44

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 03/11] 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.

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 b86cb99..bbe75d7 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);
}

@@ -412,6 +547,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);

epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
EPC_FEATURE_SET_BAR(epc->features, BAR_0);
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 14b6b4b..654dcb5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -88,6 +88,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-06 15:54:50

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 10/11] 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.

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-06 15:54:56

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 11/11] 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]>
---
Change v4->v5:
- New patch file.
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/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-06 15:55:06

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 05/11] 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 1f98db3..70d0688 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 654dcb5..90a8c95 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -84,8 +84,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-06 15:55:07

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 07/11] 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.

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-06 15:55:55

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 09/11] 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.

Documentation/ioctl/ioctl-number.txt | 2 +-
Documentation/misc-devices/pci-endpoint-test.txt | 3 +
drivers/misc/pci_endpoint_test.c | 175 +++++++++++++++++------
include/uapi/linux/pcitest.h | 2 +
4 files changed, 135 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..97082e3 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -157,6 +157,87 @@ 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 irq = -1;
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ bool res = true;
+
+ switch (irq_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 +521,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)) {
+ 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 +584,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 +605,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 +654,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");
- }
+ if (!pci_endpoint_test_alloc_irq_vectors(test))
+ goto err_disable_irq;

- 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;
- }
-
- 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 +718,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 +733,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 +749,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-06 15:56:29

by Gustavo Pimentel

[permalink] [raw]
Subject: [PATCH v8 08/11] 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.

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-ep.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-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 70d0688..36d83d1 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -585,6 +585,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);

epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
+ epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
EPC_FEATURE_SET_BAR(epc->features, BAR_0);

ep->epc = epc;
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 04:49:57

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v8 08/11] pci-epf-test/pci_endpoint_test: Add MSI-X support

Hi,

On Friday 06 July 2018 09:21 PM, Gustavo Pimentel wrote:
> 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.
>
> 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-ep.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-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 70d0688..36d83d1 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -585,6 +585,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
>
> epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
> + epc->features |= EPC_FEATURE_MSIX_AVAILABLE;

This indicates all vendors of designware has MSIX enabled which is not true.
We'll need more logic than that.

Thanks
Kishon

2018-07-09 10:12:31

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v8 08/11] pci-epf-test/pci_endpoint_test: Add MSI-X support

Hi,

On 09/07/2018 05:48, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Friday 06 July 2018 09:21 PM, Gustavo Pimentel wrote:
>> 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.
>>
>> 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-ep.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-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
>> index 70d0688..36d83d1 100644
>> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
>> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
>> @@ -585,6 +585,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
>> ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
>>
>> epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
>> + epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
>
> This indicates all vendors of designware has MSIX enabled which is not true.
> We'll need more logic than that.

You mentioned and excellent point. Any particularity related to this features
should be implemented each specific driver (in this case on
pcie-designware-plat.c file).

And by looking at this code now that you mentioned, I think the line code
"epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;" was added by mistake, if I
remember well by default the linkup notification is expected, right?

If I'm right, I may create an extra patch removing this 2 lines, do you agree?

epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
EPC_FEATURE_SET_BAR(epc->features, BAR_0);

Meanwhile can you please ack the other patch files (#3 and #4)? They have
remained unchanged for a long time.

>
> Thanks
> Kishon
>


2018-07-09 10:29:56

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v8 08/11] pci-epf-test/pci_endpoint_test: Add MSI-X support

Hi,

On Monday 09 July 2018 03:38 PM, Gustavo Pimentel wrote:
> Hi,
>
> On 09/07/2018 05:48, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On Friday 06 July 2018 09:21 PM, Gustavo Pimentel wrote:
>>> 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.
>>>
>>> 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-ep.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-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>> index 70d0688..36d83d1 100644
>>> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
>>> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>> @@ -585,6 +585,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
>>> ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
>>>
>>> epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
>>> + epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
>>
>> This indicates all vendors of designware has MSIX enabled which is not true.
>> We'll need more logic than that.
>
> You mentioned and excellent point. Any particularity related to this features
> should be implemented each specific driver (in this case on
> pcie-designware-plat.c file).
>
> And by looking at this code now that you mentioned, I think the line code
> "epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;" was added by mistake, if I
> remember well by default the linkup notification is expected, right?

right, since dra7x was the first platform to have EP support added and it has
linkup notification mechanism.
>
> If I'm right, I may create an extra patch removing this 2 lines, do you agree?

Agree. I think we should use ->ep_init() present in dw_pcie_ep_ops for
populating features. ->ep_init() right now is called in dw_pcie_ep_init() which
is not needed. Stuffs that are right now done in ->ep_init callbacks can be
done even before invoking dw_pcie_ep_init().

We might have to add a new API pci_epc_init() to be invoked from function
driver, which should invoke ->ep_init() callback. The features of a particular
platform should be populated here.

Thanks
Kishon

2018-07-09 15:24:45

by Alan Douglas

[permalink] [raw]
Subject: RE: [PATCH v8 09/11] pci_endpoint_test: Add 2 ioctl commands

Hi Gustavo,

On 06 July 2018 16:52 Gustavo Pimentel <[email protected]> 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.
>
> Documentation/ioctl/ioctl-number.txt | 2 +-
> Documentation/misc-devices/pci-endpoint-test.txt | 3 +
> drivers/misc/pci_endpoint_test.c | 175 +++++++++++++++++------
> include/uapi/linux/pcitest.h | 2 +
> 4 files changed, 135 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..97082e3 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -157,6 +157,87 @@ 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 irq = -1;
> + struct pci_dev *pdev = test->pdev;
> + struct device *dev = &pdev->dev;
> + bool res = true;
> +
> + switch (irq_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 +521,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)) {
> + pci_endpoint_test_release_irq(test);
> + return false;
> + }
I am testing the latest patch set with the cadence driver, and find this step is not working correctly.
pci_endpoint_test_alloc_irq_vectors relies on the value of static irq_type to request the appropriate IRQ.
However, you don't set this value until a few lines later, so the first attempt to set the IRQ type fails. (A
second attempt to set it will succeed however.) I suggest setting irq_type before the call, or even adding
a parameter to pci_endpoint_test_alloc_irq_vectors() with the requested IRQ type to avoid having to set it
back again after a failed call.
> +
> + if (!pci_endpoint_test_request_irq(test)) {
> + pci_endpoint_test_release_irq(test);
> + return false;
> + }

> +
> + irq_type = req_irq_type;
> +
> + return true;
> +}

2018-07-09 16:43:58

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v8 09/11] pci_endpoint_test: Add 2 ioctl commands

Hi Alan,

On 09/07/2018 16:22, Alan Douglas wrote:
> Hi Gustavo,
>
> On 06 July 2018 16:52 Gustavo Pimentel <[email protected]> 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.
>>
>> Documentation/ioctl/ioctl-number.txt | 2 +-
>> Documentation/misc-devices/pci-endpoint-test.txt | 3 +
>> drivers/misc/pci_endpoint_test.c | 175 +++++++++++++++++------
>> include/uapi/linux/pcitest.h | 2 +
>> 4 files changed, 135 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..97082e3 100644
>> --- a/drivers/misc/pci_endpoint_test.c
>> +++ b/drivers/misc/pci_endpoint_test.c
>> @@ -157,6 +157,87 @@ 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 irq = -1;
>> + struct pci_dev *pdev = test->pdev;
>> + struct device *dev = &pdev->dev;
>> + bool res = true;
>> +
>> + switch (irq_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 +521,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)) {
>> + pci_endpoint_test_release_irq(test);
>> + return false;
>> + }
> I am testing the latest patch set with the cadence driver, and find this step is not working correctly.
> pci_endpoint_test_alloc_irq_vectors relies on the value of static irq_type to request the appropriate IRQ.
> However, you don't set this value until a few lines later, so the first attempt to set the IRQ type fails. (A
> second attempt to set it will succeed however.) I suggest setting irq_type before the call, or even adding
> a parameter to pci_endpoint_test_alloc_irq_vectors() with the requested IRQ type to avoid having to set it
> back again after a failed call.

Thank you for testing the code. This bug appeared on the patch version 6 after
the Kishon's good suggestion of moving the irq type variable update immediately
before function returning. Unfortunately I forgot the
pci_endpoint_test_alloc_irq_vectors() dependency.
Once again, thanks!

Regards,
Gustavo

>> +
>> + if (!pci_endpoint_test_request_irq(test)) {
>> + pci_endpoint_test_release_irq(test);
>> + return false;
>> + }
>
>> +
>> + irq_type = req_irq_type;
>> +
>> + return true;
>> +}


2018-07-09 17:43:45

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH v8 08/11] pci-epf-test/pci_endpoint_test: Add MSI-X support

Hi,

On 09/07/2018 11:26, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Monday 09 July 2018 03:38 PM, Gustavo Pimentel wrote:
>> Hi,
>>
>> On 09/07/2018 05:48, Kishon Vijay Abraham I wrote:
>>> Hi,
>>>
>>> On Friday 06 July 2018 09:21 PM, Gustavo Pimentel wrote:
>>>> 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.
>>>>
>>>> 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-ep.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-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> index 70d0688..36d83d1 100644
>>>> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> @@ -585,6 +585,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
>>>> ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
>>>>
>>>> epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;
>>>> + epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
>>>
>>> This indicates all vendors of designware has MSIX enabled which is not true.
>>> We'll need more logic than that.
>>
>> You mentioned and excellent point. Any particularity related to this features
>> should be implemented each specific driver (in this case on
>> pcie-designware-plat.c file).
>>
>> And by looking at this code now that you mentioned, I think the line code
>> "epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER;" was added by mistake, if I
>> remember well by default the linkup notification is expected, right?
>
> right, since dra7x was the first platform to have EP support added and it has
> linkup notification mechanism.
>>
>> If I'm right, I may create an extra patch removing this 2 lines, do you agree?

I will send a patch as soon as possible to fix this nasty bug. Unfortunately it
will be more than just deleting 2 lines....

>
> Agree. I think we should use ->ep_init() present in dw_pcie_ep_ops for
> populating features. ->ep_init() right now is called in dw_pcie_ep_init() which
> is not needed. Stuffs that are right now done in ->ep_init callbacks can be
> done even before invoking dw_pcie_ep_init().

I don't think so, that we can invoke before, dw_pcie_ep_init() is responsible
for creating the epc object and set the object address to the epc pointer
present on the ep struct. This pointer is used later to access and set the
feature field.

>
> We might have to add a new API pci_epc_init() to be invoked from function
> driver, which should invoke ->ep_init() callback. The features of a particular
> platform should be populated here.

My solution for now is to repair this damage as soon as possible, for that I'll
move the the feature setting from the pcie-designware-ep.c to the
pcie-designware-plat.c and change some code order to work.

I propose we implement this change after this patch has entered, otherwise we'll
be adding yet another degree of complexity to this series, already quite complex.

Can you test the the patch series v9 on your side Kishon?

Regards,
Gustavo

>
> Thanks
> Kishon
>