PATCH: first cut at scc.c for 2.5 locking

Alan Cox (alan@lxorguk.ukuu.org.uk)
Tue, 8 Apr 2003 01:24:23 +0100


diff -u --new-file --recursive --exclude-from /usr/src/exclude linux-2.5.67/drivers/net/hamradio/scc.c linux-2.5.67-ac1/drivers/net/hamradio/scc.c
--- linux-2.5.67/drivers/net/hamradio/scc.c 2003-02-15 03:39:31.000000000 +0000
+++ linux-2.5.67-ac1/drivers/net/hamradio/scc.c 2003-04-07 20:08:53.000000000 +0100
@@ -235,13 +235,14 @@

/* These provide interrupt save 2-step access to the Z8530 registers */

+static spinlock_t iolock; /* Guards paired accesses */
+
static inline unsigned char InReg(io_port port, unsigned char reg)
{
unsigned long flags;
unsigned char r;
-
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&iolock, flags);
#ifdef SCC_LDELAY
Outb(port, reg);
udelay(SCC_LDELAY);
@@ -251,16 +252,15 @@
Outb(port, reg);
r=Inb(port);
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&iolock, flags);
return r;
}

static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
{
unsigned long flags;
-
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&iolock, flags);
#ifdef SCC_LDELAY
Outb(port, reg); udelay(SCC_LDELAY);
Outb(port, val); udelay(SCC_LDELAY);
@@ -268,7 +268,7 @@
Outb(port, reg);
Outb(port, val);
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&iolock, flags);
}

static inline void wr(struct scc_channel *scc, unsigned char reg,
@@ -295,9 +295,7 @@
{
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
if (scc->tx_buff != NULL)
{
dev_kfree_skb(scc->tx_buff);
@@ -307,7 +305,7 @@
while (skb_queue_len(&scc->tx_queue))
dev_kfree_skb(skb_dequeue(&scc->tx_queue));

- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}


@@ -609,6 +607,7 @@

static void scc_isr_dispatch(struct scc_channel *scc, int vector)
{
+ spin_lock(&scc->lock);
switch (vector & VECTOR_MASK)
{
case TXINT: scc_txint(scc); break;
@@ -616,6 +615,7 @@
case RXINT: scc_rxint(scc); break;
case SPINT: scc_spint(scc); break;
}
+ spin_unlock(&scc->lock);
}

/* If the card has a latch for the interrupt vector (like the PA0HZP card)
@@ -722,12 +722,13 @@

static inline void set_speed(struct scc_channel *scc)
{
- disable_irq(scc->irq);
+ unsigned long flags;
+ spin_lock_irqsave(&scc->lock, flags);

if (scc->modem.speed > 0) /* paranoia... */
set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);
-
- enable_irq(scc->irq);
+
+ spin_unlock_irqrestore(&scc->lock, flags);
}


@@ -988,14 +989,8 @@

/* ----> SCC timer interrupt handler and friends. <---- */

-static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when)
+static void __scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when)
{
- unsigned long flags;
-
-
- save_flags(flags);
- cli();
-
del_timer(&scc->tx_t);

if (when == 0)
@@ -1009,17 +1004,22 @@
scc->tx_t.expires = jiffies + (when*HZ)/100;
add_timer(&scc->tx_t);
}
+}
+
+static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when)
+{
+ unsigned long flags;

- restore_flags(flags);
+ spin_lock_irqsave(&scc->lock, flags);
+ __scc_start_tx_timer(scc, handler, when);
+ spin_unlock_irqrestore(&scc->lock, flags);
}

static void scc_start_defer(struct scc_channel *scc)
{
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
del_timer(&scc->tx_wdog);

if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
@@ -1029,16 +1029,14 @@
scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;
add_timer(&scc->tx_wdog);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}

static void scc_start_maxkeyup(struct scc_channel *scc)
{
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
del_timer(&scc->tx_wdog);

if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
@@ -1048,8 +1046,7 @@
scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
add_timer(&scc->tx_wdog);
}
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}

/*
@@ -1189,13 +1186,10 @@
struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
del_timer(&scc->tx_wdog);
scc_key_trx(scc, TX_OFF);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);

if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
{
@@ -1242,9 +1236,7 @@
struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
/*
* let things settle down before we start to
* accept new data.
@@ -1259,7 +1251,7 @@
cl(scc, R15, TxUIE); /* count it. */
OutReg(scc->ctrl, R0, RES_Tx_P);

- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);

scc->stat.txerrs++;
scc->stat.tx_state = TXS_TIMEOUT;
@@ -1289,13 +1281,10 @@
static void scc_init_timer(struct scc_channel *scc)
{
unsigned long flags;
-
- save_flags(flags);
- cli();
-
- scc->stat.tx_state = TXS_IDLE;

- restore_flags(flags);
+ spin_lock_irqsave(&scc->lock, flags);
+ scc->stat.tx_state = TXS_IDLE;
+ spin_unlock_irqrestore(&scc->lock, flags);
}


