diff options
author | Juli Mallett <jmallett@FreeBSD.org> | 2010-07-20 07:11:19 +0000 |
---|---|---|
committer | Juli Mallett <jmallett@FreeBSD.org> | 2010-07-20 07:11:19 +0000 |
commit | 1c305b501145f696d3597fb9b5b2091caaa6f67c (patch) | |
tree | 776ea14a76df76cd5ee4d9b63107c1e819c68914 /cvmx-spinlock.h | |
download | src-1c305b501145f696d3597fb9b5b2091caaa6f67c.tar.gz src-1c305b501145f696d3597fb9b5b2091caaa6f67c.zip |
Initial import of Cavium Networks Octeon Simple Executive, SDK version 1.9.0.vendor/octeon-sdk/1.9.0
Notes
Notes:
svn path=/vendor-sys/octeon-sdk/dist/; revision=210284
svn path=/vendor-sys/octeon-sdk/1.9.0/; revision=210285; tag=vendor/octeon-sdk/1.9.0
Diffstat (limited to 'cvmx-spinlock.h')
-rw-r--r-- | cvmx-spinlock.h | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/cvmx-spinlock.h b/cvmx-spinlock.h new file mode 100644 index 000000000000..a0725d6a6d7a --- /dev/null +++ b/cvmx-spinlock.h @@ -0,0 +1,430 @@ +/***********************license start*************** + * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights + * reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Cavium Networks nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS + * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH + * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY + * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT + * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES + * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR + * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET + * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT + * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. + * + * + * For any questions regarding licensing please contact marketing@caviumnetworks.com + * + ***********************license end**************************************/ + + + + + + +/** + * @file + * + * Implementation of spinlocks. + * + * <hr>$Revision: 41586 $<hr> + */ + + +#ifndef __CVMX_SPINLOCK_H__ +#define __CVMX_SPINLOCK_H__ + +#include "cvmx-asm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Spinlocks for Octeon */ + + +// define these to enable recursive spinlock debugging +//#define CVMX_SPINLOCK_DEBUG + + +/** + * Spinlocks for Octeon + */ +typedef struct { + volatile uint32_t value; +} cvmx_spinlock_t; + +// note - macros not expanded in inline ASM, so values hardcoded +#define CVMX_SPINLOCK_UNLOCKED_VAL 0 +#define CVMX_SPINLOCK_LOCKED_VAL 1 + + +#define CVMX_SPINLOCK_UNLOCKED_INITIALIZER {CVMX_SPINLOCK_UNLOCKED_VAL} + + +/** + * Initialize a spinlock + * + * @param lock Lock to initialize + */ +static inline void cvmx_spinlock_init(cvmx_spinlock_t *lock) +{ + lock->value = CVMX_SPINLOCK_UNLOCKED_VAL; +} + + +/** + * Return non-zero if the spinlock is currently locked + * + * @param lock Lock to check + * @return Non-zero if locked + */ +static inline int cvmx_spinlock_locked(cvmx_spinlock_t *lock) +{ + return (lock->value != CVMX_SPINLOCK_UNLOCKED_VAL); +} + + +/** + * Releases lock + * + * @param lock pointer to lock structure + */ +static inline void cvmx_spinlock_unlock(cvmx_spinlock_t *lock) +{ + CVMX_SYNCWS; + lock->value = 0; + CVMX_SYNCWS; +} + + +/** + * Attempts to take the lock, but does not spin if lock is not available. + * May take some time to acquire the lock even if it is available + * due to the ll/sc not succeeding. + * + * @param lock pointer to lock structure + * + * @return 0: lock successfully taken + * 1: lock not taken, held by someone else + * These return values match the Linux semantics. + */ + +static inline unsigned int cvmx_spinlock_trylock(cvmx_spinlock_t *lock) +{ + unsigned int tmp; + + __asm__ __volatile__( + ".set noreorder \n" + "1: ll %[tmp], %[val] \n" + " bnez %[tmp], 2f \n" // if lock held, fail immediately + " li %[tmp], 1 \n" + " sc %[tmp], %[val] \n" + " beqz %[tmp], 1b \n" + " li %[tmp], 0 \n" + "2: \n" + ".set reorder \n" + : [val] "+m" (lock->value), [tmp] "=&r" (tmp) + : + : "memory"); + + return (!!tmp); /* normalize to 0 or 1 */ +} + +/** + * Gets lock, spins until lock is taken + * + * @param lock pointer to lock structure + */ +static inline void cvmx_spinlock_lock(cvmx_spinlock_t *lock) +{ + unsigned int tmp; + + __asm__ __volatile__( + ".set noreorder \n" + "1: ll %[tmp], %[val] \n" + " bnez %[tmp], 1b \n" + " li %[tmp], 1 \n" + " sc %[tmp], %[val] \n" + " beqz %[tmp], 1b \n" + " nop \n" + ".set reorder \n" + : [val] "+m" (lock->value), [tmp] "=&r" (tmp) + : + : "memory"); + +} + + + +/** ******************************************************************** + * Bit spinlocks + * These spinlocks use a single bit (bit 31) of a 32 bit word for locking. + * The rest of the bits in the word are left undisturbed. This enables more + * compact data structures as only 1 bit is consumed for the lock. + * + */ + +/** + * Gets lock, spins until lock is taken + * Preserves the low 31 bits of the 32 bit + * word used for the lock. + * + * + * @param word word to lock bit 31 of + */ +static inline void cvmx_spinlock_bit_lock(uint32_t *word) +{ + unsigned int tmp; + unsigned int sav; + + __asm__ __volatile__( + ".set noreorder \n" + ".set noat \n" + "1: ll %[tmp], %[val] \n" + " bbit1 %[tmp], 31, 1b \n" + " li $at, 1 \n" + " ins %[tmp], $at, 31, 1 \n" + " sc %[tmp], %[val] \n" + " beqz %[tmp], 1b \n" + " nop \n" + ".set at \n" + ".set reorder \n" + : [val] "+m" (*word), [tmp] "=&r" (tmp), [sav] "=&r" (sav) + : + : "memory"); + +} + +/** + * Attempts to get lock, returns immediately with success/failure + * Preserves the low 31 bits of the 32 bit + * word used for the lock. + * + * + * @param word word to lock bit 31 of + * @return 0: lock successfully taken + * 1: lock not taken, held by someone else + * These return values match the Linux semantics. + */ +static inline unsigned int cvmx_spinlock_bit_trylock(uint32_t *word) +{ + unsigned int tmp; + + __asm__ __volatile__( + ".set noreorder \n" + ".set noat \n" + "1: ll %[tmp], %[val] \n" + " bbit1 %[tmp], 31, 2f \n" // if lock held, fail immediately + " li $at, 1 \n" + " ins %[tmp], $at, 31, 1 \n" + " sc %[tmp], %[val] \n" + " beqz %[tmp], 1b \n" + " li %[tmp], 0 \n" + "2: \n" + ".set at \n" + ".set reorder \n" + : [val] "+m" (*word), [tmp] "=&r" (tmp) + : + : "memory"); + + return (!!tmp); /* normalize to 0 or 1 */ +} +/** + * Releases bit lock + * + * Unconditionally clears bit 31 of the lock word. Note that this is + * done non-atomically, as this implementation assumes that the rest + * of the bits in the word are protected by the lock. + * + * @param word word to unlock bit 31 in + */ +static inline void cvmx_spinlock_bit_unlock(uint32_t *word) +{ + CVMX_SYNCWS; + *word &= ~(1UL << 31) ; + CVMX_SYNCWS; +} + + + +/** ******************************************************************** + * Recursive spinlocks + */ +typedef struct { + volatile unsigned int value; + volatile unsigned int core_num; +} cvmx_spinlock_rec_t; + + +/** + * Initialize a recursive spinlock + * + * @param lock Lock to initialize + */ +static inline void cvmx_spinlock_rec_init(cvmx_spinlock_rec_t *lock) +{ + lock->value = CVMX_SPINLOCK_UNLOCKED_VAL; +} + + +/** + * Return non-zero if the recursive spinlock is currently locked + * + * @param lock Lock to check + * @return Non-zero if locked + */ +static inline int cvmx_spinlock_rec_locked(cvmx_spinlock_rec_t *lock) +{ + return (lock->value != CVMX_SPINLOCK_UNLOCKED_VAL); +} + + +/** +* Unlocks one level of recursive spinlock. Lock is not unlocked +* unless this is the final unlock call for that spinlock +* +* @param lock ptr to recursive spinlock structure +*/ +static inline void cvmx_spinlock_rec_unlock(cvmx_spinlock_rec_t *lock); + +#ifdef CVMX_SPINLOCK_DEBUG +#define cvmx_spinlock_rec_unlock(x) _int_cvmx_spinlock_rec_unlock((x), __FILE__, __LINE__) +static inline void _int_cvmx_spinlock_rec_unlock(cvmx_spinlock_rec_t *lock, char *filename, int linenum) +#else +static inline void cvmx_spinlock_rec_unlock(cvmx_spinlock_rec_t *lock) +#endif +{ + + unsigned int temp, result; + int core_num; + core_num = cvmx_get_core_num(); + +#ifdef CVMX_SPINLOCK_DEBUG + { + if (lock->core_num != core_num) + { + cvmx_dprintf("ERROR: Recursive spinlock release attemped by non-owner! file: %s, line: %d\n", filename, linenum); + return; + } + } +#endif + + __asm__ __volatile__( + ".set noreorder \n" + " addi %[tmp], %[pid], 0x80 \n" + " sw %[tmp], %[lid] # set lid to invalid value\n" + CVMX_SYNCWS_STR + "1: ll %[tmp], %[val] \n" + " addu %[res], %[tmp], -1 # decrement lock count\n" + " sc %[res], %[val] \n" + " beqz %[res], 1b \n" + " nop \n" + " beq %[tmp], %[res], 2f # res is 1 on successful sc \n" + " nop \n" + " sw %[pid], %[lid] # set lid to pid, only if lock still held\n" + "2: \n" + CVMX_SYNCWS_STR + ".set reorder \n" + : [res] "=&r" (result), [tmp] "=&r" (temp), [val] "+m" (lock->value), [lid] "+m" (lock->core_num) + : [pid] "r" (core_num) + : "memory"); + + +#ifdef CVMX_SPINLOCK_DEBUG + { + if (lock->value == ~0UL) + { + cvmx_dprintf("ERROR: Recursive spinlock released too many times! file: %s, line: %d\n", filename, linenum); + } + } +#endif + + +} + +/** + * Takes recursive spinlock for a given core. A core can take the lock multiple + * times, and the lock is released only when the corresponding number of + * unlocks have taken place. + * + * NOTE: This assumes only one thread per core, and that the core ID is used as + * the lock 'key'. (This implementation cannot be generalized to allow + * multiple threads to use the same key (core id) .) + * + * @param lock address of recursive spinlock structure. Note that this is + * distinct from the standard spinlock + */ +static inline void cvmx_spinlock_rec_lock(cvmx_spinlock_rec_t *lock); + +#ifdef CVMX_SPINLOCK_DEBUG +#define cvmx_spinlock_rec_lock(x) _int_cvmx_spinlock_rec_lock((x), __FILE__, __LINE__) +static inline void _int_cvmx_spinlock_rec_lock(cvmx_spinlock_rec_t *lock, char *filename, int linenum) +#else +static inline void cvmx_spinlock_rec_lock(cvmx_spinlock_rec_t *lock) +#endif +{ + + + volatile unsigned int tmp; + volatile int core_num; + + core_num = cvmx_get_core_num(); + + + __asm__ __volatile__( + ".set noreorder \n" + "1: ll %[tmp], %[val] # load the count\n" + " bnez %[tmp], 2f # if count!=zero branch to 2\n" + " addu %[tmp], %[tmp], 1 \n" + " sc %[tmp], %[val] \n" + " beqz %[tmp], 1b # go back if not success\n" + " nop \n" + " j 3f # go to write core_num \n" + "2: lw %[tmp], %[lid] # load the core_num \n" + " bne %[tmp], %[pid], 1b # core_num no match, restart\n" + " nop \n" + " lw %[tmp], %[val] \n" + " addu %[tmp], %[tmp], 1 \n" + " sw %[tmp], %[val] # update the count\n" + "3: sw %[pid], %[lid] # store the core_num\n" + CVMX_SYNCWS_STR + ".set reorder \n" + : [tmp] "=&r" (tmp), [val] "+m" (lock->value), [lid] "+m" (lock->core_num) + : [pid] "r" (core_num) + : "memory"); + +#ifdef CVMX_SPINLOCK_DEBUG + if (lock->core_num != core_num) + { + cvmx_dprintf("cvmx_spinlock_rec_lock: lock taken, but core_num is incorrect. file: %s, line: %d\n", filename, linenum); + } +#endif + + +} + +#ifdef __cplusplus +} +#endif + +#endif /* __CVMX_SPINLOCK_H__ */ |