Commit e812cb52 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Linus Torvalds

[PATCH] smsc-ircc2: PM cleanup - do not close device when suspending

smsc-ircc2 - avoid closing network device when suspending; just release
interrupt and disable DMA ourselves.  Also make sure to reset chip when
resuming.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Cc: Jean Tourrilhes <jt@bougret.hpl.hp.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 17fd47ab
...@@ -638,21 +638,14 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) ...@@ -638,21 +638,14 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
*/ */
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
{ {
int iobase, ir_mode, ctrl, fast; int iobase = self->io.fir_base;
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.fir_base;
ir_mode = IRCC_CFGA_IRDA_SIR_A;
ctrl = 0;
fast = 0;
register_bank(iobase, 0); register_bank(iobase, 0);
outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
outb(0x00, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER);
register_bank(iobase, 1); register_bank(iobase, 1);
outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode), outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A),
iobase + IRCC_SCE_CFGA); iobase + IRCC_SCE_CFGA);
#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ #ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
...@@ -666,10 +659,10 @@ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) ...@@ -666,10 +659,10 @@ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);
register_bank(iobase, 4); register_bank(iobase, 4);
outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL); outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL);
register_bank(iobase, 0); register_bank(iobase, 0);
outb(fast, iobase + IRCC_LCR_A); outb(0, iobase + IRCC_LCR_A);
smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
...@@ -1556,6 +1549,46 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self) ...@@ -1556,6 +1549,46 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self)
} }
#endif /* unused */ #endif /* unused */
static int smsc_ircc_request_irq(struct smsc_ircc_cb *self)
{
int error;
error = request_irq(self->io.irq, smsc_ircc_interrupt, 0,
self->netdev->name, self->netdev);
if (error)
IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n",
__FUNCTION__, self->io.irq, error);
return error;
}
static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self)
{
unsigned long flags;
spin_lock_irqsave(&self->lock, flags);
self->io.speed = 0;
smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
spin_unlock_irqrestore(&self->lock, flags);
}
static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self)
{
int iobase = self->io.fir_base;
unsigned long flags;
spin_lock_irqsave(&self->lock, flags);
register_bank(iobase, 0);
outb(0, iobase + IRCC_IER);
outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
outb(0x00, iobase + IRCC_MASTER);
spin_unlock_irqrestore(&self->lock, flags);
}
/* /*
* Function smsc_ircc_net_open (dev) * Function smsc_ircc_net_open (dev)
...@@ -1567,7 +1600,6 @@ static int smsc_ircc_net_open(struct net_device *dev) ...@@ -1567,7 +1600,6 @@ static int smsc_ircc_net_open(struct net_device *dev)
{ {
struct smsc_ircc_cb *self; struct smsc_ircc_cb *self;
char hwname[16]; char hwname[16];
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_DEBUG(1, "%s\n", __FUNCTION__);
...@@ -1575,6 +1607,11 @@ static int smsc_ircc_net_open(struct net_device *dev) ...@@ -1575,6 +1607,11 @@ static int smsc_ircc_net_open(struct net_device *dev)
self = netdev_priv(dev); self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;); IRDA_ASSERT(self != NULL, return 0;);
if (self->io.suspended) {
IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__);
return -EAGAIN;
}
if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
(void *) dev)) { (void *) dev)) {
IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
...@@ -1582,11 +1619,7 @@ static int smsc_ircc_net_open(struct net_device *dev) ...@@ -1582,11 +1619,7 @@ static int smsc_ircc_net_open(struct net_device *dev)
return -EAGAIN; return -EAGAIN;
} }
spin_lock_irqsave(&self->lock, flags); smsc_ircc_start_interrupts(self);
/*smsc_ircc_sir_start(self);*/
self->io.speed = 0;
smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
spin_unlock_irqrestore(&self->lock, flags);
/* Give self a hardware name */ /* Give self a hardware name */
/* It would be cool to offer the chip revision here - Jean II */ /* It would be cool to offer the chip revision here - Jean II */
...@@ -1639,7 +1672,12 @@ static int smsc_ircc_net_close(struct net_device *dev) ...@@ -1639,7 +1672,12 @@ static int smsc_ircc_net_close(struct net_device *dev)
irlap_close(self->irlap); irlap_close(self->irlap);
self->irlap = NULL; self->irlap = NULL;
free_irq(self->io.irq, dev); smsc_ircc_stop_interrupts(self);
/* if we are called from smsc_ircc_resume we don't have IRQ reserved */
if (!self->io.suspended)
free_irq(self->io.irq, dev);
disable_dma(self->io.dma); disable_dma(self->io.dma);
free_dma(self->io.dma); free_dma(self->io.dma);
...@@ -1650,11 +1688,18 @@ static int smsc_ircc_suspend(struct device *dev, pm_message_t state) ...@@ -1650,11 +1688,18 @@ static int smsc_ircc_suspend(struct device *dev, pm_message_t state)
{ {
struct smsc_ircc_cb *self = dev_get_drvdata(dev); struct smsc_ircc_cb *self = dev_get_drvdata(dev);
IRDA_MESSAGE("%s, Suspending\n", driver_name);
if (!self->io.suspended) { if (!self->io.suspended) {
smsc_ircc_net_close(self->netdev); IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
rtnl_lock();
if (netif_running(self->netdev)) {
netif_device_detach(self->netdev);
smsc_ircc_stop_interrupts(self);
free_irq(self->io.irq, self->netdev);
disable_dma(self->io.dma);
}
self->io.suspended = 1; self->io.suspended = 1;
rtnl_unlock();
} }
return 0; return 0;
...@@ -1665,11 +1710,25 @@ static int smsc_ircc_resume(struct device *dev) ...@@ -1665,11 +1710,25 @@ static int smsc_ircc_resume(struct device *dev)
struct smsc_ircc_cb *self = dev_get_drvdata(dev); struct smsc_ircc_cb *self = dev_get_drvdata(dev);
if (self->io.suspended) { if (self->io.suspended) {
IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
smsc_ircc_net_open(self->netdev);
rtnl_lock();
smsc_ircc_init_chip(self);
if (netif_running(self->netdev)) {
if (smsc_ircc_request_irq(self)) {
/*
* Don't fail resume process, just kill this
* network interface
*/
unregister_netdevice(self->netdev);
} else {
enable_dma(self->io.dma);
smsc_ircc_start_interrupts(self);
netif_device_attach(self->netdev);
}
}
self->io.suspended = 0; self->io.suspended = 0;
rtnl_unlock();
IRDA_MESSAGE("%s, Waking up\n", driver_name);
} }
return 0; return 0;
} }
...@@ -1682,9 +1741,6 @@ static int smsc_ircc_resume(struct device *dev) ...@@ -1682,9 +1741,6 @@ static int smsc_ircc_resume(struct device *dev)
*/ */
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
{ {
int iobase;
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_DEBUG(1, "%s\n", __FUNCTION__);
IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self != NULL, return -1;);
...@@ -1694,22 +1750,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) ...@@ -1694,22 +1750,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
/* Remove netdevice */ /* Remove netdevice */
unregister_netdev(self->netdev); unregister_netdev(self->netdev);
/* Make sure the irq handler is not exectuting */ smsc_ircc_stop_interrupts(self);
spin_lock_irqsave(&self->lock, flags);
/* Stop interrupts */
iobase = self->io.fir_base;
register_bank(iobase, 0);
outb(0, iobase + IRCC_IER);
outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
outb(0x00, iobase + IRCC_MASTER);
#if 0
/* Reset to SIR mode */
register_bank(iobase, 1);
outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA);
outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB);
#endif
spin_unlock_irqrestore(&self->lock, flags);
/* Release the PORTS that this driver is using */ /* Release the PORTS that this driver is using */
IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
......
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