Subject: atomic write routine
To: None <port-arm@netbsd.org>
From: Jonathan Cline <jc.sb@verizon.net>
List: port-arm
Date: 05/16/2003 11:14:08
Hello,

In developing the psionarm port, I've now run
into writing some mach dep assembly (ARM7).  
I'd appreciate feedback on the following routine 
as this is my first attempt at arm assembly.
The problem I am solving here is simple:
on this SoC, there is a peripheral control 
register which is shared by multiple devices
(UART has some bits, timer has some bits, etc).
Since there are FIQ's active which might create
races by writes to this register and the current
arm kernels don't have intrinsic atomic routines
for blocking FIQ, I've written the below to 
set and get the register (called syscon).
I believe this explaination is longer than the
code itself, so here goes.  Also note that
there are two defines elsewhere:

#define SK_REG_BANK      (0x80000000)
#define SK_SYSCON           (0x0100)

Question ahead of time: what regs are
available for use when calling asm from C?
I've guessed that args are passed in r0..rN
respectively.  In SetSYSCON below, I'm clobbering
r3, r4, r5.  What's the c-model to save them?


/*
 * void    SetSYSCON(u_int clear_mask, u_int set_mask);
 *
 * Sets and clears bits in the SYSCON peripheral control register,
 * with interrupts disabled
 *
 *  r0 - bic mask - bits to clear
 *  r1 - eor mask - bits to set
 *
 * gets cpsr, disables ints, writes cpsr
 * modifies syscon
 * restores original cpsr
 */

ENTRY_NP(SetSYSCON)
        mrs     r3, cpsr		/* Get the CPSR */
        /* disable irq,fiq */
        bic     r4, r3, #(I32_bit | F32_bit)
        msr     cpsr_all, r4    /* Store the CPSR */

        /* Get SYSCON, modify it, Write SYSCON */
        mov     r5, #SK_REG_BANK
        ldr     r4, [r5, #SK_SYSCON]
        bic     r4, r4, r0
        eor     r4, r4, r1
        str     r4, [r5, #SK_SYSCON]

        /* Restore old CPSR / may enable irq,fiq */
        msr     cpsr_all, r3    

	mov	pc, lr


/*
 * u_int    GetSYSCON(void);
 * Gets the SYSCON register
 *
 * Returns the SYSCON in r0
 */

ENTRY_NP(GetSYSCON)
        mov     r1, #SK_REG_BANK
        ldr     r0, [r1, #SK_SYSCON]

	mov	pc, lr



Thanks

--JC