[PATCH] ide: trying to enable DMA may cause an oops

Linux Kernel Mailing List <[email protected]> Fri, 12 May 2006 18:59:49 GMT
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
commit 4abe1e2e6091d1f91fa68f7094cc44fe5c7e90c3
tree 91d11958c082096c4abe151c46cef3ff5cd1abb9
parent 78344504ec280716131d118cd488e84993f84fa3
author Willy TARREAU <willy@pcw.(none)> Sun, 07 May 2006 23:48:50 +0200
committer Willy TARREAU <willy@pcw.(none)> Sun, 07 May 2006 23:48:50 +0200

[PATCH] ide: trying to enable DMA may cause an oops

If DMA is disabled on the interface at boot time, then later calling
config_drive_for_dma() to try to enable it will cause an oops because
hwif->ide_dma_off_quietly will be NULL. The workaround is to make those
*ide_dma* functions point to a dummy one when DMA is disabled.

Originally reported by Glenn Wurster, and been running on my systems since
2.4.23.

Signed-off-by: Willy Tarreau <[email protected]>

- Willy

 drivers/ide/ide-dma.c   |   29 +++++++++++++++++++++++++++++
 drivers/ide/setup-pci.c |    1 +
 include/linux/ide.h     |    2 ++
 3 files changed, 32 insertions(+)

diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 7f408ea..9431392 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -567,6 +567,18 @@ static int dma_timer_expiry (ide_drive_t
 }
 
 /**
+ *	__ide_dma_no_op	- dummy DMA function.
+ *
+ *	This empty function prevents non-DMA controllers from causing an oops.
+ */
+
+int __ide_dma_no_op (void)
+{
+	return 0;
+}
+
+
+/**
  *	__ide_dma_host_off	-	Generic DMA kill
  *	@drive: drive to control
  *
@@ -1215,3 +1227,20 @@ void ide_setup_dma (ide_hwif_t *hwif, un
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);
+
+/*
+ * For IDE interfaces that do not support DMA, we still need to
+ * initialize some pointers to dummy functions.
+ */
+void ide_setup_no_dma (ide_hwif_t *hwif)
+{
+	if (!hwif->ide_dma_off_quietly)
+		hwif->ide_dma_off_quietly = (int (*)(ide_drive_t *))&__ide_dma_no_op;
+	if (!hwif->ide_dma_host_off)
+		hwif->ide_dma_host_off = (int (*)(ide_drive_t *))&__ide_dma_no_op;
+	if (!hwif->ide_dma_host_on)
+		hwif->ide_dma_host_on = (int (*)(ide_drive_t *))&__ide_dma_no_op;
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_no_dma);
+
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 5c14475..3ba9c82 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -507,6 +507,7 @@ static void ide_hwif_setup_dma(struct pc
 		} else {
 			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
 				"(BIOS)\n", hwif->name, d->name);
+			ide_setup_no_dma(hwif);
 		}
 	}
 }
diff --git a/include/linux/ide.h b/include/linux/ide.h
index f890c49..ed7db20 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -1691,6 +1691,7 @@ extern void ide_destroy_dmatable(ide_dri
 extern ide_startstop_t ide_dma_intr(ide_drive_t *);
 extern int ide_release_dma(ide_hwif_t *);
 extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+extern void ide_setup_no_dma(ide_hwif_t *);
 
 extern int __ide_dma_host_off(ide_drive_t *);
 extern int __ide_dma_off_quietly(ide_drive_t *);
@@ -1713,6 +1714,7 @@ extern int __ide_dma_timeout(ide_drive_t
 #else
 static inline void ide_setup_dma(ide_hwif_t *x, unsigned long y, unsigned int z) {;}
 static inline void ide_release_dma(ide_hwif_t *x) {;}
+static inline void ide_setup_no_dma(ide_hwif_t *x) {;}
 #endif
 
 extern void hwif_unregister(ide_hwif_t *);