Hi,
Sorry, I was a little bit confused on Friday, but I read about this topic on the weekend and I think that now this is more clear for me.
My doubt is about spinlocks are working together with interrupts.
As far I could understand:
If you are working with a code that can handle and interrupt, and this interrupt can hold a lock, you must use spinlocks with irq version( spin_lock_irqsave and spin_lock_irqrestore) in the functions that you need to lock, otherwise, if you acquire a lock in CPU0, and then an interrupt is raised in the same CPU0 and tries to acquire the same lock, we will have a deadlock problem.
But if you acquire a lock disabling the IRQ in the CPU0, and then an interrupt is raised at CPU1 and tries to acquire a lock, the interrupt will spin till the lock is released in the other function(the function that acquire the lock first).
A graphical example would be:
static int hardware_tx(struct net_device *dev) /* This is the function that the network subsystem calls when has a packet to transmit */
{
struct rtl_t *rtl_p = netdev_priv(dev);
int pkt_len = rtl8139_p->skb_d->len;
unsigned long flags;
spin_lock_irqsave(&rtl_p->lock, flags); /* We acquire a lock, disabling the interrupts in the local CPU */
/*
Do some private stuff
Do some private stuff
At some point an interrupt is raised, so we go to the handler
Since i_handler has to spin, we continue here
Do some private stuff
*/
spin_unlock_irqsave(&rtl_p->lock, flags); /* We are releasing the lock, and put the interrupts in the old state( in this case enabled) */
/* This is safe since kernel ensures that only one interrupt in the same line can be processed at the same time, so since i_handler is executing, kernel it will not execute it again, no? */
return 0;
}
static irqreturn_t i_handler(int irq, void *dev_id) /* This is the interrupt handler */
{
struct rtl_t *rtl_p = netdev_priv(dev);
/* Now we are on the handler */
spin_lock(&rtl8139_p->lock); /* We try to acquire a lock, but we can not since hardware_tx has already taken a lock, so we have to spin here till hardware_tx finish his work*/
/*
Ok, hardware_tx released the lock, now we can continue
Do some private stuff
Do some private stuff
Do some private stuff
*/
spin_unlock(&rtl_p->lock, flags); /* Lock released */
}
Hopefully now I explained it better.