Skip to content

Commit 381d92a

Browse files
Ley Foon Tandinguyen702
authored andcommitted
FogBugz #138162: Add Altera hardware mutex driver
Driver for Altera hardware mutex soft IP. v4: - Changed pr_debug to pr_info. v3: - Change dts compatible string from "altr,mutex-1.0" to "altr,hwmutex-1.0" v2: -Updated altera_mutex_request() for error handling message. -Updated altera_mutex_unlock(). -Used of_match_ptr. Signed-off-by: Ley Foon Tan <[email protected]>
1 parent c8f95ec commit 381d92a

File tree

5 files changed

+390
-0
lines changed

5 files changed

+390
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Altera hardware mutex
2+
Altera hardware mutex can provide hardware assistance for synchronization and
3+
mutual exclusion between processors in asymmetric/symmetric multiprocessing
4+
(AMP/SMP) system or multi processes/threads in uniprocessor system.
5+
6+
Required properties:
7+
- compatible : "altr,mutex-1.0".
8+
- reg : physical base address of the mutex and length of memory mapped
9+
region.
10+
11+
Example:
12+
mutex0: mutex0@0x100 {
13+
compatible = "altr,hwmutex-1.0";
14+
reg = <0x100 0x8>;
15+
};
16+
17+
Example of mutex's client node that includes mutex phandle.
18+
mclient0: mclient0@0x200 {
19+
compatible = "client-1.0";
20+
reg = <0x200 0x10>;
21+
mutex = <&mutex0>;
22+
};

drivers/misc/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,12 @@ config SRAM
424424
config SRAM_EXEC
425425
bool
426426

427+
config ALTERA_HWMUTEX
428+
tristate "Altera Hardware Mutex"
429+
help
430+
This option enables device driver support for Altera Hardware Mutex.
431+
Say Y here if you want to use the Altera hardware mutex support.
432+
427433
config VEXPRESS_SYSCFG
428434
bool "Versatile Express System Configuration driver"
429435
depends on VEXPRESS_CONFIG

drivers/misc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ obj-$(CONFIG_PCH_PHUB) += pch_phub.o
4141
obj-y += ti-st/
4242
obj-y += lis3lv02d/
4343
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
44+
obj-$(CONFIG_ALTERA_HWMUTEX) += altera_hwmutex.o
4445
obj-$(CONFIG_INTEL_MEI) += mei/
4546
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
4647
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o

