blob: 2bb44753c1f7c187d490bcdda57e0136172921cc [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/err.h>
15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <linux/delay.h>
18
19#include <asm/system.h>
20
21#include <mach/remote_spinlock.h>
22#include <mach/dal.h>
23#include "smd_private.h"
24#include <linux/module.h>
25
26#define SMEM_SPINLOCK_COUNT 8
27#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
28
29static int remote_spinlock_smem_init(int id, _remote_spinlock_t *lock)
30{
31 _remote_spinlock_t spinlock_start;
32
33 if (id >= SMEM_SPINLOCK_COUNT)
34 return -EINVAL;
35
36 spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
37 SMEM_SPINLOCK_ARRAY_SIZE);
38 if (spinlock_start == NULL)
39 return -ENXIO;
40
41 *lock = spinlock_start + id;
42
43 return 0;
44}
45
46static int
47remote_spinlock_dal_init(const char *chunk_name, _remote_spinlock_t *lock)
48{
49 void *dal_smem_start, *dal_smem_end;
50 uint32_t dal_smem_size;
51 struct dal_chunk_header *cur_header;
52
53 if (!chunk_name)
54 return -EINVAL;
55
56 dal_smem_start = smem_get_entry(SMEM_DAL_AREA, &dal_smem_size);
57 if (!dal_smem_start)
58 return -ENXIO;
59
60 dal_smem_end = dal_smem_start + dal_smem_size;
61
62 /* Find first chunk header */
63 cur_header = (struct dal_chunk_header *)
64 (((uint32_t)dal_smem_start + (4095)) & ~4095);
65 *lock = NULL;
66 while (cur_header->size != 0
67 && ((uint32_t)(cur_header + 1) < (uint32_t)dal_smem_end)) {
68
69 /* Check if chunk name matches */
70 if (!strncmp(cur_header->name, chunk_name,
71 DAL_CHUNK_NAME_LENGTH)) {
72 *lock = (_remote_spinlock_t)&cur_header->lock;
73 return 0;
74 }
75 cur_header = (void *)cur_header + cur_header->size;
76 }
77
78 pr_err("%s: DAL remote lock \"%s\" not found.\n", __func__,
79 chunk_name);
80 return -EINVAL;
81}
82
83int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
84{
85 BUG_ON(id == NULL);
86
87 if (id[0] == 'D' && id[1] == ':') {
88 /* DAL chunk name starts after "D:" */
89 return remote_spinlock_dal_init(&id[2], lock);
90 } else if (id[0] == 'S' && id[1] == ':') {
91 /* Single-digit SMEM lock ID follows "S:" */
92 BUG_ON(id[3] != '\0');
93 return remote_spinlock_smem_init((((uint8_t)id[2])-'0'), lock);
94 } else
95 return -EINVAL;
96}
97
98int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock)
99{
100 BUG_ON(id == NULL);
101
102 lock->delay_us = id->delay_us;
103 return _remote_spin_lock_init(id->r_spinlock_id, &(lock->r_spinlock));
104}
105EXPORT_SYMBOL(_remote_mutex_init);
106
107void _remote_mutex_lock(_remote_mutex_t *lock)
108{
109 while (!_remote_spin_trylock(&(lock->r_spinlock))) {
110 if (lock->delay_us >= 1000)
111 msleep(lock->delay_us/1000);
112 else
113 udelay(lock->delay_us);
114 }
115}
116EXPORT_SYMBOL(_remote_mutex_lock);
117
118void _remote_mutex_unlock(_remote_mutex_t *lock)
119{
120 _remote_spin_unlock(&(lock->r_spinlock));
121}
122EXPORT_SYMBOL(_remote_mutex_unlock);
123
124int _remote_mutex_trylock(_remote_mutex_t *lock)
125{
126 return _remote_spin_trylock(&(lock->r_spinlock));
127}
128EXPORT_SYMBOL(_remote_mutex_trylock);