Messages in this thread | | | Date | Sun, 31 Oct 2010 19:04:49 +0100 | From | angelo <> | Subject | Re: help, BUG: spinlock recursion on CPU#0, httpd/29 |
| |
On 31/10/2010 18:29, Greg Oliver wrote: > On Sun, Oct 31, 2010 at 12:27 PM, _angelo<angelo70@gmail.com> wrote: > >> hi all, >> i don't know if this is the right forum, but i don't see other appropriate >> kernel forums actually >> >> starting from a main line kernel 2.6.36-rc3, i am trying to interface a >> coldfire mcf5307 to a dm9000 ethernet chip in a little custom board. I did >> some small changes to the dm9000.c driver, since it was for little-endian >> cpus. Now it is mostly working, icmp ping and telnet are working fine. >> The only issue happen when i use http, through a browser i try to read the >> board html testpage: first load (GET) works, then refreshing 2 or 3 times, >> kernel goes into following error: >> >> # BUG: recent printk recursion! >> <7>dm9000 dm9000: entering dm9000_interrupt >> BUG: spinlock recursion on CPU#0, httpd/29 >> lock: 00177648, .magic: dead4ead, .owner: httpd/29, .owner_cpu: 0 >> Stack from 00e559b4: >> 0014f790 000a7d6c 00169918 00177648 dead4ead 00e26594 0000001d >> 00000000 >> 00177648 000288d4 0014f79e 000a7f2e 00177648 0016997e 00177648 >> 00e55acc >> 0000001f 00000000 0000010a 0017760c 000288d4 0014f79e 00029d90 >> 0014f7a8 >> 00177648 000289ec 00177648 0000001f 00e55acc 0000001f 0017760c >> 000288d4 >> 0014f79e 00029d90 0014f790 00000b96 0000001f 00177648 00dbe5b0 >> 000032e2 >> 0000001f 00e55a5c 00000001 00177648 00dbe5b0 0000001f 00000000 >> 00e55000 >> Call Trace with CONFIG_FRAME_POINTER disabled: >> [0014f790] [000a7d6c] [00169918] [000288d4] [0014f79e] >> [000a7f2e] [0016997e] [000288d4] [0014f79e] [00029d90] >> [0014f7a8] [000289ec] [000288d4] [0014f79e] [00029d90] >> [0014f790] [00000b96] [000032e2] [00028a6a] [0014f790] >> [0014f79e] [00000b96] [000032e2] [0014f790] [000a7fda] >> [0014f790] [0014f79e] [0014f7a8] [00109d94] [000fceb0] >> [00103a2c] [000a4510] [00117300] [00117a40] [00004000] >> [0011757e] [00118538] [000005a8] [00001ad0] [0014ce8e] >> [0012ce2a] [00007f67] [00001ad0] [0012dd82] [0012923c] >> [000005a8] [000005a8] [00002d80] [00030200] [0012a4b8] >> [0014f790] [00008b06] [00004124] [00128a4e] [0012abae] >> [000005a8] [00128048] [000005a8] [0014de4a] [00004124] >> [0012dca8] [0014de4a] [00004124] [0016fae3] [0014f79e] >> [000ee208] [0011f72a] [00002860] [000005a8] [000005a8] >> [00002860] [000005a8] [0013aad2] [00002860] [000eb4e4] >> [00002860] [0004260a] [00002860] [0004293c] [00042df6] >> [0001ffff] [00002860] [00002860] [000125fa] [00002860] >> [00042a10] [00002860] [00042e36] [00002860] [0000318c] >> [00002860] >> BUG: spinlock lockup on CPU#0, httpd/29, 00177648 >> ... >> >> Actually, from some debugging, the issue seems triggered from the >> dm9000_interrupt routine: >> >> static irqreturn_t dm9000_interrupt(int irq, void *dev_id) >> { >> struct net_device *dev = dev_id; >> board_info_t *db = netdev_priv(dev); >> int int_status; >> unsigned long flags; >> u8 reg_save; >> >> /* A real interrupt coming */ >> >> /* holders of db->lock must always block IRQs */ >> spin_lock_irqsave(&db->lock, flags); >> >> dm9000_dbg(db, 3, "entering %s\n", __func__); >> >> /* Save previous register address */ >> #ifdef BE_STRAIGHT_WIRED >> reg_save = (u8)readl(db->io_addr); >> #else >> reg_save = readb(db->io_addr); >> #endif >> >> /* Disable all interrupts */ >> iow(db, DM9000_IMR, IMR_PAR); >> >> /* Got DM9000 interrupt status */ >> int_status = ior(db, DM9000_ISR); /* Got ISR */ >> iow(db, DM9000_ISR, int_status); /* Clear ISR status */ >> >> if (netif_msg_intr(db)) >> dev_dbg(db->dev, "interrupt status %02x\n", int_status); >> >> /* Received the coming packet */ >> if (int_status& ISR_PRS) >> dm9000_rx(dev); >> >> /* Trnasmit Interrupt check */ >> if (int_status& ISR_PTS) >> dm9000_tx_done(dev, db); >> >> if (db->type != TYPE_DM9000E) { >> if (int_status& ISR_LNKCHNG) { >> /* fire a link-change request */ >> schedule_delayed_work(&db->phy_poll, 1); >> } >> } >> >> /* Re-enable interrupt mask */ >> iow(db, DM9000_IMR, db->imr_all); >> >> /* Restore previous register address */ >> #ifdef BE_STRAIGHT_WIRED >> writel(reg_save, db->io_addr); >> #else >> writeb(reg_save, db->io_addr); >> #endif >> >> spin_unlock_irqrestore(&db->lock, flags); >> >> return IRQ_HANDLED; >> } >> >> >> I really don't have the kernel experience to get out of this issue, so i >> hope in some help or suggestion >> >> many thanks >> regards, >> angelo >> >> >> -- >> View this message in context:http://old.nabble.com/help%2C-BUG%3A-spinlock-recursion-on-CPU-0%2C-httpd-29-tp30099327p30099327.html >> Sent from the linux-kernel mailing list archive at Nabble.com. >> > I would assume posting your *modifications* would be the first step.... > Hi greg,
thanks for the reply,
i changed/added only some routines, due to the fact that i wired all the 32 bit bus of the ethernet chip straight to the CPU. But since the driver is for little-endian CPUs, all the data transfer was not working, So, just for testing this prototype board (i can wire the HW bus byte-swapped in a future prototype), i reworked some functions as below:
static void iow(board_info_t * db, int reg, int value) { #ifdef BE_STRAIGHT_WIRED writel(reg, db->io_addr); writel(value, db->io_data); #else writeb(reg, db->io_addr); writeb(value, db->io_data); #endif }
/* routines for sending block to chip */
static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) { #ifdef CONFIG_COLDFIRE u8 *p=(u8 *)data;
while (count--) #ifdef BE_STRAIGHT_WIRED writel((int)(*p++), reg); #else writeb(*p++, reg); #endif #else writesb(reg, data, count); #endif }
static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) { #ifdef CONFIG_COLDFIRE // TO DO #else writesw(reg, data, (count+1) >> 1); #endif }
static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) { #ifdef CONFIG_COLDFIRE u32 *p = (u32*)data;
count = (count+3)>>2;
while (count--) #ifdef BE_STRAIGHT_WIRED writel(le32_to_cpu(*p++), reg); #else writel(*p++, reg); #endif #else writesl(reg, data, (count+3) >> 2); #endif }
and still, some ioread, as below, here and there were needed.
#ifdef BE_STRAIGHT_WIRED reg_save = (u8)readl(db->io_addr); #else reg_save = readb(db->io_addr); #endif
#ifdef BE_STRAIGHT_WIRED writel(reg_save, db->io_addr); #else writeb(reg_save, db->io_addr); #endif
I defined BE_STRAIGHT_WIRED only for testing this prototype, otherwise the driver should work as is.
I didn't change anything else, to avoid damaging the well working dm9000.c driver,
thanks angelo
| |