drivers/misc/altera_hwmutex.c

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
/*
2+
* Copyright Altera Corporation (C) 2013. All rights reserved
3+
*
4+
* This program is free software; you can redistribute it and/or modify it
5+
* under the terms and conditions of the GNU General Public License,
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope it will be useful, but WITHOUT
9+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11+
* more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along with
14+
* this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
17+
#include <linux/kernel.h>
18+
#include <linux/module.h>
19+
#include <linux/device.h>
20+
#include <linux/platform_device.h>
21+
#include <linux/io.h>
22+
#include <linux/of.h>
23+
#include <linux/altera_hwmutex.h>
24+
25+
#define DRV_NAME "altera_hwmutex"
26+
27+
28+
static DEFINE_SPINLOCK(list_lock); /* protect mutex_list */
29+
static LIST_HEAD(mutex_list);
30+
31+
/* Mutex Registers */
32+
#define MUTEX_REG 0x0
33+
34+
#define MUTEX_REG_VALUE_MASK 0xFFFF
35+
#define MUTEX_REG_OWNER_OFFSET 16
36+
#define MUTEX_REG_OWNER_MASK 0xFFFF
37+
#define MUTEX_GET_OWNER(reg) \
38+
((reg >> MUTEX_REG_OWNER_OFFSET) & MUTEX_REG_OWNER_MASK)
39+
40+
/**
41+
* altera_mutex_request - Retrieves a pointer to an acquired mutex device
42+
* structure
43+
* @mutex_np: The pointer to mutex device node
44+
*
45+
* Returns a pointer to the mutex device structure associated with the
46+
* supplied device node, or NULL if no corresponding mutex device was
47+
* found.
48+
*/
49+
struct altera_mutex *altera_mutex_request(struct device_node *mutex_np)
50+
{
51+
struct altera_mutex *mutex;
52+
53+
spin_lock(&list_lock);
54+
list_for_each_entry(mutex, &mutex_list, list) {
55+
if (mutex_np == mutex->pdev->dev.of_node) {
56+
if (!mutex->requested) {
57+
mutex->requested = true;
58+
spin_unlock(&list_lock);
59+
return mutex;
60+
} else {
61+
pr_info("Mutex device is in use.\n");
62+
spin_unlock(&list_lock);
63+
return NULL;
64+
}
65+
}
66+
}
67+
spin_unlock(&list_lock);
68+
pr_info("Mutex device not found!\n");
69+
return NULL;
70+
}
71+
EXPORT_SYMBOL(altera_mutex_request);
72+
73+
/**
74+
* altera_mutex_free - Free the mutex
75+
* @mutex: the mutex
76+
*
77+
* Return 0 if success. Otherwise, returns non-zero.
78+
*/
79+
int altera_mutex_free(struct altera_mutex *mutex)
80+
{
81+
if (!mutex || !mutex->requested)
82+
return -EINVAL;
83+
84+
spin_lock(&list_lock);
85+
mutex->requested = false;
86+
spin_unlock(&list_lock);
87+
88+
return 0;
89+
}
90+
EXPORT_SYMBOL(altera_mutex_free);
91+
92+
static int __mutex_trylock(struct altera_mutex *mutex, u16 owner, u16 value)
93+
{
94+
u32 read;
95+
int ret = 0;
96+
u32 data = (owner << MUTEX_REG_OWNER_OFFSET) | value;
97+
98+
mutex_lock(&mutex->lock);
99+
__raw_writel(data, mutex->regs + MUTEX_REG);
100+
read = __raw_readl(mutex->regs + MUTEX_REG);
101+
if (read != data)
102+
ret = -1;
103+
104+
mutex_unlock(&mutex->lock);
105+
return ret;
106+
}
107+
108+
/**
109+
* altera_mutex_lock - Acquires a hardware mutex, wait until it can get it.
110+
* @mutex: the mutex to be acquired
111+
* @owner: owner ID
112+
* @value: the new non-zero value to write to mutex
113+
*
114+
* Returns 0 if mutex was successfully locked. Otherwise, returns non-zero.
115+
*
116+
* The mutex must later on be released by the same owner that acquired it.
117+
* This function is not ISR callable.
118+
*/
119+
int altera_mutex_lock(struct altera_mutex *mutex, u16 owner, u16 value)
120+
{
121+
if (!mutex || !mutex->requested)
122+
return -EINVAL;
123+
124+
while (__mutex_trylock(mutex, owner, value) != 0)
125+
;
126+
127+
return 0;
128+
}
129+
EXPORT_SYMBOL(altera_mutex_lock);
130+
131+
/**
132+
* altera_mutex_trylock - Tries once to lock the hardware mutex and returns
133+
* immediately
134+
* @mutex: the mutex to be acquired
135+
* @owner: owner ID
136+
* @value: the new non-zero value to write to mutex
137+
*
138+
* Returns 0 if mutex was successfully locked. Otherwise, returns non-zero.
139+
*
140+
* The mutex must later on be released by the same owner that acquired it.
141+
* This function is not ISR callable.
142+
*/
143+
int altera_mutex_trylock(struct altera_mutex *mutex, u16 owner, u16 value)
144+
{
145+
if (!mutex || !mutex->requested)
146+
return -EINVAL;
147+
148+
return __mutex_trylock(mutex, owner, value);
149+
}
150+
EXPORT_SYMBOL(altera_mutex_trylock);
151+
152+
/**
153+
* altera_mutex_unlock - Unlock a mutex that has been locked by this owner
154+
* previously that was locked on the
155+
* altera_mutex_lock. Upon release, the value stored
156+
* in the mutex is set to zero.
157+
* @mutex: the mutex to be released
158+
* @owner: Owner ID
159+
*
160+
* Returns 0 if mutex was successfully unlocked. Otherwise, returns
161+
* non-zero.
162+
*
163+
* This function is not ISR callable.
164+
*/
165+
int altera_mutex_unlock(struct altera_mutex *mutex, u16 owner)
166+
{
167+
u32 reg;
168+
169+
if (!mutex || !mutex->requested)
170+
return -EINVAL;
171+
172+
mutex_lock(&mutex->lock);
173+
174+
__raw_writel(owner << MUTEX_REG_OWNER_OFFSET,
175+
mutex->regs + MUTEX_REG);
176+
177+
reg = __raw_readl(mutex->regs + MUTEX_REG);
178+
if (reg & MUTEX_REG_VALUE_MASK) {
179+
/* Unlock failed */
180+
dev_dbg(&mutex->pdev->dev,
181+
"Unlock mutex failed, owner %d and expected owner %d\n",
182+
owner, MUTEX_GET_OWNER(reg));
183+
mutex_unlock(&mutex->lock);
184+
return -EINVAL;
185+
}
186+
187+
mutex_unlock(&mutex->lock);
188+
return 0;
189+
}
190+
EXPORT_SYMBOL(altera_mutex_unlock);
191+
192+
/**
193+
* altera_mutex_owned - Determines if this owner owns the mutex
194+
* @mutex: the mutex to be queried
195+
* @owner: Owner ID
196+
*
197+
* Returns 1 if the owner owns the mutex. Otherwise, returns zero.
198+
*/
199+
int altera_mutex_owned(struct altera_mutex *mutex, u16 owner)
200+
{
201+
u32 reg;
202+
u16 actual_owner;
203+
int ret = 0;
204+
205+
if (!mutex || !mutex->requested)
206+
return ret;
207+
208+
mutex_lock(&mutex->lock);
209+
reg = __raw_readl(mutex->regs + MUTEX_REG);
210+
actual_owner = MUTEX_GET_OWNER(reg);
211+
if (actual_owner == owner)
212+
ret = 1;
213+
214+
mutex_unlock(&mutex->lock);
215+
return ret;
216+
}
217+
EXPORT_SYMBOL(altera_mutex_owned);
218+
219+
/**
220+
* altera_mutex_is_locked - Determines if the mutex is locked
221+
* @mutex: the mutex to be queried
222+
*
223+
* Returns 1 if the mutex is locked, 0 if unlocked.
224+
*/
225+
int altera_mutex_is_locked(struct altera_mutex *mutex)
226+
{
227+
u32 reg;
228+
int ret = 0;
229+
230+
if (!mutex || !mutex->requested)
231+
return ret;
232+
233+
mutex_lock(&mutex->lock);
234+
reg = __raw_readl(mutex->regs + MUTEX_REG);
235+
reg &= MUTEX_REG_VALUE_MASK;
236+
if (reg)
237+
ret = 1;
238+
239+
mutex_unlock(&mutex->lock);
240+
return ret;
241+
}
242+
EXPORT_SYMBOL(altera_mutex_is_locked);
243+
244+
static int altera_mutex_probe(struct platform_device *pdev)
245+
{
246+
struct altera_mutex *mutex;
247+
struct resource *regs;
248+
249+
mutex = devm_kzalloc(&pdev->dev, sizeof(struct altera_mutex),
250+
GFP_KERNEL);
251+
if (!mutex)
252+
return -ENOMEM;
253+
254+
mutex->pdev = pdev;
255+
256+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
257+
if (!regs)
258+
return -ENXIO;
259+
260+
mutex->regs = devm_ioremap_resource(&pdev->dev, regs);
261+
if (IS_ERR(mutex->regs))
262+
return PTR_ERR(mutex->regs);
263+
264+
mutex_init(&mutex->lock);
265+
266+
spin_lock(&list_lock);
267+
list_add_tail(&mutex->list, &mutex_list);
268+
spin_unlock(&list_lock);
269+
270+
platform_set_drvdata(pdev, mutex);
271+
272+
return 0;
273+
}
274+
275+
static int altera_mutex_remove(struct platform_device *pdev)
276+
{
277+
struct altera_mutex *mutex = platform_get_drvdata(pdev);
278+
279+
spin_lock(&list_lock);
280+
if (mutex)
281+
list_del(&mutex->list);
282+
spin_unlock(&list_lock);
283+
284+
platform_set_drvdata(pdev, NULL);
285+
return 0;
286+
}
287+
288+
static const struct of_device_id altera_mutex_match[] = {
289+
{ .compatible = "altr,hwmutex-1.0" },
290+
{ /* Sentinel */ }
291+
};
292+
293+
MODULE_DEVICE_TABLE(of, altera_mutex_match);
294+
295+
static struct platform_driver altera_mutex_platform_driver = {
296+
.driver = {
297+
.name = DRV_NAME,
298+
.of_match_table = altera_mutex_match,
299+
},
300+
.remove = altera_mutex_remove,
301+
};
302+
303+
static int __init altera_mutex_init(void)
304+
{
305+
return platform_driver_probe(&altera_mutex_platform_driver,
306+
altera_mutex_probe);
307+
}
308+
309+
static void __exit altera_mutex_exit(void)
310+
{
311+
platform_driver_unregister(&altera_mutex_platform_driver);
312+
}
313+
314+
module_init(altera_mutex_init);
315+
module_exit(altera_mutex_exit);
316+
317+
MODULE_AUTHOR("Ley Foon Tan <[email protected]>");
318+
MODULE_LICENSE("GPL v2");
319+
MODULE_DESCRIPTION("Altera Hardware Mutex driver");
320+
MODULE_ALIAS("platform:" DRV_NAME);

0 commit comments

Comments
 (0)