Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a539ac31 authored by Taniya Das's avatar Taniya Das Committed by Stephen Boyd
Browse files

ARM: gic: Patches for 8625 hardware workaround



5 patches:

  ARM: gic: Add spinlocks for SGIR/AIR/EOI for 8625

  On 8625 due to bug in AHB MUX on hready, back to back write followed
  by read (from any CPU) on QGIC2 registers (SGIR(WO) ,IAR(RO) and
  write on EOI(WO)) cause the read data to get corrupted on AHB bus.

  Due to this whenever a valid irq has occurs, and dispatched to the cpu
  interface but still cpu reads the IAR as 0x0 and that particular IRQ
  becomes active.
  But due to incorrect irq id (read as 0x0), IRQ handler will not do
  proper EOI for that particular interrupt and thus it gets trapped
  in the active state.

  Below is the qgic register dump from CPU-1, in this particular case
  we see that SGI-3 is not getting clear as cpu reads this as 0x0.

  AZSD:C0000200| 00240008 00000000 00008000 00000000 00000000 00000000
  00000000 00000000 ..$.............................
  AZSD:C0000280| 00240008 00000000 00008000 00000000 00000000 00000000
  00000000 00000000 ..$.............................
  AZSD:C0000300| 00040008 00000000 00000000 00000000 00000000 00000000
  00000000 00000000 ................................
  AZSD:C0000380| 00040008 00000000 00000000 00000000 00000000 00000000
  00000000 00000000 ................................

  As the interrupt gets trapped, no other interrupt received on the core is
  services any more causing the system hang.

  CRs-Fixed: 349219
  Change-Id: Icad2c65114377a08984b1032566cfba811bb4ca8
  Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
  (cherry picked from commit 6639886be3b2326bcce81a3d553bc91b6de793ac)

  ARM: gic: Move GIC based code out from mpm-8625

  Moving code which modifies the GIC registers. As there is no global
  lock in gic code, moving the code out.

  Change-Id: I85a2bd580dbeefc942a3307f3c0cad8b1da509b7
  Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
  (cherry picked from commit bc9248ab6fd94f9f5f2a818e7d8b67645b4310cb)

  ARM: gic: protect some of 8625 GIC functionality with irq spinlocks

  msm_gic_spi_ppi_pending, msm_gic_save and core1_gic_configure_and_raise
  gets called with interrupt enabled on the core0, so it is possible
  that we get into the spinlock deadlock since interrupt like timer PPI
  could get fired on core0 and get locked in gic_handle_irq() routine
  itself, so move these spinlocks to irqsave variants to avoid this
  scenario.

  CRs-Fixed: 363249
  Change-Id: I2d40d6e26f5d9dba4ee6b9d4602cd0e685226693
  Signed-off-by: default avatarTrilok Soni <tsoni@codeaurora.org>
  (cherry picked from commit 6278db09f0535ca05d6bc12bfbb4ef4aa9da0652)

  ARM: gic: Disable all interrupts before Power collapse

  We may enter PC from either suspend or idle path. So even
  if we enter from suspend path we should disable all interrupts
  before we go to Power collapse, so as to make sure, there
  are no pending interrupts(not even the wakeup capable) which
  could result in WFI failure.

  CRs-Fixed: 363293
  Change-Id: Ied25b21f59a9fa0a891a27a2e806876cc337a759
  Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
  (cherry picked from commit 8862d7d2202f33a6fe2f219aca0b2d7bb62b570e)

  ARM: gic: Remove unnecessary irq spinlocks from gic_resume path

  Remove the unnecessary irq spinlocks from gic resume path since it
  always gets called with interrupt disabled. It also fixes the bug
  introduced by commit 6278db09f where it called spin_lock again on the same
  lock.

  CRs-Fixed: 370894
  Change-Id: I94f81cc0d93f362ac233c9af637cbe75036903f9
  Signed-off-by: default avatarTrilok Soni <tsoni@codeaurora.org>
