The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


disable_dma() locks my motherboard... another hw bug!


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
X-RDate: Thu, 26 Feb 1998 14:24:30 +0500 (ESK)
Date: Thu, 26 Feb 1998 01:10:15 +0100
From: Andrea Arcangeli <[email protected]>
To: [email protected]
Subject: disable_dma() locks my motherboard... another hw bug!

After discovered the powerbug I replaced my old buggy motherboard with a
Epox P55VP3. Then, after a few days, I noticed that running my
soundblaster dsp with Linux 2.1.8x during high disk activities, my machine
locked. The machine was so locked that the poweroff/on button no longer
worked, I was forced to reset...

Frustrated I began to debug the kernel and after a few night (with the
help of the _great_ tracer Ingo Molnar patch that print directly on the
video ram the executing function's address during all the kernel life
time) I discovered that the computer was locking on the disable_dma() call
recalled by the soundblaster interrupt routine precisely on the underlined
line (taken from Linux kernel 2.1.88 in the file
linux/include/asm-i386/dma.h):

#define dma_outb        outb
#define DMA2_MASK_REG           0xD4    /* single-channel mask (w) */
static __inline__ void disable_dma(unsigned int dmanr)
{
        if (dmanr<=3)
                dma_outb(dmanr | 4,  DMA1_MASK_REG);
        else
                dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

I suppose the lock is due to frequently recalling of disable_dma() /
enable_dma() in cycle. The code that was recalling disable_dma() in the
interrupt handler is here (taken from Linux 2.1.88
linux/drivers/sound/dmabuf.c):

                clear_dma_ff(chan);
                disable_dma(dmap->dma);
                ^^^^^^^^^^^^^^^^^^^^^^^ here the motherboard locks.
                pos = dmap->bytes_in_use - get_dma_residue(chan);
                enable_dma(dmap->dma);

I simply removed the offending function by the sound drivers and now
all works fine even if it remains a serious bug. Here the patch to get rid
of the dma_disable() bug against 2.1.88:

--- linux/drivers/sound/dmabuf.c        Thu Feb 26 00:38:50 1998
+++ /usr/src/linux/drivers/sound/dmabuf.c       Mon Feb 23 00:26:16 1998
@@ -19,6 +19,13 @@
  *                   an explicit wake_up. current->timeout can be used instead;
  *                   if 0, the wakeup was due to the timeout.
  */
+
+/*
+ * Removed fast disable_dma()/enable_dma() cycles in order to avoid
+ * kernel locks on some motherboards.
+ *                             Andrea Arcangeli <[email protected]>
+ */
+
 #include <linux/config.h>

 #define BE_CONSERVATIVE
@@ -613,7 +620,6 @@
        else {
                int chan = dmap->dma;
                clear_dma_ff(chan);
-               disable_dma(dmap->dma);
                pos = get_dma_residue(chan);
                pos = dmap->bytes_in_use - pos;

@@ -633,7 +639,6 @@
                        pos = 0;
                if (pos >= dmap->bytes_in_use)
                        pos = 0;
-               enable_dma(dmap->dma);
        }
        restore_flags(flags);
        /* printk( "%04x ",  pos); */
@@ -988,9 +993,7 @@
        if (!(dmap->flags & DMA_NODMA)) {
                int chan = dmap->dma, pos, n;
                clear_dma_ff(chan);
-               disable_dma(dmap->dma);
                pos = dmap->bytes_in_use - get_dma_residue(chan);
-               enable_dma(dmap->dma);
                pos = pos / dmap->fragment_size;        /* Actual qhead */
                if (pos < 0 || pos >= dmap->nbufs)
                        pos = 0;
@@ -1078,9 +1081,7 @@
        if (!(dmap->flags & DMA_NODMA)) {
                int chan = dmap->dma, pos, n;
                clear_dma_ff(chan);
-               disable_dma(dmap->dma);
                pos = dmap->bytes_in_use - get_dma_residue(chan);
-               enable_dma(dmap->dma);

                pos = pos / dmap->fragment_size;        /* Actual qhead */
                if (pos < 0 || pos >= dmap->nbufs)


I also developed a DOS program in order to show the bug also to my
reseller (that said me that he don' t support linux but support DOS ;-)
but I don't know if I am allowed to publish it since it is a patched
version of a program called DELAY2.C (it' s an example of full-duplex
programming with sb16) that I downloaded some time ago from the Creative
web site. Maybe I could publish the patch against the original version on
the Creative web site?

For now if you want to know if your motherboard is buggy you need to run
your soundblaster16/32/64 (better at 44100khz in stereo in order to
increase the interrupt frequency too) with 2.1.8x and run a `cp /dev/hda
/dev/null` at the same time. BTW, on 2.0.x the sound drivers don' t lock
the machine (and so don' t show the bug) because they are very less
smarter than the new one in 2.1.x kernel series.

Andrea[s] Arcangeli

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру