add new irq api to pcie-designware
Subsystems (3)
v2 cover add new irq api to pcie-designware
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(-)
Signature · 1 line
2.9.3
RFC v2 1/8 pci: adding new irq api to pci-designware
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.
---
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(-)
drivers/pci/dwc/pcie-designware-host.c +243 -29
@@ -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 );
drivers/pci/dwc/pcie-designware.h +15 -0
@@ -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
Signature · 1 line
2.9.3
RFC v2 2/8 pci: exynos SoC driver adapted to new irq API
In reply to Joao PintoThis patch adapts Exynos SoC specific driver to use the new interrupt api available in pcie-designware.
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pci-exynos.c | 18 ------------------ 1 file changed, 18 deletions(-)
drivers/pci/dwc/pci-exynos.c +0 -18
@@ -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 ;
Signature · 1 line
2.9.3
RFC v2 3/8 pci: imx6 SoC driver adapted to new irq API
In reply to Joao PintoThis patch adapts imx6 SoC specific driver to use the new interrupt api available in pcie-designware.
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pci-imx6.c | 18 ------------------ 1 file changed, 18 deletions(-)
drivers/pci/dwc/pci-imx6.c +0 -18
@@ -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 ;
Signature · 1 line
2.9.3
RFC v2 4/8 pci: artpec6 SoC driver adapted to new irq API
In reply to Joao PintoThis patch adapts artpec6 SoC specific driver to use the new interrupt api available in pcie-designware.
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-artpec6.c | 18 ------------------ 1 file changed, 18 deletions(-)
drivers/pci/dwc/pcie-artpec6.c +0 -18
@@ -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 ;
Signature · 1 line
2.9.3
RFC v2 5/8 pci: generic PCIe DW driver adapted to new irq API
In reply to Joao PintoThis patch adapts the generic PCIe DW driver to use the new interrupt api available in pcie-designware.
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-designware-plat.c | 15 --------------- 1 file changed, 15 deletions(-)
drivers/pci/dwc/pcie-designware-plat.c +0 -15
@@ -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 ;
Signature · 1 line
2.9.3
RFC v2 6/8 pci: qcom SoC driver adapted to new irq API
In reply to Joao PintoThis patch adapts Qcom SoC specific driver to use the new interrupt api available in pcie-designware.
---
changes v1->v2:
- just to keep up patch set version
drivers/pci/dwc/pcie-qcom.c | 15 --------------- 1 file changed, 15 deletions(-)
drivers/pci/dwc/pcie-qcom.c +0 -15
@@ -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);
Signature · 1 line
2.9.3
RFC v2 7/8 pci: keystone SoC driver adapted to new irq API
In reply to Joao PintoThis 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.
---
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(-)
drivers/pci/dwc/pci-keystone-dw.c +6 -91
@@ -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)
drivers/pci/dwc/pci-keystone.c +1 -0
@@ -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, };
drivers/pci/dwc/pci-keystone.h +2 -2
@@ -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);
drivers/pci/dwc/pci-layerscape.c +1 -2
@@ -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;
drivers/pci/dwc/pcie-designware-host.c +11 -1
@@ -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; }
drivers/pci/dwc/pcie-designware.h +2 -1
@@ -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 {
Signature · 1 line
2.9.3
RFC v2 8/8 pci: removing old irq api from pcie-designware
In reply to Joao PintoThis patch removes the old interrupt API.
---
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(-)
drivers/pci/dwc/pci-keystone-dw.c +1 -1
@@ -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 ;
drivers/pci/dwc/pci-keystone.h +1 -1
@@ -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);
drivers/pci/dwc/pci-layerscape.c +1 -2
@@ -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;
drivers/pci/dwc/pcie-designware-host.c +2 -190
216 lines not on this page · raw message
drivers/pci/dwc/pcie-designware.h +1 -1
@@ -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); };
Signature · 1 line
2.9.3
Re: [RFC v2 2/8] pci: exynos SoC driver adapted to new irq API
In reply to Joao PintoQuoted 5 lines · Joao Pinto
This patch adapts Exynos SoC specific driver to use the new interrupt api available in pcie-designware.
Signed-off-by Joao Pinto <[email protected]>
Best regards,
Jingoo Han
Quoted 47 lines
---
changesv1->v2:
- just to keep up patch set versiondrivers/pci/dwc/pci-exynos.c | 18 ------------------ 1 file changed, 18 deletions(-)drivers/pci/dwc/pci-exynos.c +0
-9@@ -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) {drivers/pci/dwc/pci-exynos.c +0
-9struct 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
Re: [RFC v2 1/8] pci: adding new irq api to pci-designware
In reply to Joao PintoQuoted 45 lines · 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 <[email protected]>---
changesv1->v2:
- Now there's no config to toggle between the 2 APIs, so pcie-designware initiaties wih the new one by default
- Usinglower_32_bits/upper_32_bits
- Instead of mutex, now using spinlocks
- Instead of always readingPCIE_MSI_INTR0_ENABLE, now we use an internal variable
-dw_pcie_irq_domain_alloc()was updated to enable Multi-MSI
- usingirq_domain_create_linear()instead ofirq_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(-)drivers/pci/dwc/pcie-designware-host.c +10
-0@@ -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); +}
drivers/pci/dwc/pcie-designware-host.c static struct irq_chip dw_msi_irq_chip = { · line 75
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+ +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?
Quoted 32 lines
drivers/pci/dwc/pcie-designware-host.c +25
-0+ .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; +
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 138
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+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.
Quoted 14 lines
drivers/pci/dwc/pcie-designware-host.c +14
-0+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)
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 162
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+{ +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.
Quoted 15 lines
drivers/pci/dwc/pcie-designware-host.c +15
-0+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) +{
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 187
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+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 {Quoted 41 lines
drivers/pci/dwc/pcie-designware-host.c +41
-0+ 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);
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 238
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+ +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?
Quoted 116 lines
drivers/pci/dwc/pcie-designware-host.c +69
-11+} + +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) {
drivers/pci/dwc/pcie-designware-host.c int dw_pcie_host_init(struct pcie_port *pp) · line 597
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +4
-6- 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.
Signature · 1 line
Jazz is not dead. It just smells funny.
Re: [RFC v2 1/8] pci: adding new irq api to pci-designware
Hi Mark,
Às 9:44 AM de 5/21/2017, Marc Zyngier escreveu:
Quoted 51 lines · Joao Pinto
Quoted 50 lines
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 <[email protected]>---
changesv1->v2:
- Now there's no config to toggle between the 2 APIs, so pcie-designware initiaties wih the new one by default
- Usinglower_32_bits/upper_32_bits
- Instead of mutex, now using spinlocks
- Instead of always readingPCIE_MSI_INTR0_ENABLE, now we use an internal variable
-dw_pcie_irq_domain_alloc()was updated to enable Multi-MSI
- usingirq_domain_create_linear()instead ofirq_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(-)drivers/pci/dwc/pcie-designware-host.c +15
-0@@ -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,
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c static struct irq_chip dw_msi_irq_chip = { · line 75
Quoted 5 lines
drivers/pci/dwc/pcie-designware-host.c +5
-0+}; + +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_MSIflag?
Well spoted, it was lost in the merge.
Quoted 38 lines
Quoted 38 lines
drivers/pci/dwc/pcie-designware-host.c +30
-0+ .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); +
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 138
Quoted 5 lines
drivers/pci/dwc/pcie-designware-host.c +5
-0+ 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.
Quoted 20 lines
Quoted 20 lines
drivers/pci/dwc/pcie-designware-host.c +19
-0+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;
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 162
Quoted 5 lines
drivers/pci/dwc/pcie-designware-host.c +5
-0+ +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?
Quoted 33 lines
Quoted 16 lines
drivers/pci/dwc/pcie-designware-host.c +15
-0+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) +{drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 187
Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10
-0+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 {
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 195
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c +8
-0+ 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.
Quoted 39 lines
Quoted 39 lines
drivers/pci/dwc/pcie-designware-host.c +39
-0+ +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,
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 238
Quoted 4 lines
drivers/pci/dwc/pcie-designware-host.c +4
-0+ 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?
Quoted 124 lines
Quoted 124 lines
drivers/pci/dwc/pcie-designware-host.c +70
-17+} + +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",
Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c int dw_pcie_host_init(struct pcie_port *pp) · line 597
Quoted 3 lines
drivers/pci/dwc/pcie-designware-host.c +3
-0+ &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).
Quoted 5 lines
Thanks,
M.
Thanks,
Joao