Date: Thu, 29 Sep 2011 03:10:42 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r225860 - user/adrian/if_ath_tx/sys/mips/mips Message-ID: <201109290310.p8T3AgZO001901@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Thu Sep 29 03:10:42 2011 New Revision: 225860 URL: http://svn.freebsd.org/changeset/base/225860 Log: The MIPS cpu_idle() routine is unfortunately buggy now that mav's eventtimer code has gone into the tree. If an interrupt comes in after critical_enter() is called but before "wait" occurs, the interrupt will be handled but it won't: * preempt the current idle thread, if PREEMPTION is enabled and you're using the 4BSD scheduler; * won't interrupt "wait", because it occured before it; * won't be handled until the next interrupt that occurs after the "wait" instruction is entered. So the issues with if_arge and if_ath can be traced down to a race with this particular behaviour in MIPS cpu_idle(). The interrupt would be posted but not handled until another interrupt triggers things. I've tried doing what is done in i386 - * interrupts are disabled * sched_runnable() is checked - if it's runnable, skip calling wait and instead reenable interrupts * otherwise atomically enable interrupts and call hlt. If an interrupt has come in and scheduled a netisr or taskqueue call, it'll (hopefully!) trip sched_runnable() and thus skip the wait. The atomic nature of "sti; hlt" is apparently documented for the i386. This way there's no race where an interrupt comes in before the hlt and doesn't wake it up. Now, I've tried the same for MIPS but it doesn't seem to fix things. The behaviour of wait is unfortunately implementation dependent and someone who is much more well versed in the art of MIPS hackery will have to fix it. So for now, I've #if 0'ed the whole thing and left cpu_idle to just do nothing. This fixes all the issues I've been seeing and allows me to acheive 230mbit UDP RX/TX and 150mbit TCP TX/RX without TX/RX queue servicing issues. Whatever is left is due to ath interrupt handling and packet scheduling. Modified: user/adrian/if_ath_tx/sys/mips/mips/machdep.c Modified: user/adrian/if_ath_tx/sys/mips/mips/machdep.c ============================================================================== --- user/adrian/if_ath_tx/sys/mips/mips/machdep.c Thu Sep 29 02:57:08 2011 (r225859) +++ user/adrian/if_ath_tx/sys/mips/mips/machdep.c Thu Sep 29 03:10:42 2011 (r225860) @@ -488,20 +488,33 @@ spinlock_exit(void) void cpu_idle(int busy) { +#if 0 + register_t m; + KASSERT((mips_rd_status() & MIPS_SR_INT_IE) != 0, ("interrupts disabled in idle process.")); KASSERT((mips_rd_status() & MIPS_INT_MASK) != 0, ("all interrupts masked in idle process.")); + m = intr_disable(); if (!busy) { critical_enter(); cpu_idleclock(); } - __asm __volatile ("wait"); + + if (sched_runnable()) + intr_restore(m); + else { + /* XXX not atomic! */ + intr_restore(m); + __asm __volatile ("wait\n"); + } + if (!busy) { cpu_activeclock(); critical_exit(); } +#endif } int
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201109290310.p8T3AgZO001901>