Commit 7c5925af authored by Gustavo Pimentel's avatar Gustavo Pimentel Committed by Lorenzo Pieralisi

PCI: dwc: Move MSI IRQs allocation to IRQ domains hierarchical API

Implement a multiplexed IRQ domain hierarchy API in the pcie-designware
host bridge driver that funnels all MSI IRQs into a single parent
interrupt, moving away from the obsolete struct msi_controller based
API.

Although the old implementation API is still available, pcie-designware
will now use the multiplexed IRQ domains hierarchical API.

Remove all existing dwc based host bridges MSI IRQs handlers, in that the
hierarchical API now handles MSI IRQs through the hierarchical/chained
MSI domain implementation.
Signed-off-by: default avatarGustavo Pimentel <gustavo.pimentel@synopsys.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: default avatarNiklas Cassel <niklas.cassel@axis.com>
Tested-by: default avatarShawn Guo <shawn.guo@linaro.org>
Acked-by: default avatarJingoo Han <jingoohan1@gmail.com>
Acked-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 7928b2cb
...@@ -294,15 +294,6 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) ...@@ -294,15 +294,6 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED; 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) static void exynos_pcie_msi_init(struct exynos_pcie *ep)
{ {
struct dw_pcie *pci = ep->pci; struct dw_pcie *pci = ep->pci;
...@@ -428,15 +419,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, ...@@ -428,15 +419,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
dev_err(dev, "failed to get msi irq\n"); dev_err(dev, "failed to get msi irq\n");
return pp->msi_irq; return pp->msi_irq;
} }
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; pp->root_bus_nr = -1;
......
...@@ -542,15 +542,6 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) ...@@ -542,15 +542,6 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
return -EINVAL; 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) static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{ {
struct dw_pcie *pci = imx6_pcie->pci; struct dw_pcie *pci = imx6_pcie->pci;
...@@ -674,15 +665,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, ...@@ -674,15 +665,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
dev_err(dev, "failed to get MSI irq\n"); dev_err(dev, "failed to get MSI irq\n");
return -ENODEV; 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; pp->root_bus_nr = -1;
......
...@@ -120,20 +120,15 @@ void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) ...@@ -120,20 +120,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; u32 reg_offset, bit_pos;
struct keystone_pcie *ks_pcie; struct keystone_pcie *ks_pcie;
struct msi_desc *msi;
struct pcie_port *pp;
struct dw_pcie *pci; 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); pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci); ks_pcie = to_keystone_pcie(pci);
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
BIT(bit_pos)); BIT(bit_pos));
...@@ -162,85 +157,9 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) ...@@ -162,85 +157,9 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
BIT(bit_pos)); BIT(bit_pos));
} }
static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
{
struct msi_desc *msi;
struct pcie_port *pp;
u32 offset;
msi = irq_data_get_msi_desc(d);
pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
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 msi_desc *msi;
struct pcie_port *pp;
u32 offset;
msi = irq_data_get_msi_desc(d);
pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
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);
}
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) 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); return dw_pcie_allocate_domains(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;
} }
void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
......
...@@ -297,6 +297,7 @@ static const struct dw_pcie_host_ops keystone_pcie_host_ops = { ...@@ -297,6 +297,7 @@ static const struct dw_pcie_host_ops keystone_pcie_host_ops = {
.msi_clear_irq = ks_dw_pcie_msi_clear_irq, .msi_clear_irq = ks_dw_pcie_msi_clear_irq,
.get_msi_addr = ks_dw_pcie_get_msi_addr, .get_msi_addr = ks_dw_pcie_get_msi_addr,
.msi_host_init = ks_dw_pcie_msi_host_init, .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, .scan_bus = ks_dw_pcie_v3_65_scan_bus,
}; };
......
...@@ -49,6 +49,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, ...@@ -49,6 +49,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 *val); 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_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_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_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_msi_clear_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp); void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
......
...@@ -383,15 +383,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { ...@@ -383,15 +383,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
.host_init = artpec6_pcie_host_init, .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, static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev) struct platform_device *pdev)
{ {
...@@ -406,15 +397,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, ...@@ -406,15 +397,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
dev_err(dev, "failed to get MSI irq\n"); dev_err(dev, "failed to get MSI irq\n");
return pp->msi_irq; return pp->msi_irq;
} }
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; pp->root_bus_nr = -1;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Author: Jingoo Han <jg1.han@samsung.com> * Author: Jingoo Han <jg1.han@samsung.com>
*/ */
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_pci.h> #include <linux/of_pci.h>
...@@ -50,6 +51,36 @@ static struct irq_chip dw_msi_irq_chip = { ...@@ -50,6 +51,36 @@ static struct irq_chip dw_msi_irq_chip = {
.irq_unmask = pci_msi_unmask_irq, .irq_unmask = pci_msi_unmask_irq,
}; };
static void dw_msi_ack_irq(struct irq_data *d)
{
irq_chip_ack_parent(d);
}
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_ack = dw_msi_ack_irq,
.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 | MSI_FLAG_MULTI_PCI_MSI),
.chip = &dw_pcie_msi_irq_chip,
};
/* MSI int handler */ /* MSI int handler */
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{ {
...@@ -78,6 +109,194 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) ...@@ -78,6 +109,194 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
return ret; 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;
chained_irq_enter(chip, desc);
pp = irq_desc_get_handler_data(desc);
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 pcie_port *pp = irq_data_get_irq_chip_data(data);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target;
if (pp->ops->get_msi_addr)
msi_target = pp->ops->get_msi_addr(pp);
else
msi_target = (u64)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 pcie_port *pp = irq_data_get_irq_chip_data(data);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_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]);
}
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void dw_pci_bottom_unmask(struct irq_data *data)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_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]);
}
raw_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;
pp = msi_desc_to_pci_sysdata(msi);
if (pp->ops->msi_irq_ack)
pp->ops->msi_irq_ack(d->hwirq, 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,
.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 pcie_port *pp = domain->host_data;
unsigned long flags;
u32 i;
int bit;
raw_spin_lock_irqsave(&pp->lock, flags);
bit = bitmap_find_free_region(pp->msi_irq_in_use, pp->num_vectors,
order_base_2(nr_irqs));
raw_spin_unlock_irqrestore(&pp->lock, flags);
if (bit < 0)
return -ENOSPC;
for (i = 0; i < nr_irqs; i++)
irq_domain_set_info(domain, virq + i, bit + i,
&dw_pci_msi_bottom_irq_chip,
pp, handle_edge_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 pcie_port *pp = irq_data_get_irq_chip_data(data);
unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags);
bitmap_release_region(pp->msi_irq_in_use, data->hwirq,
order_base_2(nr_irqs));
raw_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 pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(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, pp);
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) void dw_pcie_msi_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
...@@ -96,20 +315,21 @@ void dw_pcie_msi_init(struct pcie_port *pp) ...@@ -96,20 +315,21 @@ void dw_pcie_msi_init(struct pcie_port *pp)
/* program the msi_data */ /* program the msi_data */
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4, dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
(u32)(msi_target & 0xffffffff)); lower_32_bits(msi_target));
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
(u32)(msi_target >> 32 & 0xffffffff)); upper_32_bits(msi_target));
} }
static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) 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; bit = irq % 32;
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); pp->irq_status[ctrl] &= ~(1 << bit);
val &= ~(1 << bit); dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); pp->irq_status[ctrl]);
} }
static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
...@@ -131,13 +351,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, ...@@ -131,13 +351,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) 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; bit = irq % 32;
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); pp->irq_status[ctrl] |= 1 << bit;
val |= 1 << bit; dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); pp->irq_status[ctrl]);
} }
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
...@@ -285,11 +506,13 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -285,11 +506,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
struct device *dev = pci->dev; struct device *dev = pci->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct resource_entry *win, *tmp;
struct pci_bus *bus, *child; struct pci_bus *bus, *child;
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
struct resource *cfg_res; struct resource *cfg_res;
int i, ret; int ret;
struct resource_entry *win, *tmp;
raw_spin_lock_init(&pci->pp.lock);
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (cfg_res) { if (cfg_res) {
...@@ -388,18 +611,33 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -388,18 +611,33 @@ int dw_pcie_host_init(struct pcie_port *pp)
pci->num_viewport = 2; pci->num_viewport = 2;
if (IS_ENABLED(CONFIG_PCI_MSI)) { if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (!pp->ops->msi_host_init) { /*
pp->irq_domain = irq_domain_add_linear(dev->of_node, * If a specific SoC driver needs to change the
MAX_MSI_IRQS, &msi_domain_ops, * default number of vectors, it needs to implement
&dw_pcie_msi_chip); * the set_num_vectors callback.
if (!pp->irq_domain) { */
dev_err(dev, "irq domain init failed\n"); if (!pp->ops->set_num_vectors) {
ret = -ENXIO; pp->num_vectors = MSI_DEF_NUM_VECTORS;
} else {
pp->ops->set_num_vectors(pp);
if (pp->num_vectors > MAX_MSI_IRQS ||
pp->num_vectors == 0) {
dev_err(dev,
"Invalid number of vectors\n");
goto error; goto error;
} }
}
for (i = 0; i < MAX_MSI_IRQS; i++) if (!pp->ops->msi_host_init) {
irq_create_mapping(pp->irq_domain, i); ret = dw_pcie_allocate_domains(pp);
if (ret)
goto error;
if (pp->msi_irq)
irq_set_chained_handler_and_data(pp->msi_irq,
dw_chained_msi_isr,
pp);
} else { } else {
ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip); ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
if (ret < 0) if (ret < 0)
...@@ -421,10 +659,6 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -421,10 +659,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
bridge->ops = &dw_pcie_ops; bridge->ops = &dw_pcie_ops;
bridge->map_irq = of_irq_parse_and_map_pci; bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle; bridge->swizzle_irq = pci_common_swizzle;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
bridge->msi = &dw_pcie_msi_chip;
dw_pcie_msi_chip.dev = dev;
}
ret = pci_scan_root_bus_bridge(bridge); ret = pci_scan_root_bus_bridge(bridge);
if (ret) if (ret)
...@@ -593,11 +827,15 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) ...@@ -593,11 +827,15 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
void dw_pcie_setup_rc(struct pcie_port *pp) void dw_pcie_setup_rc(struct pcie_port *pp)
{ {
u32 val; u32 val, ctrl;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
dw_pcie_setup(pci); 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 */ /* setup RC BARs */
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
......
...@@ -25,13 +25,6 @@ struct dw_plat_pcie { ...@@ -25,13 +25,6 @@ struct dw_plat_pcie {
struct dw_pcie *pci; 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 int dw_plat_pcie_host_init(struct pcie_port *pp) static int dw_plat_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
...@@ -63,15 +56,6 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp, ...@@ -63,15 +56,6 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp,
pp->msi_irq = platform_get_irq(pdev, 0); pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0) if (pp->msi_irq < 0)
return pp->msi_irq; return pp->msi_irq;
ret = devm_request_irq(dev, pp->msi_irq,
dw_plat_pcie_msi_irq_handler,
IRQF_SHARED | IRQF_NO_THREAD,
"dw-plat-pcie-msi", pp);
if (ret) {
dev_err(dev, "failed to request MSI IRQ\n");
return ret;
}
} }
pp->root_bus_nr = -1; pp->root_bus_nr = -1;
......
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
*/ */
#define MAX_MSI_IRQS 32 #define MAX_MSI_IRQS 32
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32) #define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
#define MSI_DEF_NUM_VECTORS 32
/* Maximum number of inbound/outbound iATUs */ /* Maximum number of inbound/outbound iATUs */
#define MAX_IATU_IN 256 #define MAX_IATU_IN 256
...@@ -149,7 +150,9 @@ struct dw_pcie_host_ops { ...@@ -149,7 +150,9 @@ struct dw_pcie_host_ops {
phys_addr_t (*get_msi_addr)(struct pcie_port *pp); phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos); u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp); void (*scan_bus)(struct pcie_port *pp);
void (*set_num_vectors)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip); int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
void (*msi_irq_ack)(int irq, struct pcie_port *pp);
}; };
struct pcie_port { struct pcie_port {
...@@ -174,7 +177,11 @@ struct pcie_port { ...@@ -174,7 +177,11 @@ struct pcie_port {
const struct dw_pcie_host_ops *ops; const struct dw_pcie_host_ops *ops;
int msi_irq; int msi_irq;
struct irq_domain *irq_domain; struct irq_domain *irq_domain;
struct irq_domain *msi_domain;
dma_addr_t msi_data; dma_addr_t msi_data;
u32 num_vectors;
u32 irq_status[MAX_MSI_CTRLS];
raw_spinlock_t lock;
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
}; };
...@@ -316,8 +323,10 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci) ...@@ -316,8 +323,10 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
#ifdef CONFIG_PCIE_DW_HOST #ifdef CONFIG_PCIE_DW_HOST
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(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); void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp); int dw_pcie_host_init(struct pcie_port *pp);
int dw_pcie_allocate_domains(struct pcie_port *pp);
#else #else
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{ {
...@@ -328,6 +337,10 @@ static inline void dw_pcie_msi_init(struct pcie_port *pp) ...@@ -328,6 +337,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) static inline void dw_pcie_setup_rc(struct pcie_port *pp)
{ {
} }
...@@ -336,6 +349,11 @@ static inline int dw_pcie_host_init(struct pcie_port *pp) ...@@ -336,6 +349,11 @@ static inline int dw_pcie_host_init(struct pcie_port *pp)
{ {
return 0; return 0;
} }
static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
{
return 0;
}
#endif #endif
#ifdef CONFIG_PCIE_DW_EP #ifdef CONFIG_PCIE_DW_EP
......
...@@ -207,13 +207,6 @@ static struct dw_pcie_host_ops histb_pcie_host_ops = { ...@@ -207,13 +207,6 @@ static struct dw_pcie_host_ops histb_pcie_host_ops = {
.host_init = histb_pcie_host_init, .host_init = histb_pcie_host_init,
}; };
static irqreturn_t histb_pcie_msi_irq_handler(int irq, void *arg)
{
struct pcie_port *pp = arg;
return dw_handle_msi_irq(pp);
}
static void histb_pcie_host_disable(struct histb_pcie *hipcie) static void histb_pcie_host_disable(struct histb_pcie *hipcie)
{ {
reset_control_assert(hipcie->soft_reset); reset_control_assert(hipcie->soft_reset);
...@@ -393,14 +386,6 @@ static int histb_pcie_probe(struct platform_device *pdev) ...@@ -393,14 +386,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
dev_err(dev, "Failed to get MSI IRQ\n"); dev_err(dev, "Failed to get MSI IRQ\n");
return pp->msi_irq; return pp->msi_irq;
} }
ret = devm_request_irq(dev, pp->msi_irq,
histb_pcie_msi_irq_handler,
IRQF_SHARED, "histb-pcie-msi", pp);
if (ret) {
dev_err(dev, "cannot request MSI IRQ\n");
return ret;
}
} }
hipcie->phy = devm_phy_get(dev, "phy"); hipcie->phy = devm_phy_get(dev, "phy");
......
...@@ -180,13 +180,6 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) ...@@ -180,13 +180,6 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); 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 int qcom_pcie_establish_link(struct qcom_pcie *pcie) static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
{ {
struct dw_pcie *pci = pcie->pci; struct dw_pcie *pci = pcie->pci;
...@@ -1262,15 +1255,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) ...@@ -1262,15 +1255,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pp->msi_irq = platform_get_irq_byname(pdev, "msi"); pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0) if (pp->msi_irq < 0)
return pp->msi_irq; return pp->msi_irq;
ret = devm_request_irq(dev, pp->msi_irq,
qcom_pcie_msi_irq_handler,
IRQF_SHARED | IRQF_NO_THREAD,
"qcom-pcie-msi", pp);
if (ret) {
dev_err(dev, "cannot request msi irq\n");
return ret;
}
} }
ret = phy_init(pcie->phy); ret = phy_init(pcie->phy);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment