SMP kernel hangs on C360, resolved
Turns out this is down to bugs in drivers/input/serio/gscps2.c. Looking at gscps2_probe(), there are two locks involved; one in struct gscps2port and one in struct serio. The probe function initialises the one in struct gscps2port and then calls gscps2_reset() which enables the device such that it can start generating interrupts, then adds the port to the list of ports the int handler looks at, then calls serio_register_port() which initialises the lock in struct serio. gscps2_interrupt() calls serio_interrupt(), so if an interrupt is raised before serio_register_port() is called, the code will hang trying to claim the serio lock which has not yet been initialised. Another issue is that gscps2_reset() resets the device _and_ enables the port. I think enabling the port should only happen once something calls open().
The attached patch addresses these issues. Before applying the patch I could provoke the hang easily after adding an mdelay() to the middle of the probe function and then banging on the keyboard and mouse during boot.
Richard
Index: drivers/input/serio/gscps2.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/input/serio/gscps2.c,v retrieving revision 1.16
input/serio/gscps2.c +5 -6
@@ -211,9 +211,6 @@writeb (0xff , addr+GSC_RESET );gscps2_flush (ps2port);spin_unlock_irqrestore (&ps2port->lock, flags); - -/* enable it */ -gscps2_enable (ps2port,ENABLE ); }static LIST_HEAD (ps2port_list);
@@ -307,6 +304,9 @@gscps2_reset (ps2port); +/* enable it */ +gscps2_enable (ps2port,ENABLE ); +gscps2_interrupt (0 ,NULL ,NULL );return 0 ;
@@ -370,8 +370,6 @@ serio->port_data = ps2port; serio->dev.parent = &dev->dev; -list_add_tail (&ps2port->node, &ps2port_list); - ret = -EBUSY ;if (request_irq (dev->irq, gscps2_interrupt,SA_SHIRQ , ps2port->port->name, ps2port)) goto fail_miserably;
@@ -396,13 +394,14 @@serio_register_port (ps2port->port); +list_add_tail (&ps2port->node, &ps2port_list); +return 0 ; fail:free_irq (dev->irq, ps2port); fail_miserably: -list_del (&ps2port->node);iounmap (ps2port->addr);release_mem_region (dev->hpa,GSC_STATUS +4 );
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux