[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[microblaze-uclinux] xmbserial bug fix?



Hi,

Attached is a patch that appears to fix the lingering, and deeply 
unsatisfactory xmbserial.c UARTLITE driver bug - whereby the driver can 
be hung by dumping a large number of characters via cut'n'paste or 
probably a zmodem style transfer as well.

It's based on a trial patch that Yashi posted months ago - however the 
reason I'm not overjoyed to nail this bug is that the solution is 
completely counter-intuitive.  It's too late at night to re-hash the 
technical discussion - see the comments in the patch and review earlier 
list emails about the behaviour of the interrupt controller and so on if 
you're interested.

What would be great is if a few people people could

(a) confirm that they see the bug in an unpatched kernel (easy to do, 
just copy a large amount of text to your clipboard, then paste it into a 
minicom session connected to microblaze)

and

(b) apply the patch and test again, see if it fixes things.

I tried and succesfully dumped over 160Kb of text at high speed without 
any data loss or crashing, before I got sick of pressing Shift-Insert :)

If it works, and doesn't have any other noticeable side-effects, then it 
can go in.

Thanks,

John


--- /opt/src/uClinux-2.4.x/arch/microblaze/kernel/microblaze_intc.c	2005-01-26 04:39:56.000000000 +1000
+++ microblaze_intc.c	2005-02-17 22:18:18.000000000 +1000
@@ -267,22 +267,50 @@
 }
 
   
+/* The "when-to-ack?" mystery continues.  Common sense says that level sensitive
+   interrupts should be acked after handling, and edge-sensitives before.
+   BZZZT!  Wrong!
+   Reversing this fixes the uartlite driver bug, so beats me what's going on.
+   Pragmatism argues for a confusing universe that works, over a sensible
+   universe where things are broken... sigh....
+
+   I have a sneaking suspicion that it matters more the behaviour of the 
+   individual peripheral, than whether or not the IRQ signal is edge or level
+   sensitive...  However, this is very hard to test in any clean, generic way..
+
+*/
+   
+#define MAKES_NO_SENSE_BUT_WORKS 1
+
 void microblaze_intc_disable_and_ack_irq(unsigned irq)
 {
 	microblaze_intc_disable_irq(irq);
 
+#if MAKES_NO_SENSE_BUT_WORKS
+	/* Acknowledge level sensitive interrupts immediately */
+	if(IRQ_LEVEL_SENSITIVE(irq,CONFIG_XILINX_INTC_0_KIND_OF_INTR))
+		microblaze_intc_ack_irq(irq);
+#else
 	/* Acknowledge edge sensitive interrupts immediately */
 	if(IRQ_EDGE_SENSITIVE(irq,CONFIG_XILINX_INTC_0_KIND_OF_INTR))
 		microblaze_intc_ack_irq(irq);
+#endif
 }
 
 void microblaze_intc_end(unsigned irq)
 {
 	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 		microblaze_intc_enable_irq(irq);
+
+#if MAKES_NO_SENSE_BUT_WORKS
+		/* Edge sensitive interrupts are acked after handling */
+		if(IRQ_EDGE_SENSITIVE(irq,CONFIG_XILINX_INTC_0_KIND_OF_INTR))
+			microblaze_intc_ack_irq(irq);
+#else
 		/* Level sensitive interrupts are acked after handling */
 		if(IRQ_LEVEL_SENSITIVE(irq,CONFIG_XILINX_INTC_0_KIND_OF_INTR))
 			microblaze_intc_ack_irq(irq);
+#endif
 	}
 }