Date: Mon, 3 Oct 2011 22:19:24 +0530 From: "Jayachandran C." <jchandra@freebsd.org> To: Adrian Chadd <adrian@freebsd.org> Cc: Kostik Belousov <kostikbel@gmail.com>, Alexander Motin <mav@freebsd.org>, freebsd-mips@freebsd.org Subject: Re: svn commit: r225892 - head/sys/mips/mips Message-ID: <CA%2B7sy7A%2Bq_N6Hr%2B3-tD=BJxmqtDgBeWF9HJCtopLF0RUz6hVyw@mail.gmail.com> In-Reply-To: <20111002110331.GF1511@deviant.kiev.zoral.com.ua> References: <CA%2B7sy7BiRvTB79H9=y%2BS4jQ=%2BboW1bcDJn%2BBULMmJU9KLLVJ5A@mail.gmail.com> <CAJ-VmokAsDpjJLt%2BVJ2gDGX%2BiMAwZvL2TPaaAD_LRm-Yyquxig@mail.gmail.com> <CA%2B7sy7D6h5a08Q6yNfX6xSqwabDLzE5GLu5aV3fCMYQKn_4AoQ@mail.gmail.com> <CAJ-Vmon32cVEVvC=3WJVmDkCUdyLWyec3sqU-ifzspVSPxedfg@mail.gmail.com> <CAJ-Vmomsq5PQzbCBmWob5juB9EqdcEoYV%2B9vwYjnJQYTo_%2B4kw@mail.gmail.com> <CAJ-Vmon_a_zLZmEGqwFaYaobjYFE2i1u2Viq3QD5dw4wpNNURA@mail.gmail.com> <CA%2B7sy7DFCMxo-2bJwBJcSEJf7ewG7Y=XwdgKXkhpRyDXQpvsYA@mail.gmail.com> <CAJ-VmokPFqS2oNWZ_mFSxy=0MXfgqtOcBHSQe%2BdYXvsLHAyGjQ@mail.gmail.com> <CAJ-VmomqmKPRHBCbt46_xXD0VoU47Q-vYWbAqCFaM635ZnOHWA@mail.gmail.com> <CAJ-VmomLbueaG3bmnT0WfeKaMSyXSNo80BWXqEe39z6x%2Bx8QoA@mail.gmail.com> <20111002110331.GF1511@deviant.kiev.zoral.com.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Hi Adrain,
On Sun, Oct 2, 2011 at 4:33 PM, Kostik Belousov <kostikbel@gmail.com> wrote:
> On Sun, Oct 02, 2011 at 05:28:25PM +0800, Adrian Chadd wrote:
>> Hi,
>>
>> It doesn't look like openbsd or netbsd have tried addressing this.
>>
>> I took a shot at trying to port over the relevant bits.
>>
>> Linux seems to store the "can reschedule" flag in a bit of memory,
>> rather than calling a function to check each time.
>> This means that I can't simply port r4k_wait() verbose; there's no
>> guarantee EPC would be pointing to inside r4k_wait if it had to call
>> sched_runnable().
>>
>> Also, since we are calling 'wait' inside a critical section, any EPC
>> unwinding would have to also unwind the critical section (and maybe
>> reprogram the timer) before restarting things. But since that now
>> makes the "rollback" section even larger and unwieldy.
>>
>> I really don't have the time or brain power at the moment to try and
>> port this solution over from Linux.
>>
>> I would really appreciate it if someone would help out here.
>
> I probably need to describe some details of the mentioned "kib' idea".
>
> Looking at the x86 sti; hlt sequence, I noted that, in fact, we do
> not strictly need the special CPU behaviour of delaying enabling the
> interrupts till next instruction after sti is executed. The race there
> is the interrupt happen right after sti but before hlt, causing CPU
> to enter halted state while potentially having runnable thread. On x86
> it is closed by sti not enabling interrupts till hlt started execution
> (it is more subtle, but let ignore the detail for the discussion).
>
> Now, if sti would not offer the useful postponing behaviour, we can
> easily emulate it. In the hardware interrupt handlers return path, we
> can check for $pc being equal to the address of the hlt instruction. If
> it is, we can advance $pc over the hlt, avoiding the halt if potentially
> we have a runnable thread.
>
> Briefly looking over the MIPS64 specifications, I do not see why we cannot
> implement the spirit of the trick for the ei; wait instruction sequence.
> ray talked about possibility of $pc living in the shadow register bank,
> which I think is not important. Another (minor) issue seems to be
> that our code does not use ei, directly manipulating the bit.
>
> My belief is that the trick can be done if only we have exact
> interrupts. It seems, from "run mips run" text, that possible inexact
> interrupts are either for much older platforms then modern MIPS SoC, or
> are irrelant there, because inexactness is only related to mul/div unit.
>
> [I am not on mips@]
I have implemented a variant of this, can you try out the attached
patch and see how it goes? It should apply on the version before your
changes to machdep.c
Also, if anybody on mips@ can review the code, it would be helpful...
JC.
[-- Attachment #2 --]
diff --git a/sys/mips/include/md_var.h b/sys/mips/include/md_var.h
index c2a6155..6f65a0f 100644
--- a/sys/mips/include/md_var.h
+++ b/sys/mips/include/md_var.h
@@ -56,6 +56,7 @@ void MipsSwitchFPState(struct thread *, struct trapframe *);
u_long kvtop(void *addr);
int is_cacheable_mem(vm_paddr_t addr);
void mips_generic_reset(void);
+void mips_wait(void);
#define MIPS_DEBUG 0
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S
index 729391e..4d1346d 100644
--- a/sys/mips/mips/exception.S
+++ b/sys/mips/mips/exception.S
@@ -557,6 +557,34 @@ NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
.set at
END(MipsUserGenException)
+ .align 4
+ .set push
+ .set noat
+NON_LEAF(mips_wait, CALLFRAME_SIZ, ra)
+ PTR_SUBU sp, sp, CALLFRAME_SIZ
+ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
+ REG_S ra, CALLFRAME_RA(sp) # save RA
+ mfc0 t0, MIPS_COP_0_STATUS
+ xori t1, t0, MIPS_SR_INT_IE
+ mtc0 t0, MIPS_COP_0_STATUS
+ jal sched_runnable
+ nop
+ REG_L ra, CALLFRAME_RA(sp)
+ mfc0 t0, MIPS_COP_0_STATUS
+ ori t1, t0, MIPS_SR_INT_IE
+ nop
+ nop
+StartWaitSkip: # this is 16 byte aligned
+ mtc0 t0, MIPS_COP_0_STATUS
+ bnez v0, EndWaitSkip
+ nop
+ wait
+EndWaitSkip: # StartWaitSkip + 16
+ jr ra
+ PTR_ADDU sp, sp, CALLFRAME_SIZ
+END(mips_wait)
+ .set pop
+
/*----------------------------------------------------------------------------
*
* MipsKernIntr --
@@ -578,6 +606,19 @@ NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
.set noat
PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
.mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
+
+/*
+ * Check for getting interrupts just before wait
+ */
+ MFC0 k0, MIPS_COP_0_EXC_PC
+ ori k0, 0xf
+ xori k0, 0xf # 16 byte align
+ PTR_LA k1, StartWaitSkip
+ bne k0, k1, 1f
+ nop
+ PTR_ADDU k1, 16 # skip over wait
+ MTC0 k1, MIPS_COP_0_EXC_PC
+1:
/*
* Save CPU state, building 'frame'.
*/
diff --git a/sys/mips/mips/machdep.c b/sys/mips/mips/machdep.c
index f7e5248..a0725a9 100644
--- a/sys/mips/mips/machdep.c
+++ b/sys/mips/mips/machdep.c
@@ -497,7 +497,7 @@ cpu_idle(int busy)
critical_enter();
cpu_idleclock();
}
- __asm __volatile ("wait");
+ mips_wait();
if (!busy) {
cpu_activeclock();
critical_exit();
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CA%2B7sy7A%2Bq_N6Hr%2B3-tD=BJxmqtDgBeWF9HJCtopLF0RUz6hVyw>
