From: Rodolfo Giometti <giometti@linux.it>
To: Linux MIPS <linux-mips@linux-mips.org>
Cc: ppopov@mvista.com
Subject: [PATCH] Oops! - Re: Power management for au1000_eth.c
Date: Thu, 6 Apr 2006 00:26:20 +0200 [thread overview]
Message-ID: <20060405222620.GP7029@enneenne.com> (raw)
In-Reply-To: <20060405222332.GO7029@enneenne.com>
[-- Attachment #1.1: Type: text/plain, Size: 751 bytes --]
On Thu, Apr 06, 2006 at 12:23:32AM +0200, Rodolfo Giometti wrote:
> On Wed, Apr 05, 2006 at 05:47:11PM +0200, Rodolfo Giometti wrote:
> > Hello,
> >
> > I'm trying to add power management support to au1000_eth.c driver.
>
> Solved! :)
>
> Here a patch to implement power management functions for au1000_eth.
>
> Note that this patch needs my previous one who implements new power
> management's sysfs interface.
The forgotten attachment. :)
Ciao,
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
[-- Attachment #1.2: patch-au1000_eth-pm --]
[-- Type: text/plain, Size: 22531 bytes --]
--- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/au1xxx_irqmap.c 2006-03-31 16:57:26.000000000 +0200
+++ arch/mips/au1000/common/au1xxx_irqmap.c 2006-04-03 17:50:49.000000000 +0200
@@ -118,7 +118,7 @@
{ AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
- { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
@@ -152,7 +152,7 @@
{ AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 },
- { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0},
/*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/
{ AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 },
--- /home/develop/embedded/mipsel/linux/linux-mips.git/arch/mips/au1000/common/platform.c 2006-04-03 18:22:05.000000000 +0200
+++ arch/mips/au1000/common/platform.c 2006-04-05 23:08:55.000000000 +0200
@@ -16,6 +16,78 @@
#include <asm/mach-au1x00/au1xxx.h>
+#if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
+/* Ethernet controllers */
+static struct resource au1xxx_eth0_resources[] = {
+ [0] = {
+ .name = "eth-base",
+ .start = ETH0_BASE,
+ .end = ETH0_BASE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "eth-mac",
+ .start = MAC0_ENABLE,
+ .end = MAC0_ENABLE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "eth-irq",
+#if defined(CONFIG_SOC_AU1550)
+ .start = AU1550_MAC0_DMA_INT,
+ .end = AU1550_MAC0_DMA_INT,
+#else
+ .start = AU1000_MAC0_DMA_INT,
+ .end = AU1000_MAC0_DMA_INT,
+#endif
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device au1xxx_eth0_device = {
+ .name = "au1xxx-eth",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(au1xxx_eth0_resources),
+ .resource = au1xxx_eth0_resources,
+};
+
+#if defined(CONFIG_SOC_AU1000) || \
+ defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
+static struct resource au1xxx_eth1_resources[] = {
+ [0] = {
+ .name = "eth-base",
+ .start = ETH1_BASE,
+ .end = ETH1_BASE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "eth-mac",
+ .start = MAC1_ENABLE,
+ .end = MAC1_ENABLE + 0x0ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "eth-irq",
+#if defined(CONFIG_SOC_AU1550)
+ .start = AU1550_MAC1_DMA_INT,
+ .end = AU1550_MAC1_DMA_INT,
+#else
+ .start = AU1000_MAC1_DMA_INT,
+ .end = AU1000_MAC1_DMA_INT,
+#endif
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device au1xxx_eth1_device = {
+ .name = "au1xxx-eth",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(au1xxx_eth1_resources),
+ .resource = au1xxx_eth1_resources,
+};
+#endif
+#endif
+
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
@@ -272,6 +344,13 @@
#endif
static struct platform_device *au1xxx_platform_devices[] __initdata = {
+#if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
+ &au1xxx_eth0_device,
+#if defined(CONFIG_SOC_AU1000) || \
+ defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
+ &au1xxx_eth1_device,
+#endif
+#endif
&au1xxx_usb_ohci_device,
&au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
--- a/drivers/net/Kconfig 2 Jul 2005 06:46:30 -0000 1.1.1.1
+++ b/drivers/net/Kconfig 5 Apr 2006 21:20:30 -0000
@@ -440,12 +440,12 @@
Say Y here to support the Ethernet subsystem on your GT96100 card.
config MIPS_AU1X00_ENET
- bool "MIPS AU1000 Ethernet support"
+ tristate "MIPS AU1000 Ethernet support"
depends on NET_ETHERNET && SOC_AU1X00
select CRC32
help
If you have an Alchemy Semi AU1X00 based system
- say Y. Otherwise, say N.
+ say Y or M. Otherwise, say N.
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
--- /home/develop/embedded/mipsel/linux/linux-mips.git/drivers/net/au1000_eth.c 2006-04-03 18:23:17.000000000 +0200
+++ drivers/net/au1000_eth.c 2006-04-05 23:43:18.000000000 +0200
@@ -9,6 +9,9 @@
* Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
* or riemer@riemer-nt.de: fixed the link beat detection with
* ioctls (SIOCGMIIPHY)
+ * Update: 2006 Rodolfo Giometti: PM support, module support.
+ * Copyright 2006 Rodolfo Giometti <giometti@linux.it>
+ *
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
@@ -57,6 +60,7 @@
#include <asm/io.h>
#include <asm/processor.h>
+#include <linux/platform_device.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/cpu.h>
#include "au1000_eth.h"
@@ -67,8 +71,8 @@
static int au1000_debug = 3;
#endif
-#define DRV_NAME "au1000eth"
-#define DRV_VERSION "1.5"
+#define DRV_NAME "au1xxx-eth"
+#define DRV_VERSION "1.6"
#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
@@ -79,7 +83,8 @@
// prototypes
static void hard_stop(struct net_device *);
static void enable_rx_tx(struct net_device *dev);
-static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
+static int au1000_lowlevel_probe(struct net_device *ndev, u32 ioaddr, u32 macen_addr, int port_num);
+static void au1000_lowlevel_remove(struct net_device *ndev);
static int au1000_init(struct net_device *);
static int au1000_open(struct net_device *);
static int au1000_close(struct net_device *);
@@ -432,6 +437,34 @@
return 0;
}
+#ifdef CONFIG_PM
+int am79c874_suspend(struct net_device *dev, int phy_addr, int level)
+{
+ s16 mii_control;
+
+ if (au1000_debug > 4)
+ printk("am79c874_suspend\n");
+
+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_PWRDWN);
+ mdelay(1);
+ return 0;
+}
+
+int am79c874_resume(struct net_device *dev, int phy_addr, int level)
+{
+ s16 mii_control;
+
+ if (au1000_debug > 4)
+ printk("am79c874_resume\n");
+
+ mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+ mdio_write(dev, phy_addr, MII_CONTROL, mii_control & ~MII_CNTL_PWRDWN);
+ mdelay(1);
+ return 0;
+}
+#endif
+
int lxt971a_init(struct net_device *dev, int phy_addr)
{
if (au1000_debug > 4)
@@ -727,6 +760,10 @@
am79c874_init,
am79c874_reset,
am79c874_status,
+#ifdef CONFIG_PM
+ am79c874_suspend,
+ am79c874_resume,
+#endif
};
struct phy_ops am79c901_ops = {
@@ -1108,9 +1145,6 @@
dev->name, (unsigned)aup);
spin_lock_irqsave(&aup->lock, flags);
- if (aup->timer.function == &au1000_timer) {/* check if timer initted */
- del_timer(&aup->timer);
- }
hard_stop(dev);
#ifdef CONFIG_BCM5222_DUAL_PHY
@@ -1158,84 +1192,6 @@
}
}
-static struct {
- int port;
- u32 base_addr;
- u32 macen_addr;
- int irq;
- struct net_device *dev;
-} iflist[2];
-
-static int num_ifs;
-
-/*
- * Setup the base address and interupt of the Au1xxx ethernet macs
- * based on cpu type and whether the interface is enabled in sys_pinfunc
- * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
- */
-static int __init au1000_init_module(void)
-{
- struct cpuinfo_mips *c = ¤t_cpu_data;
- int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
- struct net_device *dev;
- int i, found_one = 0;
-
- switch (c->cputype) {
-#ifdef CONFIG_SOC_AU1000
- case CPU_AU1000:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1000_ETH0_BASE;
- iflist[1].base_addr = AU1000_ETH1_BASE;
- iflist[0].macen_addr = AU1000_MAC0_ENABLE;
- iflist[1].macen_addr = AU1000_MAC1_ENABLE;
- iflist[0].irq = AU1000_MAC0_DMA_INT;
- iflist[1].irq = AU1000_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1100
- case CPU_AU1100:
- num_ifs = 1 - ni;
- iflist[0].base_addr = AU1100_ETH0_BASE;
- iflist[0].macen_addr = AU1100_MAC0_ENABLE;
- iflist[0].irq = AU1100_MAC0_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1500
- case CPU_AU1500:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1500_ETH0_BASE;
- iflist[1].base_addr = AU1500_ETH1_BASE;
- iflist[0].macen_addr = AU1500_MAC0_ENABLE;
- iflist[1].macen_addr = AU1500_MAC1_ENABLE;
- iflist[0].irq = AU1500_MAC0_DMA_INT;
- iflist[1].irq = AU1500_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1550
- case CPU_AU1550:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1550_ETH0_BASE;
- iflist[1].base_addr = AU1550_ETH1_BASE;
- iflist[0].macen_addr = AU1550_MAC0_ENABLE;
- iflist[1].macen_addr = AU1550_MAC1_ENABLE;
- iflist[0].irq = AU1550_MAC0_DMA_INT;
- iflist[1].irq = AU1550_MAC1_DMA_INT;
- break;
-#endif
- default:
- num_ifs = 0;
- }
- for(i = 0; i < num_ifs; i++) {
- dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
- iflist[i].dev = dev;
- if (dev)
- found_one++;
- }
- if (!found_one)
- return -ENODEV;
- return 0;
-}
-
static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
{
struct au1000_private *aup = (struct au1000_private *)dev->priv;
@@ -1435,40 +1391,14 @@
.get_link = au1000_get_link
};
-static struct net_device *
-au1000_probe(u32 ioaddr, int irq, int port_num)
+static int
+au1000_lowlevel_probe(struct net_device *ndev, u32 ioaddr, u32 macen_addr, int port_num)
{
- static unsigned version_printed = 0;
- struct au1000_private *aup = NULL;
- struct net_device *dev = NULL;
+ struct au1000_private *aup = ndev->priv;
db_dest_t *pDB, *pDBfree;
char *pmac, *argptr;
char ethaddr[6];
- int i, err;
-
- if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
- return NULL;
-
- if (version_printed++ == 0)
- printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
-
- dev = alloc_etherdev(sizeof(struct au1000_private));
- if (!dev) {
- printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");
- return NULL;
- }
-
- if ((err = register_netdev(dev))) {
- printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
- err);
- free_netdev(dev);
- return NULL;
- }
-
- printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
- dev->name, ioaddr, irq);
-
- aup = dev->priv;
+ int i, ret;
/* Allocate the data buffers */
/* Snooping works fine with eth on all au1xxx */
@@ -1477,15 +1407,16 @@
&aup->dma_addr,
0);
if (!aup->vaddr) {
- free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
- return NULL;
+ printk(KERN_ERR "%s: cannot dma_alloc_noncoherent\n",
+ ndev->name);
+ ret = -ENOMEM;
+ goto out;
}
/* aup->mac is the base address of the MAC's registers */
aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
/* Setup some variables for quick register address access */
- if (ioaddr == iflist[0].base_addr)
+ if (port_num == 0)
{
/* check env variables first */
if (!get_ethernet_addr(ethaddr)) {
@@ -1495,7 +1426,7 @@
argptr = prom_getcmdline();
if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
printk(KERN_INFO "%s: No mac address found\n",
- dev->name);
+ ndev->name);
/* use the hard coded mac addresses */
} else {
str2eaddr(ethaddr, pmac + strlen("ethaddr="));
@@ -1504,26 +1435,26 @@
}
}
aup->enable = (volatile u32 *)
- ((unsigned long)iflist[0].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ ((unsigned long) macen_addr);
+ memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
aup->mac_id = 0;
au_macs[0] = aup;
}
else
- if (ioaddr == iflist[1].base_addr)
+ if (port_num == 1)
{
aup->enable = (volatile u32 *)
- ((unsigned long)iflist[1].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
- dev->dev_addr[4] += 0x10;
+ ((unsigned long) macen_addr);
+ memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ ndev->dev_addr[4] += 0x10;
setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
aup->mac_id = 1;
au_macs[1] = aup;
}
else
{
- printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
+ printk(KERN_ERR "%s: bad ioaddr\n", ndev->name);
}
/* bring the device out of reset, otherwise probing the mii
@@ -1536,7 +1467,8 @@
aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
if (!aup->mii) {
- printk(KERN_ERR "%s: out of memory\n", dev->name);
+ printk(KERN_ERR "%s: out of memory\n", ndev->name);
+ ret = -ENOMEM;
goto err_out;
}
aup->mii->next = NULL;
@@ -1545,7 +1477,8 @@
aup->mii->mii_control_reg = 0;
aup->mii->mii_data_reg = 0;
- if (mii_probe(dev) != 0) {
+ if (mii_probe(ndev) != 0) {
+ ret = -EBUSY;
goto err_out;
}
@@ -1564,6 +1497,7 @@
for (i = 0; i < NUM_RX_DMA; i++) {
pDB = GetFreeDB(aup);
if (!pDB) {
+ ret = -ENOMEM;
goto err_out;
}
aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
@@ -1572,6 +1506,7 @@
for (i = 0; i < NUM_TX_DMA; i++) {
pDB = GetFreeDB(aup);
if (!pDB) {
+ ret = -ENOMEM;
goto err_out;
}
aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
@@ -1579,32 +1514,24 @@
aup->tx_db_inuse[i] = pDB;
}
- spin_lock_init(&aup->lock);
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->open = au1000_open;
- dev->hard_start_xmit = au1000_tx;
- dev->stop = au1000_close;
- dev->get_stats = au1000_get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &au1000_ioctl;
- SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
- dev->set_config = &au1000_set_config;
- dev->tx_timeout = au1000_tx_timeout;
- dev->watchdog_timeo = ETH_TX_TIMEOUT;
- /*
- * The boot code uses the ethernet controller, so reset it to start
- * fresh. au1000_init() expects that the device is in reset state.
- */
- reset_mac(dev);
+ return 0;
- return dev;
+err_out :
+ au1000_lowlevel_remove(ndev);
+out :
+ return ret;
+}
+
+static void
+au1000_lowlevel_remove(struct net_device *ndev)
+{
+ struct au1000_private *aup = ndev->priv;
+ int i;
-err_out:
/* here we should have a valid dev plus aup-> register addresses
* so we can reset the mac properly.*/
- reset_mac(dev);
+ reset_mac(ndev);
kfree(aup->mii);
for (i = 0; i < NUM_RX_DMA; i++) {
if (aup->rx_db_inuse[i])
@@ -1618,10 +1545,6 @@
MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
(void *)aup->vaddr,
aup->dma_addr);
- unregister_netdev(dev);
- free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
- return NULL;
}
/*
@@ -1779,6 +1712,7 @@
if (au1000_debug > 4)
printk("%s: close: dev=%p\n", dev->name, dev);
+ del_timer_sync(&aup->timer);
reset_mac(dev);
spin_lock_irqsave(&aup->lock, flags);
@@ -1793,36 +1727,6 @@
return 0;
}
-static void __exit au1000_cleanup_module(void)
-{
- int i, j;
- struct net_device *dev;
- struct au1000_private *aup;
-
- for (i = 0; i < num_ifs; i++) {
- dev = iflist[i].dev;
- if (dev) {
- aup = (struct au1000_private *) dev->priv;
- unregister_netdev(dev);
- kfree(aup->mii);
- for (j = 0; j < NUM_RX_DMA; j++) {
- if (aup->rx_db_inuse[j])
- ReleaseDB(aup, aup->rx_db_inuse[j]);
- }
- for (j = 0; j < NUM_TX_DMA; j++) {
- if (aup->tx_db_inuse[j])
- ReleaseDB(aup, aup->tx_db_inuse[j]);
- }
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
- free_netdev(dev);
- release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
- }
- }
-}
-
static void update_tx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -2255,5 +2162,232 @@
return 0;
}
-module_init(au1000_init_module);
-module_exit(au1000_cleanup_module);
+/*
+ * Setup the base address and interupt of the Au1xxx ethernet macs
+ * based on cpu type and whether the interface is enabled in sys_pinfunc
+ * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
+ */
+static int au1000_drv_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev;
+ struct au1000_private *aup;
+ struct resource *res;
+ static unsigned version_printed = 0;
+ u32 base_addr, macen_addr;
+ int irq, ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ base_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-mac");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ macen_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eth-irq");
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ irq = res->start;
+
+ if (!request_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE, "Au1x00 ENET")) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (version_printed++ == 0)
+ printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+
+ ndev = alloc_etherdev(sizeof(struct au1000_private));
+ if (!ndev) {
+ printk (KERN_ERR "%s: alloc etherdev failed\n", DRV_NAME);
+ ret = -ENOMEM;
+ goto out_release_io;
+ }
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, dev);
+
+ ret = au1000_lowlevel_probe(ndev, base_addr, macen_addr, pdev->id);
+ if (ret < 0) {
+ printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);
+ goto out_free_netdev;
+ }
+
+ aup = ndev->priv;
+
+ spin_lock_init(&aup->lock);
+ ndev->base_addr = base_addr;
+ ndev->irq = irq;
+ ndev->open = au1000_open;
+ ndev->hard_start_xmit = au1000_tx;
+ ndev->stop = au1000_close;
+ ndev->get_stats = au1000_get_stats;
+ ndev->set_multicast_list = &set_rx_mode;
+ ndev->do_ioctl = &au1000_ioctl;
+ SET_ETHTOOL_OPS(ndev, &au1000_ethtool_ops);
+ ndev->set_config = &au1000_set_config;
+ ndev->tx_timeout = au1000_tx_timeout;
+ ndev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+ /*
+ * The boot code uses the ethernet controller, so reset it to start
+ * fresh. au1000_init() expects that the device is in reset state.
+ */
+ reset_mac(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ printk(KERN_ERR "%s: cannot register net device err %d\n",
+ DRV_NAME, ret);
+ goto out_lowlevel_remove;
+ }
+
+ printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
+ ndev->name, base_addr, irq);
+
+ dev_set_drvdata(dev, ndev);
+
+ return 0;
+
+out_lowlevel_remove :
+ au1000_lowlevel_remove(ndev);
+out_free_netdev :
+ free_netdev(ndev);
+out_release_io :
+ release_mem_region(CPHYSADDR(base_addr), MAC_IOSIZE);
+out :
+ printk("%s: not found (%d).\n", DRV_NAME, ret);
+
+ return ret;
+}
+
+static int au1000_drv_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct resource *res;
+
+ dev_set_drvdata(dev, NULL);
+
+ unregister_netdev(ndev);
+ au1000_lowlevel_remove(ndev);
+ free_netdev(ndev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
+ if (!res) {
+ printk(DRV_NAME ": warning! Invalid data!");
+ return -EINVAL;
+ }
+ release_mem_region(CPHYSADDR(res->start), MAC_IOSIZE);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1000_drv_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);
+
+ au1000_lowlevel_remove(ndev);
+
+ break;
+
+ case SUSPEND_POWER_DOWN :
+
+ break;
+ }
+
+ return 0;
+}
+
+static int au1000_drv_resume(struct device *dev, u32 level)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct au1000_private *aup = (struct au1000_private *) ndev->priv;
+ int ret;
+
+ if (!ndev)
+ return 0;
+
+ switch (level) {
+ case RESUME_RESTORE_STATE :
+ ret = au1000_lowlevel_probe(ndev, aup->mac, aup->enable, aup->mac_id);
+ if (ret < 0) {
+ printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);
+ return ret;
+ }
+
+ 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);
+
+ break;
+
+ case RESUME_ENABLE :
+ if (netif_running(ndev))
+ netif_device_attach(ndev);
+
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static struct device_driver au1000_driver = {
+ .name = DRV_NAME,
+ .bus = &platform_bus_type,
+ .probe = au1000_drv_probe,
+ .remove = au1000_drv_remove,
+#ifdef CONFIG_PM
+ .suspend = au1000_drv_suspend,
+ .resume = au1000_drv_resume,
+#endif
+};
+
+static int __init au1000_eth_init(void)
+{
+ return driver_register(&au1000_driver);
+}
+
+static void __exit au1000_eth_cleanup(void)
+{
+ driver_unregister(&au1000_driver);
+}
+
+module_init(au1000_eth_init);
+module_exit(au1000_eth_cleanup);
--- /home/develop/embedded/mipsel/linux/linux-mips.git/drivers/net/au1000_eth.h 2006-03-31 16:58:55.000000000 +0200
+++ drivers/net/au1000_eth.h 2006-04-05 12:55:56.000000000 +0200
@@ -152,6 +152,8 @@
int (*phy_init) (struct net_device *, int);
int (*phy_reset) (struct net_device *, int);
int (*phy_status) (struct net_device *, int, u16 *, u16 *);
+ int (*phy_suspend) (struct net_device *, int, int);
+ int (*phy_resume) (struct net_device *, int, int);
};
/*
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
next prev parent reply other threads:[~2006-04-05 22:15 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-04-05 15:47 Power management for au1000_eth.c Rodolfo Giometti
2006-04-05 22:23 ` Rodolfo Giometti
2006-04-05 22:26 ` Rodolfo Giometti [this message]
2006-04-06 14:43 ` [PATCH] Oops! - " Sergei Shtylyov
2006-04-06 15:50 ` Rodolfo Giometti
2006-04-19 18:46 ` [PATCH] au1000_eth.c probe code straightened up Sergei Shtylyov
2006-05-02 15:09 ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
2006-05-03 7:47 ` Rodolfo Giometti
2006-05-31 15:01 ` Sergei Shtylyov
2006-05-31 15:21 ` Rodolfo Giometti
2006-04-06 17:10 ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060405222620.GP7029@enneenne.com \
--to=giometti@linux.it \
--cc=linux-mips@linux-mips.org \
--cc=ppopov@mvista.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox