new driver, yenta_socket and interrupts

Andrew Kohlsmith akohlsmith-pcmcia at benshaw.com
Mon Feb 12 15:02:12 EST 2007


Good day, everyone,

I've been writing a device driver for the SST 5136-DNP PCMCIA CAN/DeviceNet 
board.  I'm developing on a stock 2.6.19 (Slackware 11 system).

I have the card working fine without interrupts.  I can successfully 
communicate with the card and the CAN network it's connected to.  It's now 
time, however, to get interrupts working, and I've run up against a barrier I 
just can't seem to get beyond.

I cannot seem to get the interrupt routine to work.  I either softlock the 
system or cause an unserviced interrupt storm which causes the kernel to shut 
down the yenta_socket IRQ altogether.

My IRQ handler is dirt-stupid-simple at this point:
static irqreturn_t ss5136dn_isr(int irq, void *dev_id)
{
	ss5136dn_dev_t *dev = (ss5136dn_dev_t *)dev_id;
	u8 b;
	
	if(!dev)
		return IRQ_NONE;

	if (!(dev->p_dev->_locked))
		return IRQ_HANDLED;

	spin_lock(&dev->lock);

	b = inb(dev->portbase + BCR0);
	outb(b | 0x04, dev->portbase + BCR0);

	spin_unlock(&dev->lock);

	return IRQ_HANDLED;
}

(I have some printk()s in there I've removed, but that's really all I have in 
here.)

My _config() routine is pretty much ripped right out of one of the existing 
PCMCIA char drivers; it parses the tuples until it finds an IO region it can 
successfully request, and then requests the IRQ and finally a configuration 
lock.

The IRQ requesting part is what's causing the trouble:
	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
		link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED | 
IRQ_HANDLE_PRESENT;
		link->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
		link->irq.Handler     = ss5136dn_isr;
		link->irq.Instance    = dev;
		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
		dev->irq = link->irq.AssignedIRQ;
		}

	link->conf.IntType = INT_MEMORY_AND_IO;
	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, 
&link->conf));

	dev->portbase = link->io.BasePort1;	/* needed by ss5136dn_hwinit() */
	dev->memoffset = map.CardOffset;

	rc = ss5136dn_hwinit(dev);

Shortly after pcmcia_request_configuration() is called, I get a soft lockup.  
The backtrace indicates that I never get to my hardware init routine:

ss5136dn_cs: ss5136dn_config(0xc15b7000), dev @ 0xdf997980
BUG: soft lockup detected on CPU#0!
 [<c0141bb1>] softlockup_tick+0xa1/0xd0
 [<c01292c6>] update_process_times+0x76/0xb0
 [<c0106a78>] timer_interrupt+0x48/0xd0
 [<c0142365>] handle_IRQ_event+0x25/0x60
 [<c0143660>] handle_level_irq+0x90/0x130
 [<c0105863>] do_IRQ+0x53/0xa0
 [<c0103bda>] common_interrupt+0x1a/0x20
 [<c014235e>] handle_IRQ_event+0x1e/0x60
 [<c0143660>] handle_level_irq+0x90/0x130
 [<c0105863>] do_IRQ+0x53/0xa0
 [<c0103bda>] common_interrupt+0x1a/0x20
 [<c0124723>] __do_softirq+0x43/0xb0
 [<c01247bd>] do_softirq+0x2d/0x30
 [<c01247f7>] irq_exit+0x37/0x40
 [<c0105868>] do_IRQ+0x58/0xa0
 [<c0103bda>] common_interrupt+0x1a/0x20
 [<c0276004>] delay_tsc+0x14/0x20
 [<c0276046>] __delay+0x6/0x10
 [<e115b72b>] pcmcia_request_configuration+0x14b/0x3e0 [pcmcia]
 [<e115bbac>] pcmcia_request_irq+0xdc/0x120 [pcmcia]
 [<e12151a3>] ss5136dn_config+0x473/0x650 [ss5136dn_cs]
 [<c013882c>] clocksource_get_next+0x3c/0x70
 [<c01288f8>] change_clocksource+0x18/0x170
 [<c01288f8>] change_clocksource+0x18/0x170
 [<c012944b>] run_timer_softirq+0x13b/0x200
 [<c0124756>] __do_softirq+0x76/0xb0
 [<c0275393>] vsnprintf+0x2f3/0x560
 [<c011ffee>] release_console_sem+0xae/0x120
 [<c011fd28>] vprintk+0x1c8/0x2f0
 [<c011a471>] __activate_task+0x21/0x40
 [<c011a67a>] try_to_wake_up+0x4a/0xf0
 [<c013882c>] clocksource_get_next+0x3c/0x70
 [<c01288f8>] change_clocksource+0x18/0x170
 [<c011a471>] __activate_task+0x21/0x40
 [<c013882c>] clocksource_get_next+0x3c/0x70
 [<c01288f8>] change_clocksource+0x18/0x170
 [<c01288f8>] change_clocksource+0x18/0x170
 [<c012944b>] run_timer_softirq+0x13b/0x200
 [<c0124756>] __do_softirq+0x76/0xb0
 [<c0275393>] vsnprintf+0x2f3/0x560
 [<c011ffee>] release_console_sem+0xae/0x120
 [<c011fd28>] vprintk+0x1c8/0x2f0
 [<c011a471>] __activate_task+0x21/0x40
 [<c011a67a>] try_to_wake_up+0x4a/0xf0
 [<e1215437>] ss5136dn_probe+0x97/0xe0 [ss5136dn_cs]
 [<c02720df>] kobject_get+0xf/0x20
 [<e1159445>] pcmcia_device_probe+0xa5/0x170 [pcmcia]
 [<c02f9345>] really_probe+0xb5/0x110
 [<c02f9488>] driver_probe_device+0xc8/0xd0
 [<c03e7d39>] klist_next+0x69/0xe0
 [<c02f87aa>] bus_for_each_drv+0x3a/0x60
 [<c02f94ed>] device_attach+0x4d/0x70
 [<c02f9490>] __device_attach+0x0/0x10
 [<c02f8a26>] bus_attach_device+0x26/0x60
 [<c02f7203>] device_add+0x1a3/0x3f0
 [<e1159ad4>] pcmcia_device_add+0x1e4/0x290 [pcmcia]
 [<e1159c1a>] pcmcia_card_add+0x9a/0xc0 [pcmcia]
 [<c011fd28>] vprintk+0x1c8/0x2f0
 [<c02720df>] kobject_get+0xf/0x20
 [<e084e156>] pcmcia_get_socket+0x56/0xa0 [pcmcia_core]
 [<e115a7a8>] ds_event+0x68/0xb0 [pcmcia]
 [<e084e66e>] send_event+0x9e/0x140 [pcmcia_core]
 [<e084eb7c>] socket_insert+0xdc/0x170 [pcmcia_core]
 [<e084edc6>] socket_detect_change+0x56/0x70 [pcmcia_core]
 [<e084ef77>] pccardd+0x197/0x230 [pcmcia_core]
 [<c03e8391>] schedule+0x331/0x6a0
 [<c011b1f0>] default_wake_function+0x0/0x10
 [<c011b1f0>] default_wake_function+0x0/0x10
 [<e084ede0>] pccardd+0x0/0x230 [pcmcia_core]
 [<c0133d65>] kthread+0xa5/0xe0
 [<c0133cc0>] kthread+0x0/0xe0
 [<c0103d53>] kernel_thread_helper+0x7/0x14
 =======================
