diff options
Diffstat (limited to 'arch/arm/mvp/mvpkm/mutex_kernel.c')
-rw-r--r-- | arch/arm/mvp/mvpkm/mutex_kernel.c | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/arch/arm/mvp/mvpkm/mutex_kernel.c b/arch/arm/mvp/mvpkm/mutex_kernel.c deleted file mode 100644 index 7b76bfcf..0000000 --- a/arch/arm/mvp/mvpkm/mutex_kernel.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The host kernel mutex functions. These mutexes can be located in - * shared address space with the monitor. - */ - -#include <linux/kernel.h> - -#include <asm/string.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/hardirq.h> - -#include "mvp.h" - -#include "arm_inline.h" -#include "coproc_defs.h" -#include "mutex_kernel.h" - -#define POLL_IN_PROGRESS_FLAG (1<<(30-MUTEX_CVAR_MAX)) - -#define INITWAITQ(waitQ) do { \ - init_waitqueue_head((wait_queue_head_t *)(waitQ)); \ -} while (0) - -#define WAKEUPALL(waitQ) do { \ - wake_up_all((wait_queue_head_t *)(waitQ)); \ -} while (0) - -#define WAKEUPONE(waitQ) do { \ - wake_up((wait_queue_head_t *)(waitQ)); \ -} while (0) - -/** - * @brief initialize mutex - * @param[in,out] mutex mutex to initialize - */ -void -Mutex_Init(Mutex *mutex) -{ - wait_queue_head_t *wq; - int i; - - wq = kcalloc(MUTEX_CVAR_MAX + 1, sizeof(wait_queue_head_t), 0); - FATAL_IF(wq == NULL); - - memset(mutex, 0, sizeof *mutex); - mutex->mtxHKVA = (HKVA)mutex; - mutex->lockWaitQ = (HKVA)&wq[0]; - INITWAITQ(mutex->lockWaitQ); - for (i = 0; i < MUTEX_CVAR_MAX; i ++) { - mutex->cvarWaitQs[i] = (HKVA)&wq[i + 1]; - INITWAITQ(mutex->cvarWaitQs[i]); - } -} - -/** - * @brief Check if it is ok to sleep - * @param file the file of the caller code - * @param line the line number of the caller code - */ -static void -MutexCheckSleep(const char *file, int line) -{ -#ifdef MVP_DEVEL - static unsigned long prev_jiffy; /* ratelimiting: 1/s */ - -#ifdef CONFIG_PREEMPT - if (preemptible() && !irqs_disabled()) { - return; - } -#else - if (!irqs_disabled()) { - return; - } -#endif - if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) { - return; - } - prev_jiffy = jiffies; - printk(KERN_ERR - "BUG: sleeping function called from invalid context at %s:%d\n", - file, line); - printk(KERN_ERR - "irqs_disabled(): %d, preemtible(): %d, pid: %d, name: %s\n", - irqs_disabled(), - preemptible(), - current->pid, current->comm); - dump_stack(); -#endif -} - -/** - * @brief destroy mutex - * @param[in,out] mutex mutex to destroy - */ -void -Mutex_Destroy(Mutex *mutex) -{ - kfree((void*)mutex->lockWaitQ); -} - -/** - * @brief Lock the mutex. Also does a data barrier after locking so the - * locking is complete before any shared data is accessed. - * @param[in,out] mutex which mutex to lock - * @param mode mutex lock mode - * @param file the file of the caller code - * @param line the line number of the code that called this function - * @return rc = 0: mutex now locked by caller<br> - * < 0: interrupted - */ -int -Mutex_LockLine(Mutex *mutex, MutexMode mode, const char *file, int line) -{ - Mutex_State newState, oldState; - - MutexCheckSleep(file, line); - - /* - * If uncontended, just set new lock state and return success status. - * If contended, mark state saying there is a waiting thread to wake. - */ - do { -lock_start: - /* - * Get current state and calculate what new state would be. - * New state adds 1 for shared and 0xFFFF for exclusive. - * If the 16 bit field overflows, there is contention. - */ - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode + mode; - newState.blck = oldState.blck; - - /* - * So we are saying there is no contention if new state - * indicates no overflow. - * - * On fairness: The test here allows a new-comer thread to grab - * the lock even if there is a blocked thread. For example 2 - * threads repeatedly obtaining shared access can starve a third - * wishing to obtain an exclusive lock. Currently this is only a - * hypothetical situation as mksck use exclusive lock only and - * the code never has more than 2 threads using the same mutex. - */ - if ((uint32)newState.mode >= (uint32)mode) { - if (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)) { - goto lock_start; - } - DMB(); - mutex->line = line; - mutex->lineUnl = -1; - return 0; - } - - /* - * There is contention, so increment the number of blocking threads. - */ - newState.mode = oldState.mode; - newState.blck = oldState.blck + 1; - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - /* - * Statistics... - */ - ATOMIC_ADDV(mutex->blocked, 1); - - /* - * Mutex is contended, state has been updated to say there is a blocking - * thread. - * - * So now we block till someone wakes us up. - */ - do { - DEFINE_WAIT(waiter); - - /* - * This will make sure we catch any wakes done after we check the lock - * state again. - */ - prepare_to_wait((wait_queue_head_t *)mutex->lockWaitQ, - &waiter, - TASK_INTERRUPTIBLE); - - /* - * Now that we will catch wakes, check the lock state again. If now - * uncontended, mark it locked, abandon the wait and return success. - */ - -set_new_state: - /* - * Same as the original check for contention above, except that we - * must decrement the number of waiting threads by one - * if we are successful in locking the mutex. - */ - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode + mode; - newState.blck = oldState.blck - 1; - ASSERT(oldState.blck); - - if ((uint32)newState.mode >= (uint32)mode) { - if (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)) { - goto set_new_state; - } - /* - * Mutex is no longer contended and we were able to lock it. - */ - finish_wait((wait_queue_head_t *)mutex->lockWaitQ, &waiter); - DMB(); - mutex->line = line; - mutex->lineUnl = -1; - return 0; - } - - /* - * Wait for a wake that happens any time after prepare_to_wait() - * returned. - */ - WARN(!schedule_timeout(10*HZ), "Mutex_Lock: soft lockup - stuck for 10s!\n"); - finish_wait((wait_queue_head_t *)mutex->lockWaitQ, &waiter); - } while (!signal_pending(current)); - - /* - * We aren't waiting anymore, so decrement the number of waiting threads. - */ - do { - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode; - newState.blck = oldState.blck - 1; - - ASSERT(oldState.blck); - - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - return -ERESTARTSYS; -} - - -/** - * @brief Unlock the mutex. Also does a data barrier before unlocking so any - * modifications made before the lock gets released will be completed - * before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param line the line number of the code that called this function - */ -void -Mutex_UnlockLine(Mutex *mutex, MutexMode mode, int line) -{ - Mutex_State newState, oldState; - - DMB(); - do { - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode - mode; - newState.blck = oldState.blck; - mutex->lineUnl = line; - - ASSERT(oldState.mode >= mode); - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - /* - * If another thread was blocked, then wake it up. - */ - if (oldState.blck) { - if (mode == MutexModeSH) { - WAKEUPONE(mutex->lockWaitQ); - } else { - WAKEUPALL(mutex->lockWaitQ); - } - } -} - - -/** - * @brief Unlock the mutex and sleep. Also does a data barrier before - * unlocking so any modifications made before the lock gets released - * will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param file the file of the caller code - * @param line the line number of the caller code - * @return rc = 0: successfully waited<br> - * < 0: error waiting - */ -int -Mutex_UnlSleepLine(Mutex *mutex, MutexMode mode, uint32 cvi, const char *file, int line) -{ - return Mutex_UnlSleepTestLine(mutex, mode, cvi, NULL, 0, file, line); -} - -/** - * @brief Unlock the mutex and sleep. Also does a data barrier before - * unlocking so any modifications made before the lock gets released - * will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param test sleep only if null or pointed atomic value mismatches mask - * @param mask bitfield to check test against before sleeping - * @param file the file of the caller code - * @param line the line number of the caller code - * @return rc = 0: successfully waited<br> - * < 0: error waiting - */ -int -Mutex_UnlSleepTestLine(Mutex *mutex, MutexMode mode, uint32 cvi, AtmUInt32 *test, uint32 mask, const char *file, int line) -{ - DEFINE_WAIT(waiter); - - MutexCheckSleep(file, line); - - ASSERT(cvi < MUTEX_CVAR_MAX); - - /* - * Tell anyone who might try to wake us that they need to actually call - * WAKEUP***(). - */ - ATOMIC_ADDV(mutex->waiters, 1); - - /* - * Be sure to catch any wake that comes along just after we unlock the mutex - * but before we call schedule(). - */ - prepare_to_wait_exclusive((wait_queue_head_t *)mutex->cvarWaitQs[cvi], - &waiter, - TASK_INTERRUPTIBLE); - - /* - * Release the mutex, someone can wake us up now. - * They will see mutex->waiters non-zero so will actually do the wake. - */ - Mutex_Unlock(mutex, mode); - - /* - * Wait to be woken or interrupted. - */ - if (test == NULL || (ATOMIC_GETO(*test) & mask) == 0) { - schedule(); - } - finish_wait((wait_queue_head_t *)mutex->cvarWaitQs[cvi], &waiter); - - /* - * Done waiting, don't need a wake any more. - */ - ATOMIC_SUBV(mutex->waiters, 1); - - /* - * If interrupted, return error status. - */ - if (signal_pending(current)) { - return -ERESTARTSYS; - } - - /* - * Wait completed, return success status. - */ - return 0; -} - - -/** - * @brief Unlock the mutex and prepare to sleep on a kernel polling table - * given as anonymous parameters for poll_wait - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param filp which file to poll_wait upon - * @param wait which poll_table to poll_wait upon - */ -void -Mutex_UnlPoll(Mutex *mutex, MutexMode mode, uint32 cvi, void *filp, void *wait) -{ - ASSERT(cvi < MUTEX_CVAR_MAX); - - /* poll_wait is done with mutex locked to prevent any wake that comes and - * defer them just after we unlock the mutex but before kernel polling - * tables are used - * Note that the kernel is probably avoiding an exclusive wait in that case - * and also increments the usage for the file given in filp - */ - poll_wait(filp, (wait_queue_head_t *)mutex->cvarWaitQs[cvi], wait); - - /* - * Tell anyone who might try to wake us that they need to actually call - * WAKEUP***(). This is done in putting ourselves in a "noisy" mode since - * there is no guaranty that we would really sleep, or if we would be - * wakening the sleeping thread with that socket or condition. This is - * done using a POLL_IN_PROGRESS_FLAG, but unfortunately it has to be - * a per-cvi flag, in case we would poll independently on different cvi - */ - DMB(); - ATOMIC_ORO(mutex->waiters, (POLL_IN_PROGRESS_FLAG << cvi)); - - /* - * Release the mutex, someone can wake us up now. - * They will see mutex->waiters non-zero so will actually do the wake. - */ - Mutex_Unlock(mutex, mode); -} - - -/** - * @brief Unlock the semaphore and wake sleeping threads. Also does a data - * barrier before unlocking so any modifications made before the lock - * gets released will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to signal - * @param all false: wake a single thread<br> - * true: wake all threads - */ -void -Mutex_UnlWake(Mutex *mutex, MutexMode mode, uint32 cvi, _Bool all) -{ - Mutex_Unlock(mutex, mode); - Mutex_CondSig(mutex, cvi, all); -} - - -/** - * @brief Signal condition variable, ie, wake up anyone waiting. - * @param mutex mutex that holds the condition variable - * @param cvi which condition variable to signal - * @param all false: wake a single thread<br> - * true: wake all threads - */ -void -Mutex_CondSig(Mutex *mutex, uint32 cvi, _Bool all) -{ - uint32 waiters; - - ASSERT(cvi < MUTEX_CVAR_MAX); - - waiters = ATOMIC_GETO(mutex->waiters); - if (waiters != 0) { - /* Cleanup the effects of Mutex_UnlPoll() but only when it is SMP safe, - * considering that atomic and wakeup operations should also do memory - * barriers accordingly. This is mandatory otherwise rare SMP races are - * even possible, since Mutex_CondSig is called with the associated mutex - * unlocked, and that does not prevent from select() to run parallel ! - */ - if ((waiters >= POLL_IN_PROGRESS_FLAG) && - !waitqueue_active((wait_queue_head_t *)mutex->cvarWaitQs[cvi])) { - ATOMIC_ANDO(mutex->waiters, ~(POLL_IN_PROGRESS_FLAG << cvi)); - } - DMB(); - - if (all) { - WAKEUPALL(mutex->cvarWaitQs[cvi]); - } else { - WAKEUPONE(mutex->cvarWaitQs[cvi]); - } - } -} |