diff options
Diffstat (limited to 'arch/m68k/mm/hwtest.c')
-rw-r--r-- | arch/m68k/mm/hwtest.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/arch/m68k/mm/hwtest.c b/arch/m68k/mm/hwtest.c new file mode 100644 index 000000000000..2c7dde3c6430 --- /dev/null +++ b/arch/m68k/mm/hwtest.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* Tests for presence or absence of hardware registers. | ||
2 | * This code was originally in atari/config.c, but I noticed | ||
3 | * that it was also in drivers/nubus/nubus.c and I wanted to | ||
4 | * use it in hp300/config.c, so it seemed sensible to pull it | ||
5 | * out into its own file. | ||
6 | * | ||
7 | * The test is for use when trying to read a hardware register | ||
8 | * that isn't present would cause a bus error. We set up a | ||
9 | * temporary handler so that this doesn't kill the kernel. | ||
10 | * | ||
11 | * There is a test-by-reading and a test-by-writing; I present | ||
12 | * them here complete with the comments from the original atari | ||
13 | * config.c... | ||
14 | * -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998 | ||
15 | */ | ||
16 | |||
17 | /* This function tests for the presence of an address, specially a | ||
18 | * hardware register address. It is called very early in the kernel | ||
19 | * initialization process, when the VBR register isn't set up yet. On | ||
20 | * an Atari, it still points to address 0, which is unmapped. So a bus | ||
21 | * error would cause another bus error while fetching the exception | ||
22 | * vector, and the CPU would do nothing at all. So we needed to set up | ||
23 | * a temporary VBR and a vector table for the duration of the test. | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | |||
28 | int hwreg_present( volatile void *regp ) | ||
29 | { | ||
30 | int ret = 0; | ||
31 | long save_sp, save_vbr; | ||
32 | long tmp_vectors[3]; | ||
33 | |||
34 | __asm__ __volatile__ | ||
35 | ( "movec %/vbr,%2\n\t" | ||
36 | "movel #Lberr1,%4@(8)\n\t" | ||
37 | "movec %4,%/vbr\n\t" | ||
38 | "movel %/sp,%1\n\t" | ||
39 | "moveq #0,%0\n\t" | ||
40 | "tstb %3@\n\t" | ||
41 | "nop\n\t" | ||
42 | "moveq #1,%0\n" | ||
43 | "Lberr1:\n\t" | ||
44 | "movel %1,%/sp\n\t" | ||
45 | "movec %2,%/vbr" | ||
46 | : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) | ||
47 | : "a" (regp), "a" (tmp_vectors) | ||
48 | ); | ||
49 | |||
50 | return( ret ); | ||
51 | } | ||
52 | EXPORT_SYMBOL(hwreg_present); | ||
53 | |||
54 | /* Basically the same, but writes a value into a word register, protected | ||
55 | * by a bus error handler. Returns 1 if successful, 0 otherwise. | ||
56 | */ | ||
57 | |||
58 | int hwreg_write( volatile void *regp, unsigned short val ) | ||
59 | { | ||
60 | int ret; | ||
61 | long save_sp, save_vbr; | ||
62 | long tmp_vectors[3]; | ||
63 | |||
64 | __asm__ __volatile__ | ||
65 | ( "movec %/vbr,%2\n\t" | ||
66 | "movel #Lberr2,%4@(8)\n\t" | ||
67 | "movec %4,%/vbr\n\t" | ||
68 | "movel %/sp,%1\n\t" | ||
69 | "moveq #0,%0\n\t" | ||
70 | "movew %5,%3@\n\t" | ||
71 | "nop \n\t" /* If this nop isn't present, 'ret' may already be | ||
72 | * loaded with 1 at the time the bus error | ||
73 | * happens! */ | ||
74 | "moveq #1,%0\n" | ||
75 | "Lberr2:\n\t" | ||
76 | "movel %1,%/sp\n\t" | ||
77 | "movec %2,%/vbr" | ||
78 | : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) | ||
79 | : "a" (regp), "a" (tmp_vectors), "g" (val) | ||
80 | ); | ||
81 | |||
82 | return( ret ); | ||
83 | } | ||
84 | EXPORT_SYMBOL(hwreg_write); | ||
85 | |||