* [RFC v2 0/8] add new irq api to pcie-designware
@ 2017-05-15 17:03 Joao Pinto
2017-05-15 17:03 ` [RFC v2 1/8] pci: adding new irq api to pci-designware Joao Pinto
` (7 more replies)
0 siblings, 8 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch series adds the new interrupt api to pcie-designware
make it possible to use features like MSIX.
The work consisted of adapting the pcie-designware-host and each SoC
specific driver.
Joao Pinto (8):
pci: adding new irq api to pci-designware
pci: exynos SoC driver adapted to new irq API
pci: imx6 SoC driver adapted to new irq API
pci: artpec6 SoC driver adapted to new irq API
pci: generic PCIe DW driver adapted to new irq API
pci: qcom SoC driver adapted to new irq API
pci: keystone SoC driver adapted to new irq API
pci: removing old irq api from pcie-designware
drivers/pci/dwc/pci-exynos.c | 18 --
drivers/pci/dwc/pci-imx6.c | 18 --
drivers/pci/dwc/pci-keystone-dw.c | 97 +--------
drivers/pci/dwc/pci-keystone.c | 1 +
drivers/pci/dwc/pci-keystone.h | 4 +-
drivers/pci/dwc/pci-layerscape.c | 4 +-
drivers/pci/dwc/pcie-artpec6.c | 18 --
drivers/pci/dwc/pcie-designware-host.c | 372 ++++++++++++++++++---------------
drivers/pci/dwc/pcie-designware-plat.c | 15 --
drivers/pci/dwc/pcie-designware.h | 18 +-
drivers/pci/dwc/pcie-qcom.c | 15 --
11 files changed, 231 insertions(+), 349 deletions(-)
--
2.9.3
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC v2 1/8] pci: adding new irq api to pci-designware
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-21 8:44 ` Marc Zyngier
2017-05-15 17:03 ` [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API Joao Pinto
` (6 subsequent siblings)
7 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adds the new interrupt api to pcie-designware, keeping the old
one. Although the old API is still available, pcie-designware initiates with
the new one.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- Now there's no config to toggle between the 2 APIs, so pcie-designware
initiaties wih the new one by default
- Using lower_32_bits / upper_32_bits
- Instead of mutex, now using spinlocks
- Instead of always reading PCIE_MSI_INTR0_ENABLE, now we use an internal
variable
- dw_pcie_irq_domain_alloc() was updated to enable Multi-MSI
- using irq_domain_create_linear() instead of irq_domain_add_linear()
drivers/pci/dwc/pcie-designware-host.c | 272 +++++++++++++++++++++++++++++----
drivers/pci/dwc/pcie-designware.h | 15 ++
2 files changed, 258 insertions(+), 29 deletions(-)
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index 28ed32b..78ce002 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -11,6 +11,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
@@ -53,6 +54,28 @@ static struct irq_chip dw_msi_irq_chip = {
.irq_unmask = pci_msi_unmask_irq,
};
+static void dw_msi_mask_irq(struct irq_data *d) {
+ pci_msi_mask_irq(d);
+ irq_chip_mask_parent(d);
+}
+
+static void dw_msi_unmask_irq(struct irq_data *d) {
+ pci_msi_unmask_irq(d);
+ irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip dw_pcie_msi_irq_chip = {
+ .name = "PCI-MSI",
+ .irq_mask = dw_msi_mask_irq,
+ .irq_unmask = dw_msi_unmask_irq,
+};
+
+static struct msi_domain_info dw_pcie_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_PCI_MSIX),
+ .chip = &dw_pcie_msi_irq_chip,
+};
+
/* MSI int handler */
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{
@@ -81,6 +104,191 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
return ret;
}
+/* Chained MSI interrupt service routine */
+static void dw_chained_msi_isr(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct pcie_port *pp;
+ struct dw_pcie *pci;
+
+ chained_irq_enter(chip, desc);
+ pci = irq_desc_get_handler_data(desc);
+ pp = &pci->pp;
+
+ dw_handle_msi_irq(pp);
+
+ chained_irq_exit(chip, desc);
+}
+
+static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+ struct pcie_port *pp = &pci->pp;
+ u64 msi_target;
+
+ if (pp->ops->get_msi_addr)
+ msi_target = pp->ops->get_msi_addr(pp);
+ else
+ msi_target = virt_to_phys((void *)pp->msi_data);
+
+ msg->address_lo = lower_32_bits(msi_target);
+ msg->address_hi = upper_32_bits(msi_target);
+
+ if (pp->ops->get_msi_data)
+ msg->data = pp->ops->get_msi_data(pp, data->hwirq);
+ else
+ msg->data = data->hwirq;
+
+ dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
+ (int)data->hwirq, msg->address_hi, msg->address_lo);
+}
+
+static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ return -EINVAL;
+}
+
+static void dw_pci_bottom_mask(struct irq_data *data)
+{
+ struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+ struct pcie_port *pp = &pci->pp;
+ unsigned int res, bit, ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pp->lock, flags);
+
+ if (pp->ops->msi_clear_irq)
+ pp->ops->msi_clear_irq(pp, data->hwirq);
+ else {
+ ctrl = data->hwirq / 32;
+ res = ctrl * 12;
+ bit = data->hwirq % 32;
+
+ pp->irq_status[ctrl] &= ~(1 << bit);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
+ }
+
+ spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static void dw_pci_bottom_unmask(struct irq_data *data)
+{
+ struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+ struct pcie_port *pp = &pci->pp;
+ unsigned int res, bit, ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pp->lock, flags);
+
+ if (pp->ops->msi_set_irq)
+ pp->ops->msi_set_irq(pp, data->hwirq);
+ else {
+ ctrl = data->hwirq / 32;
+ res = ctrl * 12;
+ bit = data->hwirq % 32;
+
+ pp->irq_status[ctrl] |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
+ }
+
+ spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static struct irq_chip dw_pci_msi_bottom_irq_chip = {
+ .name = "DWPCI-MSI",
+ .irq_compose_msi_msg = dw_pci_setup_msi_msg,
+ .irq_set_affinity = dw_pci_msi_set_affinity,
+ .irq_mask = dw_pci_bottom_mask,
+ .irq_unmask = dw_pci_bottom_unmask,
+};
+
+static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs,
+ void *args)
+{
+ struct dw_pcie *pci = domain->host_data;
+ struct pcie_port *pp = &pci->pp;
+ unsigned long flags;
+ unsigned long bit;
+ u32 i;
+
+ spin_lock_irqsave(&pp->lock, flags);
+
+ bit = bitmap_find_next_zero_area(pp->msi_irq_in_use, pp->num_vectors, 0,
+ nr_irqs, 0);
+
+ if (bit >= pp->num_vectors) {
+ spin_unlock_irqrestore(&pp->lock, flags);
+ return -ENOSPC;
+ }
+
+ bitmap_set(pp->msi_irq_in_use, bit, nr_irqs);
+
+ spin_unlock_irqrestore(&pp->lock, flags);
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_info(domain, virq + i, bit + i,
+ &dw_pci_msi_bottom_irq_chip,
+ domain->host_data, handle_simple_irq,
+ NULL, NULL);
+
+ return 0;
+}
+
+static void dw_pcie_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+ struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+ struct pcie_port *pp = &pci->pp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pp->lock, flags);
+ bitmap_clear(pp->msi_irq_in_use, data->hwirq, nr_irqs);
+ spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
+ .alloc = dw_pcie_irq_domain_alloc,
+ .free = dw_pcie_irq_domain_free,
+};
+
+int dw_pcie_allocate_domains(struct dw_pcie *pci)
+{
+ struct pcie_port *pp = &pci->pp;
+ struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
+
+ pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
+ &dw_pcie_msi_domain_ops, pci);
+ if (!pp->irq_domain) {
+ dev_err(pci->dev, "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ pp->msi_domain = pci_msi_create_irq_domain(fwnode,
+ &dw_pcie_msi_domain_info,
+ pp->irq_domain);
+ if (!pp->msi_domain) {
+ dev_err(pci->dev, "failed to create MSI domain\n");
+ irq_domain_remove(pp->irq_domain);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void dw_pcie_free_msi(struct pcie_port *pp)
+{
+ irq_set_chained_handler(pp->msi_irq, NULL);
+ irq_set_handler_data(pp->msi_irq, NULL);
+
+ irq_domain_remove(pp->msi_domain);
+ irq_domain_remove(pp->irq_domain);
+}
+
void dw_pcie_msi_init(struct pcie_port *pp)
{
u64 msi_target;
@@ -97,13 +305,14 @@ void dw_pcie_msi_init(struct pcie_port *pp)
static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
{
- unsigned int res, bit, val;
+ unsigned int res, bit, ctrl;
- res = (irq / 32) * 12;
+ ctrl = irq / 32;
+ res = ctrl * 12;
bit = irq % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val &= ~(1 << bit);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+ pp->irq_status[ctrl] &= ~(1 << bit);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
}
static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
@@ -125,13 +334,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
{
- unsigned int res, bit, val;
+ unsigned int res, bit, ctrl;
- res = (irq / 32) * 12;
+ ctrl = irq / 32;
+ res = ctrl * 12;
bit = irq % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val |= 1 << bit;
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+ pp->irq_status[ctrl] |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
}
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
@@ -279,11 +489,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
struct platform_device *pdev = to_platform_device(dev);
+ struct resource_entry *win, *tmp;
struct pci_bus *bus, *child;
struct resource *cfg_res;
int i, ret;
+
LIST_HEAD(res);
- struct resource_entry *win, *tmp;
+
+ spin_lock_init(&pci->pp.lock);
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (cfg_res) {
@@ -378,17 +591,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (!pp->ops->msi_host_init) {
- pp->irq_domain = irq_domain_add_linear(dev->of_node,
- MAX_MSI_IRQS, &msi_domain_ops,
- &dw_pcie_msi_chip);
- if (!pp->irq_domain) {
- dev_err(dev, "irq domain init failed\n");
- ret = -ENXIO;
+ ret = of_property_read_u32(np, "num-vectors",
+ &pp->num_vectors);
+ if (ret)
+ pp->num_vectors = 1;
+
+ ret = dw_pcie_allocate_domains(pci);
+ if (ret)
goto error;
- }
- for (i = 0; i < MAX_MSI_IRQS; i++)
- irq_create_mapping(pp->irq_domain, i);
+ irq_set_chained_handler_and_data(pci->pp.msi_irq,
+ dw_chained_msi_isr,
+ pci);
} else {
ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
if (ret < 0)
@@ -400,14 +614,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
pp->ops->host_init(pp);
pp->root_bus_nr = pp->busn->start;
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr,
- &dw_pcie_ops, pp, &res,
- &dw_pcie_msi_chip);
- dw_pcie_msi_chip.dev = dev;
- } else
- bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
- pp, &res);
+
+ bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
+ pp, &res);
if (!bus) {
ret = -ENOMEM;
goto error;
@@ -579,11 +788,16 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
void dw_pcie_setup_rc(struct pcie_port *pp)
{
- u32 val;
+ u32 val, ctrl;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
dw_pcie_setup(pci);
+ /* Initialize IRQ Status array */
+ for (ctrl = 0; ctrl < MAX_MSI_CTRLS; ctrl++)
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + (ctrl * 12), 4,
+ &pp->irq_status[ctrl]);
+
/* setup RC BARs */
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h
index c6a8405..622ffcf 100644
--- a/drivers/pci/dwc/pcie-designware.h
+++ b/drivers/pci/dwc/pcie-designware.h
@@ -165,7 +165,11 @@ struct pcie_port {
struct dw_pcie_host_ops *ops;
int msi_irq;
struct irq_domain *irq_domain;
+ struct irq_domain *msi_domain;
unsigned long msi_data;
+ u32 num_vectors;
+ u32 irq_status[MAX_MSI_CTRLS];
+ spinlock_t lock;
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};
@@ -282,8 +286,10 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
#ifdef CONFIG_PCIE_DW_HOST
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
+void dw_pcie_free_msi(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_allocate_domains(struct dw_pcie *pci);
#else
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{
@@ -294,6 +300,10 @@ static inline void dw_pcie_msi_init(struct pcie_port *pp)
{
}
+static inline void dw_pcie_free_msi(struct pcie_port *pp)
+{
+}
+
static inline void dw_pcie_setup_rc(struct pcie_port *pp)
{
}
@@ -302,6 +312,11 @@ static inline int dw_pcie_host_init(struct pcie_port *pp)
{
return 0;
}
+
+static inline int dw_pcie_allocate_domains(struct dw_pcie *pci)
+{
+ return 0;
+}
#endif
#ifdef CONFIG_PCIE_DW_EP
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
2017-05-15 17:03 ` [RFC v2 1/8] pci: adding new irq api to pci-designware Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-18 18:50 ` Jingoo Han
2017-05-15 17:03 ` [RFC v2 3/8] pci: imx6 " Joao Pinto
` (5 subsequent siblings)
7 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts Exynos SoC specific driver to use the new interrupt api
available in pcie-designware.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pci-exynos.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c
index 546082a..e49c39a 100644
--- a/drivers/pci/dwc/pci-exynos.c
+++ b/drivers/pci/dwc/pci-exynos.c
@@ -490,15 +490,6 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
-{
- struct exynos_pcie *ep = arg;
- struct dw_pcie *pci = ep->pci;
- struct pcie_port *pp = &pci->pp;
-
- return dw_handle_msi_irq(pp);
-}
-
static void exynos_pcie_msi_init(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
@@ -622,15 +613,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
dev_err(dev, "failed to get msi irq\n");
return -ENODEV;
}
-
- ret = devm_request_irq(dev, pp->msi_irq,
- exynos_pcie_msi_irq_handler,
- IRQF_SHARED | IRQF_NO_THREAD,
- "exynos-pcie", ep);
- if (ret) {
- dev_err(dev, "failed to request msi irq\n");
- return ret;
- }
}
pp->root_bus_nr = -1;
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 3/8] pci: imx6 SoC driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
2017-05-15 17:03 ` [RFC v2 1/8] pci: adding new irq api to pci-designware Joao Pinto
2017-05-15 17:03 ` [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 4/8] pci: artpec6 " Joao Pinto
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts imx6 SoC specific driver to use the new interrupt api
available in pcie-designware.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pci-imx6.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index a98cba5..f22ce1f 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -490,15 +490,6 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
return -EINVAL;
}
-static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg)
-{
- struct imx6_pcie *imx6_pcie = arg;
- struct dw_pcie *pci = imx6_pcie->pci;
- struct pcie_port *pp = &pci->pp;
-
- return dw_handle_msi_irq(pp);
-}
-
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
@@ -620,15 +611,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
dev_err(dev, "failed to get MSI irq\n");
return -ENODEV;
}
-
- ret = devm_request_irq(dev, pp->msi_irq,
- imx6_pcie_msi_handler,
- IRQF_SHARED | IRQF_NO_THREAD,
- "mx6-pcie-msi", imx6_pcie);
- if (ret) {
- dev_err(dev, "failed to request MSI irq\n");
- return ret;
- }
}
pp->root_bus_nr = -1;
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 4/8] pci: artpec6 SoC driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
` (2 preceding siblings ...)
2017-05-15 17:03 ` [RFC v2 3/8] pci: imx6 " Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 5/8] pci: generic PCIe DW " Joao Pinto
` (3 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts artpec6 SoC specific driver to use the new interrupt api
available in pcie-designware.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-artpec6.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/dwc/pcie-artpec6.c
index 82a04ac..d81789b 100644
--- a/drivers/pci/dwc/pcie-artpec6.c
+++ b/drivers/pci/dwc/pcie-artpec6.c
@@ -188,15 +188,6 @@ static struct dw_pcie_host_ops artpec6_pcie_host_ops = {
.host_init = artpec6_pcie_host_init,
};
-static irqreturn_t artpec6_pcie_msi_handler(int irq, void *arg)
-{
- struct artpec6_pcie *artpec6_pcie = arg;
- struct dw_pcie *pci = artpec6_pcie->pci;
- struct pcie_port *pp = &pci->pp;
-
- return dw_handle_msi_irq(pp);
-}
-
static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev)
{
@@ -211,15 +202,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
dev_err(dev, "failed to get MSI irq\n");
return -ENODEV;
}
-
- ret = devm_request_irq(dev, pp->msi_irq,
- artpec6_pcie_msi_handler,
- IRQF_SHARED | IRQF_NO_THREAD,
- "artpec6-pcie-msi", artpec6_pcie);
- if (ret) {
- dev_err(dev, "failed to request MSI irq\n");
- return ret;
- }
}
pp->root_bus_nr = -1;
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 5/8] pci: generic PCIe DW driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
` (3 preceding siblings ...)
2017-05-15 17:03 ` [RFC v2 4/8] pci: artpec6 " Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 6/8] pci: qcom SoC " Joao Pinto
` (2 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts the generic PCIe DW driver to use the new interrupt api
available in pcie-designware.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-designware-plat.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/pci/dwc/pcie-designware-plat.c b/drivers/pci/dwc/pcie-designware-plat.c
index 32091b3..3b9717b 100644
--- a/drivers/pci/dwc/pcie-designware-plat.c
+++ b/drivers/pci/dwc/pcie-designware-plat.c
@@ -28,13 +28,6 @@ struct dw_plat_pcie {
struct dw_pcie *pci;
};
-static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
-{
- struct pcie_port *pp = arg;
-
- return dw_handle_msi_irq(pp);
-}
-
static void dw_plat_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -64,14 +57,6 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp,
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
-
- ret = devm_request_irq(dev, pp->msi_irq,
- dw_plat_pcie_msi_irq_handler,
- IRQF_SHARED, "dw-plat-pcie-msi", pp);
- if (ret) {
- dev_err(dev, "failed to request MSI IRQ\n");
- return ret;
- }
}
pp->root_bus_nr = -1;
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 6/8] pci: qcom SoC driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
` (4 preceding siblings ...)
2017-05-15 17:03 ` [RFC v2 5/8] pci: generic PCIe DW " Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 7/8] pci: keystone " Joao Pinto
2017-05-15 17:03 ` [RFC v2 8/8] pci: removing old irq api from pcie-designware Joao Pinto
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts Qcom SoC specific driver to use the new interrupt api
available in pcie-designware.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-qcom.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
index 5bf23d4..4e1cc02 100644
--- a/drivers/pci/dwc/pcie-qcom.c
+++ b/drivers/pci/dwc/pcie-qcom.c
@@ -126,13 +126,6 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
}
-static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
-{
- struct pcie_port *pp = arg;
-
- return dw_handle_msi_irq(pp);
-}
-
static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie)
{
u32 val;
@@ -724,14 +717,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
-
- ret = devm_request_irq(dev, pp->msi_irq,
- qcom_pcie_msi_irq_handler,
- IRQF_SHARED, "qcom-pcie-msi", pp);
- if (ret) {
- dev_err(dev, "cannot request msi irq\n");
- return ret;
- }
}
ret = phy_init(pcie->phy);
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 7/8] pci: keystone SoC driver adapted to new irq API
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
` (5 preceding siblings ...)
2017-05-15 17:03 ` [RFC v2 6/8] pci: qcom SoC " Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 8/8] pci: removing old irq api from pcie-designware Joao Pinto
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch adapts Keystone SoC specific driver to use the new interrupt api
available in pcie-designware. A new callback was added to dw_pcie_host_ops
to handle a specific Keystone function and msi_host_init callback is changed
to simplify the access to pci data structure for keystone all SoC drivers
that use the structure.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pci-keystone-dw.c | 97 +++-------------------------------
drivers/pci/dwc/pci-keystone.c | 1 +
drivers/pci/dwc/pci-keystone.h | 4 +-
drivers/pci/dwc/pci-layerscape.c | 3 +-
drivers/pci/dwc/pcie-designware-host.c | 12 ++++-
drivers/pci/dwc/pcie-designware.h | 3 +-
6 files changed, 23 insertions(+), 97 deletions(-)
diff --git a/drivers/pci/dwc/pci-keystone-dw.c b/drivers/pci/dwc/pci-keystone-dw.c
index 8bc626e..da1472e 100644
--- a/drivers/pci/dwc/pci-keystone-dw.c
+++ b/drivers/pci/dwc/pci-keystone-dw.c
@@ -124,19 +124,15 @@ void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
}
}
-static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
+void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
{
u32 offset, reg_offset, bit_pos;
struct keystone_pcie *ks_pcie;
- struct msi_desc *msi;
- struct pcie_port *pp;
struct dw_pcie *pci;
- msi = irq_data_get_msi_desc(d);
- pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
- offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
+ offset = irq - irq_linear_revmap(pp->irq_domain, 0);
update_reg_offset_bit_pos(offset, ®_offset, &bit_pos);
ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
@@ -166,93 +162,12 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
BIT(bit_pos));
}
-static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip)
{
- struct keystone_pcie *ks_pcie;
- struct msi_desc *msi;
- struct pcie_port *pp;
- struct dw_pcie *pci;
- u32 offset;
-
- msi = irq_data_get_msi_desc(d);
- pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
- pci = to_dw_pcie_from_pp(pp);
- ks_pcie = to_keystone_pcie(pci);
- offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
-
- /* Mask the end point if PVM implemented */
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- if (msi->msi_attrib.maskbit)
- pci_msi_mask_irq(d);
- }
-
- ks_dw_pcie_msi_clear_irq(pp, offset);
-}
-
-static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
-{
- struct keystone_pcie *ks_pcie;
- struct msi_desc *msi;
- struct pcie_port *pp;
- struct dw_pcie *pci;
- u32 offset;
-
- msi = irq_data_get_msi_desc(d);
- pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
- pci = to_dw_pcie_from_pp(pp);
- ks_pcie = to_keystone_pcie(pci);
- offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
-
- /* Mask the end point if PVM implemented */
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- if (msi->msi_attrib.maskbit)
- pci_msi_unmask_irq(d);
- }
-
- ks_dw_pcie_msi_set_irq(pp, offset);
-}
+ /* overide number of vectors and sent them to Keystone Max MSI IRQs */
+ pci->pp.num_vectors = MAX_MSI_IRQS;
-static struct irq_chip ks_dw_pcie_msi_irq_chip = {
- .name = "Keystone-PCIe-MSI-IRQ",
- .irq_ack = ks_dw_pcie_msi_irq_ack,
- .irq_mask = ks_dw_pcie_msi_irq_mask,
- .irq_unmask = ks_dw_pcie_msi_irq_unmask,
-};
-
-static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
- handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
- .map = ks_dw_pcie_msi_map,
-};
-
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
- struct device *dev = pci->dev;
- int i;
-
- pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np,
- MAX_MSI_IRQS,
- &ks_dw_pcie_msi_domain_ops,
- chip);
- if (!pp->irq_domain) {
- dev_err(dev, "irq domain init failed\n");
- return -ENXIO;
- }
-
- for (i = 0; i < MAX_MSI_IRQS; i++)
- irq_create_mapping(pp->irq_domain, i);
-
- return 0;
+ return dw_pcie_allocate_domains(pci);
}
void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
diff --git a/drivers/pci/dwc/pci-keystone.c b/drivers/pci/dwc/pci-keystone.c
index fcc9723..a59bd9b 100644
--- a/drivers/pci/dwc/pci-keystone.c
+++ b/drivers/pci/dwc/pci-keystone.c
@@ -299,6 +299,7 @@ static struct dw_pcie_host_ops keystone_pcie_host_ops = {
.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
.get_msi_addr = ks_dw_pcie_get_msi_addr,
.msi_host_init = ks_dw_pcie_msi_host_init,
+ .msi_irq_ack = ks_dw_pcie_msi_irq_ack,
.scan_bus = ks_dw_pcie_v3_65_scan_bus,
};
diff --git a/drivers/pci/dwc/pci-keystone.h b/drivers/pci/dwc/pci-keystone.h
index 74c5825..83179382 100644
--- a/drivers/pci/dwc/pci-keystone.h
+++ b/drivers/pci/dwc/pci-keystone.h
@@ -55,9 +55,9 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 *val);
void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp);
void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
- struct msi_controller *chip);
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip);
int ks_dw_pcie_link_up(struct dw_pcie *pci);
diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/dwc/pci-layerscape.c
index 27d638c..4fb491b 100644
--- a/drivers/pci/dwc/pci-layerscape.c
+++ b/drivers/pci/dwc/pci-layerscape.c
@@ -162,10 +162,9 @@ static void ls_pcie_host_init(struct pcie_port *pp)
iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);
}
-static int ls_pcie_msi_host_init(struct pcie_port *pp,
+static int ls_pcie_msi_host_init(struct dw_pcie *pci,
struct msi_controller *chip)
{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
struct device_node *msi_node;
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index 78ce002..f1743cb 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -197,8 +197,18 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
spin_unlock_irqrestore(&pp->lock, flags);
}
+static void dw_pci_bottom_ack(struct irq_data *d)
+{
+ struct msi_desc *msi = irq_data_get_msi_desc(d);
+ struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
+
+ if (pp->ops->msi_irq_ack)
+ pp->ops->msi_irq_ack(d->irq, pp);
+}
+
static struct irq_chip dw_pci_msi_bottom_irq_chip = {
.name = "DWPCI-MSI",
+ .irq_ack = dw_pci_bottom_ack,
.irq_compose_msi_msg = dw_pci_setup_msi_msg,
.irq_set_affinity = dw_pci_msi_set_affinity,
.irq_mask = dw_pci_bottom_mask,
@@ -604,7 +614,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
dw_chained_msi_isr,
pci);
} else {
- ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+ ret = pp->ops->msi_host_init(pci, &dw_pcie_msi_chip);
if (ret < 0)
goto error;
}
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h
index 622ffcf..2ac99fa 100644
--- a/drivers/pci/dwc/pcie-designware.h
+++ b/drivers/pci/dwc/pcie-designware.h
@@ -140,7 +140,8 @@ struct dw_pcie_host_ops {
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
- int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
+ int (*msi_host_init)(struct dw_pcie *pci, struct msi_controller *chip);
+ void (*msi_irq_ack)(int irq, struct pcie_port *pp);
};
struct pcie_port {
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC v2 8/8] pci: removing old irq api from pcie-designware
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
` (6 preceding siblings ...)
2017-05-15 17:03 ` [RFC v2 7/8] pci: keystone " Joao Pinto
@ 2017-05-15 17:03 ` Joao Pinto
7 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-15 17:03 UTC (permalink / raw)
To: bhelgaas, marc.zyngier
Cc: jingoohan1, m-karicheri2, thomas.petazzoni, minghuan.Lian,
mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci, Joao Pinto
This patch removes the old interrupt API.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v2:
- removes less because the patch set no longer has the configurable toggle
between APIs
drivers/pci/dwc/pci-keystone-dw.c | 2 +-
drivers/pci/dwc/pci-keystone.h | 2 +-
drivers/pci/dwc/pci-layerscape.c | 3 +-
drivers/pci/dwc/pcie-designware-host.c | 192 +--------------------------------
drivers/pci/dwc/pcie-designware.h | 2 +-
5 files changed, 6 insertions(+), 195 deletions(-)
diff --git a/drivers/pci/dwc/pci-keystone-dw.c b/drivers/pci/dwc/pci-keystone-dw.c
index da1472e..30a5352 100644
--- a/drivers/pci/dwc/pci-keystone-dw.c
+++ b/drivers/pci/dwc/pci-keystone-dw.c
@@ -162,7 +162,7 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
BIT(bit_pos));
}
-int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip)
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci)
{
/* overide number of vectors and sent them to Keystone Max MSI IRQs */
pci->pp.num_vectors = MAX_MSI_IRQS;
diff --git a/drivers/pci/dwc/pci-keystone.h b/drivers/pci/dwc/pci-keystone.h
index 83179382..89119271 100644
--- a/drivers/pci/dwc/pci-keystone.h
+++ b/drivers/pci/dwc/pci-keystone.h
@@ -59,5 +59,5 @@ void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp);
void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
-int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip);
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci);
int ks_dw_pcie_link_up(struct dw_pcie *pci);
diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/dwc/pci-layerscape.c
index 4fb491b..231ea75 100644
--- a/drivers/pci/dwc/pci-layerscape.c
+++ b/drivers/pci/dwc/pci-layerscape.c
@@ -162,8 +162,7 @@ static void ls_pcie_host_init(struct pcie_port *pp)
iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);
}
-static int ls_pcie_msi_host_init(struct dw_pcie *pci,
- struct msi_controller *chip)
+static int ls_pcie_msi_host_init(struct dw_pcie *pci)
{
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index f1743cb..bcd7af6 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -46,14 +46,6 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
return dw_pcie_write(pci->dbi_base + where, size, val);
}
-static struct irq_chip dw_msi_irq_chip = {
- .name = "PCI-MSI",
- .irq_enable = pci_msi_unmask_irq,
- .irq_disable = pci_msi_mask_irq,
- .irq_mask = pci_msi_mask_irq,
- .irq_unmask = pci_msi_unmask_irq,
-};
-
static void dw_msi_mask_irq(struct irq_data *d) {
pci_msi_mask_irq(d);
irq_chip_mask_parent(d);
@@ -313,186 +305,6 @@ void dw_pcie_msi_init(struct pcie_port *pp)
(u32)(msi_target >> 32 & 0xffffffff));
}
-static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
-{
- unsigned int res, bit, ctrl;
-
- ctrl = irq / 32;
- res = ctrl * 12;
- bit = irq % 32;
- pp->irq_status[ctrl] &= ~(1 << bit);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
- pp->irq_status[ctrl]);
-}
-
-static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
- unsigned int nvec, unsigned int pos)
-{
- unsigned int i;
-
- for (i = 0; i < nvec; i++) {
- irq_set_msi_desc_off(irq_base, i, NULL);
- /* Disable corresponding interrupt on MSI controller */
- if (pp->ops->msi_clear_irq)
- pp->ops->msi_clear_irq(pp, pos + i);
- else
- dw_pcie_msi_clear_irq(pp, pos + i);
- }
-
- bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
-}
-
-static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
-{
- unsigned int res, bit, ctrl;
-
- ctrl = irq / 32;
- res = ctrl * 12;
- bit = irq % 32;
- pp->irq_status[ctrl] |= 1 << bit;
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
- pp->irq_status[ctrl]);
-}
-
-static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
-{
- int irq, pos0, i;
- struct pcie_port *pp;
-
- pp = (struct pcie_port *)msi_desc_to_pci_sysdata(desc);
- pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS,
- order_base_2(no_irqs));
- if (pos0 < 0)
- goto no_valid_irq;
-
- irq = irq_find_mapping(pp->irq_domain, pos0);
- if (!irq)
- goto no_valid_irq;
-
- /*
- * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
- * descs so there is no need to allocate descs here. We can therefore
- * assume that if irq_find_mapping above returns non-zero, then the
- * descs are also successfully allocated.
- */
-
- for (i = 0; i < no_irqs; i++) {
- if (irq_set_msi_desc_off(irq, i, desc) != 0) {
- clear_irq_range(pp, irq, i, pos0);
- goto no_valid_irq;
- }
- /*Enable corresponding interrupt in MSI interrupt controller */
- if (pp->ops->msi_set_irq)
- pp->ops->msi_set_irq(pp, pos0 + i);
- else
- dw_pcie_msi_set_irq(pp, pos0 + i);
- }
-
- *pos = pos0;
- desc->nvec_used = no_irqs;
- desc->msi_attrib.multiple = order_base_2(no_irqs);
-
- return irq;
-
-no_valid_irq:
- *pos = pos0;
- return -ENOSPC;
-}
-
-static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
-{
- struct msi_msg msg;
- u64 msi_target;
-
- if (pp->ops->get_msi_addr)
- msi_target = pp->ops->get_msi_addr(pp);
- else
- msi_target = virt_to_phys((void *)pp->msi_data);
-
- msg.address_lo = (u32)(msi_target & 0xffffffff);
- msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
-
- if (pp->ops->get_msi_data)
- msg.data = pp->ops->get_msi_data(pp, pos);
- else
- msg.data = pos;
-
- pci_write_msi_msg(irq, &msg);
-}
-
-static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
- struct msi_desc *desc)
-{
- int irq, pos;
- struct pcie_port *pp = pdev->bus->sysdata;
-
- if (desc->msi_attrib.is_msix)
- return -EINVAL;
-
- irq = assign_irq(1, desc, &pos);
- if (irq < 0)
- return irq;
-
- dw_msi_setup_msg(pp, irq, pos);
-
- return 0;
-}
-
-static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
- int nvec, int type)
-{
-#ifdef CONFIG_PCI_MSI
- int irq, pos;
- struct msi_desc *desc;
- struct pcie_port *pp = pdev->bus->sysdata;
-
- /* MSI-X interrupts are not supported */
- if (type == PCI_CAP_ID_MSIX)
- return -EINVAL;
-
- WARN_ON(!list_is_singular(&pdev->dev.msi_list));
- desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
-
- irq = assign_irq(nvec, desc, &pos);
- if (irq < 0)
- return irq;
-
- dw_msi_setup_msg(pp, irq, pos);
-
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
-static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
-{
- struct irq_data *data = irq_get_irq_data(irq);
- struct msi_desc *msi = irq_data_get_msi_desc(data);
- struct pcie_port *pp = (struct pcie_port *)msi_desc_to_pci_sysdata(msi);
-
- clear_irq_range(pp, irq, 1, data->hwirq);
-}
-
-static struct msi_controller dw_pcie_msi_chip = {
- .setup_irq = dw_msi_setup_irq,
- .setup_irqs = dw_msi_setup_irqs,
- .teardown_irq = dw_msi_teardown_irq,
-};
-
-static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops msi_domain_ops = {
- .map = dw_pcie_msi_map,
-};
-
int dw_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -502,7 +314,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
struct resource_entry *win, *tmp;
struct pci_bus *bus, *child;
struct resource *cfg_res;
- int i, ret;
+ int ret;
LIST_HEAD(res);
@@ -614,7 +426,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
dw_chained_msi_isr,
pci);
} else {
- ret = pp->ops->msi_host_init(pci, &dw_pcie_msi_chip);
+ ret = pp->ops->msi_host_init(pci);
if (ret < 0)
goto error;
}
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h
index 2ac99fa..f486587 100644
--- a/drivers/pci/dwc/pcie-designware.h
+++ b/drivers/pci/dwc/pcie-designware.h
@@ -140,7 +140,7 @@ struct dw_pcie_host_ops {
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
- int (*msi_host_init)(struct dw_pcie *pci, struct msi_controller *chip);
+ int (*msi_host_init)(struct dw_pcie *pci);
void (*msi_irq_ack)(int irq, struct pcie_port *pp);
};
--
2.9.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API
2017-05-15 17:03 ` [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API Joao Pinto
@ 2017-05-18 18:50 ` Jingoo Han
0 siblings, 0 replies; 12+ messages in thread
From: Jingoo Han @ 2017-05-18 18:50 UTC (permalink / raw)
To: 'Joao Pinto', bhelgaas, marc.zyngier
Cc: m-karicheri2, thomas.petazzoni, minghuan.Lian, mingkai.hu,
tie-fei.zang, hongxing.zhu, l.stach, niklas.cassel,
jesper.nilsson, wangzhou1, gabriele.paoloni, svarbanov,
linux-pci
On Monday, May 15, 2017 1:04 PM, Joao Pinto wrote:
>
> This patch adapts Exynos SoC specific driver to use the new interrupt api
> available in pcie-designware.
>
> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
Acked-by: Jingoo Han <jingoohan1@gmail.com>
Best regards,
Jingoo Han
> ---
> changes v1->v2:
> - just to keep up patch set version
>
> drivers/pci/dwc/pci-exynos.c | 18 ------------------
> 1 file changed, 18 deletions(-)
>
> diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c
> index 546082a..e49c39a 100644
> --- a/drivers/pci/dwc/pci-exynos.c
> +++ b/drivers/pci/dwc/pci-exynos.c
> @@ -490,15 +490,6 @@ static irqreturn_t exynos_pcie_irq_handler(int irq,
> void *arg)
> return IRQ_HANDLED;
> }
>
> -static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
> -{
> - struct exynos_pcie *ep = arg;
> - struct dw_pcie *pci = ep->pci;
> - struct pcie_port *pp = &pci->pp;
> -
> - return dw_handle_msi_irq(pp);
> -}
> -
> static void exynos_pcie_msi_init(struct exynos_pcie *ep)
> {
> struct dw_pcie *pci = ep->pci;
> @@ -622,15 +613,6 @@ static int __init exynos_add_pcie_port(struct
> exynos_pcie *ep,
> dev_err(dev, "failed to get msi irq\n");
> return -ENODEV;
> }
> -
> - ret = devm_request_irq(dev, pp->msi_irq,
> - exynos_pcie_msi_irq_handler,
> - IRQF_SHARED | IRQF_NO_THREAD,
> - "exynos-pcie", ep);
> - if (ret) {
> - dev_err(dev, "failed to request msi irq\n");
> - return ret;
> - }
> }
>
> pp->root_bus_nr = -1;
> --
> 2.9.3
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC v2 1/8] pci: adding new irq api to pci-designware
2017-05-15 17:03 ` [RFC v2 1/8] pci: adding new irq api to pci-designware Joao Pinto
@ 2017-05-21 8:44 ` Marc Zyngier
2017-05-22 9:24 ` Joao Pinto
0 siblings, 1 reply; 12+ messages in thread
From: Marc Zyngier @ 2017-05-21 8:44 UTC (permalink / raw)
To: Joao Pinto
Cc: bhelgaas, jingoohan1, m-karicheri2, thomas.petazzoni,
minghuan.Lian, mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach,
niklas.cassel, jesper.nilsson, wangzhou1, gabriele.paoloni,
svarbanov, linux-pci
On Mon, May 15 2017 at 06:03:41 PM, Joao Pinto <Joao.Pinto@synopsys.com> wrote:
> This patch adds the new interrupt api to pcie-designware, keeping the old
> one. Although the old API is still available, pcie-designware initiates with
> the new one.
>
> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
> ---
> changes v1->v2:
> - Now there's no config to toggle between the 2 APIs, so pcie-designware
> initiaties wih the new one by default
> - Using lower_32_bits / upper_32_bits
> - Instead of mutex, now using spinlocks
> - Instead of always reading PCIE_MSI_INTR0_ENABLE, now we use an internal
> variable
> - dw_pcie_irq_domain_alloc() was updated to enable Multi-MSI
> - using irq_domain_create_linear() instead of irq_domain_add_linear()
>
> drivers/pci/dwc/pcie-designware-host.c | 272 +++++++++++++++++++++++++++++----
> drivers/pci/dwc/pcie-designware.h | 15 ++
> 2 files changed, 258 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
> index 28ed32b..78ce002 100644
> --- a/drivers/pci/dwc/pcie-designware-host.c
> +++ b/drivers/pci/dwc/pcie-designware-host.c
> @@ -11,6 +11,7 @@
> * published by the Free Software Foundation.
> */
>
> +#include <linux/irqchip/chained_irq.h>
> #include <linux/irqdomain.h>
> #include <linux/of_address.h>
> #include <linux/of_pci.h>
> @@ -53,6 +54,28 @@ static struct irq_chip dw_msi_irq_chip = {
> .irq_unmask = pci_msi_unmask_irq,
> };
>
> +static void dw_msi_mask_irq(struct irq_data *d) {
> + pci_msi_mask_irq(d);
> + irq_chip_mask_parent(d);
> +}
> +
> +static void dw_msi_unmask_irq(struct irq_data *d) {
> + pci_msi_unmask_irq(d);
> + irq_chip_unmask_parent(d);
> +}
> +
> +static struct irq_chip dw_pcie_msi_irq_chip = {
> + .name = "PCI-MSI",
> + .irq_mask = dw_msi_mask_irq,
> + .irq_unmask = dw_msi_unmask_irq,
> +};
> +
> +static struct msi_domain_info dw_pcie_msi_domain_info = {
> + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> + MSI_FLAG_PCI_MSIX),
How is Multi-MSI supported if you don't pass the MSI_FLAG_MULTI_PCI_MSI
flag?
> + .chip = &dw_pcie_msi_irq_chip,
> +};
> +
> /* MSI int handler */
> irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
> {
> @@ -81,6 +104,191 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
> return ret;
> }
>
> +/* Chained MSI interrupt service routine */
> +static void dw_chained_msi_isr(struct irq_desc *desc)
> +{
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + struct pcie_port *pp;
> + struct dw_pcie *pci;
> +
> + chained_irq_enter(chip, desc);
> + pci = irq_desc_get_handler_data(desc);
> + pp = &pci->pp;
> +
> + dw_handle_msi_irq(pp);
> +
> + chained_irq_exit(chip, desc);
> +}
> +
> +static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
> +{
> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
> + struct pcie_port *pp = &pci->pp;
> + u64 msi_target;
> +
> + if (pp->ops->get_msi_addr)
> + msi_target = pp->ops->get_msi_addr(pp);
> + else
> + msi_target = virt_to_phys((void *)pp->msi_data);
> +
> + msg->address_lo = lower_32_bits(msi_target);
> + msg->address_hi = upper_32_bits(msi_target);
> +
> + if (pp->ops->get_msi_data)
> + msg->data = pp->ops->get_msi_data(pp, data->hwirq);
I've already asked about the reason for this indirection, and I'd
appreciate an answer.
> + else
> + msg->data = data->hwirq;
> +
> + dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
> + (int)data->hwirq, msg->address_hi, msg->address_lo);
> +}
> +
> +static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
> + const struct cpumask *mask, bool force)
> +{
> + return -EINVAL;
> +}
> +
> +static void dw_pci_bottom_mask(struct irq_data *data)
> +{
> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
> + struct pcie_port *pp = &pci->pp;
> + unsigned int res, bit, ctrl;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pp->lock, flags);
> +
> + if (pp->ops->msi_clear_irq)
> + pp->ops->msi_clear_irq(pp, data->hwirq);
Same thing. If you have to have that kind of indirection, then this is a
different irqchip altogether. Also, see below for the coding-style.
> + else {
> + ctrl = data->hwirq / 32;
> + res = ctrl * 12;
> + bit = data->hwirq % 32;
> +
> + pp->irq_status[ctrl] &= ~(1 << bit);
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
> + pp->irq_status[ctrl]);
> + }
> +
> + spin_unlock_irqrestore(&pp->lock, flags);
> +}
> +
> +static void dw_pci_bottom_unmask(struct irq_data *data)
> +{
> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
> + struct pcie_port *pp = &pci->pp;
> + unsigned int res, bit, ctrl;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pp->lock, flags);
> +
> + if (pp->ops->msi_set_irq)
> + pp->ops->msi_set_irq(pp, data->hwirq);
> + else {
Coding-style:
if (...) {
...
} else {
> + ctrl = data->hwirq / 32;
> + res = ctrl * 12;
> + bit = data->hwirq % 32;
> +
> + pp->irq_status[ctrl] |= 1 << bit;
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
> + pp->irq_status[ctrl]);
> + }
> +
> + spin_unlock_irqrestore(&pp->lock, flags);
> +}
> +
> +static struct irq_chip dw_pci_msi_bottom_irq_chip = {
> + .name = "DWPCI-MSI",
> + .irq_compose_msi_msg = dw_pci_setup_msi_msg,
> + .irq_set_affinity = dw_pci_msi_set_affinity,
> + .irq_mask = dw_pci_bottom_mask,
> + .irq_unmask = dw_pci_bottom_unmask,
> +};
> +
> +static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
> + unsigned int virq, unsigned int nr_irqs,
> + void *args)
> +{
> + struct dw_pcie *pci = domain->host_data;
> + struct pcie_port *pp = &pci->pp;
> + unsigned long flags;
> + unsigned long bit;
> + u32 i;
> +
> + spin_lock_irqsave(&pp->lock, flags);
> +
> + bit = bitmap_find_next_zero_area(pp->msi_irq_in_use, pp->num_vectors, 0,
> + nr_irqs, 0);
> +
> + if (bit >= pp->num_vectors) {
> + spin_unlock_irqrestore(&pp->lock, flags);
> + return -ENOSPC;
> + }
> +
> + bitmap_set(pp->msi_irq_in_use, bit, nr_irqs);
> +
> + spin_unlock_irqrestore(&pp->lock, flags);
> +
> + for (i = 0; i < nr_irqs; i++)
> + irq_domain_set_info(domain, virq + i, bit + i,
> + &dw_pci_msi_bottom_irq_chip,
> + domain->host_data, handle_simple_irq,
> + NULL, NULL);
> +
> + return 0;
How does this work when you're using the indirection I've moaned about
earlier? How can you guarantee that there are similar number of
available vectors?
> +}
> +
> +static void dw_pcie_irq_domain_free(struct irq_domain *domain,
> + unsigned int virq, unsigned int nr_irqs)
> +{
> + struct irq_data *data = irq_domain_get_irq_data(domain, virq);
> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
> + struct pcie_port *pp = &pci->pp;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&pp->lock, flags);
> + bitmap_clear(pp->msi_irq_in_use, data->hwirq, nr_irqs);
> + spin_unlock_irqrestore(&pp->lock, flags);
> +}
> +
> +static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
> + .alloc = dw_pcie_irq_domain_alloc,
> + .free = dw_pcie_irq_domain_free,
> +};
> +
> +int dw_pcie_allocate_domains(struct dw_pcie *pci)
> +{
> + struct pcie_port *pp = &pci->pp;
> + struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
> +
> + pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
> + &dw_pcie_msi_domain_ops, pci);
> + if (!pp->irq_domain) {
> + dev_err(pci->dev, "failed to create IRQ domain\n");
> + return -ENOMEM;
> + }
> +
> + pp->msi_domain = pci_msi_create_irq_domain(fwnode,
> + &dw_pcie_msi_domain_info,
> + pp->irq_domain);
> + if (!pp->msi_domain) {
> + dev_err(pci->dev, "failed to create MSI domain\n");
> + irq_domain_remove(pp->irq_domain);
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +void dw_pcie_free_msi(struct pcie_port *pp)
> +{
> + irq_set_chained_handler(pp->msi_irq, NULL);
> + irq_set_handler_data(pp->msi_irq, NULL);
> +
> + irq_domain_remove(pp->msi_domain);
> + irq_domain_remove(pp->irq_domain);
> +}
> +
> void dw_pcie_msi_init(struct pcie_port *pp)
> {
> u64 msi_target;
> @@ -97,13 +305,14 @@ void dw_pcie_msi_init(struct pcie_port *pp)
>
> static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
> {
> - unsigned int res, bit, val;
> + unsigned int res, bit, ctrl;
>
> - res = (irq / 32) * 12;
> + ctrl = irq / 32;
> + res = ctrl * 12;
> bit = irq % 32;
> - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> - val &= ~(1 << bit);
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> + pp->irq_status[ctrl] &= ~(1 << bit);
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
> + pp->irq_status[ctrl]);
> }
>
> static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
> @@ -125,13 +334,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>
> static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
> {
> - unsigned int res, bit, val;
> + unsigned int res, bit, ctrl;
>
> - res = (irq / 32) * 12;
> + ctrl = irq / 32;
> + res = ctrl * 12;
> bit = irq % 32;
> - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
> - val |= 1 << bit;
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
> + pp->irq_status[ctrl] |= 1 << bit;
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
> + pp->irq_status[ctrl]);
> }
>
> static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
> @@ -279,11 +489,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
> struct device *dev = pci->dev;
> struct device_node *np = dev->of_node;
> struct platform_device *pdev = to_platform_device(dev);
> + struct resource_entry *win, *tmp;
> struct pci_bus *bus, *child;
> struct resource *cfg_res;
> int i, ret;
> +
> LIST_HEAD(res);
> - struct resource_entry *win, *tmp;
> +
> + spin_lock_init(&pci->pp.lock);
>
> cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
> if (cfg_res) {
> @@ -378,17 +591,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
>
> if (IS_ENABLED(CONFIG_PCI_MSI)) {
> if (!pp->ops->msi_host_init) {
> - pp->irq_domain = irq_domain_add_linear(dev->of_node,
> - MAX_MSI_IRQS, &msi_domain_ops,
> - &dw_pcie_msi_chip);
> - if (!pp->irq_domain) {
> - dev_err(dev, "irq domain init failed\n");
> - ret = -ENXIO;
> + ret = of_property_read_u32(np, "num-vectors",
> + &pp->num_vectors);
> + if (ret)
> + pp->num_vectors = 1;
1? As in "one bit only"? Is that a valid configuration? Also, all of
this code seems to assume a maximum number of 32 MSIs. Is that a real
limitation? Because if that's the case, you can drop all the stuff about
ctrl and the '* 12' offset all over the code.
Thanks,
M.
--
Jazz is not dead. It just smells funny.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC v2 1/8] pci: adding new irq api to pci-designware
2017-05-21 8:44 ` Marc Zyngier
@ 2017-05-22 9:24 ` Joao Pinto
0 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-22 9:24 UTC (permalink / raw)
To: Marc Zyngier, Joao Pinto
Cc: bhelgaas, jingoohan1, m-karicheri2, thomas.petazzoni,
minghuan.Lian, mingkai.hu, tie-fei.zang, hongxing.zhu, l.stach,
niklas.cassel, jesper.nilsson, wangzhou1, gabriele.paoloni,
svarbanov, linux-pci
Hi Mark,
Às 9:44 AM de 5/21/2017, Marc Zyngier escreveu:
> On Mon, May 15 2017 at 06:03:41 PM, Joao Pinto <Joao.Pinto@synopsys.com> wrote:
>> This patch adds the new interrupt api to pcie-designware, keeping the old
>> one. Although the old API is still available, pcie-designware initiates with
>> the new one.
>>
>> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
>> ---
>> changes v1->v2:
>> - Now there's no config to toggle between the 2 APIs, so pcie-designware
>> initiaties wih the new one by default
>> - Using lower_32_bits / upper_32_bits
>> - Instead of mutex, now using spinlocks
>> - Instead of always reading PCIE_MSI_INTR0_ENABLE, now we use an internal
>> variable
>> - dw_pcie_irq_domain_alloc() was updated to enable Multi-MSI
>> - using irq_domain_create_linear() instead of irq_domain_add_linear()
>>
>> drivers/pci/dwc/pcie-designware-host.c | 272 +++++++++++++++++++++++++++++----
>> drivers/pci/dwc/pcie-designware.h | 15 ++
>> 2 files changed, 258 insertions(+), 29 deletions(-)
>>
>> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
>> index 28ed32b..78ce002 100644
>> --- a/drivers/pci/dwc/pcie-designware-host.c
>> +++ b/drivers/pci/dwc/pcie-designware-host.c
>> @@ -11,6 +11,7 @@
>> * published by the Free Software Foundation.
>> */
>>
>> +#include <linux/irqchip/chained_irq.h>
>> #include <linux/irqdomain.h>
>> #include <linux/of_address.h>
>> #include <linux/of_pci.h>
>> @@ -53,6 +54,28 @@ static struct irq_chip dw_msi_irq_chip = {
>> .irq_unmask = pci_msi_unmask_irq,
>> };
>>
>> +static void dw_msi_mask_irq(struct irq_data *d) {
>> + pci_msi_mask_irq(d);
>> + irq_chip_mask_parent(d);
>> +}
>> +
>> +static void dw_msi_unmask_irq(struct irq_data *d) {
>> + pci_msi_unmask_irq(d);
>> + irq_chip_unmask_parent(d);
>> +}
>> +
>> +static struct irq_chip dw_pcie_msi_irq_chip = {
>> + .name = "PCI-MSI",
>> + .irq_mask = dw_msi_mask_irq,
>> + .irq_unmask = dw_msi_unmask_irq,
>> +};
>> +
>> +static struct msi_domain_info dw_pcie_msi_domain_info = {
>> + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
>> + MSI_FLAG_PCI_MSIX),
>
> How is Multi-MSI supported if you don't pass the MSI_FLAG_MULTI_PCI_MSI
> flag?
Well spoted, it was lost in the merge.
>
>> + .chip = &dw_pcie_msi_irq_chip,
>> +};
>> +
>> /* MSI int handler */
>> irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
>> {
>> @@ -81,6 +104,191 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
>> return ret;
>> }
>>
>> +/* Chained MSI interrupt service routine */
>> +static void dw_chained_msi_isr(struct irq_desc *desc)
>> +{
>> + struct irq_chip *chip = irq_desc_get_chip(desc);
>> + struct pcie_port *pp;
>> + struct dw_pcie *pci;
>> +
>> + chained_irq_enter(chip, desc);
>> + pci = irq_desc_get_handler_data(desc);
>> + pp = &pci->pp;
>> +
>> + dw_handle_msi_irq(pp);
>> +
>> + chained_irq_exit(chip, desc);
>> +}
>> +
>> +static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
>> +{
>> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
>> + struct pcie_port *pp = &pci->pp;
>> + u64 msi_target;
>> +
>> + if (pp->ops->get_msi_addr)
>> + msi_target = pp->ops->get_msi_addr(pp);
>> + else
>> + msi_target = virt_to_phys((void *)pp->msi_data);
>> +
>> + msg->address_lo = lower_32_bits(msi_target);
>> + msg->address_hi = upper_32_bits(msi_target);
>> +
>> + if (pp->ops->get_msi_data)
>> + msg->data = pp->ops->get_msi_data(pp, data->hwirq);
>
> I've already asked about the reason for this indirection, and I'd
> appreciate an answer.
I answered in a previous e-mail. There are some SoCs using Synopsys PCIe Core
that have a custom way of managing some operations, like the msi_data,
msi_addrr, the mask/unmask of interrupts, etc. That is the reason why we have
these callbacks. An SoC specific driver fills their callbacks, call the
pcie-designware functions that they need and initialize their IP. There is a
group of drivers that are standard, like the pcie-designware-plat, exynos, qcom,
artpec6, imx6, etc.
>
>> + else
>> + msg->data = data->hwirq;
>> +
>> + dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
>> + (int)data->hwirq, msg->address_hi, msg->address_lo);
>> +}
>> +
>> +static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
>> + const struct cpumask *mask, bool force)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +static void dw_pci_bottom_mask(struct irq_data *data)
>> +{
>> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
>> + struct pcie_port *pp = &pci->pp;
>> + unsigned int res, bit, ctrl;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&pp->lock, flags);
>> +
>> + if (pp->ops->msi_clear_irq)
>> + pp->ops->msi_clear_irq(pp, data->hwirq);
>
> Same thing. If you have to have that kind of indirection, then this is a
> different irqchip altogether. Also, see below for the coding-style.
We can have a different irqchip for each SoC specifc driver that needs it, but
the change would be bigger. I suggest that we keep the current method and get
every driver working properly using the new API and after that I can make a
second round of patches targetting these callbacks. What do you think?
>
>> + else {
>> + ctrl = data->hwirq / 32;
>> + res = ctrl * 12;
>> + bit = data->hwirq % 32;
>> +
>> + pp->irq_status[ctrl] &= ~(1 << bit);
>> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
>> + pp->irq_status[ctrl]);
>> + }
>> +
>> + spin_unlock_irqrestore(&pp->lock, flags);
>> +}
>> +
>> +static void dw_pci_bottom_unmask(struct irq_data *data)
>> +{
>> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
>> + struct pcie_port *pp = &pci->pp;
>> + unsigned int res, bit, ctrl;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&pp->lock, flags);
>> +
>> + if (pp->ops->msi_set_irq)
>> + pp->ops->msi_set_irq(pp, data->hwirq);
>> + else {
>
> Coding-style:
>
> if (...) {
> ...
> } else {
>
>> + ctrl = data->hwirq / 32;
>> + res = ctrl * 12;
>> + bit = data->hwirq % 32;
>> +
>> + pp->irq_status[ctrl] |= 1 << bit;
>> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
>> + pp->irq_status[ctrl]);
>> + }
Yes correct. I did not run the checkpatch, because I was more worried about the
functionality. I will run it next patch version.
>> +
>> + spin_unlock_irqrestore(&pp->lock, flags);
>> +}
>> +
>> +static struct irq_chip dw_pci_msi_bottom_irq_chip = {
>> + .name = "DWPCI-MSI",
>> + .irq_compose_msi_msg = dw_pci_setup_msi_msg,
>> + .irq_set_affinity = dw_pci_msi_set_affinity,
>> + .irq_mask = dw_pci_bottom_mask,
>> + .irq_unmask = dw_pci_bottom_unmask,
>> +};
>> +
>> +static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
>> + unsigned int virq, unsigned int nr_irqs,
>> + void *args)
>> +{
>> + struct dw_pcie *pci = domain->host_data;
>> + struct pcie_port *pp = &pci->pp;
>> + unsigned long flags;
>> + unsigned long bit;
>> + u32 i;
>> +
>> + spin_lock_irqsave(&pp->lock, flags);
>> +
>> + bit = bitmap_find_next_zero_area(pp->msi_irq_in_use, pp->num_vectors, 0,
>> + nr_irqs, 0);
>> +
>> + if (bit >= pp->num_vectors) {
>> + spin_unlock_irqrestore(&pp->lock, flags);
>> + return -ENOSPC;
>> + }
>> +
>> + bitmap_set(pp->msi_irq_in_use, bit, nr_irqs);
>> +
>> + spin_unlock_irqrestore(&pp->lock, flags);
>> +
>> + for (i = 0; i < nr_irqs; i++)
>> + irq_domain_set_info(domain, virq + i, bit + i,
>> + &dw_pci_msi_bottom_irq_chip,
>> + domain->host_data, handle_simple_irq,
>> + NULL, NULL);
>> +
>> + return 0;
>
> How does this work when you're using the indirection I've moaned about
> earlier? How can you guarantee that there are similar number of
> available vectors?
With MSI_FLAG_MULTI_PCI_MSI, this approach would work properly correct?
>
>> +}
>> +
>> +static void dw_pcie_irq_domain_free(struct irq_domain *domain,
>> + unsigned int virq, unsigned int nr_irqs)
>> +{
>> + struct irq_data *data = irq_domain_get_irq_data(domain, virq);
>> + struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
>> + struct pcie_port *pp = &pci->pp;
>> + unsigned long flags;
>> +
>> + spin_lock_irqsave(&pp->lock, flags);
>> + bitmap_clear(pp->msi_irq_in_use, data->hwirq, nr_irqs);
>> + spin_unlock_irqrestore(&pp->lock, flags);
>> +}
>> +
>> +static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
>> + .alloc = dw_pcie_irq_domain_alloc,
>> + .free = dw_pcie_irq_domain_free,
>> +};
>> +
>> +int dw_pcie_allocate_domains(struct dw_pcie *pci)
>> +{
>> + struct pcie_port *pp = &pci->pp;
>> + struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
>> +
>> + pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
>> + &dw_pcie_msi_domain_ops, pci);
>> + if (!pp->irq_domain) {
>> + dev_err(pci->dev, "failed to create IRQ domain\n");
>> + return -ENOMEM;
>> + }
>> +
>> + pp->msi_domain = pci_msi_create_irq_domain(fwnode,
>> + &dw_pcie_msi_domain_info,
>> + pp->irq_domain);
>> + if (!pp->msi_domain) {
>> + dev_err(pci->dev, "failed to create MSI domain\n");
>> + irq_domain_remove(pp->irq_domain);
>> + return -ENOMEM;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +void dw_pcie_free_msi(struct pcie_port *pp)
>> +{
>> + irq_set_chained_handler(pp->msi_irq, NULL);
>> + irq_set_handler_data(pp->msi_irq, NULL);
>> +
>> + irq_domain_remove(pp->msi_domain);
>> + irq_domain_remove(pp->irq_domain);
>> +}
>> +
>> void dw_pcie_msi_init(struct pcie_port *pp)
>> {
>> u64 msi_target;
>> @@ -97,13 +305,14 @@ void dw_pcie_msi_init(struct pcie_port *pp)
>>
>> static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
>> {
>> - unsigned int res, bit, val;
>> + unsigned int res, bit, ctrl;
>>
>> - res = (irq / 32) * 12;
>> + ctrl = irq / 32;
>> + res = ctrl * 12;
>> bit = irq % 32;
>> - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>> - val &= ~(1 << bit);
>> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>> + pp->irq_status[ctrl] &= ~(1 << bit);
>> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
>> + pp->irq_status[ctrl]);
>> }
>>
>> static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>> @@ -125,13 +334,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
>>
>> static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
>> {
>> - unsigned int res, bit, val;
>> + unsigned int res, bit, ctrl;
>>
>> - res = (irq / 32) * 12;
>> + ctrl = irq / 32;
>> + res = ctrl * 12;
>> bit = irq % 32;
>> - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
>> - val |= 1 << bit;
>> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
>> + pp->irq_status[ctrl] |= 1 << bit;
>> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
>> + pp->irq_status[ctrl]);
>> }
>>
>> static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
>> @@ -279,11 +489,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
>> struct device *dev = pci->dev;
>> struct device_node *np = dev->of_node;
>> struct platform_device *pdev = to_platform_device(dev);
>> + struct resource_entry *win, *tmp;
>> struct pci_bus *bus, *child;
>> struct resource *cfg_res;
>> int i, ret;
>> +
>> LIST_HEAD(res);
>> - struct resource_entry *win, *tmp;
>> +
>> + spin_lock_init(&pci->pp.lock);
>>
>> cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
>> if (cfg_res) {
>> @@ -378,17 +591,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
>>
>> if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> if (!pp->ops->msi_host_init) {
>> - pp->irq_domain = irq_domain_add_linear(dev->of_node,
>> - MAX_MSI_IRQS, &msi_domain_ops,
>> - &dw_pcie_msi_chip);
>> - if (!pp->irq_domain) {
>> - dev_err(dev, "irq domain init failed\n");
>> - ret = -ENXIO;
>> + ret = of_property_read_u32(np, "num-vectors",
>> + &pp->num_vectors);
>> + if (ret)
>> + pp->num_vectors = 1;
>
> 1? As in "one bit only"? Is that a valid configuration? Also, all of
> this code seems to assume a maximum number of 32 MSIs. Is that a real
> limitation? Because if that's the case, you can drop all the stuff about
> ctrl and the '* 12' offset all over the code.
The IP is capable of handling 256, distributed by 8 registers of 32-bit (shifted
by 12). For now the driver is hardcoded to handle 32 and so you have ctrl = 1 (1
register).
>
> Thanks,
>
> M.
>
Thanks,
Joao
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2017-05-22 9:24 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-15 17:03 [RFC v2 0/8] add new irq api to pcie-designware Joao Pinto
2017-05-15 17:03 ` [RFC v2 1/8] pci: adding new irq api to pci-designware Joao Pinto
2017-05-21 8:44 ` Marc Zyngier
2017-05-22 9:24 ` Joao Pinto
2017-05-15 17:03 ` [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API Joao Pinto
2017-05-18 18:50 ` Jingoo Han
2017-05-15 17:03 ` [RFC v2 3/8] pci: imx6 " Joao Pinto
2017-05-15 17:03 ` [RFC v2 4/8] pci: artpec6 " Joao Pinto
2017-05-15 17:03 ` [RFC v2 5/8] pci: generic PCIe DW " Joao Pinto
2017-05-15 17:03 ` [RFC v2 6/8] pci: qcom SoC " Joao Pinto
2017-05-15 17:03 ` [RFC v2 7/8] pci: keystone " Joao Pinto
2017-05-15 17:03 ` [RFC v2 8/8] pci: removing old irq api from pcie-designware Joao Pinto
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.