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