diff options
author | dfr <dfr@FreeBSD.org> | 1998-09-16 08:24:30 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1998-09-16 08:24:30 +0000 |
commit | f85d349294f8ebb481ebf7f64986bbb487a2b13d (patch) | |
tree | 0d0335002ab55bfd3a58d822027db97553f6f24e /sys/alpha | |
parent | 0fc69df41c4d53bf1e106909cc6ebbe96424ebea (diff) | |
download | FreeBSD-src-f85d349294f8ebb481ebf7f64986bbb487a2b13d.zip FreeBSD-src-f85d349294f8ebb481ebf7f64986bbb487a2b13d.tar.gz |
Workaround some EB164 wierdness.
Obtained from: NetBSD
Diffstat (limited to 'sys/alpha')
-rw-r--r-- | sys/alpha/pci/cia.c | 88 |
1 files changed, 75 insertions, 13 deletions
diff --git a/sys/alpha/pci/cia.c b/sys/alpha/pci/cia.c index c245358..e9587b4 100644 --- a/sys/alpha/pci/cia.c +++ b/sys/alpha/pci/cia.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cia.c,v 1.7 1998/08/11 08:51:09 dfr Exp $ + * $Id: cia.c,v 1.8 1998/08/13 08:11:27 dfr Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -271,6 +271,46 @@ cia_bwx_maxdevs(u_int b) return 12; /* XXX */ } +static void +cia_clear_abort(void) +{ + /* + * Some (apparently-common) revisions of EB164 and AlphaStation + * firmware do the Wrong thing with PCI master and target aborts, + * which are caused by accesing the configuration space of devices + * that don't exist (for example). + * + * To work around this, we clear the CIA error register's PCI + * master and target abort bits before touching PCI configuration + * space and check it afterwards. If it indicates a master or target + * abort, the device wasn't there so we return 0xffffffff. + */ + REGVAL(CIA_CSR_CIA_ERR) = CIA_ERR_RCVD_MAS_ABT|CIA_ERR_RCVD_TAR_ABT; + alpha_mb(); + alpha_pal_draina(); +} + +static int +cia_check_abort(void) +{ + u_int32_t errbits; + int ba = 0; + + alpha_pal_draina(); + alpha_mb(); + errbits = REGVAL(CIA_CSR_CIA_ERR); + if (errbits & (CIA_ERR_RCVD_MAS_ABT|CIA_ERR_RCVD_TAR_ABT)) + ba = 1; + + if (errbits) { + REGVAL(CIA_CSR_CIA_ERR) = errbits; + alpha_mb(); + alpha_pal_draina(); + } + + return ba; +} + #define CIA_BWX_CFGADDR(b, s, f, r) \ KV(((b) ? CIA_EV56_BWCONF1 : CIA_EV56_BWCONF0) \ | ((b) << 16) | ((s) << 11) | ((f) << 8) | (r)) @@ -279,36 +319,58 @@ static u_int8_t cia_bwx_cfgreadb(u_int b, u_int s, u_int f, u_int r) { vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); - alpha_mb(); - if (badaddr((caddr_t)va, 1)) return ~0; - return ldbu(va+BWX_EV56_INT1); + u_int8_t data; + cia_clear_abort(); + if (badaddr((caddr_t)va, 1)) { + cia_check_abort(); + return ~0; + } + data = ldbu(va+BWX_EV56_INT1); + if (cia_check_abort()) + return ~0; + return data; } static u_int16_t cia_bwx_cfgreadw(u_int b, u_int s, u_int f, u_int r) { vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); - alpha_mb(); - if (badaddr((caddr_t)va, 2)) return ~0; - return ldwu(va+BWX_EV56_INT2); + u_int16_t data; + cia_clear_abort(); + if (badaddr((caddr_t)va, 2)) { + cia_check_abort(); + return ~0; + } + data = ldwu(va+BWX_EV56_INT2); + if (cia_check_abort()) + return ~0; + return data; } static u_int32_t cia_bwx_cfgreadl(u_int b, u_int s, u_int f, u_int r) { vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); - alpha_mb(); - if (badaddr((caddr_t)va, 4)) return ~0; - return ldl(va+BWX_EV56_INT4); + u_int32_t data; + cia_clear_abort(); + if (badaddr((caddr_t)va, 4)) { + cia_check_abort(); + return ~0; + } + data = ldl(va+BWX_EV56_INT4); + if (cia_check_abort()) + return ~0; + return data; } static void cia_bwx_cfgwriteb(u_int b, u_int s, u_int f, u_int r, u_int8_t data) { vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); + cia_clear_abort(); if (badaddr((caddr_t)va, 1)) return; stb(va+BWX_EV56_INT1, data); - alpha_wmb(); + cia_check_abort(); } static void @@ -317,7 +379,7 @@ cia_bwx_cfgwritew(u_int b, u_int s, u_int f, u_int r, u_int16_t data) vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); if (badaddr((caddr_t)va, 2)) return; stw(va+BWX_EV56_INT2, data); - alpha_wmb(); + cia_check_abort(); } static void @@ -326,7 +388,7 @@ cia_bwx_cfgwritel(u_int b, u_int s, u_int f, u_int r, u_int32_t data) vm_offset_t va = CIA_BWX_CFGADDR(b, s, f, r); if (badaddr((caddr_t)va, 4)) return; stl(va+BWX_EV56_INT4, data); - alpha_wmb(); + cia_check_abort(); } static u_int8_t |