Big Fix for 2.2.1

Leonard N. Zubkoff (lnz@dandelion.com)
Tue, 26 Jan 1999 10:17:56 -0800 (PST)


Linus,

The following patch corrects problems with the I/O access and virtual/bus
translation macros in "linux/include/asm-i386/io.h". Specifically, the default
value of PAGE_OFFSET hides the underlying problems that kernels built with
PAGE_OFFSET values such as 0x7000000 as mentioned in page.h will fail due to
two errors:

(1) The identity phys_to_virt(virt_to_phys(x)) == x is violated.

(2) The readb/writeb/readw/writew/readl/writel macros are completely incorrect
since they are supposed to be applied to memory mapped I/O regions
allocated with ioremap, but ioremap returns a kernel virtual address
and hence no further mapping is appropriate.

The BusLogic driver ran into (1) and the DAC960 driver ran into (2). With the
patch enclosed below, both drivers work fine when PAGE_OFFSET is changed. The
change to traps.c is also necessary as readl was incorrect usage, even though
the modified code is now uglier. If this construct is actually needed often
enough to warrant it, we should create macros such as readl_phys.

Leonard

--- linux/include/asm-i386/io.h- Tue Jan 26 00:14:21 1999
+++ linux/include/asm-i386/io.h Tue Jan 26 01:39:55 1999
@@ -101,8 +101,8 @@
#include <linux/vmalloc.h>
#include <asm/page.h>

-#define __io_virt(x) ((void *)(PAGE_OFFSET | (unsigned long)(x)))
-#define __io_phys(x) ((unsigned long)(x) & ~PAGE_OFFSET)
+#define __io_virt(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __io_phys(x) ((unsigned long)(x) - PAGE_OFFSET)
/*
* Change virtual addresses to physical addresses and vv.
* These are pretty trivial
@@ -149,23 +149,23 @@
* memory location directly.
*/

-#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
-#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
-#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
-
-#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
-
-#define memset_io(a,b,c) memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c) memcpy(__io_virt(a),(b),(c))
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+
+#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
+
+#define memset_io(a,b,c) memset((a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(b),(c))
+#define memcpy_toio(a,b,c) memcpy((a),(b),(c))

/*
* Again, i386 does not require mem IO specific function.
*/

-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(b),(c),(d))

static inline int check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
--- linux/arch/i386/kernel/traps.c- Wed Jan 20 10:18:53 1999
+++ linux/arch/i386/kernel/traps.c Tue Jan 26 10:01:37 1999
@@ -672,7 +672,8 @@
/* Initially up all of the IDT to jump to unexpected */
init_unexpected_irq();

- if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
+ if (*(unsigned int *)(phys_to_virt(0x0FFFD9))
+ == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
set_call_gate(&default_ldt,lcall7);
set_trap_gate(0,&divide_error);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/