Hello,
I'm trying to add power management support to au1000_eth.c driver.
In order to to it I 've added these two functions:
static int au1000_eth_suspend(struct device *dev, pm_message_t state, u32
level)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct au1000_private *aup = (struct au1000_private *) ndev->priv;
if (!ndev)
return 0;
switch (level) {
case SUSPEND_DISABLE :
if (netif_running(ndev))
netif_device_detach(ndev);
break;
case SUSPEND_SAVE_STATE :
/* bring the device out of reset, otherwise accessing to mii
* will hang */
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
if (aup->phy_ops->phy_suspend)
aup->phy_ops->phy_suspend(ndev, aup->phy_addr, level);
del_timer_sync(&aup->timer); /* FIXME: REMOVED??? */
reset_mac(ndev);
netif_stop_queue(ndev);
free_irq(ndev->irq, dev);
break;
case SUSPEND_POWER_DOWN :
break;
}
return 0;
}
static int au1000_eth_resume(struct device *dev, u32 level)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct au1000_private *aup = (struct au1000_private *) ndev->priv;
u32 flags;
int ret;
if (!ndev)
return 0;
switch (level) {
case RESUME_RESTORE_STATE :
/* bring the device out of reset, otherwise accessing to mii
* will hang */
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
if (aup->phy_ops->phy_resume)
aup->phy_ops->phy_resume(ndev, aup->phy_addr, level);
aup->phy_ops->phy_init(ndev, aup->phy_addr);
/* au1000_init() expects that the device is in reset state.
*/
reset_mac(ndev); /* au1000_init() expects the device in reset */
au1000_init(ndev);
ret = request_irq(ndev->irq, &au1000_interrupt, 0, ndev->name,
ndev);
if (ret) {
printk(KERN_ERR "%s: unable to get IRQ %d\n",
ndev->name, ndev->irq);
return ret; //FIXME
}
init_timer(&aup->timer); /* used in ioctl() */
aup->timer.expires = RUN_AT((3*HZ));
aup->timer.data = (unsigned long) ndev;
aup->timer.function = &au1000_timer; /* timer handler */
add_timer(&aup->timer);
break;
case RESUME_ENABLE :
if (netif_running(ndev))
netif_device_attach(ndev);
break;
}
return 0;
}
The problem is that after wakeup the system hangs or returns lots of
errors like:
Reserved instruction in kernel code in arch/mips/kernel/traps.c::do_ri, line
706[#169]:
Note that if I compile the driver as a module and removing it before
sleeping and reinstalling it after wake up the system (and the
ethernet) works correctly...
Suggestions? :)
Thanks in advance,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
|