mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-27 11:55:06 +00:00
30a3cd0d55
r201881 | imp | 2010-01-08 20:08:22 -0700 (Fri, 08 Jan 2010) | 3 lines Rename mips_pcpu_init to mips_pcpu0_init since it applies only to the BSP. Provide a missing prototype. r200343 | imp | 2009-12-09 18:44:11 -0700 (Wed, 09 Dec 2009) | 4 lines Get the sense of this right. We use uintpr_t for bus_addr_t when we're building everything except octeon && 32-bit. As note before, we need a clearner way, but at least now the hack is right. r199760 | imp | 2009-11-24 10:15:22 -0700 (Tue, 24 Nov 2009) | 2 lines Add in Cavium's CID. Report what the unknown CID is. r199754 | imp | 2009-11-24 09:32:31 -0700 (Tue, 24 Nov 2009) | 6 lines Include opt_cputype.h for all .c and .S files referencing TARGET_OCTEON. Spell ld script name right. r199599 | imp | 2009-11-20 09:32:26 -0700 (Fri, 20 Nov 2009) | 2 lines Another kludge for 64-bit bus_addr_t with 32-bit pointers... r199496 | gonzo | 2009-11-18 15:52:05 -0700 (Wed, 18 Nov 2009) | 5 lines - Add cpu_init_interrupts function that is supposed to prepeare stuff required for spinning out interrupts later - Add API for managing intrcnt/intrnames arrays - Some minor style(9) fixes r198958 | rrs | 2009-11-05 11:15:47 -0700 (Thu, 05 Nov 2009) | 2 lines For XLR adds extern for its bus space routines r198669 | rrs | 2009-10-30 02:53:11 -0600 (Fri, 30 Oct 2009) | 5 lines With this commit our friend RMI will now compile. I have not tested it and the chances of it running yet are about ZERO.. but it will now compile. The hard part now begins, making it run ;-) r198666 | imp | 2009-10-29 18:37:50 -0600 (Thu, 29 Oct 2009) | 2 lines Add some newer MIPS CO cores. r198665 | imp | 2009-10-29 18:37:04 -0600 (Thu, 29 Oct 2009) | 4 lines db_expr_t is really closer to a register_t. Submitted by: bde@ r198531 | gonzo | 2009-10-27 18:01:20 -0600 (Tue, 27 Oct 2009) | 3 lines - Remove bunch of declared but not defined cach-related variables - Add mips_picache_linesize and mips_pdcache_linesize variables r198354 | neel | 2009-10-21 20:51:31 -0600 (Wed, 21 Oct 2009) | 9 lines Get rid of the hardcoded constants to define cacheable memory: SDRAM_ADDR_START, SDRAM_ADDR_END and SDRAM_MEM_SIZE Instead we now keep a copy of the memory regions enumerated by platform-specific code and use that to determine whether an address is cacheable or not. r198310 | gonzo | 2009-10-20 17:13:08 -0600 (Tue, 20 Oct 2009) | 5 lines - Commit missing part of "bt" fix: store PC register in pcb_context struct in cpu_switch and use it in stack_trace function later. pcb_regs contains state of the process stored by exception handler and therefor is not valid for sleeping processes. r198207 | imp | 2009-10-18 08:57:04 -0600 (Sun, 18 Oct 2009) | 2 lines Undo spamage of last MFC. r198206 | imp | 2009-10-18 08:56:33 -0600 (Sun, 18 Oct 2009) | 3 lines _ALIGN has to return u_long, since pointers don't fit into u_int in 64-bit mips. r198182 | gonzo | 2009-10-16 18:22:07 -0600 (Fri, 16 Oct 2009) | 11 lines - Use PC/RA/SP values as arguments for stacktrace_subr instead of trapframe. Context info could be obtained from other sources (see below) no only from td_pcb field - Do not show a0..a3 values unless they're obtained from the stack. These are only confirmed values. - Fix bt command in DDB. Previous implementation used thread's trapframe structure as a source info for trace unwinding, but this structure is filled only when exception occurs. Valid register values for sleeping processes are in pcb_context array. For curthread use pc/sp/ra for current frame r198181 | gonzo | 2009-10-16 16:52:18 -0600 (Fri, 16 Oct 2009) | 2 lines - Get rid of label_t. It came from NetBSD and was used only in one place r198154 | rrs | 2009-10-15 15:03:32 -0600 (Thu, 15 Oct 2009) | 10 lines Does 4 things: 1) Adds future RMI directories 2) Places intr_machdep.c in specfic files.arch pointing to the generic intr_machdep.c. This allows us to have an architecture dependant intr_machdep.c (which we will need for RMI) in the machine specific directory 3) removes intr_machdep.c from files.mips 4) Adds some TARGET_XLR_XLS ifdef's for the machine specific intra_machdep.h. We may need to look at finding a better place to put this. But first I want to get this thing compiling. r198066 | gonzo | 2009-10-13 19:43:53 -0600 (Tue, 13 Oct 2009) | 5 lines - Move stack tracing function to db_trace.c - Axe unused extern MipsXXX declarations - Move all declarations for functions in exceptions.S/swtch.S from trap.c to respective headers r197685 | gonzo | 2009-10-01 14:05:36 -0600 (Thu, 01 Oct 2009) | 2 lines - Sync caches properly when dealing with sf_buf r196215 | imp | 2009-08-14 10:15:18 -0600 (Fri, 14 Aug 2009) | 6 lines (u_int) is the wrong type here. Use unsigned long instead, even though that's only less wrong... r196199 | imp | 2009-08-13 13:47:13 -0600 (Thu, 13 Aug 2009) | 7 lines Use unsigned long instead of unsigned for the integer casts here. The former works for both ILP32 and LP64 programming models, while the latter fails LP64. r196089 | gonzo | 2009-08-09 19:49:59 -0600 (Sun, 09 Aug 2009) | 4 lines - Make i/d cache size field 32-bit to prevent overflow Submited by: Neelkanth Natu r195582 | imp | 2009-07-10 13:07:07 -0600 (Fri, 10 Jul 2009) | 2 lines fix prototype for MipsEmulateBranch. r195581 | imp | 2009-07-10 13:06:43 -0600 (Fri, 10 Jul 2009) | 2 lines Better definitions for a few types for n32/n64. r195580 | imp | 2009-07-10 13:06:15 -0600 (Fri, 10 Jul 2009) | 5 lines Fixed aligned macros... r195478 | gonzo | 2009-07-08 16:28:36 -0600 (Wed, 08 Jul 2009) | 5 lines - Port busdma code from FreeBSD/arm. This is more mature version that takes into account all limitation to DMA memory (boundaries, alignment) and implements bounce pages. - Add BUS_DMASYNC_POSTREAD case to bus_dmamap_sync_buf r195440 | imp | 2009-07-08 00:01:37 -0600 (Wed, 08 Jul 2009) | 2 lines Fix atomic_store_64 prototype for 64-bit systems. r195392 | imp | 2009-07-05 20:27:03 -0600 (Sun, 05 Jul 2009) | 3 lines The MCOUNT macro isn't going to work in 64-bit mode. Add a note to this effect. r195391 | imp | 2009-07-05 20:22:51 -0600 (Sun, 05 Jul 2009) | 3 lines Provide a macro for PTR_ADDU as well. We may need to implement this differently for N32... Use PTR_ADDU in DO_AST macro. r195390 | imp | 2009-07-05 20:22:06 -0600 (Sun, 05 Jul 2009) | 4 lines Change the addu here to daddu. addu paranoina prodded by: jmallet@ r195382 | imp | 2009-07-05 15:16:26 -0600 (Sun, 05 Jul 2009) | 5 lines addu and subu are special. We need to use daddu and dsubu here to get proper behavior. Submitted by: jmallet@ r195370 | imp | 2009-07-05 09:20:16 -0600 (Sun, 05 Jul 2009) | 6 lines The SB1 has cohernet memory, so add it. Also, Maxmem is better as a long. Submitted by: Neelkanth Natu r195369 | imp | 2009-07-05 09:19:28 -0600 (Sun, 05 Jul 2009) | 4 lines The SB1 needs a special value for the cache field of the pte. Submitted by: Neelkanth Natu r195368 | imp | 2009-07-05 09:18:06 -0600 (Sun, 05 Jul 2009) | 2 lines compute the areas to save registers in for 64-bit access correctly. r195367 | imp | 2009-07-05 09:17:11 -0600 (Sun, 05 Jul 2009) | 3 lines First cut at 64-bit types. not 100% sure these are all correct for N32 ABI. r195366 | imp | 2009-07-05 09:16:27 -0600 (Sun, 05 Jul 2009) | 3 lines Trim unreferenced goo. SDRAM likely should be next, but it is still referenced. r195365 | imp | 2009-07-05 09:13:24 -0600 (Sun, 05 Jul 2009) | 9 lines First cut at atomics for 64-bit machines and SMP machines. # Note: Cavium provided a port that has atomics similar to these, but # that does a syncw; sync; atomic; sync; syncw where we just do the classic # mips 'atomic' operation (eg ll; frob; sc). It is unclear to me why # the extra is needed. Since my initial target is one core, I'll defer # investigation until I bring up multiple cores. syncw is an octeon specific # instruction. r195359 | imp | 2009-07-05 02:14:00 -0600 (Sun, 05 Jul 2009) | 4 lines Bring in cdefs.h from NetBSD to define ABI goo. Obtained from: NetBSD r195358 | imp | 2009-07-05 02:13:19 -0600 (Sun, 05 Jul 2009) | 4 lines Pull in machine/cdefs.h for the ABI definitions. Provide a PTR_LA, ala sgi, and use it in preference to a bare 'la' so that it gets translated to a 'dla' for the 64-bit pointer ABIs. r195357 | imp | 2009-07-05 01:01:34 -0600 (Sun, 05 Jul 2009) | 2 lines Use uintptr_t rather than unsigned here for 64-bit correctness. r195356 | imp | 2009-07-05 01:00:51 -0600 (Sun, 05 Jul 2009) | 6 lines Define __ELF_WORD_SIZE appropriately for n64. Note for N32 I believe this is correct. While registers are 64-bit, n32 is a 32-bit ABI and lives in a 32-bit world (with explicit 64-bit registers, however). Change an 8, which was 4 + 4 or sizeof(int) + SZREG to be a simple '4 + SZREG' to reflect the actual offset of the structure in question. r195355 | imp | 2009-07-05 00:56:51 -0600 (Sun, 05 Jul 2009) | 7 lines (1) Use uintptr_t in preference to unsigned. The latter isn't right for 64-bit case, while the former is. (2) include a SB1 specific coherency mapping Submitted by: Neelkanth Nath (2) r195352 | imp | 2009-07-05 00:44:37 -0600 (Sun, 05 Jul 2009) | 3 lines db_expr_t should be a intptr_t, not an int. These expressions can be addresses or numbers, and that's a intptr_t if I ever saw one. r195351 | imp | 2009-07-05 00:43:01 -0600 (Sun, 05 Jul 2009) | 4 lines Define COP0_SYNC for SB1 CPU. Submitted by: Neelkanth Natu r195350 | imp | 2009-07-05 00:39:37 -0600 (Sun, 05 Jul 2009) | 7 lines Switch to ABI agnostic ta0-ta3. Provide defs for this in the right places. Provide n32/n64 register name defintions. This should have no effect for the O32 builds that everybody else uses, but should help make N64 builds possible (lots of other changes are needed for that). Obtained from: NetBSD (for the regdef.h changes) r195128 | gonzo | 2009-06-27 17:27:41 -0600 (Sat, 27 Jun 2009) | 4 lines - Add support for handling TLS area address in kernel space. From the userland point of view get/set operations are performed using sysarch(2) call. r195076 | gonzo | 2009-06-26 13:54:06 -0600 (Fri, 26 Jun 2009) | 2 lines - Add guards to ensure that these files are included only once r194469 | gonzo | 2009-06-18 22:43:49 -0600 (Thu, 18 Jun 2009) | 16 lines - Mark temp variable as "earlyclobber" in assembler inline in atomic_fetchadd_32. Without it gcc would use it as input register for v and sometimes generate following code for function call like atomic_fetchadd_32(&(fp)->f_count, -1): 801238b4: 2402ffff li v0,-1 801238b8: c2230018 ll v1,24(s1) 801238bc: 00431021 addu v0,v0,v1 801238c0: e2220018 sc v0,24(s1) 801238c4: 1040fffc beqz v0,801238b8 <dupfdopen+0x2e8> 801238c8: 00000000 nop Which is definitly wrong because if sc fails v0 is set to 0 and previous value of -1 is overriden hence whole operation turns to bogus r194164 | imp | 2009-06-14 00:14:25 -0600 (Sun, 14 Jun 2009) | 3 lines bye bye. This is no longer referenced, but much code from it will resurface for a bus-space implementation. r194160 | imp | 2009-06-14 00:10:36 -0600 (Sun, 14 Jun 2009) | 3 lines Cavium-specific goo is no longer necessary here. Of course, I now have to write a bus space for cavium, but that shouldn't be too hard. r194157 | imp | 2009-06-14 00:01:46 -0600 (Sun, 14 Jun 2009) | 2 lines Move this to a more approrpiate plae. r194156 | imp | 2009-06-13 23:29:13 -0600 (Sat, 13 Jun 2009) | 2 lines Bring this in from the cavium port. r193487 | gonzo | 2009-06-05 02:37:11 -0600 (Fri, 05 Jun 2009) | 2 lines - Use restoreintr instead of enableint while accessing pcpu in DO_AST r192864 | gonzo | 2009-05-26 16:40:12 -0600 (Tue, 26 May 2009) | 4 lines - Replace CPU_NOFPU and SOFTFLOAT options with CPU_FPU. By default we assume that there is no FPU, because majority of SoC does not have it. r192817 | gonzo | 2009-05-26 10:35:05 -0600 (Tue, 26 May 2009) | 2 lines - Add type cast for atomic_cmpset_acq_ptr arguments r192792 | gonzo | 2009-05-26 00:01:17 -0600 (Tue, 26 May 2009) | 2 lines - Remove now unused NetBSDism intr.h r192177 | gonzo | 2009-05-15 20:39:13 -0600 (Fri, 15 May 2009) | 4 lines - Add MIPS_IS_KSEG0_ADDR, MIPS_IS_KSEG1_ADDR and MIPS_IS_VALID_PTR macroses thet check if address belongs to KSEG0, KSEG1 or both of them respectively. r191589 | gonzo | 2009-04-27 13:18:55 -0600 (Mon, 27 Apr 2009) | 3 lines - Cast argument to proper type in order to avoid warnings like "shift value is too large for given type" r191577 | gonzo | 2009-04-27 12:29:59 -0600 (Mon, 27 Apr 2009) | 4 lines - Use naming convention the same as MIPS spec does: eliminate _sel1 sufix and just use selector number. e.g. mips_rd_config_sel1 -> mips_rd_config1 - Add WatchHi/WatchLo accessors for selctors 1..3 (for debug purposes) r191451 | gonzo | 2009-04-23 22:17:21 -0600 (Thu, 23 Apr 2009) | 4 lines - Define accessor functions for CP0 Config(16) register selects 1, 2, 3. Content of these registers is defined in MIPS spec and can be used for obtaining info about CPU capabilities. r191282 | gonzo | 2009-04-19 16:02:14 -0600 (Sun, 19 Apr 2009) | 3 lines - Make mips_bus_space_generic be of type bus_space_tag_t instead of struct bus_space and update all relevant places. r191084 | gonzo | 2009-04-14 20:28:26 -0600 (Tue, 14 Apr 2009) | 6 lines Use FreeBSD/arm approach for handling bus space access: space tag is a pointer to bus_space structure that defines access methods and hence every bus can define own accessors. Default space is mips_bus_space_generic. It's a simple interface to physical memory, values are read with regard to host system byte order.
634 lines
18 KiB
C
634 lines
18 KiB
C
/*-
|
|
* Copyright (c) 1998 Doug Rabson
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* from: src/sys/alpha/include/atomic.h,v 1.21.2.3 2005/10/06 18:12:05 jhb
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#ifndef _MACHINE_ATOMIC_H_
|
|
#define _MACHINE_ATOMIC_H_
|
|
|
|
#ifndef _SYS_CDEFS_H_
|
|
#error this file needs sys/cdefs.h as a prerequisite
|
|
#endif
|
|
|
|
/*
|
|
* Note: All the 64-bit atomic operations are only atomic when running
|
|
* in 64-bit mode. It is assumed that code compiled for n32 and n64
|
|
* fits into this definition and no further safeties are needed.
|
|
*
|
|
* It is also assumed that the add, subtract and other arithmetic is
|
|
* done on numbers not pointers. The special rules for n32 pointers
|
|
* do not have atomic operations defined for them, but generally shouldn't
|
|
* need atomic operations.
|
|
*/
|
|
|
|
static __inline void
|
|
mips_sync(void)
|
|
{
|
|
__asm __volatile (".set noreorder\n\t"
|
|
"sync\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
".set reorder\n"
|
|
: : : "memory");
|
|
}
|
|
|
|
#define mb() mips_sync()
|
|
#define wmb() mips_sync()
|
|
#define rmb() mips_sync()
|
|
|
|
/*
|
|
* Various simple arithmetic on memory which is atomic in the presence
|
|
* of interrupts and SMP safe.
|
|
*/
|
|
|
|
void atomic_set_8(__volatile uint8_t *, uint8_t);
|
|
void atomic_clear_8(__volatile uint8_t *, uint8_t);
|
|
void atomic_add_8(__volatile uint8_t *, uint8_t);
|
|
void atomic_subtract_8(__volatile uint8_t *, uint8_t);
|
|
|
|
void atomic_set_16(__volatile uint16_t *, uint16_t);
|
|
void atomic_clear_16(__volatile uint16_t *, uint16_t);
|
|
void atomic_add_16(__volatile uint16_t *, uint16_t);
|
|
void atomic_subtract_16(__volatile uint16_t *, uint16_t);
|
|
|
|
static __inline void
|
|
atomic_set_32(__volatile uint32_t *p, uint32_t v)
|
|
{
|
|
uint32_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %3\n\t" /* load old value */
|
|
"or %0, %2, %0\n\t" /* calculate new value */
|
|
"sc %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
|
|
}
|
|
|
|
static __inline void
|
|
atomic_clear_32(__volatile uint32_t *p, uint32_t v)
|
|
{
|
|
uint32_t temp;
|
|
v = ~v;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %3\n\t" /* load old value */
|
|
"and %0, %2, %0\n\t" /* calculate new value */
|
|
"sc %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline void
|
|
atomic_add_32(__volatile uint32_t *p, uint32_t v)
|
|
{
|
|
uint32_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %3\n\t" /* load old value */
|
|
"addu %0, %2, %0\n\t" /* calculate new value */
|
|
"sc %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline void
|
|
atomic_subtract_32(__volatile uint32_t *p, uint32_t v)
|
|
{
|
|
uint32_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %3\n\t" /* load old value */
|
|
"subu %0, %2\n\t" /* calculate new value */
|
|
"sc %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline uint32_t
|
|
atomic_readandclear_32(__volatile uint32_t *addr)
|
|
{
|
|
uint32_t result,temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0,%3\n\t" /* load current value, asserting lock */
|
|
"li %1,0\n\t" /* value to store */
|
|
"sc %1,%2\n\t" /* attempt to store */
|
|
"beqz %1, 1b\n\t" /* if the store failed, spin */
|
|
: "=&r"(result), "=&r"(temp), "=m" (*addr)
|
|
: "m" (*addr)
|
|
: "memory");
|
|
|
|
return result;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
atomic_readandset_32(__volatile uint32_t *addr, uint32_t value)
|
|
{
|
|
uint32_t result,temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0,%3\n\t" /* load current value, asserting lock */
|
|
"or %1,$0,%4\n\t"
|
|
"sc %1,%2\n\t" /* attempt to store */
|
|
"beqz %1, 1b\n\t" /* if the store failed, spin */
|
|
: "=&r"(result), "=&r"(temp), "=m" (*addr)
|
|
: "m" (*addr), "r" (value)
|
|
: "memory");
|
|
|
|
return result;
|
|
}
|
|
|
|
#if defined(__mips_n64) || defined(__mips_n32)
|
|
static __inline void
|
|
atomic_set_64(__volatile uint64_t *p, uint64_t v)
|
|
{
|
|
uint64_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %3\n\t" /* load old value */
|
|
"or %0, %2, %0\n\t" /* calculate new value */
|
|
"scd %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
|
|
}
|
|
|
|
static __inline void
|
|
atomic_clear_64(__volatile uint64_t *p, uint64_t v)
|
|
{
|
|
uint64_t temp;
|
|
v = ~v;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %3\n\t" /* load old value */
|
|
"and %0, %2, %0\n\t" /* calculate new value */
|
|
"scd %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline void
|
|
atomic_add_64(__volatile uint64_t *p, uint64_t v)
|
|
{
|
|
uint64_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %3\n\t" /* load old value */
|
|
"daddu %0, %2, %0\n\t" /* calculate new value */
|
|
"scd %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline void
|
|
atomic_subtract_64(__volatile uint64_t *p, uint64_t v)
|
|
{
|
|
uint64_t temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %3\n\t" /* load old value */
|
|
"dsubu %0, %2\n\t" /* calculate new value */
|
|
"scd %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* spin if failed */
|
|
: "=&r" (temp), "=m" (*p)
|
|
: "r" (v), "m" (*p)
|
|
: "memory");
|
|
}
|
|
|
|
static __inline uint64_t
|
|
atomic_readandclear_64(__volatile uint64_t *addr)
|
|
{
|
|
uint64_t result,temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %3\n\t" /* load old value */
|
|
"li %1, 0\n\t" /* value to store */
|
|
"scd %1, %2\n\t" /* attempt to store */
|
|
"beqz %1, 1b\n\t" /* if the store failed, spin */
|
|
: "=&r"(result), "=&r"(temp), "=m" (*addr)
|
|
: "m" (*addr)
|
|
: "memory");
|
|
|
|
return result;
|
|
}
|
|
|
|
static __inline uint64_t
|
|
atomic_readandset_64(__volatile uint64_t *addr, uint64_t value)
|
|
{
|
|
uint64_t result,temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0,%3\n\t" /* Load old value*/
|
|
"or %1,$0,%4\n\t"
|
|
"scd %1,%2\n\t" /* attempt to store */
|
|
"beqz %1, 1b\n\t" /* if the store failed, spin */
|
|
: "=&r"(result), "=&r"(temp), "=m" (*addr)
|
|
: "m" (*addr), "r" (value)
|
|
: "memory");
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#define ATOMIC_ACQ_REL(NAME, WIDTH) \
|
|
static __inline void \
|
|
atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
|
|
{ \
|
|
atomic_##NAME##_##WIDTH(p, v); \
|
|
mips_sync(); \
|
|
} \
|
|
\
|
|
static __inline void \
|
|
atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
|
|
{ \
|
|
mips_sync(); \
|
|
atomic_##NAME##_##WIDTH(p, v); \
|
|
}
|
|
|
|
/* Variants of simple arithmetic with memory barriers. */
|
|
ATOMIC_ACQ_REL(set, 8)
|
|
ATOMIC_ACQ_REL(clear, 8)
|
|
ATOMIC_ACQ_REL(add, 8)
|
|
ATOMIC_ACQ_REL(subtract, 8)
|
|
ATOMIC_ACQ_REL(set, 16)
|
|
ATOMIC_ACQ_REL(clear, 16)
|
|
ATOMIC_ACQ_REL(add, 16)
|
|
ATOMIC_ACQ_REL(subtract, 16)
|
|
ATOMIC_ACQ_REL(set, 32)
|
|
ATOMIC_ACQ_REL(clear, 32)
|
|
ATOMIC_ACQ_REL(add, 32)
|
|
ATOMIC_ACQ_REL(subtract, 32)
|
|
#if defined(__mips_n64) || defined(__mips_n32)
|
|
ATOMIC_ACQ_REL(set, 64)
|
|
ATOMIC_ACQ_REL(clear, 64)
|
|
ATOMIC_ACQ_REL(add, 64)
|
|
ATOMIC_ACQ_REL(subtract, 64)
|
|
#endif
|
|
|
|
#undef ATOMIC_ACQ_REL
|
|
|
|
/*
|
|
* We assume that a = b will do atomic loads and stores.
|
|
*/
|
|
#define ATOMIC_STORE_LOAD(WIDTH) \
|
|
static __inline uint##WIDTH##_t \
|
|
atomic_load_acq_##WIDTH(__volatile uint##WIDTH##_t *p) \
|
|
{ \
|
|
uint##WIDTH##_t v; \
|
|
\
|
|
v = *p; \
|
|
mips_sync(); \
|
|
return (v); \
|
|
} \
|
|
\
|
|
static __inline void \
|
|
atomic_store_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
|
|
{ \
|
|
mips_sync(); \
|
|
*p = v; \
|
|
}
|
|
|
|
ATOMIC_STORE_LOAD(32)
|
|
ATOMIC_STORE_LOAD(64)
|
|
#if !defined(__mips_n64) && !defined(__mips_n32)
|
|
void atomic_store_64(__volatile uint64_t *, uint64_t *);
|
|
void atomic_load_64(__volatile uint64_t *, uint64_t *);
|
|
#else
|
|
static __inline void
|
|
atomic_store_64(__volatile uint64_t *p, uint64_t *v)
|
|
{
|
|
*p = *v;
|
|
}
|
|
|
|
static __inline void
|
|
atomic_load_64(__volatile uint64_t *p, uint64_t *v)
|
|
{
|
|
*v = *p;
|
|
}
|
|
#endif
|
|
|
|
#undef ATOMIC_STORE_LOAD
|
|
|
|
/*
|
|
* Atomically compare the value stored at *p with cmpval and if the
|
|
* two values are equal, update the value of *p with newval. Returns
|
|
* zero if the compare failed, nonzero otherwise.
|
|
*/
|
|
static __inline uint32_t
|
|
atomic_cmpset_32(__volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
|
|
{
|
|
uint32_t ret;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %4\n\t" /* load old value */
|
|
"bne %0, %2, 2f\n\t" /* compare */
|
|
"move %0, %3\n\t" /* value to store */
|
|
"sc %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* if it failed, spin */
|
|
"j 3f\n\t"
|
|
"2:\n\t"
|
|
"li %0, 0\n\t"
|
|
"3:\n"
|
|
: "=&r" (ret), "=m" (*p)
|
|
: "r" (cmpval), "r" (newval), "m" (*p)
|
|
: "memory");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Atomically compare the value stored at *p with cmpval and if the
|
|
* two values are equal, update the value of *p with newval. Returns
|
|
* zero if the compare failed, nonzero otherwise.
|
|
*/
|
|
static __inline uint32_t
|
|
atomic_cmpset_acq_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
|
|
{
|
|
int retval;
|
|
|
|
retval = atomic_cmpset_32(p, cmpval, newval);
|
|
mips_sync();
|
|
return (retval);
|
|
}
|
|
|
|
static __inline uint32_t
|
|
atomic_cmpset_rel_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
|
|
{
|
|
mips_sync();
|
|
return (atomic_cmpset_32(p, cmpval, newval));
|
|
}
|
|
|
|
/*
|
|
* Atomically add the value of v to the integer pointed to by p and return
|
|
* the previous value of *p.
|
|
*/
|
|
static __inline uint32_t
|
|
atomic_fetchadd_32(__volatile uint32_t *p, uint32_t v)
|
|
{
|
|
uint32_t value, temp;
|
|
|
|
__asm __volatile (
|
|
"1:\tll %0, %1\n\t" /* load old value */
|
|
"addu %2, %3, %0\n\t" /* calculate new value */
|
|
"sc %2, %1\n\t" /* attempt to store */
|
|
"beqz %2, 1b\n\t" /* spin if failed */
|
|
: "=&r" (value), "=m" (*p), "=&r" (temp)
|
|
: "r" (v), "m" (*p));
|
|
return (value);
|
|
}
|
|
|
|
#if defined(__mips_n64) || defined(__mips_n32)
|
|
/*
|
|
* Atomically compare the value stored at *p with cmpval and if the
|
|
* two values are equal, update the value of *p with newval. Returns
|
|
* zero if the compare failed, nonzero otherwise.
|
|
*/
|
|
static __inline uint64_t
|
|
atomic_cmpset_64(__volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
|
|
{
|
|
uint64_t ret;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %4\n\t" /* load old value */
|
|
"bne %0, %2, 2f\n\t" /* compare */
|
|
"move %0, %3\n\t" /* value to store */
|
|
"scd %0, %1\n\t" /* attempt to store */
|
|
"beqz %0, 1b\n\t" /* if it failed, spin */
|
|
"j 3f\n\t"
|
|
"2:\n\t"
|
|
"li %0, 0\n\t"
|
|
"3:\n"
|
|
: "=&r" (ret), "=m" (*p)
|
|
: "r" (cmpval), "r" (newval), "m" (*p)
|
|
: "memory");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Atomically compare the value stored at *p with cmpval and if the
|
|
* two values are equal, update the value of *p with newval. Returns
|
|
* zero if the compare failed, nonzero otherwise.
|
|
*/
|
|
static __inline uint64_t
|
|
atomic_cmpset_acq_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
|
|
{
|
|
int retval;
|
|
|
|
retval = atomic_cmpset_64(p, cmpval, newval);
|
|
mips_sync();
|
|
return (retval);
|
|
}
|
|
|
|
static __inline uint64_t
|
|
atomic_cmpset_rel_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
|
|
{
|
|
mips_sync();
|
|
return (atomic_cmpset_64(p, cmpval, newval));
|
|
}
|
|
|
|
/*
|
|
* Atomically add the value of v to the integer pointed to by p and return
|
|
* the previous value of *p.
|
|
*/
|
|
static __inline uint64_t
|
|
atomic_fetchadd_64(__volatile uint64_t *p, uint64_t v)
|
|
{
|
|
uint64_t value, temp;
|
|
|
|
__asm __volatile (
|
|
"1:\n\t"
|
|
"lld %0, %1\n\t" /* load old value */
|
|
"daddu %2, %3, %0\n\t" /* calculate new value */
|
|
"scd %2, %1\n\t" /* attempt to store */
|
|
"beqz %2, 1b\n\t" /* spin if failed */
|
|
: "=&r" (value), "=m" (*p), "=&r" (temp)
|
|
: "r" (v), "m" (*p));
|
|
return (value);
|
|
}
|
|
#endif
|
|
|
|
/* Operations on chars. */
|
|
#define atomic_set_char atomic_set_8
|
|
#define atomic_set_acq_char atomic_set_acq_8
|
|
#define atomic_set_rel_char atomic_set_rel_8
|
|
#define atomic_clear_char atomic_clear_8
|
|
#define atomic_clear_acq_char atomic_clear_acq_8
|
|
#define atomic_clear_rel_char atomic_clear_rel_8
|
|
#define atomic_add_char atomic_add_8
|
|
#define atomic_add_acq_char atomic_add_acq_8
|
|
#define atomic_add_rel_char atomic_add_rel_8
|
|
#define atomic_subtract_char atomic_subtract_8
|
|
#define atomic_subtract_acq_char atomic_subtract_acq_8
|
|
#define atomic_subtract_rel_char atomic_subtract_rel_8
|
|
|
|
/* Operations on shorts. */
|
|
#define atomic_set_short atomic_set_16
|
|
#define atomic_set_acq_short atomic_set_acq_16
|
|
#define atomic_set_rel_short atomic_set_rel_16
|
|
#define atomic_clear_short atomic_clear_16
|
|
#define atomic_clear_acq_short atomic_clear_acq_16
|
|
#define atomic_clear_rel_short atomic_clear_rel_16
|
|
#define atomic_add_short atomic_add_16
|
|
#define atomic_add_acq_short atomic_add_acq_16
|
|
#define atomic_add_rel_short atomic_add_rel_16
|
|
#define atomic_subtract_short atomic_subtract_16
|
|
#define atomic_subtract_acq_short atomic_subtract_acq_16
|
|
#define atomic_subtract_rel_short atomic_subtract_rel_16
|
|
|
|
/* Operations on ints. */
|
|
#define atomic_set_int atomic_set_32
|
|
#define atomic_set_acq_int atomic_set_acq_32
|
|
#define atomic_set_rel_int atomic_set_rel_32
|
|
#define atomic_clear_int atomic_clear_32
|
|
#define atomic_clear_acq_int atomic_clear_acq_32
|
|
#define atomic_clear_rel_int atomic_clear_rel_32
|
|
#define atomic_add_int atomic_add_32
|
|
#define atomic_add_acq_int atomic_add_acq_32
|
|
#define atomic_add_rel_int atomic_add_rel_32
|
|
#define atomic_subtract_int atomic_subtract_32
|
|
#define atomic_subtract_acq_int atomic_subtract_acq_32
|
|
#define atomic_subtract_rel_int atomic_subtract_rel_32
|
|
#define atomic_cmpset_int atomic_cmpset_32
|
|
#define atomic_cmpset_acq_int atomic_cmpset_acq_32
|
|
#define atomic_cmpset_rel_int atomic_cmpset_rel_32
|
|
#define atomic_load_acq_int atomic_load_acq_32
|
|
#define atomic_store_rel_int atomic_store_rel_32
|
|
#define atomic_readandclear_int atomic_readandclear_32
|
|
#define atomic_readandset_int atomic_readandset_32
|
|
#define atomic_fetchadd_int atomic_fetchadd_32
|
|
|
|
/*
|
|
* I think the following is right, even for n32. For n32 the pointers
|
|
* are still 32-bits, so we need to operate on them as 32-bit quantities,
|
|
* even though they are sign extended in operation. For longs, there's
|
|
* no question because they are always 32-bits.
|
|
*/
|
|
#ifdef __mips_n64
|
|
/* Operations on longs. */
|
|
#define atomic_set_long atomic_set_64
|
|
#define atomic_set_acq_long atomic_set_acq_64
|
|
#define atomic_set_rel_long atomic_set_rel_64
|
|
#define atomic_clear_long atomic_clear_64
|
|
#define atomic_clear_acq_long atomic_clear_acq_64
|
|
#define atomic_clear_rel_long atomic_clear_rel_64
|
|
#define atomic_add_long atomic_add_64
|
|
#define atomic_add_acq_long atomic_add_acq_64
|
|
#define atomic_add_rel_long atomic_add_rel_64
|
|
#define atomic_subtract_long atomic_subtract_64
|
|
#define atomic_subtract_acq_long atomic_subtract_acq_64
|
|
#define atomic_subtract_rel_long atomic_subtract_rel_64
|
|
#define atomic_cmpset_long atomic_cmpset_64
|
|
#define atomic_cmpset_acq_long atomic_cmpset_acq_64
|
|
#define atomic_cmpset_rel_long atomic_cmpset_rel_64
|
|
#define atomic_load_acq_long atomic_load_acq_64
|
|
#define atomic_store_rel_long atomic_store_rel_64
|
|
#define atomic_fetchadd_long atomic_fetchadd_64
|
|
#define atomic_readandclear_long atomic_readandclear_64
|
|
|
|
#else /* !__mips_n64 */
|
|
|
|
/* Operations on longs. */
|
|
#define atomic_set_long atomic_set_32
|
|
#define atomic_set_acq_long atomic_set_acq_32
|
|
#define atomic_set_rel_long atomic_set_rel_32
|
|
#define atomic_clear_long atomic_clear_32
|
|
#define atomic_clear_acq_long atomic_clear_acq_32
|
|
#define atomic_clear_rel_long atomic_clear_rel_32
|
|
#define atomic_add_long(p, v) \
|
|
atomic_add_32((volatile u_int *)(p), (u_int)(v))
|
|
#define atomic_add_acq_long atomic_add_acq_32
|
|
#define atomic_add_rel_long atomic_add_rel_32
|
|
#define atomic_subtract_long(p, v) \
|
|
atomic_subtract_32((volatile u_int *)(p), (u_int)(v))
|
|
#define atomic_subtract_acq_long atomic_subtract_acq_32
|
|
#define atomic_subtract_rel_long atomic_subtract_rel_32
|
|
#define atomic_cmpset_long atomic_cmpset_32
|
|
#define atomic_cmpset_acq_long(p, cmpval, newval) \
|
|
atomic_cmpset_acq_32((volatile u_int *)(p), \
|
|
(u_int)(cmpval), (u_int)(newval))
|
|
#define atomic_cmpset_rel_long(p, cmpval, newval) \
|
|
atomic_cmpset_rel_32((volatile u_int *)(p), \
|
|
(u_int)(cmpval), (u_int)(newval))
|
|
#define atomic_load_acq_long atomic_load_acq_32
|
|
#define atomic_store_rel_long atomic_store_rel_32
|
|
#define atomic_fetchadd_long(p, v) \
|
|
atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v))
|
|
#define atomic_readandclear_long atomic_readandclear_32
|
|
|
|
#endif /* __mips_n64 */
|
|
|
|
/* Operations on pointers. */
|
|
#define atomic_set_ptr atomic_set_long
|
|
#define atomic_set_acq_ptr atomic_set_acq_long
|
|
#define atomic_set_rel_ptr atomic_set_rel_long
|
|
#define atomic_clear_ptr atomic_clear_long
|
|
#define atomic_clear_acq_ptr atomic_clear_acq_long
|
|
#define atomic_clear_rel_ptr atomic_clear_rel_long
|
|
#define atomic_add_ptr atomic_add_long
|
|
#define atomic_add_acq_ptr atomic_add_acq_long
|
|
#define atomic_add_rel_ptr atomic_add_rel_long
|
|
#define atomic_subtract_ptr atomic_subtract_long
|
|
#define atomic_subtract_acq_ptr atomic_subtract_acq_long
|
|
#define atomic_subtract_rel_ptr atomic_subtract_rel_long
|
|
#define atomic_cmpset_ptr atomic_cmpset_long
|
|
#define atomic_cmpset_acq_ptr atomic_cmpset_acq_long
|
|
#define atomic_cmpset_rel_ptr atomic_cmpset_rel_long
|
|
#define atomic_load_acq_ptr atomic_load_acq_long
|
|
#define atomic_store_rel_ptr atomic_store_rel_long
|
|
#define atomic_readandclear_ptr atomic_readandclear_long
|
|
|
|
#endif /* ! _MACHINE_ATOMIC_H_ */
|