212 lines
6.5 KiB
C
212 lines
6.5 KiB
C
/* Copyright (c) 2008-2009, Code Aurora Forum. 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 Code Aurora Forum nor
|
|
* the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* Alternatively, provided that this notice is retained in full, this software
|
|
* may be relicensed by the recipient under the terms of the GNU General Public
|
|
* License version 2 ("GPL") and only version 2, in which case the provisions of
|
|
* the GPL apply INSTEAD OF those given above. If the recipient relicenses the
|
|
* software under the GPL, then the identification text in the MODULE_LICENSE
|
|
* macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
|
|
* recipient changes the license terms to the GPL, subsequent recipients shall
|
|
* not relicense under alternate licensing terms, including the BSD or dual
|
|
* BSD/GPL terms. In addition, the following license statement immediately
|
|
* below and between the words START and END shall also then apply when this
|
|
* software is relicensed under the GPL:
|
|
*
|
|
* START
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License version 2 and only 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; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* END
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
|
*
|
|
*/
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
|
|
#include <asm/system.h>
|
|
|
|
#include <mach/remote_spinlock.h>
|
|
#include <mach/dal.h>
|
|
#include "smd_private.h"
|
|
|
|
#define SMEM_SPINLOCK_COUNT 8
|
|
#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
|
|
|
|
#if defined(CONFIG_ARCH_MSM7X30)
|
|
static int remote_spinlock_smem_init(int id, _remote_spinlock_t *lock)
|
|
{
|
|
_remote_spinlock_t spinlock_start;
|
|
|
|
if (id >= SMEM_SPINLOCK_COUNT)
|
|
return -EINVAL;
|
|
|
|
spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
|
|
SMEM_SPINLOCK_ARRAY_SIZE);
|
|
if (spinlock_start == NULL)
|
|
return -ENXIO;
|
|
|
|
*lock = spinlock_start + id;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
remote_spinlock_dal_init(const char *chunk_name, _remote_spinlock_t *lock)
|
|
{
|
|
void *dal_smem_start, *dal_smem_end;
|
|
uint32_t dal_smem_size;
|
|
struct dal_chunk_header *cur_header;
|
|
|
|
if (!chunk_name)
|
|
return -EINVAL;
|
|
|
|
dal_smem_start = smem_item(SMEM_DAL_AREA, &dal_smem_size);
|
|
if (!dal_smem_start)
|
|
return -ENXIO;
|
|
|
|
dal_smem_end = dal_smem_start + dal_smem_size;
|
|
|
|
/* Find first chunk header */
|
|
cur_header = (struct dal_chunk_header *)
|
|
(((uint32_t)dal_smem_start + (4095)) & ~4095);
|
|
*lock = NULL;
|
|
while (cur_header->size != 0
|
|
&& ((uint32_t)(cur_header + 1) < (uint32_t)dal_smem_end)) {
|
|
|
|
/* Check if chunk name matches */
|
|
if (!strncmp(cur_header->name, chunk_name,
|
|
DAL_CHUNK_NAME_LENGTH)) {
|
|
*lock = (_remote_spinlock_t)&cur_header->lock;
|
|
return 0;
|
|
}
|
|
cur_header = (void *)cur_header + cur_header->size;
|
|
}
|
|
|
|
pr_err("%s: DAL remote lock \"%s\" not found.\n", __func__,
|
|
chunk_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#define DEK_LOCK_REQUEST 1
|
|
#define DEK_LOCK_YIELD (!DEK_LOCK_REQUEST)
|
|
#define DEK_YIELD_TURN_SELF 0
|
|
static inline void __raw_remote_dek_spin_lock(raw_remote_spinlock_t *lock)
|
|
{
|
|
lock->dek.self_lock = DEK_LOCK_REQUEST;
|
|
|
|
while (lock->dek.other_lock) {
|
|
|
|
if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
|
|
lock->dek.self_lock = DEK_LOCK_YIELD;
|
|
|
|
while (lock->dek.other_lock)
|
|
;
|
|
|
|
lock->dek.self_lock = DEK_LOCK_REQUEST;
|
|
}
|
|
lock->dek.next_yield = DEK_YIELD_TURN_SELF;
|
|
|
|
smp_mb();
|
|
}
|
|
|
|
static inline int __raw_remote_dek_spin_trylock(raw_remote_spinlock_t *lock)
|
|
{
|
|
lock->dek.self_lock = DEK_LOCK_REQUEST;
|
|
|
|
if (lock->dek.other_lock) {
|
|
lock->dek.self_lock = DEK_LOCK_YIELD;
|
|
return 0;
|
|
}
|
|
|
|
lock->dek.next_yield = DEK_YIELD_TURN_SELF;
|
|
|
|
smp_mb();
|
|
return 1;
|
|
}
|
|
|
|
static inline void __raw_remote_dek_spin_unlock(raw_remote_spinlock_t *lock)
|
|
{
|
|
smp_mb();
|
|
|
|
lock->dek.self_lock = DEK_LOCK_YIELD;
|
|
}
|
|
#endif
|
|
|
|
int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock)
|
|
{
|
|
#if defined(CONFIG_ARCH_MSM7X30)
|
|
BUG_ON(id == NULL);
|
|
|
|
if (id[0] == 'D' && id[1] == ':') {
|
|
/* DAL chunk name starts after "D:" */
|
|
return remote_spinlock_dal_init(&id[2], lock);
|
|
} else if (id[0] == 'S' && id[1] == ':') {
|
|
/* Single-digit SMEM lock ID follows "S:" */
|
|
BUG_ON(id[3] != '\0');
|
|
return remote_spinlock_smem_init((((uint8_t)id[2])-'0'), lock);
|
|
} else
|
|
return -EINVAL;
|
|
#else
|
|
_remote_spinlock_t spinlock_start;
|
|
|
|
if (id >= SMEM_SPINLOCK_COUNT)
|
|
return -EINVAL;
|
|
|
|
spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
|
|
SMEM_SPINLOCK_ARRAY_SIZE);
|
|
if (spinlock_start == NULL)
|
|
return -ENXIO;
|
|
|
|
*lock = spinlock_start + id;
|
|
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#if defined(CONFIG_ARCH_MSM7X30)
|
|
void _remote_spin_lock(_remote_spinlock_t *lock)
|
|
{
|
|
__raw_remote_dek_spin_lock((raw_remote_spinlock_t *) (*lock));
|
|
}
|
|
|
|
void _remote_spin_unlock(_remote_spinlock_t *lock)
|
|
{
|
|
__raw_remote_dek_spin_unlock((raw_remote_spinlock_t *) (*lock));
|
|
}
|
|
#endif |