A general question on SMP-safe driver code.
From: Jim Nelson
Date: Fri Dec 24 2004 - 18:00:19 EST
Looking at a few older drivers, I'm trying to figure out the best ways to handle
some locking. Using drivers/char/esp.c as an example (since it's the one I'm
trying to grok right now), here is one example:
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long orig_jiffies, char_time;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
return;
orig_jiffies = jiffies;
char_time = ((info->timeout - HZ / 50) / 1024) / 5;
if (!char_time)
char_time = 1;
save_flags(flags); cli();
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
(serial_in(info, UART_ESI_STAT2) != 0xff)) {
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
}
restore_flags(flags);
set_current_state(TASK_RUNNING);
}
Now, it seems like the cli()/sti() pair is to prevent other code from interrupting
the whole sequence. It looks like the only things actually need interrupts
disabled (from a command sequencing perspective) is the serial_out pairs, but you
want to keep other parts of the driver from sending other commands to the board.
So, would:
down_interruptible(&info->sem);
spin_lock_irq(&info->esp_lock);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
spin_unlock_irq(&info->esp_lock);
while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
(serial_in(info, UART_ESI_STAT2) != 0xff)) {
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
spin_lock_irq(&info->esp_lock);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
spin_unlock_irq(&info->esp_lock);
up(&info->esp_sem);
work if all other areas of the driver that send commands to the board also try for
the semaphore?
Is there an easier way of doing this?
Jim
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/