]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.39/patches.arch/ppc-axon-missing-msi-workaround-5.diff
Add ignored *.diff files of the xen patches
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / ppc-axon-missing-msi-workaround-5.diff
diff --git a/src/patches/suse-2.6.27.39/patches.arch/ppc-axon-missing-msi-workaround-5.diff b/src/patches/suse-2.6.27.39/patches.arch/ppc-axon-missing-msi-workaround-5.diff
new file mode 100644 (file)
index 0000000..29d11c4
--- /dev/null
@@ -0,0 +1,143 @@
+From: Arnd Bergmann <arnd.bergmann@de.ibm.com>
+Subject: powerpc/cell/axon-msi: retry on missing interrupt
+References: bnc#445964,bnc#467633
+
+The MSI capture logic on the axon bridge can sometimes
+lose interrupts in case of high DMA and interrupt load,
+when it signals an MSI interrupt to the MPIC interrupt
+controller while we are already handling another MSI.
+
+Each MSI vector gets written into a FIFO buffer in main
+memory using DMA, and that DMA access is normally flushed
+by the actual interrupt packet on the IOIF. An MMIO
+register in the MSIC holds the position of the last
+entry in the FIFO buffer that was written. However,
+reading that position does not flush the DMA, so that
+we can observe stale data in the buffer.
+
+In a stress test, we have observed the DMA to arrive
+up to 14 microseconds after reading the register.
+We can reliably detect this conditioning by writing
+an invalid MSI vector into the FIFO buffer after
+reading from it, assuming that all MSIs we get
+are valid. After detecting an invalid MSI vector,
+we udelay(1) in the interrupt cascade for up to
+100 times before giving up.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: John Jolly <jjolly@novell.com>
+
+commit 23e0e8afafd9ac065d81506524adf3339584044b
+Author: Arnd Bergmann <arnd@arndb.de>
+Date:   Fri Dec 12 09:19:50 2008 +0000
+
+    powerpc/cell/axon-msi: Fix MSI after kexec
+    
+    Commit d015fe995 'powerpc/cell/axon-msi: Retry on missing interrupt'
+    has turned a rare failure to kexec on QS22 into a reproducible
+    error, which we have now analysed.
+    
+    The problem is that after a kexec, the MSIC hardware still points
+    into the middle of the old ring buffer.  We set up the ring buffer
+    during reboot, but not the offset into it.  On older kernels, this
+    would cause a storm of thousands of spurious interrupts after a
+    kexec, which would most of the time get dropped silently.
+    
+    With the new code, we time out on each interrupt, waiting for
+    it to become valid.  If more interrupts come in that we time
+    out on, this goes on indefinitely, which eventually leads to
+    a hard crash.
+    
+    The solution in this commit is to read the current offset from
+    the MSIC when reinitializing it.  This now works correctly, as
+    expected.
+    
+    Reported-by: Dirk Herrendoerfer <d.herrendoerfer@de.ibm.com>
+    Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+    Acked-by: Michael Ellerman <michael@ellerman.id.au>
+    Signed-off-by: Paul Mackerras <paulus@samba.org>
+
+
+---
+ arch/powerpc/platforms/cell/axon_msi.c |   39 ++++++++++++++++++++++++++++-----
+ 1 file changed, 34 insertions(+), 5 deletions(-)
+
+--- a/arch/powerpc/platforms/cell/axon_msi.c
++++ b/arch/powerpc/platforms/cell/axon_msi.c
+@@ -95,6 +95,7 @@ static void axon_msi_cascade(unsigned in
+       struct axon_msic *msic = get_irq_data(irq);
+       u32 write_offset, msi;
+       int idx;
++      int retry = 0;
+       write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
+       pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+@@ -102,7 +103,7 @@ static void axon_msi_cascade(unsigned in
+       /* write_offset doesn't wrap properly, so we have to mask it */
+       write_offset &= MSIC_FIFO_SIZE_MASK;
+-      while (msic->read_offset != write_offset) {
++      while (msic->read_offset != write_offset && retry < 100) {
+               idx  = msic->read_offset / sizeof(__le32);
+               msi  = le32_to_cpu(msic->fifo_virt[idx]);
+               msi &= 0xFFFF;
+@@ -110,13 +111,37 @@ static void axon_msi_cascade(unsigned in
+               pr_debug("axon_msi: woff %x roff %x msi %x\n",
+                         write_offset, msic->read_offset, msi);
++              if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) {
++                      generic_handle_irq(msi);
++                      msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
++              } else {
++                      /*
++                       * Reading the MSIC_WRITE_OFFSET_REG does not
++                       * reliably flush the outstanding DMA to the
++                       * FIFO buffer. Here we were reading stale
++                       * data, so we need to retry.
++                       */
++                      udelay(1);
++                      retry++;
++                      pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
++                      continue;
++              }
++
++              if (retry) {
++                      pr_debug("axon_msi: late irq 0x%x, retry %d\n",
++                               msi, retry);
++                      retry = 0;
++              }
++
+               msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+               msic->read_offset &= MSIC_FIFO_SIZE_MASK;
++      }
+-              if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
+-                      generic_handle_irq(msi);
+-              else
+-                      pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
++      if (retry) {
++              printk(KERN_WARNING "axon_msi: irq timed out\n");
++
++              msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
++              msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+       }
+       desc->chip->eoi(irq);
+@@ -364,6 +389,7 @@ static int axon_msi_probe(struct of_devi
+                      dn->full_name);
+               goto out_free_fifo;
+       }
++      memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
+       msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP,
+                                       NR_IRQS, &msic_host_ops, 0);
+@@ -387,6 +413,9 @@ static int axon_msi_probe(struct of_devi
+                       MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
+                       MSIC_CTRL_FIFO_SIZE);
++      msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
++                              & MSIC_FIFO_SIZE_MASK;
++
+       device->dev.platform_data = msic;
+       ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;