@@ -1414,9 +1403,7 @@
struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
del_timer(&scc->tx_wdog);
scc_key_trx(scc, TX_OFF);
wr(scc, R6, 0);
@@ -1425,7 +1412,7 @@
Outb(scc->ctrl,RES_EXT_INT);

netif_wake_queue(scc->dev);
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}


@@ -1434,9 +1421,7 @@
{
unsigned long flags;

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
netif_stop_queue(scc->dev);
scc_discard_buffers(scc);

@@ -1460,7 +1445,7 @@
Outb(scc->ctrl,RES_EXT_INT);

scc_key_trx(scc, TX_ON);
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}

/* ******************************************************************* */
@@ -1508,16 +1493,14 @@

/* Reset and pre-init Z8530 */

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
+
Outb(scc->ctrl, 0);
OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
udelay(100); /* give it 'a bit' more time than required */
wr(scc, R2, chip*16); /* interrupt vector */
wr(scc, R9, VIS); /* vector includes status */
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
}


@@ -1548,6 +1531,8 @@
dev->priv = (void *) scc;
dev->init = scc_net_init;

+ spin_lock_init(&scc->lock);
+
if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) {
kfree(dev);
return -EIO;
@@ -1625,17 +1610,14 @@

netif_stop_queue(dev);

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
Outb(scc->ctrl,0); /* Make sure pointer is written */
wr(scc,R1,0); /* disable interrupts */
wr(scc,R3,0);
+ spin_unlock_irqrestore(&scc->lock, flags);

- del_timer(&scc->tx_t);
- del_timer(&scc->tx_wdog);
-
- restore_flags(flags);
+ del_timer_sync(&scc->tx_t);
+ del_timer_sync(&scc->tx_wdog);

scc_discard_buffers(scc);

@@ -1689,9 +1671,8 @@
return 0;
}

- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&scc->lock, flags);
+
if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {
struct sk_buff *skb_del;
skb_del = skb_dequeue(&scc->tx_queue);
@@ -1710,12 +1691,11 @@
if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) {
scc->stat.tx_state = TXS_BUSY;
if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
- scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);
+ __scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);
else
- scc_start_tx_timer(scc, t_dwait, 0);
+ __scc_start_tx_timer(scc, t_dwait, 0);
}
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&scc->lock, flags);
return 0;
}

@@ -1785,19 +1765,23 @@
hwcfg.clock = SCC_DEFAULT_CLOCK;

#ifndef SCC_DONT_CHECK
- disable_irq(hwcfg.irq);
-
- check_region(scc->ctrl, 1);
- Outb(hwcfg.ctrl_a, 0);
- OutReg(hwcfg.ctrl_a, R9, FHWRES);
- udelay(100);
- OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
- udelay(5);

- if (InReg(hwcfg.ctrl_a,R13) != 0x55)
+ if(request_region(scc->ctrl, 1, "scc-probe"))
+ {
+ disable_irq(hwcfg.irq);
+ Outb(hwcfg.ctrl_a, 0);
+ OutReg(hwcfg.ctrl_a, R9, FHWRES);
+ udelay(100);
+ OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
+ udelay(5);
+
+ if (InReg(hwcfg.ctrl_a,R13) != 0x55)
+ found = 0;
+ enable_irq(hwcfg.irq);
+ release_region(scc->ctrl, 1);
+ }
+ else
found = 0;
-
- enable_irq(hwcfg.irq);
#endif

if (found)
@@ -2111,6 +2095,8 @@

printk(banner);

+ spin_lock_init(&iolock);
+
sprintf(devname,"%s0", SCC_DriverName);

result = scc_net_setup(SCC_Info, devname, 0);
@@ -2127,20 +2113,19 @@

static void __exit scc_cleanup_driver(void)
{
- unsigned long flags;
io_port ctrl;
int k;
struct scc_channel *scc;

- save_flags(flags);
- cli();
-
if (Nchips == 0)
{
unregister_netdev(SCC_Info[0].dev);
kfree(SCC_Info[0].dev);
}

+ /* Guard against chip prattle */
+ local_irq_disable();
+
for (k = 0; k < Nchips; k++)
if ( (ctrl = SCC_ctrl[k].chan_A) )
{
@@ -2149,6 +2134,13 @@
udelay(50);
}

+ /* To unload the port must be closed so no real IRQ pending */
+ for (k=0; k < NR_IRQS ; k++)
+ if (Ivec[k].used) free_irq(k, NULL);
+
+ local_irq_enable();
+
+ /* Now clean up */
for (k = 0; k < Nchips*2; k++)
{
scc = &SCC_Info[k];
@@ -2164,14 +2156,10 @@
}
}

- for (k=0; k < NR_IRQS ; k++)
- if (Ivec[k].used) free_irq(k, NULL);

if (Vector_Latch)
release_region(Vector_Latch, 1);

- restore_flags(flags);
-
proc_net_remove("z8530drv");
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/