Commit 5a74db06 authored by Philippe De Muyter's avatar Philippe De Muyter Committed by Linus Torvalds

floppy: request and release only the ports we actually use

The floppy driver requests an I/O port it doesn't need, and sometimes this
causes a conflict with a motherboard device reported by PNPBIOS.

This patch makes the floppy driver request and release only the ports it
actually uses.  It also factors out the request/release stuff and the
io-ports list so they're all in one place now.

The current floppy driver uses only these ports:

    0x3f2 (FD_DOR)
    0x3f4 (FD_STATUS)
    0x3f5 (FD_DATA)
    0x3f7 (FD_DCR/FD_DIR)

but it requests 0x3f2-0x3f5 and 0x3f7, which includes the unused port
0x3f3.

Some BIOSes report 0x3f3 as a motherboard resource.  The PNP system driver
reserves that, which causes a conflict when the floppy driver requests
0x3f2-0x3f5 later.

Philippe reported that this conflict broke the floppy driver between
2.6.11 and 2.6.22.  His PNPBIOS reports these devices:

    $ cat 00:07/id 00:07/resources	# motherboard device
    PNP0c02
    state = active
    io 0x80-0x80
    io 0x10-0x1f
    io 0x22-0x3f
    io 0x44-0x5f
    io 0x90-0x9f
    io 0xa2-0xbf
    io 0x3f0-0x3f1
    io 0x3f3-0x3f3

    $ cat 00:03/id 00:03/resources	# floppy device
    PNP0700
    state = active
    io 0x3f4-0x3f5
    io 0x3f2-0x3f2

Reference:
    http://lkml.org/lkml/2009/1/31/162Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarPhilippe De Muyter <phdm@macqel.be>
