blob: 83c247360fe68246ed7376a7f66e0863004c0b25 [file] [log] [blame]
/*
* (C) Copyright 2012 Quantenna Communications Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* This is implementation of Peterson's algorithm for mutual exclusion for 2 processes.
* Implemented for little endian system only now.
*
* //flag[] is boolean array; and turn is an integer
* flag[0] = false;
* flag[1] = false;
* turn;
*
* P0: flag[0] = true;
* turn = 1;
* while (flag[1] == true && turn == 1)
* {
* // busy wait
* }
* // critical section
* ...
* // end of critical section
* flag[0] = false;
*
* P1: flag[1] = true;
* turn = 0;
* while (flag[0] == true && turn == 0)
* {
* // busy wait
* }
* // critical section
* ...
* // end of critical section
* flag[1] = false;
*
*/
#ifndef __QTN_MPROC_SYNC_MUTEX_H
#define __QTN_MPROC_SYNC_MUTEX_H
#include "mproc_sync_base.h"
#ifndef __ASSEMBLY__
/* Initial value must be zero. */
typedef union __qtn_mproc_sync_mutex
{
uint32_t dword;
struct
{
uint16_t raw_w0;
uint16_t raw_w1;
} words;
struct
{
uint8_t __reserved0;
uint8_t flag1;
uint8_t turn;
uint8_t flag0;
} bytes;
} qtn_mproc_sync_mutex;
RUBY_INLINE void
qtn_mproc_sync_mutex_init(volatile qtn_mproc_sync_mutex *mutex)
{
mutex->dword = 0;
}
#if !defined(__GNUC__) && defined(_ARC)
_Inline _Asm void
__qtn_mproc_sync_mutex_relax(int count)
{
% reg count;
mov_s %r12, count;
1:
sub.f %r12, %r12, 1;
bnz_s 1b;
}
RUBY_INLINE void
qtn_mproc_sync_mutex_relax(int count)
{
if (count) {
__qtn_mproc_sync_mutex_relax(count);
}
}
#else
RUBY_INLINE void
qtn_mproc_sync_mutex_relax(int count)
{
int i;
for (i = 0; i < count; ++i) {
qtn_pipeline_drain();
}
}
#endif // #if !defined(__GNUC__) && defined(_ARC)
RUBY_INLINE void
qtn_mproc_sync_mutex0_lock(volatile qtn_mproc_sync_mutex *mutex, int relax_count)
{
mutex->words.raw_w1 = 0x0101;
while ((mutex->dword & 0x00FFFF00) == 0x00010100) {
qtn_mproc_sync_mutex_relax(relax_count);
}
}
RUBY_INLINE void
qtn_mproc_sync_mutex0_unlock(volatile qtn_mproc_sync_mutex *mutex)
{
mutex->bytes.flag0 = 0;
}
RUBY_INLINE void
qtn_mproc_sync_mutex1_lock(volatile qtn_mproc_sync_mutex *mutex, int relax_count)
{
mutex->bytes.flag1 = 1;
mutex->bytes.turn = 0;
while (mutex->words.raw_w1 == 0x0100) {
qtn_mproc_sync_mutex_relax(relax_count);
}
}
RUBY_INLINE void
qtn_mproc_sync_mutex1_unlock(volatile qtn_mproc_sync_mutex *mutex)
{
mutex->bytes.flag1 = 0;
}
#endif // #ifndef __ASSEMBLY__
#endif // #ifndef __QTN_MPROC_SYNC_MUTEX_H