>>List: linux-kernel
>>Subject: 2.5.66-bk5 spinlock warnings/errors
>From: Narayan Desai <desai () mcs ! anl ! gov>
>>Date: 2003-04-02 4:01:02
>>hda: dma_timer_expiry: dma status == 0x24
>>drivers/ide/ide-io.c:109: spin_lock(drivers/ide/ide.c:c037abe8) already
>>locked by drivers/ide/ide-io.c/948 drivers/ide/ide-io.c:990:
>>spin_unlock(drivers/ide/ide.c:c037abe8) not locked
>>hda: lost interrupt
>>hda: dma_intr: bad DMA status (dma_stat=30)
>>hda: dma_intr: status=0x50 { DriveReady SeekComplete }
>I had this problem last night while making a huge debian package (tar.bz2
>stage). It occured once.
The attached patch should fix the problem:
the dma_timer_expiry handler calls HWGROUP(drive)->handler in the wrong
context. Instead of calling ->handler directly, the ->expiry handler
must inform the caller that ->handler must be called, and then the
caller must do some setup before calling ->handler.
--
Manfred
[
patch-ide-expiry 1K ]
// $Header$
// Kernel Version:
// VERSION = 2
// PATCHLEVEL = 5
// SUBLEVEL = 66
// EXTRAVERSION =
--- 2.5/include/linux/ide.h 2003-03-25 17:49:52.000000000 +0100
typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
typedef int (ide_expiry_t)(ide_drive_t *);
+#define EXPIRY_ABORT (0)
+#define EXPIRY_CALLHANDLER (-1)
typedef struct hwgroup_s {
/* irq handler, if active */
--- 2.5/drivers/ide/ide-io.c 2003-03-25 17:49:40.000000000 +0100
}
if ((expiry = hwgroup->expiry) != NULL) {
/* continue */
- if ((wait = expiry(drive)) != 0) {
+ if ((wait = expiry(drive)) > 0) {
/* reset timer */
hwgroup->timer.expires = jiffies + wait;
/* local CPU only,
* as if we were handling an interrupt */
local_irq_disable();
- if (hwgroup->poll_timeout != 0) {
+ if (hwgroup->poll_timeout != 0 || wait == EXPIRY_CALLHANDLER) {
startstop = handler(drive);
} else if (drive_is_ready(drive)) {
if (drive->waiting_for_dma)
--- 2.5/drivers/ide/ide-dma.c 2003-03-25 17:49:40.000000000 +0100
return WAIT_CMD;
if (dma_stat & 4) /* Got an Interrupt */
- HWGROUP(drive)->handler(drive);
+ return EXPIRY_CALLHANDLER;
- return 0;
+ return EXPIRY_ABORT;
}
/**