ss5136dn_cs: ss5136dn_shutdown(0xdf997980)<6>ss5136dn_cs: Card failed "are you 
there" test.
ss5136dn_cs: ss5136dn_shutdown(0xdf997980)<6>ss5136dn_cs: ss5136dn_reset 
returned failure code -1
ss5136dn_cs: ss5136dn_hwinit failed (-1)
ss5136dn_cs: ss5136dn_shutdown(0xdf997980)<7>ss5136dn_cs: 
ss5136dn_try_to_release(0xdf997980)
pccard: card ejected from slot 0

If I set link->irq.Handler to NULL and do not set the IRQ_HANDLE_PRESENT bit 
in link->irq.Attributes, I run into the situation where the kernel shuts down 
the IRQ altogether (thus killing any further development until I reboot since 
I can no longer see yenta interrupts for card insertion/removal).

I was using a NULL handler in the hopes of getting the IRQ set up, but unused, 
so I could call my hwinit() routine and then, after hwinit(), call 
pcmcia_modify_configuration with link->irq.Attributes |= IRQ_HANDLE_PRESENT 
and link->irq.Handler = ss5136dn_isr.  Unfortunately that didn't work.  :-)

I also tried IRQ_PULSE_ID, rationalizing that the PCMCIA subsystem is really 
ISA-based and ISA interrupts were all edge-triggered.  This didn't do 
anything useful, either.

Now digging through the 2.6.18 (http://lxr.linux.no doesn't have 2.6.19 up 
yet) kernel source and looking at the pcmcia_request_irq() routine, I see 
that so long as IRQ_HANDLE_PRESENT is set, my handler and my instance data 
should be correct.  However I get an interrupt before my hardware's even been 
configured, and since my dev structure isn't initialized, I can't clear the 
interrupt if it really is my card that's causing it (since no other handler 
seems to be claiming it).

Some of my earlier debugging in the interrupt handler showed that as soon as 
pcmcia_request_configuration() was called, my interrupt handler got hit, but 
the configuration was not locked yet.  I was returning IRQ_HANDLED though, so 
it should have been fine.  On a whim, I returned IRQ_NONE in that case (i.e. 
if (!(dev->p_dev->_locked))) and that promptly caused the kernel to shut down 
the IRQ line.  :-)  I also tried setting the IRQ flags for exclusive IRQ 
access, but I just got a runtime warning that it couldn't grant IRQ 
exclusivity and to update my driver.

This is all on a Compaq Evo N160 with a TI PCI1410 controller.  lspci -vvv 
output looks like this:
# lspci -vvv -s 2:06.0
02:06.0 CardBus bridge: Texas Instruments PCI1410 PC card Cardbus Controller 
(rev 01)
        Subsystem: Compaq Computer Corporation Unknown device b103
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR-
        Latency: 168, Cache Line Size: 32 bytes
        Interrupt: pin A routed to IRQ 10
        Region 0: Memory at d0202000 (32-bit, non-prefetchable) [size=4K]
        Bus: primary=02, secondary=03, subordinate=06, sec-latency=176
        Memory window 0: 30000000-31fff000 (prefetchable)
        Memory window 1: 34000000-35fff000
        I/O window 0: 00003400-000034ff
        I/O window 1: 00003800-000038ff
        BridgeCtl: Parity- SERR- ISA- VGA- MAbort- >Reset+ 16bInt- PostWrite+
        16-bit legacy interface ports at 0001

I'm not running any special kernel parameters for BIOS or APIC IRQ routing, 
it's all pretty stock.

Oh yeah -- I also tried to initialize my hardware BEFORE 
pcmcia_request_configuration() ran, to see if I could set up the hardware 
interrupts, clear any pending ones and THEN get the PCMCIA system to lock 
down the configuration, but (obviously, in hindsight) I couldn't access my 
card until the PCMCIA configuration was done.

Can anyone assist me?

Regards,
Andrew



More information about the linux-pcmcia mailing list