[PATCH] Oops! - Re: Power management for au1000_eth.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxx
Linux Device Driver                             giometti@xxxxxxxxx
Embedded Systems                     		giometti@xxxxxxxx
UNIX programming                     phone:     +39 349 2432127
--- /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@xxxxxxxxxxxxxxxxxxx 
  * or riemer@xxxxxxxxxxxx: fixed the link beat detection with 
  * ioctls (SIOCGMIIPHY)
+ * Update: 2006 Rodolfo Giometti: PM support, module support.
+ * Copyright 2006 Rodolfo Giometti <giometti@xxxxxxxx>
+ *
  * Author: MontaVista Software, Inc.
  *         	ppopov@xxxxxxxxxx or source@xxxxxxxxxx
  *
@@ -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@xxxxxxxxxxxxxxxxx>"
 #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 = &current_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: signature.asc
Description: Digital signature


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux