Commit c8778707 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'remotes/lorenzo/pci/dwc-msi'

  - Mask DesignWare interrupts instead of disabling them to avoid lost
    interrupts (Marc Zyngier)

  - Add locking when acking DesignWare interrupts (Marc Zyngier)

  - Ack DesignWare interrupts in the proper callbacks (Marc Zyngier)

* remotes/lorenzo/pci/dwc-msi:
  PCI: dwc: Move interrupt acking into the proper callback
  PCI: dwc: Take lock when ACKing an interrupt
  PCI: dwc: Use interrupt masking instead of disabling
parents 6a790bf0 3f7bb2ec
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -99,9 +99,6 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
					       (i * MAX_MSI_IRQS_PER_CTRL) +
					       pos);
			generic_handle_irq(irq);
			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS +
						(i * MSI_REG_CTRL_BLOCK_SIZE),
					    4, 1 << pos);
			pos++;
		}
	}
@@ -168,8 +165,8 @@ static void dw_pci_bottom_mask(struct irq_data *data)
		bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;

		pp->irq_status[ctrl] &= ~(1 << bit);
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
				    pp->irq_status[ctrl]);
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
				    ~pp->irq_status[ctrl]);
	}

	raw_spin_unlock_irqrestore(&pp->lock, flags);
@@ -191,8 +188,8 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
		bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;

		pp->irq_status[ctrl] |= 1 << bit;
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4,
				    pp->irq_status[ctrl]);
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
				    ~pp->irq_status[ctrl]);
	}

	raw_spin_unlock_irqrestore(&pp->lock, flags);
@@ -200,13 +197,22 @@ static void dw_pci_bottom_unmask(struct irq_data *data)

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 *pp  = irq_data_get_irq_chip_data(d);
	unsigned int res, bit, ctrl;
	unsigned long flags;

	ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
	res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
	bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;

	pp = msi_desc_to_pci_sysdata(msi);
	raw_spin_lock_irqsave(&pp->lock, flags);

	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);

	if (pp->ops->msi_irq_ack)
		pp->ops->msi_irq_ack(d->hwirq, pp);

	raw_spin_unlock_irqrestore(&pp->lock, flags);
}

static struct irq_chip dw_pci_msi_bottom_irq_chip = {
@@ -658,10 +664,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
	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 +
	for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
					(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
				    4, ~0);
		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
					(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
				    4, &pp->irq_status[ctrl]);
				    4, ~0);
		pp->irq_status[ctrl] = 0;
	}

	/* Setup RC BARs */
	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);