lkml.org 
[lkml]   [1998]   [Jan]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectThe floppy driver and its DMA allocation problems
Date
From

The patch at the end of the mail switches the floppy driver in DMA
less mode on boxes with more than 16 MB of memory.

Background:
-----------
On boxes with more than 16 Megs of Ram it often happens that DMA
allocations fails. This is because only memory below the 16 MB
barrier is suitable for DMA. In a situation where there is still
plenty of memory available above 16MB, but not below, the memory
management code exhibits the following paradoxical behavior:
1. In a first step, it fails to try to free up pages (by tossing out
buffers, or by swapping) because there is still plenty of memory (only
not of the right kind ...)
2. In a second step it returns an out-of-memory condition because no
free page could have been found.

Similar problems can happen if the memory is too fragmented.

Because of this, the floppy driver (and also the sound driver) often
fail with "Unable to allocate DMA memory\n".

The workaround:
---------------

Unfortunately, the real problem, which has been known for quite a
while, is rather hard to fix. But fortunately, there is a work-around:

Since the late 1.1 days, the floppy driver has a "nodma" flag
documented in linux/drivers/block/README.fd which switches the floppy
driver into a DMA-less mode, where it does need memory below the 16M
mark. However, as apparently not many people read the docs any more,
I've now chosen to automatically switch the floppy driver into the
DMA-less mode if the following conditions are met:

1. The floppy controller has a FIFO (needed for DMA-less mode. Most
of today's floppy controllers do have a FIFO).
2. There is more than 16MB memory in the box (with less the problem
usually does not occur).

The user can still explicitely request DMA mode with the "yesdma"
flag.

Regards,

Alain

diff -ur 2.1.78/linux/drivers/block/README.fd linux/drivers/block/README.fd
--- 2.1.78/linux/drivers/block/README.fd Tue Nov 18 00:13:48 1997
+++ linux/drivers/block/README.fd Tue Jan 6 23:23:31 1998
@@ -85,16 +85,20 @@
This is needed on HP Omnibooks, which don't have a workable
DMA channel for the floppy driver. This option is also useful
if you frequently get "Unable to allocate DMA memory" messages.
- Indeed, dma memory needs to be continuous in physical, and is
- thus harder to find, whereas non-dma buffers may be allocated
- in virtual memory. However, I advise against this if you have
- an FDC without a FIFO (8272A or 82072). 82072A and later are
- OK. You also need at least a 486 to use nodma.
+ Indeed, dma memory needs to be continuous in physical memory,
+ and is thus harder to find, whereas non-dma buffers may be
+ allocated in virtual memory. However, I advise against this if
+ you have an FDC without a FIFO (8272A or 82072). 82072A and
+ later are OK). You also need at least a 486 to use nodma.
If you use nodma mode, I suggest you also set the FIFO
threshold to 10 or lower, in order to limit the number of data
transfer interrupts.
-
- floppy=dma
+ If you have more than 16 Megabytes of memory and a FIFO-able
+ FDC, the floppy driver automatically choses nodma mode in
+ order to work around a bug in memory management. If you want
+ to avoid this, explicitely ask for 'yesdma'.
+
+ floppy=yesdma
Tells the floppy driver that a workable DMA channel is available
(the default).

diff -ur 2.1.78/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- 2.1.78/linux/drivers/block/floppy.c Tue Jan 6 19:07:27 1998
+++ linux/drivers/block/floppy.c Tue Jan 6 23:20:16 1998
@@ -148,7 +148,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>

-static int use_virtual_dma=0; /* virtual DMA for Intel */
+static int use_virtual_dma=2; /* virtual DMA for Intel */
static unsigned short virtual_dma_port=0x3f0;
void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int set_dor(int fdc, char mask, char data);
@@ -3888,7 +3888,7 @@

{ "nodma", 0, &use_virtual_dma, 1, 0 },
{ "omnibook", 0, &use_virtual_dma, 1, 0 },
- { "dma", 0, &use_virtual_dma, 0, 0 },
+ { "yesdma", 0, &use_virtual_dma, 0, 0 },

{ "fifo_depth", 0, &fifo_depth, 0xa, 0 },
{ "nofifo", 0, &no_fifo, 0x20, 0 },
@@ -3936,6 +3936,7 @@
}

static int have_no_fdc= -EIO;
+static int all_fdcs_have_fifo = 1;

__initfunc(int floppy_init(void))
{
@@ -4017,6 +4018,8 @@
FDCS->address = -1;
continue;
}
+ if(FDCS->version < FDC_82072A)
+ all_fdcs_have_fifo = 0;

have_no_fdc = 0;
/* Not all FDCs seem to be able to handle the version command
@@ -4032,7 +4035,16 @@
initialising=0;
if (have_no_fdc) {
DPRINT("no floppy controllers found\n");
- unregister_blkdev(MAJOR_NR,"fd");
+ unregister_blkdev(MAJOR_NR,"fd");
+#ifdef AUTO_DMA
+ } else if(all_fdcs_have_fifo &&
+ use_virtual_dma == 2 &&
+ num_physpages > 0x1000) {
+ /* if we are on an Intel, we have a FIFO capable FDC, and
+ * we have too much memory, enable virtual DMA in order to
+ * work around a long standing bug in memory management */
+ use_virtual_dma = 1;
+#endif
}
return have_no_fdc;
}
diff -ur 2.1.78/linux/include/asm-i386/floppy.h linux/include/asm-i386/floppy.h
--- 2.1.78/linux/include/asm-i386/floppy.h Tue Jan 6 19:25:45 1998
+++ linux/include/asm-i386/floppy.h Tue Jan 6 23:02:45 1998
@@ -152,7 +152,7 @@
{
doing_pdma = 0;
virtual_dma_residue += virtual_dma_count;
- virtual_dma_count=0;
+ virtual_dma_count=0;
}

static int vdma_request_dma(unsigned int dmanr, const char * device_id)
@@ -221,6 +221,23 @@
return vfree((void *)addr);
}

+static int have_dma = 0;
+
+static int fd__request_dma(unsigned int dmanr, const char * device_id)
+{
+ have_dma = 1;
+ return request_dma(dmanr, device_id);
+}
+
+
+static void fd__free_dma(unsigned int dmanr)
+{
+ if(have_dma) {
+ have_dma = 0;
+ free_dma(dmanr);
+ }
+}
+
struct fd_routine_l {
void (*_enable_dma)(unsigned int dummy);
void (*_disable_dma)(unsigned int dummy);
@@ -242,8 +259,8 @@
{
enable_dma,
disable_dma,
- request_dma,
- free_dma,
+ fd__request_dma,
+ fd__free_dma,
clear_dma_ff,
set_dma_mode,
hset_dma_addr,
@@ -257,7 +274,7 @@
vdma_enable_dma,
vdma_disable_dma,
vdma_request_dma,
- vdma_nop,
+ fd__free_dma,
vdma_nop,
vdma_set_dma_mode,
vdma_set_dma_addr,
@@ -269,10 +286,6 @@
}
};

-__inline__ void virtual_dma_init(void)
-{
- /* Nothing to do on an i386 */
-}

static int FDC1 = 0x3f0;
static int FDC2 = -1;
@@ -284,6 +297,8 @@
#define N_DRIVE 8

#define FLOPPY_MOTOR_MASK 0xf0
+
+#define AUTO_DMA

/*
* The DMA channel used by the floppy controller cannot access data at
\
 
 \ /
  Last update: 2005-03-22 13:41    [W:0.043 / U:0.284 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site