Skip site navigation (1)Skip section navigation (2)
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>