summaryrefslogtreecommitdiff
path: root/drivers/pci/host/pcie-designware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/host/pcie-designware.c')
-rw-r--r--drivers/pci/host/pcie-designware.c83
1 files changed, 58 insertions, 25 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index b3a87159e457..b27d85b36f56 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -190,11 +190,14 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
return dw_pcie_cfg_write(pp->dbi_base + where, size, val);
}
-static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
+void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
int type, u64 cpu_addr, u64 pci_addr, u32 size)
{
u32 retries, val;
+ if (cpu_addr >= pp->mem_base)
+ cpu_addr = cpu_addr + pp->cpu_addr_offset;
+
if (pp->iatu_unroll_enabled) {
dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_LOWER_BASE,
lower_32_bits(cpu_addr));
@@ -241,7 +244,7 @@ static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
if (val == PCIE_ATU_ENABLE)
return;
- usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX);
+ mdelay(LINK_WAIT_IATU_MAX/1000);
}
dev_err(pp->dev, "iATU is not being enabled\n");
}
@@ -284,16 +287,36 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
void dw_pcie_msi_init(struct pcie_port *pp)
{
- u64 msi_target;
-
- pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
- msi_target = virt_to_phys((void *)pp->msi_data);
+ dma_addr_t msi_addr;
+ dma_alloc_coherent(pp->dev, 64, &msi_addr, GFP_KERNEL);
+ pp->msi_target = (u64)msi_addr;
/* program the msi_data */
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
- (u32)(msi_target & 0xffffffff));
+ (u32)(pp->msi_target & 0xffffffff));
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
- (u32)(msi_target >> 32 & 0xffffffff));
+ (u32)(pp->msi_target >> 32 & 0xffffffff));
+}
+
+void dw_pcie_msi_cfg_store(struct pcie_port *pp)
+{
+ int i;
+
+ for (i = 0; i < MAX_MSI_CTRLS; i++)
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + i * 12, 4,
+ &pp->msi_enable[i]);
+}
+
+void dw_pcie_msi_cfg_restore(struct pcie_port *pp)
+{
+ int i;
+
+ for (i = 0; i < MAX_MSI_CTRLS; i++) {
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4, pp->msi_target);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + i * 12, 4,
+ pp->msi_enable[i]);
+ }
}
static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
@@ -382,15 +405,12 @@ no_valid_irq:
static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
{
struct msi_msg msg;
- u64 msi_target;
if (pp->ops->get_msi_addr)
- msi_target = pp->ops->get_msi_addr(pp);
- else
- msi_target = virt_to_phys((void *)pp->msi_data);
+ pp->msi_target = pp->ops->get_msi_addr(pp);
- msg.address_lo = (u32)(msi_target & 0xffffffff);
- msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+ msg.address_lo = (u32)(pp->msi_target & 0xffffffff);
+ msg.address_hi = (u32)(pp->msi_target >> 32 & 0xffffffff);
if (pp->ops->get_msi_data)
msg.data = pp->ops->get_msi_data(pp, pos);
@@ -406,9 +426,6 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
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;
@@ -426,9 +443,20 @@ static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc;
struct pcie_port *pp = pdev->bus->sysdata;
- /* MSI-X interrupts are not supported */
- if (type == PCI_CAP_ID_MSIX)
- return -EINVAL;
+ if (type == PCI_CAP_ID_MSIX) {
+ if ((MAX_MSI_IRQS - bitmap_weight(pp->msi_irq_in_use,
+ MAX_MSI_IRQS)) < nvec)
+ return -ENOSPC;
+
+ for_each_pci_msi_entry(desc, pdev) {
+ int ret = dw_msi_setup_irq(chip, pdev, desc);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+ }
WARN_ON(!list_is_singular(&pdev->dev.msi_list));
desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
@@ -637,8 +665,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
}
}
- if (pp->ops->host_init)
- pp->ops->host_init(pp);
+ if (pp->ops->host_init) {
+ ret = pp->ops->host_init(pp);
+ if (ret < 0)
+ return ret;
+ }
pp->root_bus_nr = pp->busn->start;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
@@ -882,9 +913,11 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dev_dbg(pp->dev, "iATU unroll: %s\n",
pp->iatu_unroll_enabled ? "enabled" : "disabled");
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, pp->mem_base,
- pp->mem_bus_addr, pp->mem_size);
+ if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+ && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM, pp->mem_base,
+ pp->mem_bus_addr, pp->mem_size);
if (pp->num_viewport > 2)
dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX2,
PCIE_ATU_TYPE_IO, pp->io_base,