From owner-svn-src-head@FreeBSD.ORG Thu May 20 21:07:58 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7C00C1065673; Thu, 20 May 2010 21:07:58 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (unknown [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 60F178FC0C; Thu, 20 May 2010 21:07:58 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o4KL7w5Y009947; Thu, 20 May 2010 21:07:58 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o4KL7wtH009945; Thu, 20 May 2010 21:07:58 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201005202107.o4KL7wtH009945@svn.freebsd.org> From: Nathan Whitehorn Date: Thu, 20 May 2010 21:07:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r208364 - head/sys/powerpc/aim X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 May 2010 21:07:58 -0000 Author: nwhitehorn Date: Thu May 20 21:07:58 2010 New Revision: 208364 URL: http://svn.freebsd.org/changeset/base/208364 Log: Fix a long-standing bug in the PowerPC OFW call function on SMP machines where running ofwdump could cause hangs by forcing all secondary CPUs into a busy wait with interrupts off during the call. Following section 8.4 of the Open Firmware PowerPC processor binding, the firmware is free to overwrite the system interrupt handlers during OF calls, restoring the OS handlers on exit. On single CPU systems, this process is invisible to the operating system. On multiple CPU systems, taking any exception on a secondary CPU while an OF call is in progress ends with that exception vectored into OF, resulting in a slow movement of the entire system into firmware context and a machine hang. MFC after: 3 days Modified: head/sys/powerpc/aim/ofw_machdep.c Modified: head/sys/powerpc/aim/ofw_machdep.c ============================================================================== --- head/sys/powerpc/aim/ofw_machdep.c Thu May 20 20:15:56 2010 (r208363) +++ head/sys/powerpc/aim/ofw_machdep.c Thu May 20 21:07:58 2010 (r208364) @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -348,17 +349,18 @@ ofw_quiesce(void) } static int -openfirmware(void *args) +openfirmware_core(void *args) { long oldmsr; int result; u_int srsave[16]; u_int i; - if (pmap_bootstrapped && ofw_real_mode) - args = (void *)pmap_kextract((vm_offset_t)args); - - mtx_lock(&ofw_mutex); + /* + * NOTE: This MUST be called with the OF mutex held. Because the CPU + * holding the lock is not necessarily the CPU running this function, + * we can't put an assert here. + */ __asm __volatile( "\t" "sync\n\t" @@ -412,6 +414,63 @@ openfirmware(void *args) : : "r" (oldmsr) ); + return (result); +} + +#ifdef SMP +struct ofw_rv_args { + void *args; + int retval; + volatile int in_progress; +}; + +static void +ofw_rendezvous_dispatch(void *xargs) +{ + struct ofw_rv_args *rv_args = xargs; + + /* NOTE: Interrupts are disabled here */ + + if (PCPU_GET(cpuid) == 0) { + /* + * Execute all OF calls on CPU 0 + */ + rv_args->retval = openfirmware_core(rv_args->args); + rv_args->in_progress = 0; + } else { + /* + * Spin with interrupts off on other CPUs while OF has + * control of the machine. + */ + while (rv_args->in_progress) + cpu_spinwait(); + } +} +#endif + +static int +openfirmware(void *args) +{ + int result; + #ifdef SMP + struct ofw_rv_args rv_args; + #endif + + if (pmap_bootstrapped && ofw_real_mode) + args = (void *)pmap_kextract((vm_offset_t)args); + + mtx_lock(&ofw_mutex); + + #ifdef SMP + rv_args.args = args; + rv_args.in_progress = 1; + smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, + smp_no_rendevous_barrier, &rv_args); + result = rv_args.retval; + #else + result = openfirmware_core(args); + #endif + mtx_unlock(&ofw_mutex); return (result);