parent 4ffd8271
Loading
Loading
Loading
Loading
+151 −2
Original line number Diff line number Diff line
@@ -216,8 +216,14 @@ static int gic_suspend_one(struct gic_chip_data *gic)
{
	unsigned int i;
	void __iomem *base = gic_data_dist_base(gic);
#ifdef CONFIG_ARCH_MSM8625
	unsigned long flags;
#endif

	for (i = 0; i * 32 < gic->gic_irqs; i++) {
#ifdef CONFIG_ARCH_MSM8625
		raw_spin_lock_irqsave(&irq_controller_lock, flags);
#endif
		gic->enabled_irqs[i]
			= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
		/* disable all of them */
@@ -225,6 +231,9 @@ static int gic_suspend_one(struct gic_chip_data *gic)
		/* enable the wakeup set */
		writel_relaxed(gic->wakeup_irqs[i],
			base + GIC_DIST_ENABLE_SET + i * 4);
#ifdef CONFIG_ARCH_MSM8625
		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
#endif
	}
	mb();
	return 0;
@@ -250,12 +259,13 @@ static void gic_show_resume_irq(struct gic_chip_data *gic)
	if (!msm_show_resume_irq_mask)
		return;

	raw_spin_lock(&irq_controller_lock);
	for (i = 0; i * 32 < gic->gic_irqs; i++) {
		enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
		pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
		pending[i] &= enabled;
	}
	spin_unlock(&irq_controller_lock);
	raw_spin_unlock(&irq_controller_lock);

	for (i = find_first_bit(pending, gic->gic_irqs);
	     i < gic->gic_irqs;
@@ -269,6 +279,7 @@ static void gic_resume_one(struct gic_chip_data *gic)
{
	unsigned int i;
	void __iomem *base = gic_data_dist_base(gic);

	gic_show_resume_irq(gic);
	for (i = 0; i * 32 < gic->gic_irqs; i++) {
		/* disable all of them */
@@ -308,8 +319,13 @@ static void gic_eoi_irq(struct irq_data *d)
		gic_arch_extn.irq_eoi(d);
		raw_spin_unlock(&irq_controller_lock);
	}

#ifdef CONFIG_ARCH_MSM8625
	raw_spin_lock(&irq_controller_lock);
#endif
	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
#ifdef CONFIG_ARCH_MSM8625
	raw_spin_unlock(&irq_controller_lock);
#endif
}

static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -429,7 +445,13 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
	void __iomem *cpu_base = gic_data_cpu_base(gic);

	do {
#ifdef CONFIG_ARCH_MSM8625
		raw_spin_lock(&irq_controller_lock);
#endif
		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
#ifdef CONFIG_ARCH_MSM8625
		raw_spin_unlock(&irq_controller_lock);
#endif
		irqnr = irqstat & ~0x1c00;

		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -438,7 +460,13 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
			continue;
		}
		if (irqnr < 16) {
#ifdef CONFIG_ARCH_MSM8625
			raw_spin_lock(&irq_controller_lock);
#endif
			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
#ifdef CONFIG_ARCH_MSM8625
			raw_spin_unlock(&irq_controller_lock);
#endif
#ifdef CONFIG_SMP
			handle_IPI(irqnr, regs);
#endif
@@ -595,6 +623,9 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
	 * Deal with the banked PPI and SGI interrupts - disable all
	 * PPI interrupts, ensure all SGI interrupts are enabled.
	 */
#ifdef CONFIG_ARCH_MSM8625
	raw_spin_lock(&irq_controller_lock);
#endif
	writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
	writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);

@@ -614,6 +645,9 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
		writel_relaxed(0xF, base + GIC_CPU_CTRL);
	else
		writel_relaxed(1, base + GIC_CPU_CTRL);
#ifdef CONFIG_ARCH_MSM8625
	raw_spin_unlock(&irq_controller_lock);
#endif
	mb();
}

@@ -825,6 +859,9 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
	int cpu;
	unsigned long sgir;
	unsigned long map = 0;
#ifdef CONFIG_ARCH_MSM8625
	unsigned long flags;
#endif

	/* Convert our logical CPU mask into a physical one. */
	for_each_cpu(cpu, mask)
@@ -839,8 +876,14 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
	 */
	dsb();

#ifdef CONFIG_ARCH_MSM8625
	raw_spin_lock_irqsave(&irq_controller_lock, flags);
#endif
	/* this always happens on GIC0 */
	writel_relaxed(sgir, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
#ifdef CONFIG_ARCH_MSM8625
	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
#endif
	mb();
}
#endif
@@ -1109,3 +1152,109 @@ void gic_clear_spi_pending(unsigned int irq)
			GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
	raw_spin_unlock(&irq_controller_lock);
}

