All of lore.kernel.org
 help / color / mirror / Atom feed
* Power management for au1000_eth.c
@ 2006-04-05 15:47 Rodolfo Giometti
  2006-04-05 22:23 ` Rodolfo Giometti
  0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 15:47 UTC (permalink / raw)
  To: Linux MIPS; +Cc: ppopov

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Power management for au1000_eth.c
  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   ` [PATCH] Oops! - " Rodolfo Giometti
  0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 22:23 UTC (permalink / raw)
  To: Linux MIPS; +Cc: ppopov

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.

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] Oops! - Re: Power management for au1000_eth.c
  2006-04-05 22:23 ` Rodolfo Giometti
@ 2006-04-05 22:26   ` Rodolfo Giometti
  2006-04-06 14:43     ` Sergei Shtylyov
  0 siblings, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-05 22:26 UTC (permalink / raw)
  To: Linux MIPS; +Cc: ppopov


[-- 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 = &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 #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Oops! - Re: Power management for au1000_eth.c
  2006-04-05 22:26   ` [PATCH] Oops! - " Rodolfo Giometti
@ 2006-04-06 14:43     ` Sergei Shtylyov
  2006-04-06 15:50       ` Rodolfo Giometti
  2006-04-06 17:10       ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
  0 siblings, 2 replies; 11+ messages in thread
From: Sergei Shtylyov @ 2006-04-06 14:43 UTC (permalink / raw)
  To: Linux MIPS; +Cc: Rodolfo Giometti, Jordan Crouse, Pete Popov

Hello.

Rodolfo Giometti wrote:

>>>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.

    Actually, the network driver patches should be sent to Jeff Garzik and 
Andrew Morton.

>>Note that this patch needs my previous one who implements new power
>>management's sysfs interface.

> The forgotten attachment. :)

    Funny, I've also been cooking a patch to straighten Alchemy Ethernet 
probing code a bit...

> ------------------------------------------------------------------------
> 
> --- /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 },

    Don't think these changes are necessary.

> --- /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,
 > +	},

    NAK, ETH0_BASE not defined anywhere, and that address differs between SOCs.
Note that this must be a *physical* address, not KSEG1-base.

> +	[1] = {
> +		.name	= "eth-mac",
> +		.start	= MAC0_ENABLE,
> +		.end	= MAC0_ENABLE + 0x0ffff,
 > +		.flags	= IORESOURCE_MEM,
 > +	},

    NAK, because:

1) MAC0_ENABLE not defined anywhere, and that address differs between SOCs;
2) MAC enable register occupies 4 bytes, not 65536.

[...]

> +#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,
 > +	},

    Same here.

> --- /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

[...]

> @@ -67,8 +71,8 @@
>  static int au1000_debug = 3;
>  #endif
>  
> -#define DRV_NAME	"au1000eth"
> -#define DRV_VERSION	"1.5"
> +#define DRV_NAME	"au1xxx-eth"

    au1000_eth, according to the driver name.

> +#define DRV_VERSION	"1.6"

    Heh, nobody keeps track of the versions. :-)

> @@ -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)

[...]

> @@ -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);

    NAK, ioaddr should be physical address.

>  	/* Setup some variables for quick register address access */
> -	if (ioaddr == iflist[0].base_addr)
> +	if (port_num == 0)

    Yep, I disliked this code too. :-)

