summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMisael Lopez Cruz <misael.lopez@ti.com>2015-12-18 15:50:52 -0600
committerAngela Stegmaier <angelabaker@ti.com>2015-12-21 16:05:04 -0600
commitf8affd036b856fb493b4663ac0b4e436660a2192 (patch)
tree5457692aec18b3c13565154ebb85312b4dda5ece
parente0b95f9b90473ffedc6e8f6999a933b9f77246ce (diff)
downloadipc-f8affd036b856fb493b4663ac0b4e436660a2192.tar.gz
Linux: Add support for the hwspinlock_user driver
The hwspinlock_user is a character driver that exposes ioctls to lock and unlock a given hwspinlock instance. The hwspinlock_user creates the /dev/hwspinlock device file. The hwspinlock_user driver is used as the first option when available, otherwise the previous /dev/mem approach is used. The hwspinlock_user.h uapi header file is kept locally as it may not be present in all supported kernels. Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
-rw-r--r--linux/include/linux/hwspinlock_user.h63
-rw-r--r--linux/src/api/gates/GateHWSpinlock.c92
-rw-r--r--linux/src/daemon/GateHWSpinlock.c50
3 files changed, 169 insertions, 36 deletions
diff --git a/linux/include/linux/hwspinlock_user.h b/linux/include/linux/hwspinlock_user.h
new file mode 100644
index 0000000..68f3dff
--- /dev/null
+++ b/linux/include/linux/hwspinlock_user.h
@@ -0,0 +1,63 @@
+/*
+ * Userspace interface to hardware spinlocks
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * 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 Texas Instruments nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#ifndef _UAPI_HWSPINLOCK_USER_H
+#define _UAPI_HWSPINLOCK_USER_H
+
+#include <linux/ioctl.h>
+
+/**
+ * struct hwspinlock_user_lock - Sent to lock a specific hwspinlock
+ * @id: hardware spinlock id
+ * @timeout: timeout value in msecs
+ */
+struct hwspinlock_user_lock {
+ int id;
+ unsigned int timeout;
+};
+
+/**
+ * struct hwspinlock_user_unlock - Sent to unlock a specific hwspinlock
+ * @id: hardware spinlock id
+ */
+struct hwspinlock_user_unlock {
+ int id;
+};
+
+#define HWSPINLOCK_IOC_MAGIC 'h'
+
+#define HWSPINLOCK_USER_LOCK _IOW(HWSPINLOCK_IOC_MAGIC, 0, \
+ struct hwspinlock_user_lock)
+#define HWSPINLOCK_USER_UNLOCK _IOW(HWSPINLOCK_IOC_MAGIC, 1, \
+ struct hwspinlock_user_unlock)
+
+#endif /* _UAPI_HWSPINLOCK_USER_H */
diff --git a/linux/src/api/gates/GateHWSpinlock.c b/linux/src/api/gates/GateHWSpinlock.c
index 142f3e1..64fa93a 100644
--- a/linux/src/api/gates/GateHWSpinlock.c
+++ b/linux/src/api/gates/GateHWSpinlock.c
@@ -64,6 +64,9 @@ typedef UInt32 Error_Block;
#include <sys/mman.h>
#include <sys/stat.h>
+#include <linux/ioctl.h>
+#include <linux/hwspinlock_user.h>
+
/* =============================================================================
* Structures & Enums
* =============================================================================
@@ -73,6 +76,7 @@ typedef struct {
Int32 fd; /* spinlock device handle */
UInt32 * baseAddr; /* base addr lock registers */
GateMutex_Handle gmHandle; /* handle to gate mutex */
+ Bool useHwlockDrv; /* use the hwspinlock driver */
} GateHWSpinlock_Module_State;
/* GateHWSpinlock instance object */
@@ -95,7 +99,8 @@ static GateHWSpinlock_Module_State GateHWSpinlock_state =
{
.fd = -1,
.baseAddr = NULL,
- .gmHandle = NULL
+ .gmHandle = NULL,
+ .useHwlockDrv = false,
};
static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
@@ -174,34 +179,44 @@ Int32 GateHWSpinlock_start(Void)
UInt32 dst;
int flags;
- Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
- if (Mod->fd < 0){
- PRINTVERBOSE0("GateHWSpinlock_start: failed to open the /dev/mem");
- status = GateHWSpinlock_E_OSFAILURE;
+ /* Fall back to /dev/mem if hwspinlock_user driver is not supported */
+ Mod->fd = open("/dev/hwspinlock", O_RDWR);
+ if (Mod->fd < 0) {
+ Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
+ }
+ else {
+ Mod->useHwlockDrv = true;
}
- /* make sure /dev/mem fd doesn't exist for 'fork() -> exec*()'ed child */
- flags = fcntl(Mod->fd, F_GETFD);
- if (flags != -1) {
- fcntl(Mod->fd, F_SETFD, flags | FD_CLOEXEC);
+ if (Mod->fd < 0){
+ PRINTVERBOSE0("GateHWSpinlock_start: failed to open the spinlock device");
+ status = GateHWSpinlock_E_OSFAILURE;
}
- /* map the hardware lock registers into the local address space */
- if (status == GateHWSpinlock_S_SUCCESS) {
- dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
- (PROT_READ | PROT_WRITE),
- (MAP_SHARED), Mod->fd,
- (off_t)_GateHWSpinlock_cfgParams.baseAddr);
-
- if (dst == (UInt32)MAP_FAILED) {
- PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
- status = GateHWSpinlock_E_OSFAILURE;
- close(Mod->fd);
- Mod->fd = -1;
+ if (!Mod->useHwlockDrv) {
+ /* make sure /dev/mem fd doesn't exist for 'fork() -> exec*()'ed child */
+ flags = fcntl(Mod->fd, F_GETFD);
+ if (flags != -1) {
+ fcntl(Mod->fd, F_SETFD, flags | FD_CLOEXEC);
}
- else {
- Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
- status = GateHWSpinlock_S_SUCCESS;
+
+ /* map the hardware lock registers into the local address space */
+ if (status == GateHWSpinlock_S_SUCCESS) {
+ dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
+ (PROT_READ | PROT_WRITE),
+ (MAP_SHARED), Mod->fd,
+ (off_t)_GateHWSpinlock_cfgParams.baseAddr);
+
+ if (dst == (UInt32)MAP_FAILED) {
+ PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
+ status = GateHWSpinlock_E_OSFAILURE;
+ close(Mod->fd);
+ Mod->fd = -1;
+ }
+ else {
+ Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
+ status = GateHWSpinlock_S_SUCCESS;
+ }
}
}
@@ -232,7 +247,7 @@ Int GateHWSpinlock_stop(Void)
}
/* release lock register mapping */
- if (Mod->baseAddr != NULL) {
+ if (!Mod->useHwlockDrv && (Mod->baseAddr != NULL)) {
munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
_GateHWSpinlock_cfgParams.size);
}
@@ -310,7 +325,12 @@ Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
{
volatile UInt32 *baseAddr = Mod->baseAddr;
+ struct hwspinlock_user_lock data = {
+ .id = obj->lockNum,
+ .timeout = 10,
+ };
IArg key;
+ Bool locked;
key = IGateProvider_enter(obj->localGate);
@@ -322,10 +342,18 @@ IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
/* enter the spinlock */
while (1) {
- /* read the spinlock, returns non-zero when we get it */
- if (baseAddr[obj->lockNum] == 0) {
+ if (Mod->useHwlockDrv) {
+ locked = !ioctl(Mod->fd, HWSPINLOCK_USER_LOCK, &data);
+ }
+ else {
+ /* read the spinlock, returns non-zero when we get it */
+ locked = (baseAddr[obj->lockNum] == 0);
+ }
+
+ if (locked) {
break;
}
+
obj->nested--;
IGateProvider_leave(obj->localGate, key);
key = IGateProvider_enter(obj->localGate);
@@ -341,12 +369,20 @@ IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
{
volatile UInt32 *baseAddr = Mod->baseAddr;
+ struct hwspinlock_user_unlock data = {
+ .id = obj->lockNum,
+ };
obj->nested--;
/* release the spinlock if not nested */
if (obj->nested == 0) {
- baseAddr[obj->lockNum] = 0;
+ if (Mod->useHwlockDrv) {
+ ioctl(Mod->fd, HWSPINLOCK_USER_UNLOCK, &data);
+ }
+ else {
+ baseAddr[obj->lockNum] = 0;
+ }
}
IGateProvider_leave(obj->localGate, key);
diff --git a/linux/src/daemon/GateHWSpinlock.c b/linux/src/daemon/GateHWSpinlock.c
index 9ea4d09..391b6f6 100644
--- a/linux/src/daemon/GateHWSpinlock.c
+++ b/linux/src/daemon/GateHWSpinlock.c
@@ -63,6 +63,9 @@ typedef UInt32 Error_Block;
#include <sys/mman.h>
#include <sys/stat.h>
+#include <linux/ioctl.h>
+#include <linux/hwspinlock_user.h>
+
/* =============================================================================
* Structures & Enums
* =============================================================================
@@ -72,6 +75,7 @@ typedef struct {
Int32 fd; /* spinlock device handle */
UInt32 * baseAddr; /* base addr lock registers */
GateMutex_Handle gmHandle; /* handle to gate mutex */
+ Bool useHwlockDrv; /* use the hwspinlock driver */
} GateHWSpinlock_Module_State;
/* GateHWSpinlock instance object */
@@ -94,7 +98,8 @@ static GateHWSpinlock_Module_State GateHWSpinlock_state =
{
.fd = -1,
.baseAddr = NULL,
- .gmHandle = NULL
+ .gmHandle = NULL,
+ .useHwlockDrv = false,
};
static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
@@ -119,14 +124,22 @@ Int32 GateHWSpinlock_start(Void)
Int32 status = GateHWSpinlock_S_SUCCESS;
UInt32 dst;
- Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
+ /* Fall back to /dev/mem if hwspinlock_user driver is not supported */
+ Mod->fd = open("/dev/hwspinlock", O_RDWR);
+ if (Mod->fd < 0) {
+ Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
+ }
+ else {
+ Mod->useHwlockDrv = true;
+ }
+
if (Mod->fd < 0){
- LOG0("GateHWSpinlock_start: failed to open the /dev/mem");
+ LOG0("GateHWSpinlock_start: failed to open the spinlock device");
status = GateHWSpinlock_E_OSFAILURE;
}
/* map the hardware lock registers into the local address space */
- if (status == GateHWSpinlock_S_SUCCESS) {
+ if (!Mod->useHwlockDrv && status == GateHWSpinlock_S_SUCCESS) {
dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
(PROT_READ | PROT_WRITE),
(MAP_SHARED), Mod->fd,
@@ -171,7 +184,7 @@ Int GateHWSpinlock_stop(Void)
}
/* release lock register mapping */
- if (Mod->baseAddr != NULL) {
+ if (!Mod->useHwlockDrv && (Mod->baseAddr != NULL)) {
munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
_GateHWSpinlock_cfgParams.size);
}
@@ -249,7 +262,12 @@ Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
{
volatile UInt32 *baseAddr = Mod->baseAddr;
+ struct hwspinlock_user_lock data = {
+ .id = obj->lockNum,
+ .timeout = 10,
+ };
IArg key;
+ Bool locked;
key = IGateProvider_enter(obj->localGate);
@@ -261,10 +279,18 @@ IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
/* enter the spinlock */
while (1) {
- /* read the spinlock, returns non-zero when we get it */
- if (baseAddr[obj->lockNum] == 0) {
+ if (Mod->useHwlockDrv) {
+ locked = !ioctl(Mod->fd, HWSPINLOCK_USER_LOCK, &data);
+ }
+ else {
+ /* read the spinlock, returns non-zero when we get it */
+ locked = (baseAddr[obj->lockNum] == 0);
+ }
+
+ if (locked) {
break;
}
+
obj->nested--;
IGateProvider_leave(obj->localGate, key);
key = IGateProvider_enter(obj->localGate);
@@ -280,12 +306,20 @@ IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
{
volatile UInt32 *baseAddr = Mod->baseAddr;
+ struct hwspinlock_user_unlock data = {
+ .id = obj->lockNum,
+ };
obj->nested--;
/* release the spinlock if not nested */
if (obj->nested == 0) {
- baseAddr[obj->lockNum] = 0;
+ if (Mod->useHwlockDrv) {
+ ioctl(Mod->fd, HWSPINLOCK_USER_UNLOCK, &data);
+ }
+ else {
+ baseAddr[obj->lockNum] = 0;
+ }
}
IGateProvider_leave(obj->localGate, key);