195ca6d73SMauro Carvalho Chehab=========================== 295ca6d73SMauro Carvalho ChehabHardware Spinlock Framework 395ca6d73SMauro Carvalho Chehab=========================== 495ca6d73SMauro Carvalho Chehab 595ca6d73SMauro Carvalho ChehabIntroduction 695ca6d73SMauro Carvalho Chehab============ 795ca6d73SMauro Carvalho Chehab 895ca6d73SMauro Carvalho ChehabHardware spinlock modules provide hardware assistance for synchronization 995ca6d73SMauro Carvalho Chehaband mutual exclusion between heterogeneous processors and those not operating 1095ca6d73SMauro Carvalho Chehabunder a single, shared operating system. 1195ca6d73SMauro Carvalho Chehab 1295ca6d73SMauro Carvalho ChehabFor example, OMAP4 has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP, 1395ca6d73SMauro Carvalho Chehabeach of which is running a different Operating System (the master, A9, 1495ca6d73SMauro Carvalho Chehabis usually running Linux and the slave processors, the M3 and the DSP, 1595ca6d73SMauro Carvalho Chehabare running some flavor of RTOS). 1695ca6d73SMauro Carvalho Chehab 1795ca6d73SMauro Carvalho ChehabA generic hwspinlock framework allows platform-independent drivers to use 1895ca6d73SMauro Carvalho Chehabthe hwspinlock device in order to access data structures that are shared 1995ca6d73SMauro Carvalho Chehabbetween remote processors, that otherwise have no alternative mechanism 2095ca6d73SMauro Carvalho Chehabto accomplish synchronization and mutual exclusion operations. 2195ca6d73SMauro Carvalho Chehab 2295ca6d73SMauro Carvalho ChehabThis is necessary, for example, for Inter-processor communications: 2395ca6d73SMauro Carvalho Chehabon OMAP4, cpu-intensive multimedia tasks are offloaded by the host to the 2495ca6d73SMauro Carvalho Chehabremote M3 and/or C64x+ slave processors (by an IPC subsystem called Syslink). 2595ca6d73SMauro Carvalho Chehab 2695ca6d73SMauro Carvalho ChehabTo achieve fast message-based communications, a minimal kernel support 2795ca6d73SMauro Carvalho Chehabis needed to deliver messages arriving from a remote processor to the 2895ca6d73SMauro Carvalho Chehabappropriate user process. 2995ca6d73SMauro Carvalho Chehab 3095ca6d73SMauro Carvalho ChehabThis communication is based on simple data structures that is shared between 3195ca6d73SMauro Carvalho Chehabthe remote processors, and access to it is synchronized using the hwspinlock 3295ca6d73SMauro Carvalho Chehabmodule (remote processor directly places new messages in this shared data 3395ca6d73SMauro Carvalho Chehabstructure). 3495ca6d73SMauro Carvalho Chehab 3595ca6d73SMauro Carvalho ChehabA common hwspinlock interface makes it possible to have generic, platform- 3695ca6d73SMauro Carvalho Chehabindependent, drivers. 3795ca6d73SMauro Carvalho Chehab 3895ca6d73SMauro Carvalho ChehabUser API 3995ca6d73SMauro Carvalho Chehab======== 4095ca6d73SMauro Carvalho Chehab 4195ca6d73SMauro Carvalho Chehab:: 4295ca6d73SMauro Carvalho Chehab 4395ca6d73SMauro Carvalho Chehab struct hwspinlock *hwspin_lock_request(void); 4495ca6d73SMauro Carvalho Chehab 4595ca6d73SMauro Carvalho ChehabDynamically assign an hwspinlock and return its address, or NULL 4695ca6d73SMauro Carvalho Chehabin case an unused hwspinlock isn't available. Users of this 4795ca6d73SMauro Carvalho ChehabAPI will usually want to communicate the lock's id to the remote core 4895ca6d73SMauro Carvalho Chehabbefore it can be used to achieve synchronization. 4995ca6d73SMauro Carvalho Chehab 5095ca6d73SMauro Carvalho ChehabShould be called from a process context (might sleep). 5195ca6d73SMauro Carvalho Chehab 5295ca6d73SMauro Carvalho Chehab:: 5395ca6d73SMauro Carvalho Chehab 5495ca6d73SMauro Carvalho Chehab struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 5595ca6d73SMauro Carvalho Chehab 5695ca6d73SMauro Carvalho ChehabAssign a specific hwspinlock id and return its address, or NULL 5795ca6d73SMauro Carvalho Chehabif that hwspinlock is already in use. Usually board code will 5895ca6d73SMauro Carvalho Chehabbe calling this function in order to reserve specific hwspinlock 5995ca6d73SMauro Carvalho Chehabids for predefined purposes. 6095ca6d73SMauro Carvalho Chehab 6195ca6d73SMauro Carvalho ChehabShould be called from a process context (might sleep). 6295ca6d73SMauro Carvalho Chehab 6395ca6d73SMauro Carvalho Chehab:: 6495ca6d73SMauro Carvalho Chehab 6595ca6d73SMauro Carvalho Chehab int of_hwspin_lock_get_id(struct device_node *np, int index); 6695ca6d73SMauro Carvalho Chehab 6795ca6d73SMauro Carvalho ChehabRetrieve the global lock id for an OF phandle-based specific lock. 6895ca6d73SMauro Carvalho ChehabThis function provides a means for DT users of a hwspinlock module 6995ca6d73SMauro Carvalho Chehabto get the global lock id of a specific hwspinlock, so that it can 7095ca6d73SMauro Carvalho Chehabbe requested using the normal hwspin_lock_request_specific() API. 7195ca6d73SMauro Carvalho Chehab 7295ca6d73SMauro Carvalho ChehabThe function returns a lock id number on success, -EPROBE_DEFER if 7395ca6d73SMauro Carvalho Chehabthe hwspinlock device is not yet registered with the core, or other 7495ca6d73SMauro Carvalho Chehaberror values. 7595ca6d73SMauro Carvalho Chehab 7695ca6d73SMauro Carvalho ChehabShould be called from a process context (might sleep). 7795ca6d73SMauro Carvalho Chehab 7895ca6d73SMauro Carvalho Chehab:: 7995ca6d73SMauro Carvalho Chehab 8095ca6d73SMauro Carvalho Chehab int hwspin_lock_free(struct hwspinlock *hwlock); 8195ca6d73SMauro Carvalho Chehab 8295ca6d73SMauro Carvalho ChehabFree a previously-assigned hwspinlock; returns 0 on success, or an 8395ca6d73SMauro Carvalho Chehabappropriate error code on failure (e.g. -EINVAL if the hwspinlock 8495ca6d73SMauro Carvalho Chehabis already free). 8595ca6d73SMauro Carvalho Chehab 8695ca6d73SMauro Carvalho ChehabShould be called from a process context (might sleep). 8795ca6d73SMauro Carvalho Chehab 8895ca6d73SMauro Carvalho Chehab:: 8995ca6d73SMauro Carvalho Chehab 90*a6978d1bSRichard Maina int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id); 91*a6978d1bSRichard Maina 92*a6978d1bSRichard MainaAfter verifying the owner of the hwspinlock, release a previously acquired 93*a6978d1bSRichard Mainahwspinlock; returns 0 on success, or an appropriate error code on failure 94*a6978d1bSRichard Maina(e.g. -EOPNOTSUPP if the bust operation is not defined for the specific 95*a6978d1bSRichard Mainahwspinlock). 96*a6978d1bSRichard Maina 97*a6978d1bSRichard MainaShould be called from a process context (might sleep). 98*a6978d1bSRichard Maina 99*a6978d1bSRichard Maina:: 100*a6978d1bSRichard Maina 10195ca6d73SMauro Carvalho Chehab int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); 10295ca6d73SMauro Carvalho Chehab 10395ca6d73SMauro Carvalho ChehabLock a previously-assigned hwspinlock with a timeout limit (specified in 10495ca6d73SMauro Carvalho Chehabmsecs). If the hwspinlock is already taken, the function will busy loop 10595ca6d73SMauro Carvalho Chehabwaiting for it to be released, but give up when the timeout elapses. 10695ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption is disabled so 10795ca6d73SMauro Carvalho Chehabthe caller must not sleep, and is advised to release the hwspinlock as 10895ca6d73SMauro Carvalho Chehabsoon as possible, in order to minimize remote cores polling on the 10995ca6d73SMauro Carvalho Chehabhardware interconnect. 11095ca6d73SMauro Carvalho Chehab 11195ca6d73SMauro Carvalho ChehabReturns 0 when successful and an appropriate error code otherwise (most 11295ca6d73SMauro Carvalho Chehabnotably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). 11395ca6d73SMauro Carvalho ChehabThe function will never sleep. 11495ca6d73SMauro Carvalho Chehab 11595ca6d73SMauro Carvalho Chehab:: 11695ca6d73SMauro Carvalho Chehab 11795ca6d73SMauro Carvalho Chehab int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int timeout); 11895ca6d73SMauro Carvalho Chehab 11995ca6d73SMauro Carvalho ChehabLock a previously-assigned hwspinlock with a timeout limit (specified in 12095ca6d73SMauro Carvalho Chehabmsecs). If the hwspinlock is already taken, the function will busy loop 12195ca6d73SMauro Carvalho Chehabwaiting for it to be released, but give up when the timeout elapses. 12295ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption and the local 12395ca6d73SMauro Carvalho Chehabinterrupts are disabled, so the caller must not sleep, and is advised to 12495ca6d73SMauro Carvalho Chehabrelease the hwspinlock as soon as possible. 12595ca6d73SMauro Carvalho Chehab 12695ca6d73SMauro Carvalho ChehabReturns 0 when successful and an appropriate error code otherwise (most 12795ca6d73SMauro Carvalho Chehabnotably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). 12895ca6d73SMauro Carvalho ChehabThe function will never sleep. 12995ca6d73SMauro Carvalho Chehab 13095ca6d73SMauro Carvalho Chehab:: 13195ca6d73SMauro Carvalho Chehab 13295ca6d73SMauro Carvalho Chehab int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to, 13395ca6d73SMauro Carvalho Chehab unsigned long *flags); 13495ca6d73SMauro Carvalho Chehab 13595ca6d73SMauro Carvalho ChehabLock a previously-assigned hwspinlock with a timeout limit (specified in 13695ca6d73SMauro Carvalho Chehabmsecs). If the hwspinlock is already taken, the function will busy loop 13795ca6d73SMauro Carvalho Chehabwaiting for it to be released, but give up when the timeout elapses. 13895ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption is disabled, 13995ca6d73SMauro Carvalho Chehablocal interrupts are disabled and their previous state is saved at the 14095ca6d73SMauro Carvalho Chehabgiven flags placeholder. The caller must not sleep, and is advised to 14195ca6d73SMauro Carvalho Chehabrelease the hwspinlock as soon as possible. 14295ca6d73SMauro Carvalho Chehab 14395ca6d73SMauro Carvalho ChehabReturns 0 when successful and an appropriate error code otherwise (most 14495ca6d73SMauro Carvalho Chehabnotably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). 14595ca6d73SMauro Carvalho Chehab 14695ca6d73SMauro Carvalho ChehabThe function will never sleep. 14795ca6d73SMauro Carvalho Chehab 14895ca6d73SMauro Carvalho Chehab:: 14995ca6d73SMauro Carvalho Chehab 15095ca6d73SMauro Carvalho Chehab int hwspin_lock_timeout_raw(struct hwspinlock *hwlock, unsigned int timeout); 15195ca6d73SMauro Carvalho Chehab 15295ca6d73SMauro Carvalho ChehabLock a previously-assigned hwspinlock with a timeout limit (specified in 15395ca6d73SMauro Carvalho Chehabmsecs). If the hwspinlock is already taken, the function will busy loop 15495ca6d73SMauro Carvalho Chehabwaiting for it to be released, but give up when the timeout elapses. 15595ca6d73SMauro Carvalho Chehab 15695ca6d73SMauro Carvalho ChehabCaution: User must protect the routine of getting hardware lock with mutex 15795ca6d73SMauro Carvalho Chehabor spinlock to avoid dead-lock, that will let user can do some time-consuming 15895ca6d73SMauro Carvalho Chehabor sleepable operations under the hardware lock. 15995ca6d73SMauro Carvalho Chehab 16095ca6d73SMauro Carvalho ChehabReturns 0 when successful and an appropriate error code otherwise (most 16195ca6d73SMauro Carvalho Chehabnotably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). 16295ca6d73SMauro Carvalho Chehab 16395ca6d73SMauro Carvalho ChehabThe function will never sleep. 16495ca6d73SMauro Carvalho Chehab 16595ca6d73SMauro Carvalho Chehab:: 16695ca6d73SMauro Carvalho Chehab 16795ca6d73SMauro Carvalho Chehab int hwspin_lock_timeout_in_atomic(struct hwspinlock *hwlock, unsigned int to); 16895ca6d73SMauro Carvalho Chehab 16995ca6d73SMauro Carvalho ChehabLock a previously-assigned hwspinlock with a timeout limit (specified in 17095ca6d73SMauro Carvalho Chehabmsecs). If the hwspinlock is already taken, the function will busy loop 17195ca6d73SMauro Carvalho Chehabwaiting for it to be released, but give up when the timeout elapses. 17295ca6d73SMauro Carvalho Chehab 17395ca6d73SMauro Carvalho ChehabThis function shall be called only from an atomic context and the timeout 17495ca6d73SMauro Carvalho Chehabvalue shall not exceed a few msecs. 17595ca6d73SMauro Carvalho Chehab 17695ca6d73SMauro Carvalho ChehabReturns 0 when successful and an appropriate error code otherwise (most 17795ca6d73SMauro Carvalho Chehabnotably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs). 17895ca6d73SMauro Carvalho Chehab 17995ca6d73SMauro Carvalho ChehabThe function will never sleep. 18095ca6d73SMauro Carvalho Chehab 18195ca6d73SMauro Carvalho Chehab:: 18295ca6d73SMauro Carvalho Chehab 18395ca6d73SMauro Carvalho Chehab int hwspin_trylock(struct hwspinlock *hwlock); 18495ca6d73SMauro Carvalho Chehab 18595ca6d73SMauro Carvalho Chehab 18695ca6d73SMauro Carvalho ChehabAttempt to lock a previously-assigned hwspinlock, but immediately fail if 18795ca6d73SMauro Carvalho Chehabit is already taken. 18895ca6d73SMauro Carvalho Chehab 18995ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption is disabled so 19095ca6d73SMauro Carvalho Chehabcaller must not sleep, and is advised to release the hwspinlock as soon as 19195ca6d73SMauro Carvalho Chehabpossible, in order to minimize remote cores polling on the hardware 19295ca6d73SMauro Carvalho Chehabinterconnect. 19395ca6d73SMauro Carvalho Chehab 19495ca6d73SMauro Carvalho ChehabReturns 0 on success and an appropriate error code otherwise (most 19595ca6d73SMauro Carvalho Chehabnotably -EBUSY if the hwspinlock was already taken). 19695ca6d73SMauro Carvalho ChehabThe function will never sleep. 19795ca6d73SMauro Carvalho Chehab 19895ca6d73SMauro Carvalho Chehab:: 19995ca6d73SMauro Carvalho Chehab 20095ca6d73SMauro Carvalho Chehab int hwspin_trylock_irq(struct hwspinlock *hwlock); 20195ca6d73SMauro Carvalho Chehab 20295ca6d73SMauro Carvalho Chehab 20395ca6d73SMauro Carvalho ChehabAttempt to lock a previously-assigned hwspinlock, but immediately fail if 20495ca6d73SMauro Carvalho Chehabit is already taken. 20595ca6d73SMauro Carvalho Chehab 20695ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption and the local 20795ca6d73SMauro Carvalho Chehabinterrupts are disabled so caller must not sleep, and is advised to 20895ca6d73SMauro Carvalho Chehabrelease the hwspinlock as soon as possible. 20995ca6d73SMauro Carvalho Chehab 21095ca6d73SMauro Carvalho ChehabReturns 0 on success and an appropriate error code otherwise (most 21195ca6d73SMauro Carvalho Chehabnotably -EBUSY if the hwspinlock was already taken). 21295ca6d73SMauro Carvalho Chehab 21395ca6d73SMauro Carvalho ChehabThe function will never sleep. 21495ca6d73SMauro Carvalho Chehab 21595ca6d73SMauro Carvalho Chehab:: 21695ca6d73SMauro Carvalho Chehab 21795ca6d73SMauro Carvalho Chehab int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags); 21895ca6d73SMauro Carvalho Chehab 21995ca6d73SMauro Carvalho ChehabAttempt to lock a previously-assigned hwspinlock, but immediately fail if 22095ca6d73SMauro Carvalho Chehabit is already taken. 22195ca6d73SMauro Carvalho Chehab 22295ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption is disabled, 22395ca6d73SMauro Carvalho Chehabthe local interrupts are disabled and their previous state is saved 22495ca6d73SMauro Carvalho Chehabat the given flags placeholder. The caller must not sleep, and is advised 22595ca6d73SMauro Carvalho Chehabto release the hwspinlock as soon as possible. 22695ca6d73SMauro Carvalho Chehab 22795ca6d73SMauro Carvalho ChehabReturns 0 on success and an appropriate error code otherwise (most 22895ca6d73SMauro Carvalho Chehabnotably -EBUSY if the hwspinlock was already taken). 22995ca6d73SMauro Carvalho ChehabThe function will never sleep. 23095ca6d73SMauro Carvalho Chehab 23195ca6d73SMauro Carvalho Chehab:: 23295ca6d73SMauro Carvalho Chehab 23395ca6d73SMauro Carvalho Chehab int hwspin_trylock_raw(struct hwspinlock *hwlock); 23495ca6d73SMauro Carvalho Chehab 23595ca6d73SMauro Carvalho ChehabAttempt to lock a previously-assigned hwspinlock, but immediately fail if 23695ca6d73SMauro Carvalho Chehabit is already taken. 23795ca6d73SMauro Carvalho Chehab 23895ca6d73SMauro Carvalho ChehabCaution: User must protect the routine of getting hardware lock with mutex 23995ca6d73SMauro Carvalho Chehabor spinlock to avoid dead-lock, that will let user can do some time-consuming 24095ca6d73SMauro Carvalho Chehabor sleepable operations under the hardware lock. 24195ca6d73SMauro Carvalho Chehab 24295ca6d73SMauro Carvalho ChehabReturns 0 on success and an appropriate error code otherwise (most 24395ca6d73SMauro Carvalho Chehabnotably -EBUSY if the hwspinlock was already taken). 24495ca6d73SMauro Carvalho ChehabThe function will never sleep. 24595ca6d73SMauro Carvalho Chehab 24695ca6d73SMauro Carvalho Chehab:: 24795ca6d73SMauro Carvalho Chehab 24895ca6d73SMauro Carvalho Chehab int hwspin_trylock_in_atomic(struct hwspinlock *hwlock); 24995ca6d73SMauro Carvalho Chehab 25095ca6d73SMauro Carvalho ChehabAttempt to lock a previously-assigned hwspinlock, but immediately fail if 25195ca6d73SMauro Carvalho Chehabit is already taken. 25295ca6d73SMauro Carvalho Chehab 25395ca6d73SMauro Carvalho ChehabThis function shall be called only from an atomic context. 25495ca6d73SMauro Carvalho Chehab 25595ca6d73SMauro Carvalho ChehabReturns 0 on success and an appropriate error code otherwise (most 25695ca6d73SMauro Carvalho Chehabnotably -EBUSY if the hwspinlock was already taken). 25795ca6d73SMauro Carvalho ChehabThe function will never sleep. 25895ca6d73SMauro Carvalho Chehab 25995ca6d73SMauro Carvalho Chehab:: 26095ca6d73SMauro Carvalho Chehab 26195ca6d73SMauro Carvalho Chehab void hwspin_unlock(struct hwspinlock *hwlock); 26295ca6d73SMauro Carvalho Chehab 26395ca6d73SMauro Carvalho ChehabUnlock a previously-locked hwspinlock. Always succeed, and can be called 26495ca6d73SMauro Carvalho Chehabfrom any context (the function never sleeps). 26595ca6d73SMauro Carvalho Chehab 26695ca6d73SMauro Carvalho Chehab.. note:: 26795ca6d73SMauro Carvalho Chehab 26895ca6d73SMauro Carvalho Chehab code should **never** unlock an hwspinlock which is already unlocked 26995ca6d73SMauro Carvalho Chehab (there is no protection against this). 27095ca6d73SMauro Carvalho Chehab 27195ca6d73SMauro Carvalho Chehab:: 27295ca6d73SMauro Carvalho Chehab 27395ca6d73SMauro Carvalho Chehab void hwspin_unlock_irq(struct hwspinlock *hwlock); 27495ca6d73SMauro Carvalho Chehab 27595ca6d73SMauro Carvalho ChehabUnlock a previously-locked hwspinlock and enable local interrupts. 27695ca6d73SMauro Carvalho ChehabThe caller should **never** unlock an hwspinlock which is already unlocked. 27795ca6d73SMauro Carvalho Chehab 27895ca6d73SMauro Carvalho ChehabDoing so is considered a bug (there is no protection against this). 27995ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption and local 28095ca6d73SMauro Carvalho Chehabinterrupts are enabled. This function will never sleep. 28195ca6d73SMauro Carvalho Chehab 28295ca6d73SMauro Carvalho Chehab:: 28395ca6d73SMauro Carvalho Chehab 28495ca6d73SMauro Carvalho Chehab void 28595ca6d73SMauro Carvalho Chehab hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags); 28695ca6d73SMauro Carvalho Chehab 28795ca6d73SMauro Carvalho ChehabUnlock a previously-locked hwspinlock. 28895ca6d73SMauro Carvalho Chehab 28995ca6d73SMauro Carvalho ChehabThe caller should **never** unlock an hwspinlock which is already unlocked. 29095ca6d73SMauro Carvalho ChehabDoing so is considered a bug (there is no protection against this). 29195ca6d73SMauro Carvalho ChehabUpon a successful return from this function, preemption is reenabled, 29295ca6d73SMauro Carvalho Chehaband the state of the local interrupts is restored to the state saved at 29395ca6d73SMauro Carvalho Chehabthe given flags. This function will never sleep. 29495ca6d73SMauro Carvalho Chehab 29595ca6d73SMauro Carvalho Chehab:: 29695ca6d73SMauro Carvalho Chehab 29795ca6d73SMauro Carvalho Chehab void hwspin_unlock_raw(struct hwspinlock *hwlock); 29895ca6d73SMauro Carvalho Chehab 29995ca6d73SMauro Carvalho ChehabUnlock a previously-locked hwspinlock. 30095ca6d73SMauro Carvalho Chehab 30195ca6d73SMauro Carvalho ChehabThe caller should **never** unlock an hwspinlock which is already unlocked. 30295ca6d73SMauro Carvalho ChehabDoing so is considered a bug (there is no protection against this). 30395ca6d73SMauro Carvalho ChehabThis function will never sleep. 30495ca6d73SMauro Carvalho Chehab 30595ca6d73SMauro Carvalho Chehab:: 30695ca6d73SMauro Carvalho Chehab 30795ca6d73SMauro Carvalho Chehab void hwspin_unlock_in_atomic(struct hwspinlock *hwlock); 30895ca6d73SMauro Carvalho Chehab 30995ca6d73SMauro Carvalho ChehabUnlock a previously-locked hwspinlock. 31095ca6d73SMauro Carvalho Chehab 31195ca6d73SMauro Carvalho ChehabThe caller should **never** unlock an hwspinlock which is already unlocked. 31295ca6d73SMauro Carvalho ChehabDoing so is considered a bug (there is no protection against this). 31395ca6d73SMauro Carvalho ChehabThis function will never sleep. 31495ca6d73SMauro Carvalho Chehab 31595ca6d73SMauro Carvalho Chehab:: 31695ca6d73SMauro Carvalho Chehab 31795ca6d73SMauro Carvalho Chehab int hwspin_lock_get_id(struct hwspinlock *hwlock); 31895ca6d73SMauro Carvalho Chehab 31995ca6d73SMauro Carvalho ChehabRetrieve id number of a given hwspinlock. This is needed when an 32095ca6d73SMauro Carvalho Chehabhwspinlock is dynamically assigned: before it can be used to achieve 32195ca6d73SMauro Carvalho Chehabmutual exclusion with a remote cpu, the id number should be communicated 32295ca6d73SMauro Carvalho Chehabto the remote task with which we want to synchronize. 32395ca6d73SMauro Carvalho Chehab 32495ca6d73SMauro Carvalho ChehabReturns the hwspinlock id number, or -EINVAL if hwlock is null. 32595ca6d73SMauro Carvalho Chehab 32695ca6d73SMauro Carvalho ChehabTypical usage 32795ca6d73SMauro Carvalho Chehab============= 32895ca6d73SMauro Carvalho Chehab 32995ca6d73SMauro Carvalho Chehab:: 33095ca6d73SMauro Carvalho Chehab 33195ca6d73SMauro Carvalho Chehab #include <linux/hwspinlock.h> 33295ca6d73SMauro Carvalho Chehab #include <linux/err.h> 33395ca6d73SMauro Carvalho Chehab 33495ca6d73SMauro Carvalho Chehab int hwspinlock_example1(void) 33595ca6d73SMauro Carvalho Chehab { 33695ca6d73SMauro Carvalho Chehab struct hwspinlock *hwlock; 33795ca6d73SMauro Carvalho Chehab int ret; 33895ca6d73SMauro Carvalho Chehab 33995ca6d73SMauro Carvalho Chehab /* dynamically assign a hwspinlock */ 34095ca6d73SMauro Carvalho Chehab hwlock = hwspin_lock_request(); 34195ca6d73SMauro Carvalho Chehab if (!hwlock) 34295ca6d73SMauro Carvalho Chehab ... 34395ca6d73SMauro Carvalho Chehab 34495ca6d73SMauro Carvalho Chehab id = hwspin_lock_get_id(hwlock); 34595ca6d73SMauro Carvalho Chehab /* probably need to communicate id to a remote processor now */ 34695ca6d73SMauro Carvalho Chehab 34795ca6d73SMauro Carvalho Chehab /* take the lock, spin for 1 sec if it's already taken */ 34895ca6d73SMauro Carvalho Chehab ret = hwspin_lock_timeout(hwlock, 1000); 34995ca6d73SMauro Carvalho Chehab if (ret) 35095ca6d73SMauro Carvalho Chehab ... 35195ca6d73SMauro Carvalho Chehab 35295ca6d73SMauro Carvalho Chehab /* 35395ca6d73SMauro Carvalho Chehab * we took the lock, do our thing now, but do NOT sleep 35495ca6d73SMauro Carvalho Chehab */ 35595ca6d73SMauro Carvalho Chehab 35695ca6d73SMauro Carvalho Chehab /* release the lock */ 35795ca6d73SMauro Carvalho Chehab hwspin_unlock(hwlock); 35895ca6d73SMauro Carvalho Chehab 35995ca6d73SMauro Carvalho Chehab /* free the lock */ 36095ca6d73SMauro Carvalho Chehab ret = hwspin_lock_free(hwlock); 36195ca6d73SMauro Carvalho Chehab if (ret) 36295ca6d73SMauro Carvalho Chehab ... 36395ca6d73SMauro Carvalho Chehab 36495ca6d73SMauro Carvalho Chehab return ret; 36595ca6d73SMauro Carvalho Chehab } 36695ca6d73SMauro Carvalho Chehab 36795ca6d73SMauro Carvalho Chehab int hwspinlock_example2(void) 36895ca6d73SMauro Carvalho Chehab { 36995ca6d73SMauro Carvalho Chehab struct hwspinlock *hwlock; 37095ca6d73SMauro Carvalho Chehab int ret; 37195ca6d73SMauro Carvalho Chehab 37295ca6d73SMauro Carvalho Chehab /* 37395ca6d73SMauro Carvalho Chehab * assign a specific hwspinlock id - this should be called early 37495ca6d73SMauro Carvalho Chehab * by board init code. 37595ca6d73SMauro Carvalho Chehab */ 37695ca6d73SMauro Carvalho Chehab hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID); 37795ca6d73SMauro Carvalho Chehab if (!hwlock) 37895ca6d73SMauro Carvalho Chehab ... 37995ca6d73SMauro Carvalho Chehab 38095ca6d73SMauro Carvalho Chehab /* try to take it, but don't spin on it */ 38195ca6d73SMauro Carvalho Chehab ret = hwspin_trylock(hwlock); 38295ca6d73SMauro Carvalho Chehab if (!ret) { 38395ca6d73SMauro Carvalho Chehab pr_info("lock is already taken\n"); 38495ca6d73SMauro Carvalho Chehab return -EBUSY; 38595ca6d73SMauro Carvalho Chehab } 38695ca6d73SMauro Carvalho Chehab 38795ca6d73SMauro Carvalho Chehab /* 38895ca6d73SMauro Carvalho Chehab * we took the lock, do our thing now, but do NOT sleep 38995ca6d73SMauro Carvalho Chehab */ 39095ca6d73SMauro Carvalho Chehab 39195ca6d73SMauro Carvalho Chehab /* release the lock */ 39295ca6d73SMauro Carvalho Chehab hwspin_unlock(hwlock); 39395ca6d73SMauro Carvalho Chehab 39495ca6d73SMauro Carvalho Chehab /* free the lock */ 39595ca6d73SMauro Carvalho Chehab ret = hwspin_lock_free(hwlock); 39695ca6d73SMauro Carvalho Chehab if (ret) 39795ca6d73SMauro Carvalho Chehab ... 39895ca6d73SMauro Carvalho Chehab 39995ca6d73SMauro Carvalho Chehab return ret; 40095ca6d73SMauro Carvalho Chehab } 40195ca6d73SMauro Carvalho Chehab 40295ca6d73SMauro Carvalho Chehab 40395ca6d73SMauro Carvalho ChehabAPI for implementors 40495ca6d73SMauro Carvalho Chehab==================== 40595ca6d73SMauro Carvalho Chehab 40695ca6d73SMauro Carvalho Chehab:: 40795ca6d73SMauro Carvalho Chehab 40895ca6d73SMauro Carvalho Chehab int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, 40995ca6d73SMauro Carvalho Chehab const struct hwspinlock_ops *ops, int base_id, int num_locks); 41095ca6d73SMauro Carvalho Chehab 41195ca6d73SMauro Carvalho ChehabTo be called from the underlying platform-specific implementation, in 41295ca6d73SMauro Carvalho Chehaborder to register a new hwspinlock device (which is usually a bank of 41395ca6d73SMauro Carvalho Chehabnumerous locks). Should be called from a process context (this function 41495ca6d73SMauro Carvalho Chehabmight sleep). 41595ca6d73SMauro Carvalho Chehab 41695ca6d73SMauro Carvalho ChehabReturns 0 on success, or appropriate error code on failure. 41795ca6d73SMauro Carvalho Chehab 41895ca6d73SMauro Carvalho Chehab:: 41995ca6d73SMauro Carvalho Chehab 42095ca6d73SMauro Carvalho Chehab int hwspin_lock_unregister(struct hwspinlock_device *bank); 42195ca6d73SMauro Carvalho Chehab 42295ca6d73SMauro Carvalho ChehabTo be called from the underlying vendor-specific implementation, in order 42395ca6d73SMauro Carvalho Chehabto unregister an hwspinlock device (which is usually a bank of numerous 42495ca6d73SMauro Carvalho Chehablocks). 42595ca6d73SMauro Carvalho Chehab 42695ca6d73SMauro Carvalho ChehabShould be called from a process context (this function might sleep). 42795ca6d73SMauro Carvalho Chehab 42895ca6d73SMauro Carvalho ChehabReturns the address of hwspinlock on success, or NULL on error (e.g. 42995ca6d73SMauro Carvalho Chehabif the hwspinlock is still in use). 43095ca6d73SMauro Carvalho Chehab 43195ca6d73SMauro Carvalho ChehabImportant structs 43295ca6d73SMauro Carvalho Chehab================= 43395ca6d73SMauro Carvalho Chehab 43495ca6d73SMauro Carvalho Chehabstruct hwspinlock_device is a device which usually contains a bank 43595ca6d73SMauro Carvalho Chehabof hardware locks. It is registered by the underlying hwspinlock 43695ca6d73SMauro Carvalho Chehabimplementation using the hwspin_lock_register() API. 43795ca6d73SMauro Carvalho Chehab 43895ca6d73SMauro Carvalho Chehab:: 43995ca6d73SMauro Carvalho Chehab 44095ca6d73SMauro Carvalho Chehab /** 44195ca6d73SMauro Carvalho Chehab * struct hwspinlock_device - a device which usually spans numerous hwspinlocks 44295ca6d73SMauro Carvalho Chehab * @dev: underlying device, will be used to invoke runtime PM api 44395ca6d73SMauro Carvalho Chehab * @ops: platform-specific hwspinlock handlers 44495ca6d73SMauro Carvalho Chehab * @base_id: id index of the first lock in this device 44595ca6d73SMauro Carvalho Chehab * @num_locks: number of locks in this device 44695ca6d73SMauro Carvalho Chehab * @lock: dynamically allocated array of 'struct hwspinlock' 44795ca6d73SMauro Carvalho Chehab */ 44895ca6d73SMauro Carvalho Chehab struct hwspinlock_device { 44995ca6d73SMauro Carvalho Chehab struct device *dev; 45095ca6d73SMauro Carvalho Chehab const struct hwspinlock_ops *ops; 45195ca6d73SMauro Carvalho Chehab int base_id; 45295ca6d73SMauro Carvalho Chehab int num_locks; 45395ca6d73SMauro Carvalho Chehab struct hwspinlock lock[0]; 45495ca6d73SMauro Carvalho Chehab }; 45595ca6d73SMauro Carvalho Chehab 45695ca6d73SMauro Carvalho Chehabstruct hwspinlock_device contains an array of hwspinlock structs, each 45795ca6d73SMauro Carvalho Chehabof which represents a single hardware lock:: 45895ca6d73SMauro Carvalho Chehab 45995ca6d73SMauro Carvalho Chehab /** 46095ca6d73SMauro Carvalho Chehab * struct hwspinlock - this struct represents a single hwspinlock instance 46195ca6d73SMauro Carvalho Chehab * @bank: the hwspinlock_device structure which owns this lock 46295ca6d73SMauro Carvalho Chehab * @lock: initialized and used by hwspinlock core 46395ca6d73SMauro Carvalho Chehab * @priv: private data, owned by the underlying platform-specific hwspinlock drv 46495ca6d73SMauro Carvalho Chehab */ 46595ca6d73SMauro Carvalho Chehab struct hwspinlock { 46695ca6d73SMauro Carvalho Chehab struct hwspinlock_device *bank; 46795ca6d73SMauro Carvalho Chehab spinlock_t lock; 46895ca6d73SMauro Carvalho Chehab void *priv; 46995ca6d73SMauro Carvalho Chehab }; 47095ca6d73SMauro Carvalho Chehab 47195ca6d73SMauro Carvalho ChehabWhen registering a bank of locks, the hwspinlock driver only needs to 47295ca6d73SMauro Carvalho Chehabset the priv members of the locks. The rest of the members are set and 47395ca6d73SMauro Carvalho Chehabinitialized by the hwspinlock core itself. 47495ca6d73SMauro Carvalho Chehab 47595ca6d73SMauro Carvalho ChehabImplementation callbacks 47695ca6d73SMauro Carvalho Chehab======================== 47795ca6d73SMauro Carvalho Chehab 47895ca6d73SMauro Carvalho ChehabThere are three possible callbacks defined in 'struct hwspinlock_ops':: 47995ca6d73SMauro Carvalho Chehab 48095ca6d73SMauro Carvalho Chehab struct hwspinlock_ops { 48195ca6d73SMauro Carvalho Chehab int (*trylock)(struct hwspinlock *lock); 48295ca6d73SMauro Carvalho Chehab void (*unlock)(struct hwspinlock *lock); 48395ca6d73SMauro Carvalho Chehab void (*relax)(struct hwspinlock *lock); 48495ca6d73SMauro Carvalho Chehab }; 48595ca6d73SMauro Carvalho Chehab 48695ca6d73SMauro Carvalho ChehabThe first two callbacks are mandatory: 48795ca6d73SMauro Carvalho Chehab 48895ca6d73SMauro Carvalho ChehabThe ->trylock() callback should make a single attempt to take the lock, and 48995ca6d73SMauro Carvalho Chehabreturn 0 on failure and 1 on success. This callback may **not** sleep. 49095ca6d73SMauro Carvalho Chehab 49195ca6d73SMauro Carvalho ChehabThe ->unlock() callback releases the lock. It always succeed, and it, too, 49295ca6d73SMauro Carvalho Chehabmay **not** sleep. 49395ca6d73SMauro Carvalho Chehab 49495ca6d73SMauro Carvalho ChehabThe ->relax() callback is optional. It is called by hwspinlock core while 49595ca6d73SMauro Carvalho Chehabspinning on a lock, and can be used by the underlying implementation to force 49695ca6d73SMauro Carvalho Chehaba delay between two successive invocations of ->trylock(). It may **not** sleep. 497