aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2009-02-02 17:52:00 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2009-02-02 17:52:00 -0500
commit3bd323a1da42525317e2ce6c93b97b5ba653bc9d (patch)
tree8139baab8ed22cba923b73cca095f12706a3935b /arch/x86/boot
parent042cbaf88ab48e11afb725541e3c2cbf5b483680 (diff)
x86 setup: a20: early timeout for a nonexistent keyboard controller
When probing the keyboard controller to enable A20, if we get FF back (which is *possible* as a valid status word, but is extremely unlikely) then bail after much fewer iterations than we otherwise would, and abort the attempt to access the KBC. This hopefully should make it work a lot better for embedded platforms which don't have a KBC and where the BIOS doesn't implement INT 15h AX=2401h (and doesn't boot with A20 already enabled.) If this works, it will be the one remaining use of CONFIG_X86_ELAN as anything other than a processor type optimization option. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/boot')
-rw-r--r--arch/x86/boot/a20.c75
1 files changed, 41 insertions, 34 deletions
diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c
index 4063d630deff..fba8e9c6a504 100644
--- a/arch/x86/boot/a20.c
+++ b/arch/x86/boot/a20.c
@@ -2,6 +2,7 @@
2 * 2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds 3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007-2008 rPath, Inc. - All Rights Reserved 4 * Copyright 2007-2008 rPath, Inc. - All Rights Reserved
5 * Copyright 2009 Intel Corporation
5 * 6 *
6 * This file is part of the Linux kernel, and is made available under 7 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2. 8 * the terms of the GNU General Public License version 2.
@@ -15,16 +16,23 @@
15#include "boot.h" 16#include "boot.h"
16 17
17#define MAX_8042_LOOPS 100000 18#define MAX_8042_LOOPS 100000
19#define MAX_8042_FF 32
18 20
19static int empty_8042(void) 21static int empty_8042(void)
20{ 22{
21 u8 status; 23 u8 status;
22 int loops = MAX_8042_LOOPS; 24 int loops = MAX_8042_LOOPS;
25 int ffs = MAX_8042_FF;
23 26
24 while (loops--) { 27 while (loops--) {
25 io_delay(); 28 io_delay();
26 29
27 status = inb(0x64); 30 status = inb(0x64);
31 if (status == 0xff) {
32 /* FF is a plausible, but very unlikely status */
33 if (!--ffs)
34 return -1; /* Assume no KBC present */
35 }
28 if (status & 1) { 36 if (status & 1) {
29 /* Read and discard input data */ 37 /* Read and discard input data */
30 io_delay(); 38 io_delay();
@@ -118,44 +126,43 @@ static void enable_a20_fast(void)
118 126
119int enable_a20(void) 127int enable_a20(void)
120{ 128{
121#if defined(CONFIG_X86_ELAN) 129#ifdef CONFIG_X86_VOYAGER
122 /* Elan croaks if we try to touch the KBC */
123 enable_a20_fast();
124 while (!a20_test_long())
125 ;
126 return 0;
127#elif defined(CONFIG_X86_VOYAGER)
128 /* On Voyager, a20_test() is unsafe? */ 130 /* On Voyager, a20_test() is unsafe? */
129 enable_a20_kbc(); 131 enable_a20_kbc();
130 return 0; 132 return 0;
131#else 133#else
132 int loops = A20_ENABLE_LOOPS; 134 int loops = A20_ENABLE_LOOPS;
133 while (loops--) { 135 int kbc_err;
134 /* First, check to see if A20 is already enabled 136
135 (legacy free, etc.) */ 137 while (loops--) {
136 if (a20_test_short()) 138 /* First, check to see if A20 is already enabled
137 return 0; 139 (legacy free, etc.) */
138 140 if (a20_test_short())
139 /* Next, try the BIOS (INT 0x15, AX=0x2401) */ 141 return 0;
140 enable_a20_bios(); 142
141 if (a20_test_short()) 143 /* Next, try the BIOS (INT 0x15, AX=0x2401) */
142 return 0; 144 enable_a20_bios();
143 145 if (a20_test_short())
144 /* Try enabling A20 through the keyboard controller */ 146 return 0;
145 empty_8042(); 147
146 if (a20_test_short()) 148 /* Try enabling A20 through the keyboard controller */
147 return 0; /* BIOS worked, but with delayed reaction */ 149 kbc_err = empty_8042();
148 150
149 enable_a20_kbc(); 151 if (a20_test_short())
150 if (a20_test_long()) 152 return 0; /* BIOS worked, but with delayed reaction */
151 return 0; 153
152 154 if (!kbc_err) {
153 /* Finally, try enabling the "fast A20 gate" */ 155 enable_a20_kbc();
154 enable_a20_fast(); 156 if (a20_test_long())
155 if (a20_test_long()) 157 return 0;
156 return 0; 158 }
157 } 159
158 160 /* Finally, try enabling the "fast A20 gate" */
159 return -1; 161 enable_a20_fast();
162 if (a20_test_long())
163 return 0;
164 }
165
166 return -1;
160#endif 167#endif
161} 168}