summaryrefslogtreecommitdiffstats
path: root/drivers/pci/dwc
diff options
context:
space:
mode:
authorLinus Torvalds2018-04-07 03:31:06 +0200
committerLinus Torvalds2018-04-07 03:31:06 +0200
commit3c0d551e02b2590fa71a1354f2f1994551a33315 (patch)
treeda94dc3559fe0c63fcc13852b53ba3d3b08d5292 /drivers/pci/dwc
parentMerge tag 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff)
parentMerge remote-tracking branch 'lorenzo/pci/cadence' into next (diff)
downloadkernel-qcow2-linux-3c0d551e02b2590fa71a1354f2f1994551a33315.tar.gz
kernel-qcow2-linux-3c0d551e02b2590fa71a1354f2f1994551a33315.tar.xz
kernel-qcow2-linux-3c0d551e02b2590fa71a1354f2f1994551a33315.zip
Merge tag 'pci-v4.17-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: - move pci_uevent_ers() out of pci.h (Michael Ellerman) - skip ASPM common clock warning if BIOS already configured it (Sinan Kaya) - fix ASPM Coverity warning about threshold_ns (Gustavo A. R. Silva) - remove last user of pci_get_bus_and_slot() and the function itself (Sinan Kaya) - add decoding for 16 GT/s link speed (Jay Fang) - add interfaces to get max link speed and width (Tal Gilboa) - add pcie_bandwidth_capable() to compute max supported link bandwidth (Tal Gilboa) - add pcie_bandwidth_available() to compute bandwidth available to device (Tal Gilboa) - add pcie_print_link_status() to log link speed and whether it's limited (Tal Gilboa) - use PCI core interfaces to report when device performance may be limited by its slot instead of doing it in each driver (Tal Gilboa) - fix possible cpqphp NULL pointer dereference (Shawn Lin) - rescan more of the hierarchy on ACPI hotplug to fix Thunderbolt/xHCI hotplug (Mika Westerberg) - add support for PCI I/O port space that's neither directly accessible via CPU in/out instructions nor directly mapped into CPU physical memory space. This is fairly intrusive and includes minor changes to interfaces used for I/O space on most platforms (Zhichang Yuan, John Garry) - add support for HiSilicon Hip06/Hip07 LPC I/O space (Zhichang Yuan, John Garry) - use PCI_EXP_DEVCTL2_COMP_TIMEOUT in rapidio/tsi721 (Bjorn Helgaas) - remove possible NULL pointer dereference in of_pci_bus_find_domain_nr() (Shawn Lin) - report quirk timings with dev_info (Bjorn Helgaas) - report quirks that take longer than 10ms (Bjorn Helgaas) - add and use Altera Vendor ID (Johannes Thumshirn) - tidy Makefiles and comments (Bjorn Helgaas) - don't set up INTx if MSI or MSI-X is enabled to align cris, frv, ia64, and mn10300 with x86 (Bjorn Helgaas) - move pcieport_if.h to drivers/pci/pcie/ to encapsulate it (Frederick Lawler) - merge pcieport_if.h into portdrv.h (Bjorn Helgaas) - move workaround for BIOS PME issue from portdrv to PCI core (Bjorn Helgaas) - completely disable portdrv with "pcie_ports=compat" (Bjorn Helgaas) - remove portdrv link order dependency (Bjorn Helgaas) - remove support for unused VC portdrv service (Bjorn Helgaas) - simplify portdrv feature permission checking (Bjorn Helgaas) - remove "pcie_hp=nomsi" parameter (use "pci=nomsi" instead) (Bjorn Helgaas) - remove unnecessary "pcie_ports=auto" parameter (Bjorn Helgaas) - use cached AER capability offset (Frederick Lawler) - don't enable DPC if BIOS hasn't granted AER control (Mika Westerberg) - rename pcie-dpc.c to dpc.c (Bjorn Helgaas) - use generic pci_mmap_resource_range() instead of powerpc and xtensa arch-specific versions (David Woodhouse) - support arbitrary PCI host bridge offsets on sparc (Yinghai Lu) - remove System and Video ROM reservations on sparc (Bjorn Helgaas) - probe for device reset support during enumeration instead of runtime (Bjorn Helgaas) - add ACS quirk for Ampere (née APM) root ports (Feng Kan) - add function 1 DMA alias quirk for Marvell 88SE9220 (Thomas Vincent-Cross) - protect device restore with device lock (Sinan Kaya) - handle failure of FLR gracefully (Sinan Kaya) - handle CRS (config retry status) after device resets (Sinan Kaya) - skip various config reads for SR-IOV VFs as an optimization (KarimAllah Ahmed) - consolidate VPD code in vpd.c (Bjorn Helgaas) - add Tegra dependency on PCI_MSI_IRQ_DOMAIN (Arnd Bergmann) - add DT support for R-Car r8a7743 (Biju Das) - fix a PCI_EJECT vs PCI_BUS_RELATIONS race condition in Hyper-V host bridge driver that causes a general protection fault (Dexuan Cui) - fix Hyper-V host bridge hang in MSI setup on 1-vCPU VMs with SR-IOV (Dexuan Cui) - fix Hyper-V host bridge hang when ejecting a VF before setting up MSI (Dexuan Cui) - make several structures static (Fengguang Wu) - increase number of MSI IRQs supported by Synopsys DesignWare bridges from 32 to 256 (Gustavo Pimentel) - implemented multiplexed IRQ domain API and remove obsolete MSI IRQ API from DesignWare drivers (Gustavo Pimentel) - add Tegra power management support (Manikanta Maddireddy) - add Tegra loadable module support (Manikanta Maddireddy) - handle 64-bit BARs correctly in endpoint support (Niklas Cassel) - support optional regulator for HiSilicon STB (Shawn Guo) - use regulator bulk API for Qualcomm apq8064 (Srinivas Kandagatla) - support power supplies for Qualcomm msm8996 (Srinivas Kandagatla) * tag 'pci-v4.17-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (123 commits) MAINTAINERS: Add John Garry as maintainer for HiSilicon LPC driver HISI LPC: Add ACPI support ACPI / scan: Do not enumerate Indirect IO host children ACPI / scan: Rename acpi_is_serial_bus_slave() for more general use HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings of: Add missing I/O range exception for indirect-IO devices PCI: Apply the new generic I/O management on PCI IO hosts PCI: Add fwnode handler as input param of pci_register_io_range() PCI: Remove __weak tag from pci_register_io_range() MAINTAINERS: Add missing /drivers/pci/cadence directory entry fm10k: Report PCIe link properties with pcie_print_link_status() net/mlx5e: Use pcie_bandwidth_available() to compute bandwidth net/mlx5: Report PCIe link properties with pcie_print_link_status() net/mlx4_core: Report PCIe link properties with pcie_print_link_status() PCI: Add pcie_print_link_status() to log link speed and whether it's limited PCI: Add pcie_bandwidth_available() to compute bandwidth available to device misc: pci_endpoint_test: Handle 64-bit BARs properly PCI: designware-ep: Make dw_pcie_ep_reset_bar() handle 64-bit BARs properly PCI: endpoint: Make sure that BAR_5 does not have 64-bit flag set when clearing PCI: endpoint: Make epc->ops->clear_bar()/pci_epc_clear_bar() take struct *epf_bar ...
Diffstat (limited to 'drivers/pci/dwc')
-rw-r--r--drivers/pci/dwc/Kconfig1
-rw-r--r--drivers/pci/dwc/pci-exynos.c18
-rw-r--r--drivers/pci/dwc/pci-imx6.c18
-rw-r--r--drivers/pci/dwc/pci-keystone-dw.c91
-rw-r--r--drivers/pci/dwc/pci-keystone.c1
-rw-r--r--drivers/pci/dwc/pci-keystone.h4
-rw-r--r--drivers/pci/dwc/pci-layerscape.c3
-rw-r--r--drivers/pci/dwc/pcie-artpec6.c18
-rw-r--r--drivers/pci/dwc/pcie-designware-ep.c36
-rw-r--r--drivers/pci/dwc/pcie-designware-host.c396
-rw-r--r--drivers/pci/dwc/pcie-designware-plat.c16
-rw-r--r--drivers/pci/dwc/pcie-designware.h30
-rw-r--r--drivers/pci/dwc/pcie-histb.c43
-rw-r--r--drivers/pci/dwc/pcie-kirin.c3
-rw-r--r--drivers/pci/dwc/pcie-qcom.c91
15 files changed, 347 insertions, 422 deletions
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig
index 0f666b1ce289..2f3f5c50aa48 100644
--- a/drivers/pci/dwc/Kconfig
+++ b/drivers/pci/dwc/Kconfig
@@ -176,6 +176,7 @@ config PCIE_ARTPEC6_EP
config PCIE_KIRIN
depends on OF && ARM64
bool "HiSilicon Kirin series SoCs PCIe controllers"
+ depends on PCI_MSI_IRQ_DOMAIN
depends on PCI
select PCIEPORTBUS
select PCIE_DW_HOST
diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c
index ca6278113936..4cc1e5df8c79 100644
--- a/drivers/pci/dwc/pci-exynos.c
+++ b/drivers/pci/dwc/pci-exynos.c
@@ -294,15 +294,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;
@@ -428,15 +419,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
dev_err(dev, "failed to get msi irq\n");
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;
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index 4fddbd08b089..4818ef875f8a 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -542,15 +542,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;
@@ -674,15 +665,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;
diff --git a/drivers/pci/dwc/pci-keystone-dw.c b/drivers/pci/dwc/pci-keystone-dw.c
index 99a0e7076221..0682213328e9 100644
--- a/drivers/pci/dwc/pci-keystone-dw.c
+++ b/drivers/pci/dwc/pci-keystone-dw.c
@@ -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 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);
- update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+ update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
BIT(bit_pos));
@@ -162,85 +157,9 @@ 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)
-{
- 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)
+int ks_dw_pcie_msi_host_init(struct pcie_port *pp)
{
- 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(pp);
}
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 d4f8ab90c018..d55ae0716adf 100644
--- a/drivers/pci/dwc/pci-keystone.c
+++ b/drivers/pci/dwc/pci-keystone.c
@@ -297,6 +297,7 @@ static const 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 1dd1f3ef98e7..8a13da391543 100644
--- a/drivers/pci/dwc/pci-keystone.h
+++ b/drivers/pci/dwc/pci-keystone.h
@@ -49,9 +49,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 pcie_port *pp);
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 a7b4159631ae..3724d3ef7008 100644
--- a/drivers/pci/dwc/pci-layerscape.c
+++ b/drivers/pci/dwc/pci-layerscape.c
@@ -182,8 +182,7 @@ static int ls1021_pcie_host_init(struct pcie_port *pp)
return ls_pcie_host_init(pp);
}
-static int ls_pcie_msi_host_init(struct pcie_port *pp,
- struct msi_controller *chip)
+static int ls_pcie_msi_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/dwc/pcie-artpec6.c
index 93b3df9ed1b5..e66cede2b5b7 100644
--- a/drivers/pci/dwc/pcie-artpec6.c
+++ b/drivers/pci/dwc/pcie-artpec6.c
@@ -383,15 +383,6 @@ static const 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)
{
@@ -406,15 +397,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
dev_err(dev, "failed to get MSI irq\n");
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;
diff --git a/drivers/pci/dwc/pcie-designware-ep.c b/drivers/pci/dwc/pcie-designware-ep.c
index 3a6feeff5f5b..f07678bf7cfc 100644
--- a/drivers/pci/dwc/pcie-designware-ep.c
+++ b/drivers/pci/dwc/pcie-designware-ep.c
@@ -19,7 +19,8 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
pci_epc_linkup(epc);
}
-void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
+static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
+ int flags)
{
u32 reg;
@@ -27,9 +28,18 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
dw_pcie_dbi_ro_wr_en(pci);
dw_pcie_writel_dbi2(pci, reg, 0x0);
dw_pcie_writel_dbi(pci, reg, 0x0);
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ dw_pcie_writel_dbi2(pci, reg + 4, 0x0);
+ dw_pcie_writel_dbi(pci, reg + 4, 0x0);
+ }
dw_pcie_dbi_ro_wr_dis(pci);
}
+void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
+{
+ __dw_pcie_ep_reset_bar(pci, bar, 0);
+}
+
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
struct pci_epf_header *hdr)
{
@@ -104,25 +114,28 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
}
static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
- enum pci_barno bar)
+ struct pci_epf_bar *epf_bar)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ enum pci_barno bar = epf_bar->barno;
u32 atu_index = ep->bar_to_atu[bar];
- dw_pcie_ep_reset_bar(pci, bar);
+ __dw_pcie_ep_reset_bar(pci, bar, epf_bar->flags);
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
clear_bit(atu_index, ep->ib_window_map);
}
static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
- enum pci_barno bar,
- dma_addr_t bar_phys, size_t size, int flags)
+ struct pci_epf_bar *epf_bar)
{
int ret;
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ enum pci_barno bar = epf_bar->barno;
+ size_t size = epf_bar->size;
+ int flags = epf_bar->flags;
enum dw_pcie_as_type as_type;
u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
@@ -131,13 +144,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
else
as_type = DW_PCIE_AS_IO;
- ret = dw_pcie_ep_inbound_atu(ep, bar, bar_phys, as_type);
+ ret = dw_pcie_ep_inbound_atu(ep, bar, epf_bar->phys_addr, as_type);
if (ret)
return ret;
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writel_dbi2(pci, reg, size - 1);
+
+ dw_pcie_writel_dbi2(pci, reg, lower_32_bits(size - 1));
dw_pcie_writel_dbi(pci, reg, flags);
+
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ dw_pcie_writel_dbi2(pci, reg + 4, upper_32_bits(size - 1));
+ dw_pcie_writel_dbi(pci, reg + 4, 0);
+ }
+
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
@@ -322,7 +342,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
struct device_node *np = dev->of_node;
if (!pci->dbi_base || !pci->dbi_base2) {
- dev_err(dev, "dbi_base/deb_base2 is not populated\n");
+ dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
return -EINVAL;
}
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index dc9303abda42..6c409079d514 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -8,6 +8,7 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
@@ -42,22 +43,46 @@ 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 = {
+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_enable = pci_msi_unmask_irq,
- .irq_disable = pci_msi_mask_irq,
- .irq_mask = pci_msi_mask_irq,
- .irq_unmask = pci_msi_unmask_irq,
+ .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 */
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{
- u32 val;
int i, pos, irq;
+ u32 val, num_ctrls;
irqreturn_t ret = IRQ_NONE;
- for (i = 0; i < MAX_MSI_CTRLS; i++) {
+ num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+
+ for (i = 0; i < num_ctrls; i++) {
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
&val);
if (!val)
@@ -78,206 +103,216 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
return ret;
}
-void dw_pcie_msi_init(struct pcie_port *pp)
+/* Chained MSI interrupt service routine */
+static void dw_chained_msi_isr(struct irq_desc *desc)
{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct device *dev = pci->dev;
- struct page *page;
- u64 msi_target;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct pcie_port *pp;
- page = alloc_page(GFP_KERNEL);
- pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, pp->msi_data)) {
- dev_err(dev, "failed to map MSI data\n");
- __free_page(page);
- return;
- }
- msi_target = (u64)pp->msi_data;
+ chained_irq_enter(chip, desc);
- /* program the msi_data */
- dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
- (u32)(msi_target & 0xffffffff));
- dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
- (u32)(msi_target >> 32 & 0xffffffff));
+ pp = irq_desc_get_handler_data(desc);
+ dw_handle_msi_irq(pp);
+
+ chained_irq_exit(chip, desc);
}
-static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
- unsigned int res, bit, val;
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ u64 msi_target;
- res = (irq / 32) * 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);
-}
+ if (pp->ops->get_msi_addr)
+ msi_target = pp->ops->get_msi_addr(pp);
+ else
+ msi_target = (u64)pp->msi_data;
-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);
- }
+ msg->address_lo = lower_32_bits(msi_target);
+ msg->address_hi = upper_32_bits(msi_target);
- bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
+ 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 void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
{
- unsigned int res, bit, val;
-
- res = (irq / 32) * 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);
+ return -EINVAL;
}
-static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
+static void dw_pci_bottom_mask(struct irq_data *data)
{
- 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;
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ unsigned int res, bit, ctrl;
+ unsigned long flags;
- irq = irq_find_mapping(pp->irq_domain, pos0);
- if (!irq)
- goto no_valid_irq;
+ raw_spin_lock_irqsave(&pp->lock, flags);
- /*
- * 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.
- */
+ 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;
- 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);
+ pp->irq_status[ctrl] &= ~(1 << bit);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
}
- *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;
+ raw_spin_unlock_irqrestore(&pp->lock, flags);
}
-static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
+static void dw_pci_bottom_unmask(struct irq_data *data)
{
- struct msi_msg msg;
- u64 msi_target;
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ unsigned int res, bit, ctrl;
+ unsigned long flags;
- if (pp->ops->get_msi_addr)
- msi_target = pp->ops->get_msi_addr(pp);
- else
- msi_target = (u64)pp->msi_data;
+ raw_spin_lock_irqsave(&pp->lock, flags);
- msg.address_lo = (u32)(msi_target & 0xffffffff);
- msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+ 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;
- if (pp->ops->get_msi_data)
- msg.data = pp->ops->get_msi_data(pp, pos);
- else
- msg.data = pos;
+ pp->irq_status[ctrl] |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
+ pp->irq_status[ctrl]);
+ }
- pci_write_msi_msg(irq, &msg);
+ raw_spin_unlock_irqrestore(&pp->lock, flags);
}
-static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
- struct msi_desc *desc)
+static void dw_pci_bottom_ack(struct irq_data *d)
{
- 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;
+ struct msi_desc *msi = irq_data_get_msi_desc(d);
+ struct pcie_port *pp;
- dw_msi_setup_msg(pp, irq, pos);
+ pp = msi_desc_to_pci_sysdata(msi);
- return 0;
+ if (pp->ops->msi_irq_ack)
+ pp->ops->msi_irq_ack(d->hwirq, pp);
}
-static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
- int nvec, int type)
+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)
{
-#ifdef CONFIG_PCI_MSI
- int irq, pos;
- struct msi_desc *desc;
- struct pcie_port *pp = pdev->bus->sysdata;
+ struct pcie_port *pp = domain->host_data;
+ unsigned long flags;
+ u32 i;
+ int bit;
+
+ raw_spin_lock_irqsave(&pp->lock, flags);
- /* MSI-X interrupts are not supported */
- if (type == PCI_CAP_ID_MSIX)
- return -EINVAL;
+ bit = bitmap_find_free_region(pp->msi_irq_in_use, pp->num_vectors,
+ order_base_2(nr_irqs));
- WARN_ON(!list_is_singular(&pdev->dev.msi_list));
- desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+ raw_spin_unlock_irqrestore(&pp->lock, flags);
- irq = assign_irq(nvec, desc, &pos);
- if (irq < 0)
- return irq;
+ if (bit < 0)
+ return -ENOSPC;
- dw_msi_setup_msg(pp, irq, pos);
+ 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;
-#else
- return -EINVAL;
-#endif
}
-static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
+static void dw_pcie_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
{
- 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);
+ 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 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 const struct irq_domain_ops dw_pcie_msi_domain_ops = {
+ .alloc = dw_pcie_irq_domain_alloc,
+ .free = dw_pcie_irq_domain_free,
};
-static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
+int dw_pcie_allocate_domains(struct pcie_port *pp)
{
- irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
- irq_set_chip_data(irq, domain->host_data);
+ 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;
}
-static const struct irq_domain_ops msi_domain_ops = {
- .map = dw_pcie_msi_map,
-};
+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)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
+ struct page *page;
+ u64 msi_target;
+
+ page = alloc_page(GFP_KERNEL);
+ pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, pp->msi_data)) {
+ dev_err(dev, "failed to map MSI data\n");
+ __free_page(page);
+ return;
+ }
+ msi_target = (u64)pp->msi_data;
+
+ /* program the msi_data */
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
+ lower_32_bits(msi_target));
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
+ upper_32_bits(msi_target));
+}
int dw_pcie_host_init(struct pcie_port *pp)
{
@@ -285,11 +320,13 @@ 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 pci_host_bridge *bridge;
struct resource *cfg_res;
- int i, ret;
- struct resource_entry *win, *tmp;
+ int ret;
+
+ raw_spin_lock_init(&pci->pp.lock);
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (cfg_res) {
@@ -388,20 +425,35 @@ int dw_pcie_host_init(struct pcie_port *pp)
pci->num_viewport = 2;
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;
+ /*
+ * If a specific SoC driver needs to change the
+ * default number of vectors, it needs to implement
+ * the set_num_vectors callback.
+ */
+ if (!pp->ops->set_num_vectors) {
+ 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;
}
+ }
- for (i = 0; i < MAX_MSI_IRQS; i++)
- irq_create_mapping(pp->irq_domain, i);
+ if (!pp->ops->msi_host_init) {
+ 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 {
- ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+ ret = pp->ops->msi_host_init(pp);
if (ret < 0)
goto error;
}
@@ -421,10 +473,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
bridge->ops = &dw_pcie_ops;
bridge->map_irq = of_irq_parse_and_map_pci;
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);
if (ret)
@@ -593,11 +641,17 @@ 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, num_ctrls;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
dw_pcie_setup(pci);
+ num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+
+ /* Initialize IRQ Status array */
+ for (ctrl = 0; ctrl < num_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-plat.c b/drivers/pci/dwc/pcie-designware-plat.c
index ebdf28bcd67d..5416aa8a07a5 100644
--- a/drivers/pci/dwc/pcie-designware-plat.c
+++ b/drivers/pci/dwc/pcie-designware-plat.c
@@ -25,13 +25,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 int dw_plat_pcie_host_init(struct pcie_port *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,
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 | 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;
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h
index 11b13864a406..fe811dbc12cf 100644
--- a/drivers/pci/dwc/pcie-designware.h
+++ b/drivers/pci/dwc/pcie-designware.h
@@ -107,13 +107,10 @@
#define MSI_MESSAGE_DATA_32 0x58
#define MSI_MESSAGE_DATA_64 0x5C
-/*
- * Maximum number of MSI IRQs can be 256 per controller. But keep
- * it 32 as of now. Probably we will never need more than 32. If needed,
- * then increment it in multiple of 32.
- */
-#define MAX_MSI_IRQS 32
-#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
+#define MAX_MSI_IRQS 256
+#define MAX_MSI_IRQS_PER_CTRL 32
+#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
+#define MSI_DEF_NUM_VECTORS 32
/* Maximum number of inbound/outbound iATUs */
#define MAX_IATU_IN 256
@@ -149,7 +146,9 @@ 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);
+ void (*set_num_vectors)(struct pcie_port *pp);
+ int (*msi_host_init)(struct pcie_port *pp);
+ void (*msi_irq_ack)(int irq, struct pcie_port *pp);
};
struct pcie_port {
@@ -174,7 +173,11 @@ struct pcie_port {
const struct dw_pcie_host_ops *ops;
int msi_irq;
struct irq_domain *irq_domain;
+ struct irq_domain *msi_domain;
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);
};
@@ -316,8 +319,10 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
#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 pcie_port *pp);
#else
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
{
@@ -328,6 +333,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)
{
}
@@ -336,6 +345,11 @@ static inline int dw_pcie_host_init(struct pcie_port *pp)
{
return 0;
}
+
+static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
+{
+ return 0;
+}
#endif
#ifdef CONFIG_PCIE_DW_EP
diff --git a/drivers/pci/dwc/pcie-histb.c b/drivers/pci/dwc/pcie-histb.c
index 70b5c0b108bf..3611d6ce9a92 100644
--- a/drivers/pci/dwc/pcie-histb.c
+++ b/drivers/pci/dwc/pcie-histb.c
@@ -61,6 +61,7 @@ struct histb_pcie {
struct reset_control *bus_reset;
void __iomem *ctrl;
int reset_gpio;
+ struct regulator *vpcie;
};
static u32 histb_pcie_readl(struct histb_pcie *histb_pcie, u32 reg)
@@ -207,13 +208,6 @@ static struct dw_pcie_host_ops histb_pcie_host_ops = {
.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)
{
reset_control_assert(hipcie->soft_reset);
@@ -227,6 +221,9 @@ static void histb_pcie_host_disable(struct histb_pcie *hipcie)
if (gpio_is_valid(hipcie->reset_gpio))
gpio_set_value_cansleep(hipcie->reset_gpio, 0);
+
+ if (hipcie->vpcie)
+ regulator_disable(hipcie->vpcie);
}
static int histb_pcie_host_enable(struct pcie_port *pp)
@@ -237,6 +234,14 @@ static int histb_pcie_host_enable(struct pcie_port *pp)
int ret;
/* power on PCIe device if have */
+ if (hipcie->vpcie) {
+ ret = regulator_enable(hipcie->vpcie);
+ if (ret) {
+ dev_err(dev, "failed to enable regulator: %d\n", ret);
+ return ret;
+ }
+ }
+
if (gpio_is_valid(hipcie->reset_gpio))
gpio_set_value_cansleep(hipcie->reset_gpio, 1);
@@ -276,13 +281,14 @@ static int histb_pcie_host_enable(struct pcie_port *pp)
return 0;
err_aux_clk:
- clk_disable_unprepare(hipcie->aux_clk);
-err_pipe_clk:
clk_disable_unprepare(hipcie->pipe_clk);
-err_sys_clk:
+err_pipe_clk:
clk_disable_unprepare(hipcie->sys_clk);
-err_bus_clk:
+err_sys_clk:
clk_disable_unprepare(hipcie->bus_clk);
+err_bus_clk:
+ if (hipcie->vpcie)
+ regulator_disable(hipcie->vpcie);
return ret;
}
@@ -332,6 +338,13 @@ static int histb_pcie_probe(struct platform_device *pdev)
return PTR_ERR(pci->dbi_base);
}
+ hipcie->vpcie = devm_regulator_get_optional(dev, "vpcie");
+ if (IS_ERR(hipcie->vpcie)) {
+ if (PTR_ERR(hipcie->vpcie) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ hipcie->vpcie = NULL;
+ }
+
hipcie->reset_gpio = of_get_named_gpio_flags(np,
"reset-gpios", 0, &of_flags);
if (of_flags & OF_GPIO_ACTIVE_LOW)
@@ -393,14 +406,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
dev_err(dev, "Failed to get MSI IRQ\n");
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");
diff --git a/drivers/pci/dwc/pcie-kirin.c b/drivers/pci/dwc/pcie-kirin.c
index 13d839bd6160..a6b88c7f6e3e 100644
--- a/drivers/pci/dwc/pcie-kirin.c
+++ b/drivers/pci/dwc/pcie-kirin.c
@@ -8,7 +8,6 @@
* Author: Xiaowei Song <songxiaowei@huawei.com>
*/
-#include <asm/compiler.h>
#include <linux/compiler.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -505,7 +504,7 @@ static const struct of_device_id kirin_pcie_match[] = {
{},
};
-struct platform_driver kirin_pcie_driver = {
+static struct platform_driver kirin_pcie_driver = {
.probe = kirin_pcie_probe,
.driver = {
.name = "kirin-pcie",
diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
index 6310c66e265c..5897af7d3355 100644
--- a/drivers/pci/dwc/pcie-qcom.c
+++ b/drivers/pci/dwc/pcie-qcom.c
@@ -79,6 +79,7 @@
#define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358
#define SLV_ADDR_SPACE_SZ 0x10000000
+#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
struct qcom_pcie_resources_2_1_0 {
struct clk *iface_clk;
struct clk *core_clk;
@@ -88,9 +89,7 @@ struct qcom_pcie_resources_2_1_0 {
struct reset_control *ahb_reset;
struct reset_control *por_reset;
struct reset_control *phy_reset;
- struct regulator *vdda;
- struct regulator *vdda_phy;
- struct regulator *vdda_refclk;
+ struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
};
struct qcom_pcie_resources_1_0_0 {
@@ -102,12 +101,14 @@ struct qcom_pcie_resources_1_0_0 {
struct regulator *vdda;
};
+#define QCOM_PCIE_2_3_2_MAX_SUPPLY 2
struct qcom_pcie_resources_2_3_2 {
struct clk *aux_clk;
struct clk *master_clk;
struct clk *slave_clk;
struct clk *cfg_clk;
struct clk *pipe_clk;
+ struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
};
struct qcom_pcie_resources_2_4_0 {
@@ -180,13 +181,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 int qcom_pcie_establish_link(struct qcom_pcie *pcie)
{
struct dw_pcie *pci = pcie->pci;
@@ -216,18 +210,15 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ int ret;
- res->vdda = devm_regulator_get(dev, "vdda");
- if (IS_ERR(res->vdda))
- return PTR_ERR(res->vdda);
-
- res->vdda_phy = devm_regulator_get(dev, "vdda_phy");
- if (IS_ERR(res->vdda_phy))
- return PTR_ERR(res->vdda_phy);
-
- res->vdda_refclk = devm_regulator_get(dev, "vdda_refclk");
- if (IS_ERR(res->vdda_refclk))
- return PTR_ERR(res->vdda_refclk);
+ res->supplies[0].supply = "vdda";
+ res->supplies[1].supply = "vdda_phy";
+ res->supplies[2].supply = "vdda_refclk";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
+ res->supplies);
+ if (ret)
+ return ret;
res->iface_clk = devm_clk_get(dev, "iface");
if (IS_ERR(res->iface_clk))
@@ -273,9 +264,7 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
clk_disable_unprepare(res->iface_clk);
clk_disable_unprepare(res->core_clk);
clk_disable_unprepare(res->phy_clk);
- regulator_disable(res->vdda);
- regulator_disable(res->vdda_phy);
- regulator_disable(res->vdda_refclk);
+ regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
@@ -286,24 +275,12 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
u32 val;
int ret;
- ret = regulator_enable(res->vdda);
- if (ret) {
- dev_err(dev, "cannot enable vdda regulator\n");
+ ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
+ if (ret < 0) {
+ dev_err(dev, "cannot enable regulators\n");
return ret;
}
- ret = regulator_enable(res->vdda_refclk);
- if (ret) {
- dev_err(dev, "cannot enable vdda_refclk regulator\n");
- goto err_refclk;
- }
-
- ret = regulator_enable(res->vdda_phy);
- if (ret) {
- dev_err(dev, "cannot enable vdda_phy regulator\n");
- goto err_vdda_phy;
- }
-
ret = reset_control_assert(res->ahb_reset);
if (ret) {
dev_err(dev, "cannot assert ahb reset\n");
@@ -387,11 +364,7 @@ err_clk_core:
err_clk_phy:
clk_disable_unprepare(res->iface_clk);
err_assert_ahb:
- regulator_disable(res->vdda_phy);
-err_vdda_phy:
- regulator_disable(res->vdda_refclk);
-err_refclk:
- regulator_disable(res->vdda);
+ regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
return ret;
}
@@ -521,6 +494,14 @@ static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ int ret;
+
+ res->supplies[0].supply = "vdda";
+ res->supplies[1].supply = "vddpe-3v3";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
+ res->supplies);
+ if (ret)
+ return ret;
res->aux_clk = devm_clk_get(dev, "aux");
if (IS_ERR(res->aux_clk))
@@ -550,6 +531,8 @@ static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
clk_disable_unprepare(res->master_clk);
clk_disable_unprepare(res->cfg_clk);
clk_disable_unprepare(res->aux_clk);
+
+ regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
static void qcom_pcie_post_deinit_2_3_2(struct qcom_pcie *pcie)
@@ -567,10 +550,16 @@ static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
u32 val;
int ret;
+ ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
+ if (ret < 0) {
+ dev_err(dev, "cannot enable regulators\n");
+ return ret;
+ }
+
ret = clk_prepare_enable(res->aux_clk);
if (ret) {
dev_err(dev, "cannot prepare/enable aux clock\n");
- return ret;
+ goto err_aux_clk;
}
ret = clk_prepare_enable(res->cfg_clk);
@@ -621,6 +610,9 @@ err_master_clk:
err_cfg_clk:
clk_disable_unprepare(res->aux_clk);
+err_aux_clk:
+ regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
+
return ret;
}
@@ -1262,15 +1254,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 | IRQF_NO_THREAD,
- "qcom-pcie-msi", pp);
- if (ret) {
- dev_err(dev, "cannot request msi irq\n");
- return ret;
- }
}
ret = phy_init(pcie->phy);