Reported-by: default avatarPhilippe De Muyter <phdm@macqel.be>
Tested-by: default avatarPhilippe De Muyter <phdm@macqel.be>
Cc: Adam M Belay <abelay@mit.edu>
Cc: Robert Hancock <hancockrwd@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ffa7525c
...@@ -558,6 +558,8 @@ static void process_fd_request(void); ...@@ -558,6 +558,8 @@ static void process_fd_request(void);
static void recalibrate_floppy(void); static void recalibrate_floppy(void);
static void floppy_shutdown(unsigned long); static void floppy_shutdown(unsigned long);
static int floppy_request_regions(int);
static void floppy_release_regions(int);
static int floppy_grab_irq_and_dma(void); static int floppy_grab_irq_and_dma(void);
static void floppy_release_irq_and_dma(void); static void floppy_release_irq_and_dma(void);
...@@ -4274,8 +4276,7 @@ static int __init floppy_init(void) ...@@ -4274,8 +4276,7 @@ static int __init floppy_init(void)
FDCS->rawcmd = 2; FDCS->rawcmd = 2;
if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) { if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
/* free ioports reserved by floppy_grab_irq_and_dma() */ /* free ioports reserved by floppy_grab_irq_and_dma() */
release_region(FDCS->address + 2, 4); floppy_release_regions(fdc);
release_region(FDCS->address + 7, 1);
FDCS->address = -1; FDCS->address = -1;
FDCS->version = FDC_NONE; FDCS->version = FDC_NONE;
continue; continue;
...@@ -4284,8 +4285,7 @@ static int __init floppy_init(void) ...@@ -4284,8 +4285,7 @@ static int __init floppy_init(void)
FDCS->version = get_fdc_version(); FDCS->version = get_fdc_version();
if (FDCS->version == FDC_NONE) { if (FDCS->version == FDC_NONE) {
/* free ioports reserved by floppy_grab_irq_and_dma() */ /* free ioports reserved by floppy_grab_irq_and_dma() */
release_region(FDCS->address + 2, 4); floppy_release_regions(fdc);
release_region(FDCS->address + 7, 1);
FDCS->address = -1; FDCS->address = -1;
continue; continue;
} }
...@@ -4358,6 +4358,47 @@ static int __init floppy_init(void) ...@@ -4358,6 +4358,47 @@ static int __init floppy_init(void)
static DEFINE_SPINLOCK(floppy_usage_lock); static DEFINE_SPINLOCK(floppy_usage_lock);
static const struct io_region {
int offset;
int size;
} io_regions[] = {
{ 2, 1 },
/* address + 3 is sometimes reserved by pnp bios for motherboard */
{ 4, 2 },
/* address + 6 is reserved, and may be taken by IDE.
* Unfortunately, Adaptec doesn't know this :-(, */
{ 7, 1 },
};
static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
{
while (p != io_regions) {
p--;
release_region(FDCS->address + p->offset, p->size);
}
}
#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
static int floppy_request_regions(int fdc)
{
const struct io_region *p;
for (p = io_regions; p < ARRAY_END(io_regions); p++) {
if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
floppy_release_allocated_regions(fdc, p);
return -EBUSY;
}
}
return 0;
}
static void floppy_release_regions(int fdc)
{
floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
}
static int floppy_grab_irq_and_dma(void) static int floppy_grab_irq_and_dma(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -4399,18 +4440,8 @@ static int floppy_grab_irq_and_dma(void) ...@@ -4399,18 +4440,8 @@ static int floppy_grab_irq_and_dma(void)
for (fdc = 0; fdc < N_FDC; fdc++) { for (fdc = 0; fdc < N_FDC; fdc++) {
if (FDCS->address != -1) { if (FDCS->address != -1) {
if (!request_region(FDCS->address + 2, 4, "floppy")) { if (floppy_request_regions(fdc))
DPRINT("Floppy io-port 0x%04lx in use\n", goto cleanup;
FDCS->address + 2);
goto cleanup1;
}
if (!request_region(FDCS->address + 7, 1, "floppy DIR")) {
DPRINT("Floppy io-port 0x%04lx in use\n",
FDCS->address + 7);
goto cleanup2;
}
/* address + 6 is reserved, and may be taken by IDE.
* Unfortunately, Adaptec doesn't know this :-(, */
} }
} }
for (fdc = 0; fdc < N_FDC; fdc++) { for (fdc = 0; fdc < N_FDC; fdc++) {
...@@ -4432,15 +4463,11 @@ static int floppy_grab_irq_and_dma(void) ...@@ -4432,15 +4463,11 @@ static int floppy_grab_irq_and_dma(void)
fdc = 0; fdc = 0;
irqdma_allocated = 1; irqdma_allocated = 1;
return 0; return 0;
cleanup2: cleanup:
release_region(FDCS->address + 2, 4);
cleanup1:
fd_free_irq(); fd_free_irq();
fd_free_dma(); fd_free_dma();
while (--fdc >= 0) { while (--fdc >= 0)
release_region(FDCS->address + 2, 4); floppy_release_regions(fdc);
release_region(FDCS->address + 7, 1);
}
spin_lock_irqsave(&floppy_usage_lock, flags); spin_lock_irqsave(&floppy_usage_lock, flags);
usage_count--; usage_count--;
spin_unlock_irqrestore(&floppy_usage_lock, flags); spin_unlock_irqrestore(&floppy_usage_lock, flags);
...@@ -4501,10 +4528,8 @@ static void floppy_release_irq_and_dma(void) ...@@ -4501,10 +4528,8 @@ static void floppy_release_irq_and_dma(void)
#endif #endif
old_fdc = fdc; old_fdc = fdc;
for (fdc = 0; fdc < N_FDC; fdc++) for (fdc = 0; fdc < N_FDC; fdc++)
if (FDCS->address != -1) { if (FDCS->address != -1)
release_region(FDCS->address + 2, 4); floppy_release_regions(fdc);
release_region(FDCS->address + 7, 1);
}
fdc = old_fdc; fdc = old_fdc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment