0
votes

I read this article http://www.linuxjournal.com/article/5833 to learn about spinlock. I try this to use it in my kernel driver.

Here is what my driver code needs to do: In f1(), it will get the spin lock, and caller can call f2() will wait for the lock since the spin lock is not being unlock. The spin lock will be unlock in my interrupt handler (triggered by the HW).

void f1() {
spin_lock(&mylock);
// write hardware 
REG_ADDR += FLAG_A;

}

void f2() {
spin_lock(&mylock);
//...
}

The hardware will send the application an interrupt and my interrupt handler will call spin_unlock(&mylock);

My question is if I call f1() f2() // i want this to block until the interrupt return saying setting REG_ADDR is done.

when I run this, I get an exception in kernel saying a deadlock " INFO: possible recursive locking detected"

How can I re-write my code so that kernel does not think I have a deadlock?

I want my driver code to wait until HW sends me an interrupt saying setting REG_ADDR is done.

Thank you.

2
I don't think you understand how spinlocks work and what they're used for. A spinlock is usually used to efficiently protect a piece of code where contention is unlikely to occur (a lock is only held for a short amount of time). What exactly are you trying to achieve?tangrs
I want to set a bit in a HW Register 1. HW will send an interrupt when setting the register is done. I want my driver code to block until the interrupt is sent from the HW.michael
What happens if two kernel threads sets same bit at the same time? Who gets the notification from the interrupt handler?tangrs
In my original code, it locks a spin lock before setting the register, so no 2 kernel threads can set the same bit at the same time.michael

2 Answers

2
votes

First, since you'll be expecting to block while waiting for the interrupt, you shouldn't be using spinlocks to lock the hardware as you'll probably be holding the lock for a long time. Using a spinlock in this case will waste a lot of CPU cycles if that function is called frequently.

I would first use a mutex to lock access to the hardware register in question so other kernel threads can't simultaneously modify the register. A mutex is allowed to sleep so if it can't acquire the lock, the thread is able to go to sleep until it can.

Then, I'd use a wait queue to block the thread until the interrupt arrives and signals that the bit has finished setting.

Also, as an aside, I noticed you're trying to access your peripheral by using the following expression REG_ADDR += FLAG_A;. In the kernel, that's not the correct way to do it. It may seem to work but will break on some architectures. You should be using the read{b,w,l} and write{b,w,l} macros like

unsigned long reg;
reg = readl(REG_ADDR);
reg |= FLAG_A;
writel(reg, REG_ADDR);

where REG_ADDR is an address you obtained from ioremap.

0
votes

I will agree with Michael that Spinlock, Semaphores, Mutex ( Or any other Locking Mechanisms) must be used when any of the resources(Memory/variable/piece of code) has the probability of getting shared among the kernel/user threads. Instead of using any of the Locking primitives available I would suggest using other sleeping functionalities available in kernel like wait_event_interruptibleand wake_up. They are simple and easy to exploit them into your code. You can find its details and exploitation on net.