>  	{
>  		/* 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);

    NAK, macen_addr should have been a physical address at that point too
(if the plarform definitions were correct :-).  Also, this could have been done
outside of "if".

> +		memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));

    That too.

>  		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;

    Actually, the DBAu15x0 boards have their Ethernet addresess differ by 1 in 
the last byte, not by 0x10 in the next to last one. This code assigns to the 
port an address different to what's printed on a port's sticker. This should 
be fixed I guess...

>  		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);
>  	}

    Doubt we need this "else" at all...

> @@ -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")) {

    NAK, base_addr should adready be a physical address. Also, why no 
request_mem_region()
for the MAC enable register?

> +	ret = au1000_lowlevel_probe(ndev, base_addr, macen_addr, pdev->id);

    Remember, The passed addresses are physical at that point.

[...]

WBR, Sergei

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Oops! - Re: Power management for au1000_eth.c
  2006-04-06 14:43     ` 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-04-06 17:10       ` Oops! - Re: Power management for au1000_eth.c Jordan Crouse
  1 sibling, 1 reply; 11+ messages in thread
From: Rodolfo Giometti @ 2006-04-06 15:50 UTC (permalink / raw)
  To: Linux MIPS; +Cc: Sergei Shtylyov, Jordan Crouse, Pete Popov


[-- Attachment #1.1: Type: text/plain, Size: 6811 bytes --]

On Thu, Apr 06, 2006 at 06:43:24PM +0400, Sergei Shtylyov wrote:
> 
>    Actually, the network driver patches should be sent to Jeff Garzik and 
> Andrew Morton.

Ok. Sorry. Hope they can get the patch from this list.

>    Funny, I've also been cooking a patch to straighten Alchemy Ethernet 
> probing code a bit...

:)

> >------------------------------------------------------------------------
> >
> >--- 
> >/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 },
> 
>    Don't think these changes are necessary.

These are necessary to group togheter CPUs that have the same
parameters.

> >--- 
> >/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,
> > +	},
> 
>    NAK, ETH0_BASE not defined anywhere, and that address differs between 
>    SOCs.
> Note that this must be a *physical* address, not KSEG1-base.

You are right! I forgot to add the attached file... I'm very sorry but
I must work on an older Linux version which still use CVS. I can't
switch to GIT right now and I have to build my patches by hands.

In the attached file you can see that I grouped togheter CPUs that
have the same configuration parameters.

> > 	/* Setup some variables for quick register address access */
> >-	if (ioaddr == iflist[0].base_addr)
> >+	if (port_num == 0)
> 
>    Yep, I disliked this code too. :-)

I just use the "id" filed instaed of using the base address. It seems
to me more readable...

