summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/ofw/rtas.c
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2011-06-26 16:11:36 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2011-06-26 16:11:36 +0000
commit173e40756b0a87ae6de3b59b385bd2738df7e4cf (patch)
tree7c52bed1f51c6dae05a33f68be22ef96d3e65f57 /sys/powerpc/ofw/rtas.c
parenta7d17981201bb7c35b2a46ada38b7a2d98ab4c5c (diff)
downloadFreeBSD-src-173e40756b0a87ae6de3b59b385bd2738df7e4cf.zip
FreeBSD-src-173e40756b0a87ae6de3b59b385bd2738df7e4cf.tar.gz
Add better error handling for RTAS calls. These can potentially cause
machine checks (e.g. invalid PCI configuration cycles), but these can be caught and recovered from. This change also the RTAS PCI driver to work without modification as a replacement for the Grackle driver on Grackle-based Powermacs.
Diffstat (limited to 'sys/powerpc/ofw/rtas.c')
-rw-r--r--sys/powerpc/ofw/rtas.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c
index 59692c9..66ce12f 100644
--- a/sys/powerpc/ofw/rtas.c
+++ b/sys/powerpc/ofw/rtas.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
+#include <sys/proc.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
@@ -39,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/md_var.h>
+#include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/rtas.h>
#include <machine/stdarg.h>
@@ -60,6 +62,8 @@ int rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat);
extern uintptr_t rtas_entry;
extern register_t rtasmsr;
+int setfault(faultbuf); /* defined in locore.S */
+
/*
* After the VM is up, allocate RTAS memory and instantiate it
*/
@@ -188,6 +192,7 @@ int
rtas_call_method(cell_t token, int nargs, int nreturns, ...)
{
vm_offset_t argsptr;
+ faultbuf env;
va_list ap;
struct {
cell_t token;
@@ -213,7 +218,19 @@ rtas_call_method(cell_t token, int nargs, int nreturns, ...)
args.args_n_results[n] = va_arg(ap, cell_t);
argsptr = rtas_real_map(&args, sizeof(args));
- result = rtascall(argsptr, rtas_private_data);
+
+ /* Get rid of any stale machine checks that have been waiting. */
+ __asm __volatile ("sync; isync");
+ if (!setfault(env)) {
+ __asm __volatile ("sync");
+ result = rtascall(argsptr, rtas_private_data);
+ __asm __volatile ("sync; isync");
+ } else {
+ result = RTAS_HW_ERROR;
+ }
+ curthread->td_pcb->pcb_onfault = 0;
+ __asm __volatile ("sync");
+
rtas_real_unmap(argsptr, &args, sizeof(args));
mtx_unlock(&rtas_mtx);
OpenPOWER on IntegriCloud