#ifdef CONFIG_ARCH_MSM8625
 /*
  *  Check for any interrupts which are enabled are pending
  *  in the pending set or not.
  *  Return :
  *       0 : No pending interrupts
  *       1 : Pending interrupts other than A9_M2A_5
  */
unsigned int msm_gic_spi_ppi_pending(void)
{
	unsigned int i, bit = 0;
	unsigned int pending_enb = 0, pending = 0;
	unsigned long value = 0;
	struct gic_chip_data *gic = &gic_data[0];
	void __iomem *base = gic_data_dist_base(gic);
	unsigned long flags;

	raw_spin_lock_irqsave(&irq_controller_lock, flags);
	/*
	 * PPI and SGI to be included.
	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
	 * requesting sleep triggers it
	 */
	for (i = 0; (i * 32) < gic->gic_irqs; i++) {
		pending = readl_relaxed(base +
				GIC_DIST_PENDING_SET + i * 4);
		pending_enb = readl_relaxed(base +
				GIC_DIST_ENABLE_SET + i * 4);
		value = pending & pending_enb;

		if (value) {
			for (bit = 0; bit < 32; bit++) {
				bit = find_next_bit(&value, 32, bit);
				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
					raw_spin_unlock_irqrestore(
						&irq_controller_lock, flags);
					return 1;
				}
			}
		}
	}
	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);

	return 0;
}

void msm_gic_save(bool modem_wake, int from_idle)
{
	unsigned int i;
	struct gic_chip_data *gic = &gic_data[0];
	void __iomem *base = gic_data_dist_base(gic);

	gic_cpu_save(0);
	gic_dist_save(0);
	/* Disable all the Interrupts, before we enter pc */
	for (i = 0; (i * 32) < gic->gic_irqs; i++) {
		raw_spin_lock(&irq_controller_lock);
		writel_relaxed(0xffffffff, base
				+ GIC_DIST_ENABLE_CLEAR + i * 4);
		raw_spin_unlock(&irq_controller_lock);
	}
}

void msm_gic_restore(void)
{
	gic_dist_restore(0);
	gic_cpu_restore(0);
}

/*
 * Configure the GIC after we come out of power collapse.
 * This function will configure some of the GIC registers so as to prepare the
 * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
 * which will bring cores out of GDFS.
 */
void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
{
	struct gic_chip_data *gic = &gic_data[0];
	struct irq_data *d = irq_get_irq_data(irq);
	void __iomem *base = gic_data_dist_base(gic);
	unsigned int value = 0, byte_offset, offset, bit;
	unsigned long flags;

	offset = ((gic_irq(d) / 32) * 4);
	bit = BIT(gic_irq(d) % 32);

	raw_spin_lock_irqsave(&irq_controller_lock, flags);

	value = __raw_readl(base + GIC_DIST_ACTIVE_SET + offset);
	__raw_writel(value | bit, base + GIC_DIST_ACTIVE_SET + offset);
	mb();

	value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
	byte_offset = (gic_irq(d) % 4) * 8;
	value |= 1 << (cpu + byte_offset);
	__raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
	mb();

	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
	__raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
	mb();

	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#endif
+6 −0
Original line number Diff line number Diff line
@@ -82,4 +82,10 @@ void gic_clear_spi_pending(unsigned int irq);

#endif /* __ASSEMBLY */

#ifdef CONFIG_ARCH_MSM8625
void msm_gic_save(bool modem_wake, int from_idle);
void msm_gic_restore(void);
void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
#endif

#endif