> > 	{
> > 		/* 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);
> 
>    NAK, macen_addr should have been a physical address at that point too
> (if the plarform definitions were correct :-).  Also, this could have been 
> done
> outside of "if".

I just keeped the original structure...

> > 		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;
> 
>    Actually, the DBAu15x0 boards have their Ethernet addresess differ by 1 
>    in the last byte, not by 0x10 in the next to last one. This code assigns to 
> the port an address different to what's printed on a port's sticker. This 
> should be fixed I guess...

Yes. However this comes from the previous driver version and I'm
working on an Au1100 based board. :)

> >@@ -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")) {
> 
>    NAK, base_addr should adready be a physical address. Also, why no 
> request_mem_region()
> for the MAC enable register?

Yes. I forgot to add it.

Thanks for your suggestions! But I'd like to know if I have to change
something and resubmit the patch or these suggestions can be resolved
during the merging of the code...

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-2 --]
[-- Type: text/plain, Size: 2999 bytes --]

--- /home/develop/embedded/mipsel/linux/linux-mips.git/include/asm-mips/mach-au1x00/au1000.h	2006-04-03 18:24:38.000000000 +0200
+++ include/asm-mips/mach-au1x00/au1000.h	2006-04-06 17:31:04.000000000 +0200
@@ -606,11 +690,10 @@
 #define USB_OHCI_BASE             0x10100000 // phys addr for ioremap
 #define USB_HOST_CONFIG           0xB017fffc
 
-#define AU1000_ETH0_BASE      0xB0500000
-#define AU1000_ETH1_BASE      0xB0510000
-#define AU1000_MAC0_ENABLE       0xB0520000
-#define AU1000_MAC1_ENABLE       0xB0520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE		  0xB0500000
+#define ETH1_BASE		  0xB0510000
+#define MAC0_ENABLE		  0xB0520000
+#define MAC1_ENABLE		  0xB0520004
 #endif /* CONFIG_SOC_AU1000 */
 
 /* Au1500 */
@@ -635,8 +718,8 @@
 #define AU1000_USB_DEV_SUS_INT    25
 #define AU1000_USB_HOST_INT       26
 #define AU1000_ACSYNC_INT         27
-#define AU1500_MAC0_DMA_INT       28
-#define AU1500_MAC1_DMA_INT       29
+#define AU1000_MAC0_DMA_INT       28
+#define AU1000_MAC1_DMA_INT       29
 #define AU1000_AC97C_INT          31
 #define AU1000_GPIO_0             32
 #define AU1000_GPIO_1             33
@@ -683,11 +766,10 @@
 #define USB_OHCI_BASE             0x10100000 // phys addr for ioremap
 #define USB_HOST_CONFIG           0xB017fffc
 
-#define AU1500_ETH0_BASE	  0xB1500000
-#define AU1500_ETH1_BASE	  0xB1510000
-#define AU1500_MAC0_ENABLE       0xB1520000
-#define AU1500_MAC1_ENABLE       0xB1520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE		  0xB1500000
+#define ETH1_BASE		  0xB1510000
+#define MAC0_ENABLE		  0xB1520000
+#define MAC1_ENABLE		  0xB1520004
 #endif /* CONFIG_SOC_AU1500 */
 
 /* Au1100 */
@@ -713,8 +795,8 @@
 #define AU1000_USB_DEV_SUS_INT    25
 #define AU1000_USB_HOST_INT       26
 #define AU1000_ACSYNC_INT         27
-#define AU1100_MAC0_DMA_INT       28
-#define	AU1100_GPIO_208_215	29
+#define AU1000_MAC0_DMA_INT	  28
+#define	AU1100_GPIO_208_215	  29
 #define	AU1100_LCD_INT            30
 #define AU1000_AC97C_INT          31
 #define AU1000_GPIO_0             32
@@ -757,8 +839,8 @@
 #define USB_OHCI_BASE             0x10100000 // phys addr for ioremap
 #define USB_HOST_CONFIG           0xB017fffc
 
-#define AU1100_ETH0_BASE	  0xB0500000
-#define AU1100_MAC0_ENABLE       0xB0520000
+#define ETH0_BASE		  0xB0500000
+#define MAC0_ENABLE		  0xB0520000
 #define NUM_ETH_INTERFACES 1
 #endif /* CONFIG_SOC_AU1100 */
 
@@ -841,11 +923,10 @@
 #define USB_OHCI_LEN              0x00060000
 #define USB_HOST_CONFIG           0xB4027ffc
 
-#define AU1550_ETH0_BASE      0xB0500000
-#define AU1550_ETH1_BASE      0xB0510000
-#define AU1550_MAC0_ENABLE       0xB0520000
-#define AU1550_MAC1_ENABLE       0xB0520004
-#define NUM_ETH_INTERFACES 2
+#define ETH0_BASE		  0xB0500000
+#define ETH1_BASE		  0xB0510000
+#define MAC0_ENABLE		  0xB0520000
+#define MAC1_ENABLE		  0xB0520004
 #endif /* CONFIG_SOC_AU1550 */
 
 #ifdef CONFIG_SOC_AU1200

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Oops! - Re: Power management for au1000_eth.c
  2006-04-06 14:43     ` Sergei Shtylyov
  2006-04-06 15:50       ` Rodolfo Giometti
@ 2006-04-06 17:10       ` Jordan Crouse
  1 sibling, 0 replies; 11+ messages in thread
From: Jordan Crouse @ 2006-04-06 17:10 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: Linux MIPS, Rodolfo Giometti, Pete Popov

On 06/04/06 18:43 +0400, Sergei Shtylyov wrote:
> Hello.
> 
> Rodolfo Giometti wrote:
> 
> >>>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.
> 
>    Actually, the network driver patches should be sent to Jeff Garzik and 
> Andrew Morton.

And the description is wrong - this isn't exactly just power management,
there are lots of changes here.  You should separate them out into multiple
patches. 

> >>Note that this patch needs my previous one who implements new power
> >>management's sysfs interface.

Thats OK, as long as this patch can be applied on its own, without requiring
the previous patch.  It is one thing to write a new PM interface for the 
whole system, but the driver suspend and resume functions should never be
system specific.  That makes life easier for future developers.

>    Funny, I've also been cooking a patch to straighten Alchemy Ethernet 
> probing code a bit...

I think we can all get along here.  The PM stuff looks decent to me, and
Sergei had some good comments about the rest of the patch.  I don't see
any reason why the two of you can't get together and bang out a few patches
to fix all of our ills.

Jordan

--
Jordan Crouse
Senior Linux Engineer
AMD - Personal Connectivity Solutions Group
<www.amd.com/embeddedprocessors>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] au1000_eth.c probe code straightened up
  2006-04-06 15:50       ` Rodolfo Giometti
@ 2006-04-19 18:46         ` Sergei Shtylyov
  2006-05-02 15:09           ` [PATCH] au1000_eth.c Power Management, driver registration and module support Rodolfo Giometti
  0 siblings, 1 reply; 11+ messages in thread
From: Sergei Shtylyov @ 2006-04-19 18:46 UTC (permalink / raw)
  To: jgarzik; +Cc: Rodolfo Giometti, netdev, Linux-MIPS

[-- Attachment #1: Type: text/plain, Size: 429 bytes --]

      Straighten up the AMD Au1xx0 Ethernet probing code, make it print out (and
store in the 'net_device' structure) the physical address of the controller,
not the KSEG1-based virtual. Make the driver also claim/release the 4-byte MAC
enable registers and assign to the Ethernet ports two consecutive MAC
addresses to match those that are printed on their stickers.

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>




[-- Attachment #2: au1000_eth-probe-rewrite.patch --]
[-- Type: text/plain, Size: 10374 bytes --]

diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 1363083..d5dfc78 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -2,7 +2,7 @@
  *
  * Alchemy Au1x00 ethernet driver
  *
- * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2001-2003, 2006 MontaVista Software Inc.
  * Copyright 2002 TimeSys Corp.
  * Added ethtool/mii-tool support,
  * Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
@@ -67,7 +67,7 @@ static int au1000_debug = 5;
 static int au1000_debug = 3;
 #endif
 
-#define DRV_NAME	"au1000eth"
+#define DRV_NAME	"au1000_eth"
 #define DRV_VERSION	"1.5"
 #define DRV_AUTHOR	"Pete Popov <ppopov@embeddedalley.com>"
 #define DRV_DESC	"Au1xxx on-chip Ethernet driver"
@@ -79,7 +79,7 @@ MODULE_LICENSE("GPL");
 // 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 struct net_device * au1000_probe(int port_num);
 static int au1000_init(struct net_device *);
 static int au1000_open(struct net_device *);
 static int au1000_close(struct net_device *);
@@ -1159,12 +1159,27 @@ setup_hw_rings(struct au1000_private *au
 }
 
 static struct {
-	int port;
 	u32 base_addr;
 	u32 macen_addr;
 	int irq;
 	struct net_device *dev;
-} iflist[2];
+} iflist[2] = {
+#ifdef CONFIG_SOC_AU1000
+	{AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT},
+	{AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1100
+	{AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1500
+	{AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT},
+	{AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1550
+	{AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT},
+	{AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT}
+#endif
+};
 
 static int num_ifs;
 
@@ -1175,58 +1190,14 @@ static int num_ifs;
  */
 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;
-	}
+	num_ifs = NUM_ETH_INTERFACES - ni;
+
 	for(i = 0; i < num_ifs; i++) {
-		dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
+		dev = au1000_probe(i);
 		iflist[i].dev = dev;
 		if (dev)
 			found_one++;
@@ -1435,8 +1406,7 @@ static struct ethtool_ops au1000_ethtool
 	.get_link = au1000_get_link
 };
 
-static struct net_device *
-au1000_probe(u32 ioaddr, int irq, int port_num)
+static struct net_device * au1000_probe(int port_num)
 {
 	static unsigned version_printed = 0;
 	struct au1000_private *aup = NULL;
@@ -1444,94 +1414,95 @@ au1000_probe(u32 ioaddr, int irq, int po
 	db_dest_t *pDB, *pDBfree;
 	char *pmac, *argptr;
 	char ethaddr[6];
-	int i, err;
+	int irq, i, err;
+	u32 base, macen;
+
+	if (port_num >= NUM_ETH_INTERFACES)
+ 		return NULL;
 
-	if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
+	base  = CPHYSADDR(iflist[port_num].base_addr );
+	macen = CPHYSADDR(iflist[port_num].macen_addr);
+	irq = iflist[port_num].irq;
+
+	if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
+	    !request_mem_region(macen, 4, "Au1x00 ENET"))
 		return NULL;
 
-	if (version_printed++ == 0) 
+	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");  
+		printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
 		return NULL;
 	}
 
-	if ((err = register_netdev(dev))) {
-		printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
-				err);
+	if ((err = register_netdev(dev)) != 0) {
+		printk(KERN_ERR "%s: Cannot register net device, error %d\n",
+				DRV_NAME, err);
 		free_netdev(dev);
 		return NULL;
 	}
 
-	printk("%s: Au1x Ethernet found at 0x%x, irq %d\n", 
-			dev->name, ioaddr, irq);
+	printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
+		dev->name, base, irq);
 
 	aup = dev->priv;
 
 	/* Allocate the data buffers */
 	/* Snooping works fine with eth on all au1xxx */
-	aup->vaddr = (u32)dma_alloc_noncoherent(NULL,
-			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
-			&aup->dma_addr,
-			0);
+	aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
+						(NUM_TX_BUFFS + NUM_RX_BUFFS),
+						&aup->dma_addr,	0);
 	if (!aup->vaddr) {
 		free_netdev(dev);
-		release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+		release_mem_region( base, MAC_IOSIZE);
+		release_mem_region(macen, 4);
 		return NULL;
 	}
 
 	/* aup->mac is the base address of the MAC's registers */
-	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
+	aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
+
 	/* Setup some variables for quick register address access */
-	if (ioaddr == iflist[0].base_addr)
-	{
-		/* check env variables first */
-		if (!get_ethernet_addr(ethaddr)) { 
+	aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
+	aup->mac_id = port_num;
+	au_macs[port_num] = aup;
+
+	if (port_num == 0) {
+		/* Check the environment variables first */
+		if (get_ethernet_addr(ethaddr) == 0)
 			memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
-		} else {
+		else {
 			/* Check command line */
 			argptr = prom_getcmdline();
-			if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
-				printk(KERN_INFO "%s: No mac address found\n", 
-						dev->name);
-				/* use the hard coded mac addresses */
-			} else {
+			if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
+				printk(KERN_INFO "%s: No MAC address found\n",
+						 dev->name);
+				/* Use the hard coded MAC addresses */
+			else {
 				str2eaddr(ethaddr, pmac + strlen("ethaddr="));
 				memcpy(au1000_mac_addr, ethaddr, 
-						sizeof(au1000_mac_addr));
+				       sizeof(au1000_mac_addr));
 			}
 		}
-			aup->enable = (volatile u32 *) 
-				((unsigned long)iflist[0].macen_addr);
-		memcpy(dev->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)
-	{
-			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;
+	} else if (port_num == 1)
 		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);
-	}
 
-	/* bring the device out of reset, otherwise probing the mii
-	 * will hang */
+	/*
+	 * Assign to the Ethernet ports two consecutive MAC addresses
+	 * to match those that are printed on their stickers
+	 */
+	memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+	dev->dev_addr[5] += port_num;
+
+	/* Bring the device out of reset, otherwise probing the 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;
+	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 |
+		       MAC_EN_CLOCK_ENABLE;
 	au_sync_delay(2);
 
 	aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
@@ -1580,7 +1551,7 @@ au1000_probe(u32 ioaddr, int irq, int po
 	}
 
 	spin_lock_init(&aup->lock);
-	dev->base_addr = ioaddr;
+	dev->base_addr = base;
 	dev->irq = irq;
 	dev->open = au1000_open;
 	dev->hard_start_xmit = au1000_tx;
@@ -1614,13 +1585,12 @@ err_out:
 		if (aup->tx_db_inuse[i])
 			ReleaseDB(aup, aup->tx_db_inuse[i]);
 	}
-	dma_free_noncoherent(NULL,
-			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
-			(void *)aup->vaddr,
-			aup->dma_addr);
+	dma_free_noncoherent(NULL, 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);
+	release_mem_region( base, MAC_IOSIZE);
+	release_mem_region(macen, 4);
 	return NULL;
 }
 
@@ -1805,20 +1775,18 @@ static void __exit au1000_cleanup_module
 			aup = (struct au1000_private *) dev->priv;
 			unregister_netdev(dev);
 			kfree(aup->mii);
-			for (j = 0; j < NUM_RX_DMA; j++) {
+			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++) {
+			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);
+ 			dma_free_noncoherent(NULL, MAX_BUF_SIZE *
+ 					     (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ 					     (void *)aup->vaddr, aup->dma_addr);
+ 			release_mem_region(dev->base_addr, MAC_IOSIZE);
+ 			release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
 			free_netdev(dev);
-			release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
 		}
 	}
 }


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
  2006-04-19 18:46         ` [PATCH] au1000_eth.c probe code straightened up Sergei Shtylyov
@ 2006-05-02 15:09           ` Rodolfo Giometti
  2006-05-03  7:47             ` Rodolfo Giometti
  2006-05-31 15:01             ` Sergei Shtylyov
  0 siblings, 2 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-02 15:09 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS

[-- Attachment #1: Type: text/plain, Size: 1492 bytes --]

Hello,

here:

   http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1000_eth-pm-and-registration

the new version of my patch for au1000_eth.c who should implement:

* Module support.

   -	bool "MIPS AU1000 Ethernet support"
   +	tristate "MIPS AU1000 Ethernet support"

* Driver registration.

   +static int __init au1000_eth_init(void)
   +{
   +	return driver_register(&au1000_driver);
   +}
   +
   +static void __exit au1000_eth_cleanup(void)
   +{
   +	driver_unregister(&au1000_driver);
   +}      

* Power Management.

   +#ifdef CONFIG_PM
   +	.suspend        = au1000_drv_suspend,
   +	.resume         = au1000_drv_resume,
   +#endif

Also, as suggested by Sergei it:

* uses physical addresses and not KSEG1-based virtual anymore and
  claims/releases the 4-byte MAC enable registers:

   wwpc:~# cat /proc/iomem
   10500000-1050ffff : eth-base
   10520000-10520003 : eth-mac
      
* assigns to the Ethernet ports two consecutive MAC addresses:

   -		dev->dev_addr[4] += 0x10;
   +				((unsigned long) macen_addr);
   +		memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
   +		ndev->dev_addr[5] += 0x01;
      
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 #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
  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
  1 sibling, 0 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-03  7:47 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS

[-- Attachment #1: Type: text/plain, Size: 467 bytes --]

Hello,

yesterday I did a little mess with GIT... now the patch is
complete. Sorry. :)

I forgot also to say that it has been done against
«linux-2.6.16-stable» branch.

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 #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
  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
  1 sibling, 1 reply; 11+ messages in thread
From: Sergei Shtylyov @ 2006-05-31 15:01 UTC (permalink / raw)
  To: Rodolfo Giometti; +Cc: jgarzik, netdev, Linux-MIPS, Jordan Crouse

Hello.

Rodolfo Giometti wrote:

> here:

>    http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1000_eth-pm-and-registration

> the new version of my patch for au1000_eth.c who should implement:

> Also, as suggested by Sergei it:
> 
> * uses physical addresses and not KSEG1-based virtual anymore and
>   claims/releases the 4-byte MAC enable registers:
> 
>    wwpc:~# cat /proc/iomem
>    10500000-1050ffff : eth-base
>    10520000-10520003 : eth-mac
>       
> * assigns to the Ethernet ports two consecutive MAC addresses:
> 
>    -		dev->dev_addr[4] += 0x10;
>    +				((unsigned long) macen_addr);
>    +		memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
>    +		ndev->dev_addr[5] += 0x01;
>       
> Ciao,

    Now that this is merged, Rodolfo's patch should probably preempt mine...
but it looks like something was lost during the transition: I failed to see
where SYS_PINFUNC register is actually read (the comment mentioning this was 
retained :-) to check whether Ethernet port 1 is enabled (its pins are shared 
w/GPIO)...

> Rodolfo

WBR, Sergei

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] au1000_eth.c Power Management, driver registration and module support
  2006-05-31 15:01             ` Sergei Shtylyov
@ 2006-05-31 15:21               ` Rodolfo Giometti
  0 siblings, 0 replies; 11+ messages in thread
From: Rodolfo Giometti @ 2006-05-31 15:21 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: jgarzik, netdev, Linux-MIPS, Jordan Crouse

[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]

On Wed, May 31, 2006 at 07:01:02PM +0400, Sergei Shtylyov wrote:
> 
>    Now that this is merged, Rodolfo's patch should probably preempt mine...
> but it looks like something was lost during the transition: I failed to see
> where SYS_PINFUNC register is actually read (the comment mentioning this 
> was retained :-) to check whether Ethernet port 1 is enabled (its pins are 
> shared w/GPIO)...

You are right! Maybe something like this may fix the problem:

   diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
   index 341fdc4..8a6427e 100644
   --- a/drivers/net/au1000_eth.c
   +++ b/drivers/net/au1000_eth.c
   @@ -2149,6 +2149,9 @@ static int au1000_drv_probe(struct devic
           void *base_addr, *macen_addr;
           int irq, ret;

   +       if (pdev->id == 1 && (au_readl(SYS_PINFUNC) & SYS_PF_NI2) != 0)
   +               return -ENODEV;
   +
           /* Get the resource info */
           res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
           if (!res) {

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 #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2006-05-31 15:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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   ` [PATCH] Oops! - " Rodolfo Giometti
2006-04-06 14:43     ` 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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.