diff options
author | Misael Lopez Cruz <misael.lopez@ti.com> | 2015-12-18 15:50:52 -0600 |
---|---|---|
committer | Angela Stegmaier <angelabaker@ti.com> | 2015-12-21 16:05:04 -0600 |
commit | f8affd036b856fb493b4663ac0b4e436660a2192 (patch) | |
tree | 5457692aec18b3c13565154ebb85312b4dda5ece | |
parent | e0b95f9b90473ffedc6e8f6999a933b9f77246ce (diff) | |
download | ipc-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.h | 63 | ||||
-rw-r--r-- | linux/src/api/gates/GateHWSpinlock.c | 92 | ||||
-rw-r--r-- | linux/src/daemon/GateHWSpinlock.c | 50 |
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); |