Commit ecd2a4c0 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] first cut at scc.c for 2.5 locking

parent 3ba32a67
...@@ -235,13 +235,14 @@ static io_port Vector_Latch; ...@@ -235,13 +235,14 @@ static io_port Vector_Latch;
/* These provide interrupt save 2-step access to the Z8530 registers */ /* 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) static inline unsigned char InReg(io_port port, unsigned char reg)
{ {
unsigned long flags; unsigned long flags;
unsigned char r; unsigned char r;
save_flags(flags); spin_lock_irqsave(&iolock, flags);
cli();
#ifdef SCC_LDELAY #ifdef SCC_LDELAY
Outb(port, reg); Outb(port, reg);
udelay(SCC_LDELAY); udelay(SCC_LDELAY);
...@@ -251,16 +252,15 @@ static inline unsigned char InReg(io_port port, unsigned char reg) ...@@ -251,16 +252,15 @@ static inline unsigned char InReg(io_port port, unsigned char reg)
Outb(port, reg); Outb(port, reg);
r=Inb(port); r=Inb(port);
#endif #endif
restore_flags(flags); spin_unlock_irqrestore(&iolock, flags);
return r; return r;
} }
static inline void OutReg(io_port port, unsigned char reg, unsigned char val) static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&iolock, flags);
cli();
#ifdef SCC_LDELAY #ifdef SCC_LDELAY
Outb(port, reg); udelay(SCC_LDELAY); Outb(port, reg); udelay(SCC_LDELAY);
Outb(port, val); udelay(SCC_LDELAY); Outb(port, val); udelay(SCC_LDELAY);
...@@ -268,7 +268,7 @@ static inline void OutReg(io_port port, unsigned char reg, unsigned char val) ...@@ -268,7 +268,7 @@ static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
Outb(port, reg); Outb(port, reg);
Outb(port, val); Outb(port, val);
#endif #endif
restore_flags(flags); spin_unlock_irqrestore(&iolock, flags);
} }
static inline void wr(struct scc_channel *scc, unsigned char reg, static inline void wr(struct scc_channel *scc, unsigned char reg,
...@@ -295,9 +295,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc) ...@@ -295,9 +295,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
if (scc->tx_buff != NULL) if (scc->tx_buff != NULL)
{ {
dev_kfree_skb(scc->tx_buff); dev_kfree_skb(scc->tx_buff);
...@@ -307,7 +305,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc) ...@@ -307,7 +305,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc)
while (skb_queue_len(&scc->tx_queue)) while (skb_queue_len(&scc->tx_queue))
dev_kfree_skb(skb_dequeue(&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 inline void scc_spint(struct scc_channel *scc) ...@@ -609,6 +607,7 @@ static inline void scc_spint(struct scc_channel *scc)
static void scc_isr_dispatch(struct scc_channel *scc, int vector) static void scc_isr_dispatch(struct scc_channel *scc, int vector)
{ {
spin_lock(&scc->lock);
switch (vector & VECTOR_MASK) switch (vector & VECTOR_MASK)
{ {
case TXINT: scc_txint(scc); break; case TXINT: scc_txint(scc); break;
...@@ -616,6 +615,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector) ...@@ -616,6 +615,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
case RXINT: scc_rxint(scc); break; case RXINT: scc_rxint(scc); break;
case SPINT: scc_spint(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) /* If the card has a latch for the interrupt vector (like the PA0HZP card)
...@@ -722,12 +722,13 @@ static inline void set_brg(struct scc_channel *scc, unsigned int tc) ...@@ -722,12 +722,13 @@ static inline void set_brg(struct scc_channel *scc, unsigned int tc)
static inline void set_speed(struct scc_channel *scc) 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... */ if (scc->modem.speed > 0) /* paranoia... */
set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2); 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 @@ static void scc_key_trx(struct scc_channel *scc, char tx) ...@@ -988,14 +989,8 @@ static void scc_key_trx(struct scc_channel *scc, char tx)
/* ----> SCC timer interrupt handler and friends. <---- */ /* ----> 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); del_timer(&scc->tx_t);
if (when == 0) if (when == 0)
...@@ -1009,17 +1004,22 @@ static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned ...@@ -1009,17 +1004,22 @@ static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned
scc->tx_t.expires = jiffies + (when*HZ)/100; scc->tx_t.expires = jiffies + (when*HZ)/100;
add_timer(&scc->tx_t); 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) static void scc_start_defer(struct scc_channel *scc)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
del_timer(&scc->tx_wdog); del_timer(&scc->tx_wdog);
if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF) if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
...@@ -1029,16 +1029,14 @@ static void scc_start_defer(struct scc_channel *scc) ...@@ -1029,16 +1029,14 @@ static void scc_start_defer(struct scc_channel *scc)
scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer; scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;
add_timer(&scc->tx_wdog); add_timer(&scc->tx_wdog);
} }
restore_flags(flags); spin_unlock_irqrestore(&scc->lock, flags);
} }
static void scc_start_maxkeyup(struct scc_channel *scc) static void scc_start_maxkeyup(struct scc_channel *scc)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
del_timer(&scc->tx_wdog); del_timer(&scc->tx_wdog);
if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF) if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
...@@ -1048,8 +1046,7 @@ static void scc_start_maxkeyup(struct scc_channel *scc) ...@@ -1048,8 +1046,7 @@ static void scc_start_maxkeyup(struct scc_channel *scc)
scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
add_timer(&scc->tx_wdog); add_timer(&scc->tx_wdog);
} }
spin_unlock_irqrestore(&scc->lock, flags);
restore_flags(flags);
} }
/* /*
...@@ -1189,13 +1186,10 @@ static void t_tail(unsigned long channel) ...@@ -1189,13 +1186,10 @@ static void t_tail(unsigned long channel)
struct scc_channel *scc = (struct scc_channel *) channel; struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
del_timer(&scc->tx_wdog); del_timer(&scc->tx_wdog);
scc_key_trx(scc, TX_OFF); scc_key_trx(scc, TX_OFF);
spin_unlock_irqrestore(&scc->lock, flags);
restore_flags(flags);
if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
{ {
...@@ -1242,9 +1236,7 @@ static void t_maxkeyup(unsigned long channel) ...@@ -1242,9 +1236,7 @@ static void t_maxkeyup(unsigned long channel)
struct scc_channel *scc = (struct scc_channel *) channel; struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
/* /*
* let things settle down before we start to * let things settle down before we start to
* accept new data. * accept new data.
...@@ -1259,7 +1251,7 @@ static void t_maxkeyup(unsigned long channel) ...@@ -1259,7 +1251,7 @@ static void t_maxkeyup(unsigned long channel)
cl(scc, R15, TxUIE); /* count it. */ cl(scc, R15, TxUIE); /* count it. */
OutReg(scc->ctrl, R0, RES_Tx_P); OutReg(scc->ctrl, R0, RES_Tx_P);
restore_flags(flags); spin_unlock_irqrestore(&scc->lock, flags);
scc->stat.txerrs++; scc->stat.txerrs++;
scc->stat.tx_state = TXS_TIMEOUT; scc->stat.tx_state = TXS_TIMEOUT;
...@@ -1289,13 +1281,10 @@ static void t_idle(unsigned long channel) ...@@ -1289,13 +1281,10 @@ static void t_idle(unsigned long channel)
static void scc_init_timer(struct scc_channel *scc) static void scc_init_timer(struct scc_channel *scc)
{ {
unsigned long flags; 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 @@ static void scc_stop_calibrate(unsigned long channel) ...@@ -1414,9 +1403,7 @@ static void scc_stop_calibrate(unsigned long channel)
struct scc_channel *scc = (struct scc_channel *) channel; struct scc_channel *scc = (struct scc_channel *) channel;
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
del_timer(&scc->tx_wdog); del_timer(&scc->tx_wdog);
scc_key_trx(scc, TX_OFF); scc_key_trx(scc, TX_OFF);
wr(scc, R6, 0); wr(scc, R6, 0);
...@@ -1425,7 +1412,7 @@ static void scc_stop_calibrate(unsigned long channel) ...@@ -1425,7 +1412,7 @@ static void scc_stop_calibrate(unsigned long channel)
Outb(scc->ctrl,RES_EXT_INT); Outb(scc->ctrl,RES_EXT_INT);
netif_wake_queue(scc->dev); netif_wake_queue(scc->dev);
restore_flags(flags); spin_unlock_irqrestore(&scc->lock, flags);
} }
...@@ -1434,9 +1421,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern ...@@ -1434,9 +1421,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
netif_stop_queue(scc->dev); netif_stop_queue(scc->dev);
scc_discard_buffers(scc); scc_discard_buffers(scc);
...@@ -1460,7 +1445,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern ...@@ -1460,7 +1445,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern
Outb(scc->ctrl,RES_EXT_INT); Outb(scc->ctrl,RES_EXT_INT);
scc_key_trx(scc, TX_ON); scc_key_trx(scc, TX_ON);
restore_flags(flags); spin_unlock_irqrestore(&scc->lock, flags);
} }
/* ******************************************************************* */ /* ******************************************************************* */
...@@ -1508,16 +1493,14 @@ static void z8530_init(void) ...@@ -1508,16 +1493,14 @@ static void z8530_init(void)
/* Reset and pre-init Z8530 */ /* Reset and pre-init Z8530 */
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
Outb(scc->ctrl, 0); Outb(scc->ctrl, 0);
OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
udelay(100); /* give it 'a bit' more time than required */ udelay(100); /* give it 'a bit' more time than required */
wr(scc, R2, chip*16); /* interrupt vector */ wr(scc, R2, chip*16); /* interrupt vector */
wr(scc, R9, VIS); /* vector includes status */ wr(scc, R9, VIS); /* vector includes status */
spin_unlock_irqrestore(&scc->lock, flags);
restore_flags(flags);
} }
...@@ -1548,6 +1531,8 @@ static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev ...@@ -1548,6 +1531,8 @@ static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev
dev->priv = (void *) scc; dev->priv = (void *) scc;
dev->init = scc_net_init; dev->init = scc_net_init;
spin_lock_init(&scc->lock);
if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) { if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) {
kfree(dev); kfree(dev);
return -EIO; return -EIO;
...@@ -1625,17 +1610,14 @@ static int scc_net_close(struct net_device *dev) ...@@ -1625,17 +1610,14 @@ static int scc_net_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
Outb(scc->ctrl,0); /* Make sure pointer is written */ Outb(scc->ctrl,0); /* Make sure pointer is written */
wr(scc,R1,0); /* disable interrupts */ wr(scc,R1,0); /* disable interrupts */
wr(scc,R3,0); wr(scc,R3,0);
spin_unlock_irqrestore(&scc->lock, flags);
del_timer(&scc->tx_t); del_timer_sync(&scc->tx_t);
del_timer(&scc->tx_wdog); del_timer_sync(&scc->tx_wdog);
restore_flags(flags);
scc_discard_buffers(scc); scc_discard_buffers(scc);
...@@ -1689,9 +1671,8 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1689,9 +1671,8 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
save_flags(flags); spin_lock_irqsave(&scc->lock, flags);
cli();
if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) { if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {
struct sk_buff *skb_del; struct sk_buff *skb_del;
skb_del = skb_dequeue(&scc->tx_queue); skb_del = skb_dequeue(&scc->tx_queue);
...@@ -1710,12 +1691,11 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1710,12 +1691,11 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) { if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) {
scc->stat.tx_state = TXS_BUSY; scc->stat.tx_state = TXS_BUSY;
if (scc->kiss.fulldup == KISS_DUPLEX_HALF) 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 else
scc_start_tx_timer(scc, t_dwait, 0); __scc_start_tx_timer(scc, t_dwait, 0);
} }
spin_unlock_irqrestore(&scc->lock, flags);
restore_flags(flags);
return 0; return 0;
} }
...@@ -1785,19 +1765,23 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1785,19 +1765,23 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
hwcfg.clock = SCC_DEFAULT_CLOCK; hwcfg.clock = SCC_DEFAULT_CLOCK;
#ifndef SCC_DONT_CHECK #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; found = 0;
enable_irq(hwcfg.irq);
#endif #endif
if (found) if (found)
...@@ -2111,6 +2095,8 @@ static int __init scc_init_driver (void) ...@@ -2111,6 +2095,8 @@ static int __init scc_init_driver (void)
printk(banner); printk(banner);
spin_lock_init(&iolock);
sprintf(devname,"%s0", SCC_DriverName); sprintf(devname,"%s0", SCC_DriverName);
result = scc_net_setup(SCC_Info, devname, 0); result = scc_net_setup(SCC_Info, devname, 0);
...@@ -2127,20 +2113,19 @@ static int __init scc_init_driver (void) ...@@ -2127,20 +2113,19 @@ static int __init scc_init_driver (void)
static void __exit scc_cleanup_driver(void) static void __exit scc_cleanup_driver(void)
{ {
unsigned long flags;
io_port ctrl; io_port ctrl;
int k; int k;
struct scc_channel *scc; struct scc_channel *scc;
save_flags(flags);
cli();
if (Nchips == 0) if (Nchips == 0)
{ {
unregister_netdev(SCC_Info[0].dev); unregister_netdev(SCC_Info[0].dev);
kfree(SCC_Info[0].dev); kfree(SCC_Info[0].dev);
} }
/* Guard against chip prattle */
local_irq_disable();
for (k = 0; k < Nchips; k++) for (k = 0; k < Nchips; k++)
if ( (ctrl = SCC_ctrl[k].chan_A) ) if ( (ctrl = SCC_ctrl[k].chan_A) )
{ {
...@@ -2149,6 +2134,13 @@ static void __exit scc_cleanup_driver(void) ...@@ -2149,6 +2134,13 @@ static void __exit scc_cleanup_driver(void)
udelay(50); 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++) for (k = 0; k < Nchips*2; k++)
{ {
scc = &SCC_Info[k]; scc = &SCC_Info[k];
...@@ -2164,14 +2156,10 @@ static void __exit scc_cleanup_driver(void) ...@@ -2164,14 +2156,10 @@ static void __exit scc_cleanup_driver(void)
} }
} }
for (k=0; k < NR_IRQS ; k++)
if (Ivec[k].used) free_irq(k, NULL);
if (Vector_Latch) if (Vector_Latch)
release_region(Vector_Latch, 1); release_region(Vector_Latch, 1);
restore_flags(flags);
proc_net_remove("z8530drv"); proc_net_remove("z8530drv");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment