firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-drivers_pci_host_pcie...

178 lines
4.8 KiB
Diff

diff -drupN a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
--- a/drivers/pci/host/pcie-designware.c 2018-08-06 17:23:04.000000000 +0300
+++ b/drivers/pci/host/pcie-designware.c 2022-06-12 05:28:14.000000000 +0300
@@ -101,6 +101,12 @@
#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+#define PCIE_MISC_CONTROL_1_CFG 0x8bc
+
+#ifdef CONFIG_ARCH_SUN50IW6
+extern void __iomem *dbi_base;
+#endif
+
static struct pci_ops dw_pcie_ops;
int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
@@ -335,6 +341,29 @@ static void dw_pcie_msi_set_irq(struct p
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
}
+static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
+{
+ int flag = 1;
+
+ do {
+ pos = find_next_zero_bit(pp->msi_irq_in_use, MAX_MSI_IRQS, pos);
+ /*if you have reached to the end then get out from here.*/
+ if (pos == MAX_MSI_IRQS)
+ return -ENOSPC;
+ /*
+ * Check if this position is at correct offset.nvec is always a
+ * power of two. pos0 must be nvec bit aligned.
+ */
+ if (pos % msgvec)
+ pos += msgvec - (pos % msgvec);
+ else
+ flag = 0;
+ } while (flag);
+
+ *pos0 = pos;
+ return 0;
+}
+
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
{
int irq, pos0, i;
@@ -379,6 +408,68 @@ no_valid_irq:
return -ENOSPC;
}
+static int assign_irq_msix(int no_irqs, struct msi_desc *desc, int *pos)
+{
+ int irq, pos0, pos1, i;
+ struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(desc);
+
+ pos0 = find_first_zero_bit(pp->msi_irq_in_use,
+ MAX_MSI_IRQS);
+ if (pos0 % no_irqs) {
+ if (find_valid_pos0(pp, no_irqs, pos0, &pos0))
+ goto no_valid_irq;
+ }
+ if (no_irqs > 1) {
+ pos1 = find_next_bit(pp->msi_irq_in_use,
+ MAX_MSI_IRQS, pos0);
+ /* there must be nvec number of consecutive free bits */
+ while ((pos1 - pos0) < no_irqs) {
+ if (find_valid_pos0(pp, no_irqs, pos1, &pos0))
+ goto no_valid_irq;
+ pos1 = find_next_bit(pp->msi_irq_in_use,
+ MAX_MSI_IRQS, pos0);
+ }
+ }
+
+ if (pos0 < 0)
+ goto no_valid_irq;
+
+ irq = irq_find_mapping(pp->irq_domain, pos0);
+ if (!irq)
+ goto no_valid_irq;
+
+ /*
+ * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
+ * descs so there is no need to allocate descs here. We can therefore
+ * assume that if irq_find_mapping above returns non-zero, then the
+ * descs are also successfully allocated.
+ */
+
+ for (i = 0; i < no_irqs; i++) {
+ if (irq_set_msi_desc_off(irq, i, desc) != 0) {
+ clear_irq_range(pp, irq, i, pos0);
+ goto no_valid_irq;
+ }
+ set_bit(pos0 + i, pp->msi_irq_in_use);
+ /*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);
+
+ }
+ desc->nvec_used = no_irqs;
+ desc->msi_attrib.multiple = order_base_2(no_irqs);
+
+ *pos = pos0;
+ return irq;
+
+no_valid_irq:
+ *pos = pos0;
+ return -ENOSPC;
+}
+
static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
{
struct msi_msg msg;
@@ -406,8 +497,14 @@ static int dw_msi_setup_irq(struct msi_c
int irq, pos;
struct pcie_port *pp = pdev->bus->sysdata;
- if (desc->msi_attrib.is_msix)
- return -EINVAL;
+ if (desc->msi_attrib.is_msix) {
+ irq = assign_irq_msix(1, desc, &pos);
+ if (irq < 0)
+ return irq;
+ dw_msi_setup_msg(pp, irq, pos);
+
+ return 0;
+ }
irq = assign_irq(1, desc, &pos);
if (irq < 0)
@@ -427,8 +524,18 @@ static int dw_msi_setup_irqs(struct msi_
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) {
+ for_each_pci_msi_entry(desc, pdev) {
+ irq = assign_irq_msix(1, desc, &pos);
+ if (irq < 0)
+ return irq;
+
+ dw_msi_setup_msg(pp, irq, pos);
+ }
+
+ return 0;
+ }
WARN_ON(!list_is_singular(&pdev->dev.msi_list));
desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
@@ -586,7 +693,7 @@ int dw_pcie_host_init(struct pcie_port *
goto error;
}
}
-
+ dbi_base = pp->dbi_base;
pp->mem_base = pp->mem->start;
if (!pp->va_cfg0_base) {
@@ -893,8 +1000,14 @@ void dw_pcie_setup_rc(struct pcie_port *
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
+ dw_pcie_rd_own_conf(pp, PCIE_MISC_CONTROL_1_CFG, 4, &val);
+ val |= 0x1;
+ dw_pcie_wr_own_conf(pp, PCIE_MISC_CONTROL_1_CFG, 4, val);
/* program correct class for RC */
dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
+ dw_pcie_rd_own_conf(pp, PCIE_MISC_CONTROL_1_CFG, 4, &val);
+ val &= ~(0x1<<0);
+ dw_pcie_wr_own_conf(pp, PCIE_MISC_CONTROL_1_CFG, 4, val);
dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
val |= PORT_LOGIC_SPEED_CHANGE;