Skip to contentSkip to conversation

Problems after merge to 2.6.18-rc1

PATCH New Rodolfo Giometti 4 participants 8 messages Jul 13, 2006 – Jul 19, 2006

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Hello,

I just finished a (big) merge with linux-mips 2.6.18-rc1 and my tree and at boot I get:

Linux version 2.6.18-rc1-g2636fd13-dirty (giometti@gundam) (gcc version 3.4.3) #165 Thu Jul 13 18:13:26 CEST 2006 CPU revision is: 02030204
Board WWPC1000 version 1.0
WWPC-setup: uC=off
(PRId 02030204) @ 396MHZ
BCLK switching enabled!
Determined physical RAM map:

    memory: 04000000 @ 00000000 (usable)
   Early serial console at AU 0x11100000 (options '115200')
   Determined physical RAM map:
    memory: 04000000 @ 00000000 (usable)
   Built 1 zonelists.  Total pages: 16384
   Kernel command line: wwpc=uc-off console=uart,au,0x11100000,115200 root=/dev/nfs rw nfsroot=192.168.32.254:/homemipsel/distro/debian ip=192.168.32.24:192.168.32.254::255.255.255.0:000:eth0:off
   Primary instruction cache 16kB, physically tagged, 4-way, linesize 32 bytes.
   Primary data cache 16kB, 4-way, linesize 32 bytes.
   Synthesized TLB refill handler (17 instructions).
   Synthesized TLB load handler fastpath (34 instructions).
   Synthesized TLB store handler fastpath (34 instructions).
   Synthesized TLB modify handler fastpath (33 instructions).
   PID hash table entries: 1024 (order: 10, 4096 bytes)
   calculating r4koff... 00182b80(1584000)
   CPU frequency 396.00 MHz
   Console: colour dummy device 80x25
   Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
   Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
   Bad page state in process 'swapper'
   page:810092a0 flags:0x00000000 mapping:00000000 mapcount:1 count:0
   Trying to fix it up, but a reboot is needed
   Backtrace:
   Call Trace:
    [<8015d91c>] bad_page+0x6c/0xac
    [<8015e4c0>] free_hot_cold_page+0x190/0x1ec
    [<8046099c>] free_all_bootmem_core+0x1ec/0x228
    [<80457110>] mem_init+0x4c/0x218
    [<80462a50>] inode_init_early+0x68/0xbc
    [<804657d8>] console_init+0x48/0x68
    [<80450824>] start_kernel+0x208/0x400
    [<8045081c>] start_kernel+0x200/0x400
    [<80450134>] unknown_bootoption+0x0/0x310

Bad page state in process 'swapper'
page:810092c0 flags:0x00000000 mapping:00000000 mapcount:1 count:0 Trying to fix it up, but a reboot is needed
...

Suggestions? :)

Thanks,

Rodolfo

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
#1 lore raw

Hi,

Quoted 10 lines · Rodolfo Giometti
   Call Trace:
    [<8015d91c>] bad_page+0x6c/0xac
    [<8015e4c0>] free_hot_cold_page+0x190/0x1ec
    [<8046099c>] free_all_bootmem_core+0x1ec/0x228
    [<80457110>] mem_init+0x4c/0x218
    [<80462a50>] inode_init_early+0x68/0xbc
    [<804657d8>] console_init+0x48/0x68
    [<80450824>] start_kernel+0x208/0x400
    [<8045081c>] start_kernel+0x200/0x400
    [<80450134>] unknown_bootoption+0x0/0x310

Well, what might 'unknown_bootoption' be trying to tell you? What boot options did you set?

Daniel

#2 lore raw
In reply to Rodolfo Giometti
Quoted 15 lines · Rodolfo Giometti

I just finished a (big) merge with linux-mips 2.6.18-rc1 and my tree and at boot I get:

   Linux version 2.6.18-rc1-g2636fd13-dirty (giometti@gundam) (gcc version 3.4.3) #165 Thu Jul 13 18:13:26 CEST 2006
   CPU revision is: 02030204
   Board WWPC1000 version 1.0
   WWPC-setup: uC=off 
   (PRId 02030204) @ 396MHZ
   BCLK switching enabled!
   Determined physical RAM map:
    memory: 04000000 @ 00000000 (usable)
   Early serial console at AU 0x11100000 (options '115200')
   Determined physical RAM map:
    memory: 04000000 @ 00000000 (usable)
   Built 1 zonelists.  Total pages: 16384

Two "Determined physycal RAM map:" line here. If both were printed in parse_cmdline_early() (i.e. parse_cmdline_early was called twice), something is seriously broken.

---
Atsushi Nemoto

#3 lore raw
Quoted 4 lines · Atsushi Nemoto

Two "Determined physycal RAM map:" line here. If both were printed in parse_cmdline_early() (i.e. parse_cmdline_early was called twice), something is seriously broken.

Yes, you was right. I fixed it! :)

However now I have another (strange) problem.

Attached you can find my patch to add power managament to the new version of file "drivers/net/au1000_eth.c" that implements the PHY-layer support.

Please, note the hack after the function mii_probe() called by au1000_lowlevel_probe().

Kernel messages during suspend are:

   hostname:~# apm --suspend
   Stopping tasks: ===============================|
   au1xxx_pm_prepare: state = 3
    usbdev1.1_ep81: PM: suspend 0->2, parent 1-0:1.0 already 1
   warning! Serial console ttyS0 is not disabled in debug kernel mode
   au1xxx_pm_enter: state = 3
   au_sleep: reason -3 force 0 wakeup 100 ticks 3000
   au_sleep: Zzz...
   au_sleep: Yep!
   kobject_add failed for 0:1f with -EEXIST, don't try to register things with the same name in the same directory.
   Call Trace:
    [<80252ca8>] kobject_add+0x17c/0x1e0
    [<80252b98>] kobject_add+0x6c/0x1e0
    [<80292008>] device_add+0xc0/0x464
    [<80291ff4>] device_add+0xac/0x464
    [<802a2e64>] mdiobus_register+0x134/0x198
    [<802a3ac0>] au1000_lowlevel_probe+0x104/0x4b4
    [<802a58a4>] au1000_drv_resume+0x3c/0xc8
    [<80138978>] process_timeout+0x0/0x8
    [<80298610>] platform_resume+0x34/0x40
    [<8029bf7c>] resume_device+0x19c/0x200
    [<802528e4>] kobject_get+0x20/0x34
    [<8029391c>] __sysdev_resume+0xf0/0xf8
    [<80291da4>] get_device+0x20/0x34
    [<8029c1c4>] dpm_resume+0x1e4/0x3c0
    [<8029c3fc>] device_resume+0x5c/0x174
    [<80153848>] enter_state+0x290/0x314
    [<80153840>] enter_state+0x288/0x314
    [<8010e824>] apm_suspend+0x1c/0xa0
    [<80219750>] nfs_getattr+0x88/0xf8
    [<80219708>] nfs_getattr+0x40/0xf8
    [<8010eca8>] apm_ioctl+0x198/0x22c
    [<80110e84>] do_page_fault+0x364/0x3d0
    [<80110c24>] do_page_fault+0x104/0x3d0
    [<801a0d24>] do_ioctl+0x54/0x90
    [<801a0f6c>] vfs_ioctl+0x20c/0x394
    [<801b7950>] sync_inodes+0x20/0x54
    [<801a1144>] sys_ioctl+0x50/0x9c
    [<8010f66c>] stack_done+0x20/0x40
    [<8010f66c>] stack_done+0x20/0x40

phy 31 failed to register
au1000_eth_mii: probed
eth0: 0:1f already attached
eth0: Could not attach to PHY
usb usb1: root hub lost power or was reset
Restarting tasks... done
au1xxx_pm_finish: state = 3
hostname:~#

The first strange thing is that this time the kernel messages stop after "au1xxx_pm_prepare: state = 3" and not after "au_sleep: Zzz..." as before the merge! Maybe something as changed in serial console magement?

The second strange thing is that _only_ calling the mii_probe() the resume works correctly, otherwise the CPU loops forever calling the au1000_lowlevel_probe() without showing the printk() messages through the serial console. =:-o

Suggestions?

Ciao,

Rodolfo

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
#4 lore raw
Quoted 2 lines · Rodolfo Giometti

Attached you can find my patch to add power managament to the new

Sorry... :)

Ciao,

Rodolfo

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
drivers/net/au1000_eth.c +297 -191
index 55f6e3f..ff536c4 100644
@@ -11,6 +11,8 @@
  * ioctls (SIOCGMIIPHY)
  * Copyright 2006 Herbert Valerio Riedel <[email protected]>
  *  converted to use linux-2.6.x's PHY framework
+ * Copyright 2006 Rodolfo Giometti <[email protected]>
+ *  power management, driver registration and module support.
  *
  * Author: MontaVista Software, Inc.
  *         	[email protected] or [email protected]
@@ -61,6 +63,7 @@ #include <asm/irq.h>
 #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"
@@ -83,7 +86,8 @@ 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(int port_num);
+static int au1000_lowlevel_probe(struct net_device *ndev, void *ioaddr, void *macen_addr, int port_num, int skip_prom);
+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 *);
@@ -520,59 +524,6 @@ setup_hw_rings(struct au1000_private *au
 	}
 }
 
-static struct {
-	u32 base_addr;
-	u32 macen_addr;
-	int irq;
-	struct net_device *dev;
-} 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;
-
-/*
- * 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)
-{
-	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
-	struct net_device *dev;
-	int i, found_one = 0;
-
-	num_ifs = NUM_ETH_INTERFACES - ni;
-
-	for(i = 0; i < num_ifs; i++) {
-		dev = au1000_probe(i);
-		iflist[i].dev = dev;
-		if (dev)
-			found_one++;
-	}
-	if (!found_one)
-		return -ENODEV;
-	return 0;
-}
-
-/*
- * ethtool operations
- */
-
 static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct au1000_private *aup = (struct au1000_private *)dev->priv;
@@ -615,48 +566,14 @@ static struct ethtool_ops au1000_ethtool
 	.get_link = ethtool_op_get_link,
 };
 
-static struct net_device * au1000_probe(int port_num)
+static int 
+au1000_lowlevel_probe(struct net_device *ndev, void *ioaddr, void *macen_addr, int port_num, int skip_prom)
 {
-	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 irq, i, err;
-	u32 base, macen;
-
-	if (port_num >= NUM_ETH_INTERFACES)
- 		return NULL;
-
-	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)
-		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
-
-	dev = alloc_etherdev(sizeof(struct au1000_private));
-	if (!dev) {
-		printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
-		return NULL;
-	}
-
-	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: Au1xx0 Ethernet found at 0x%x, irq %d\n",
-		dev->name, base, irq);
-
-	aup = dev->priv;
+	int i, ret;
 
 	/* Allocate the data buffers */
 	/* Snooping works fine with eth on all au1xxx */
@@ -664,53 +581,62 @@ static struct net_device * au1000_probe(
 						(NUM_TX_BUFFS + NUM_RX_BUFFS),
 						&aup->dma_addr,	0);
 	if (!aup->vaddr) {
-		free_netdev(dev);
-		release_mem_region( base, MAC_IOSIZE);
-		release_mem_region(macen, 4);
-		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 *)iflist[port_num].base_addr;
-
+	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
 	/* Setup some variables for quick register address access */
-	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 {
-			/* 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 {
-				str2eaddr(ethaddr, pmac + strlen("ethaddr="));
-				memcpy(au1000_mac_addr, ethaddr, 
-				       sizeof(au1000_mac_addr));
+	if (port_num == 0)
+	{
+		if (!skip_prom) {
+			/* check env variables first */
+			if (!get_ethernet_addr(ethaddr)) { 
+				memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
+			} else {
+				/* Check command line */
+				argptr = prom_getcmdline();
+				if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
+					printk(KERN_INFO "%s: No mac address found\n", 
+							ndev->name);
+					/* use the hard coded mac addresses */
+				} else {
+					str2eaddr(ethaddr, pmac + strlen("ethaddr="));
+					memcpy(au1000_mac_addr, ethaddr, 
+							sizeof(au1000_mac_addr));
+				}
 			}
 		}
 
+		aup->enable = (volatile u32 *) ((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);
-	} else if (port_num == 1)
-		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
+		aup->mac_id = 0;
+		au_macs[0] = aup;
+	}
+		else
+	if (port_num == 1)
+	{
+		aup->enable = (volatile u32 *) ((unsigned long) macen_addr);
+		memcpy(ndev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+		ndev->dev_addr[5] += 0x01;
 
-	/*
-	 * 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;
+		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", ndev->name);
+	}
 
 	*aup->enable = 0;
 	aup->mac_enabled = 0;
 
-	aup->mii_bus.priv = dev;
+	aup->mii_bus.priv = ndev;
 	aup->mii_bus.read = mdiobus_read;
 	aup->mii_bus.write = mdiobus_write;
 	aup->mii_bus.reset = mdiobus_reset;
@@ -733,8 +659,18 @@ # endif
 #endif
 	mdiobus_register(&aup->mii_bus);
 
-	if (mii_probe(dev) != 0) {
-		goto err_out;
+	if (mii_probe(ndev) != 0) {
+		/* Hack, hack, hack!
+		 * This is needed during resume... you'll get a "Call Trace"
+		 * error message, but at least the wake up works...
+		 * Feel free to post a patch. :)
+		 *
+		 * Rodolfo Giometti
+		 * */
+		if (!skip_prom) {
+			ret = -EBUSY;
+			goto err_out;
+		}
 	}
 
 	pDBfree = NULL;
@@ -752,6 +688,7 @@ #endif
 	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;
@@ -760,6 +697,7 @@ #endif
 	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;
@@ -767,31 +705,23 @@ #endif
 		aup->tx_db_inuse[i] = pDB;
 	}
 
-	spin_lock_init(&aup->lock);
-	dev->base_addr = base;
-	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->tx_timeout = au1000_tx_timeout;
-	dev->watchdog_timeo = ETH_TX_TIMEOUT;
+	return 0;
 
-	/* 
-	 * 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);
+err_out :
+	au1000_lowlevel_remove(ndev);
+out :
+	return ret;
+}
 
-	return dev;
+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);
 
 	for (i = 0; i < NUM_RX_DMA; i++) {
 		if (aup->rx_db_inuse[i])
@@ -801,13 +731,10 @@ 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);
-	unregister_netdev(dev);
-	free_netdev(dev);
-	release_mem_region( base, MAC_IOSIZE);
-	release_mem_region(macen, 4);
-	return NULL;
+	dma_free_noncoherent(NULL,
+			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
+			(void *)aup->vaddr,
+			aup->dma_addr);
 }
 
 /* 
@@ -1009,38 +936,15 @@ static int au1000_close(struct net_devic
 	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);
-			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);
- 			release_mem_region(dev->base_addr, MAC_IOSIZE);
- 			release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
-			free_netdev(dev);
-		}
-	}
-}
-
-static void update_tx_stats(struct net_device *dev, u32 status)
+static inline void
+update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
 	struct net_device_stats *ps = &aup->stats;
 
+	ps->tx_packets++;
+	ps->tx_bytes += pkt_len;
+
 	if (status & TX_FRAME_ABORTED) {
 		if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
 			if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
@@ -1073,7 +977,7 @@ static void au1000_tx_ack(struct net_dev
 	ptxd = aup->tx_dma_ring[aup->tx_tail];
 
 	while (ptxd->buff_stat & TX_T_DONE) {
-		update_tx_stats(dev, ptxd->status);
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
 		ptxd->buff_stat &= ~TX_T_DONE;
 		ptxd->len = 0;
 		au_sync();
@@ -1095,7 +999,6 @@ static void au1000_tx_ack(struct net_dev
 static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	struct net_device_stats *ps = &aup->stats;
 	volatile tx_dma_t *ptxd;
 	u32 buff_stat;
 	db_dest_t *pDB;
@@ -1115,7 +1018,7 @@ static int au1000_tx(struct sk_buff *skb
 		return 1;
 	}
 	else if (buff_stat & TX_T_DONE) {
-		update_tx_stats(dev, ptxd->status);
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
 		ptxd->len = 0;
 	}
 
@@ -1135,9 +1038,6 @@ static int au1000_tx(struct sk_buff *skb
 	else
 		ptxd->len = skb->len;
 
-	ps->tx_packets++;
-	ps->tx_bytes += ptxd->len;
-
 	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
 	au_sync();
 	dev_kfree_skb(skb);
@@ -1340,5 +1240,211 @@ static struct net_device_stats *au1000_g
 	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_phys;
+	void *base_addr, *macen_addr;
+	int irq, ret;
+
+	/* Get the resource info */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-base");
+	if (!res) {
+		ret = -ENODEV;
+		goto out;
+	}
+	base_addr_phys = res->start;
+	base_addr = ioremap(res->start, res->end - res->start);
+	if (!base_addr) {
+		printk (KERN_ERR "%s: unable to remap address %lx\n",
+		        DRV_NAME, (long unsigned int) res->start);  
+		ret = -EINVAL;
+		goto out;
+	}
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth-mac");
+	if (!res) {
+		ret = -ENODEV;
+		goto out_release_io;
+	}
+	macen_addr = ioremap(res->start, res->end - res->start);
+	if (!macen_addr) {
+		printk (KERN_ERR "%s: unable to remap address %lx\n",
+		        DRV_NAME, (long unsigned int) res->start);  
+		ret = -ENOMEM;
+		goto out_release_io;
+	}
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eth-irq");
+	if (!res) {
+		ret = -ENODEV;
+		goto out_release_iomac;
+	}
+	irq = res->start;
+
+	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_iomac;
+	}
+	SET_MODULE_OWNER(ndev);
+	SET_NETDEV_DEV(ndev, dev);
+
+	/* Force the device name to a know state... */
+	sprintf(ndev->name, "au1xxx_eth(%d)", pdev->id);
+	ret = au1000_lowlevel_probe(ndev, base_addr, macen_addr, pdev->id, 0);
+	if (ret < 0) {
+		printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);  
+		goto out_free_netdev;
+	}
+	/* ...and then came back to a more standard name. */
+	strcpy(ndev->name, "eth%d");
+
+	aup = ndev->priv;
+
+	spin_lock_init(&aup->lock);
+	ndev->base_addr = base_addr_phys;
+	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->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_phys, irq);
+
+	dev_set_drvdata(dev, ndev);
+
+	return 0;
+
+out_lowlevel_remove :
+	au1000_lowlevel_remove(ndev);
+out_free_netdev :
+	free_netdev(ndev);
+out_release_iomac :
+	iounmap(macen_addr);
+out_release_io :
+	iounmap(base_addr);
+out :
+	printk("%s: not found (%d).\n", DRV_NAME, ret);
+
+	return ret;
+}
+
+static int au1000_drv_remove(struct device *dev)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+
+	dev_set_drvdata(dev, NULL);
+
+	unregister_netdev(ndev);
+	au1000_lowlevel_remove(ndev);
+	free_netdev(ndev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1000_drv_suspend(struct device *dev, pm_message_t state)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct au1000_private *aup;
+	struct phy_device *phydev;
+
+	if (!ndev)
+		return 0;
+
+	aup = (struct au1000_private *) ndev->priv;
+	phydev = aup->phy_dev;
+
+	if (netif_running(ndev))
+		netif_device_detach(ndev);
+
+	au1000_lowlevel_remove(ndev);
+
+	return 0;
+}
+
+static int au1000_drv_resume(struct device *dev)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct au1000_private *aup;
+	struct phy_device *phydev;
+	int ret;
+
+	if (!ndev)
+		return 0;
+
+	aup = (struct au1000_private *) ndev->priv;
+	phydev = aup->phy_dev;
+
+	ret = au1000_lowlevel_probe(ndev, (void *) aup->mac, (void *) aup->enable, aup->mac_id, ~0);
+	if (ret < 0) {
+		printk (KERN_ERR "%s: low level probe failed\n", DRV_NAME);  
+		return ret;
+	}
+
+	/* au1000_init() expects that the device is in reset state.
+	 */
+	reset_mac(ndev); /* au1000_init() expects the device in reset */
+	au1000_init(ndev);
+
+	if (netif_running(ndev))
+		netif_device_attach(ndev);
+
+	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);
#5 lore raw
In reply to Rodolfo Giometti
Quoted 5 lines · Rodolfo Giometti

The first strange thing is that this time the kernel messages stop after "au1xxx_pm_prepare: state = 3" and not after "au_sleep: Zzz..." as before the merge! Maybe something as changed in serial console magement?

Yes, something as changed... here the patch to remove the problem.

   diff --git a/kernel/power/main.c b/kernel/power/main.c
   index 6d295c7..10bf859 100644
   --- a/kernel/power/main.c
   +++ b/kernel/power/main.c
   @@ -86,7 +86,9 @@ static int suspend_prepare(suspend_state
    			goto Thaw;
    	}
    
   +#ifndef CONFIG_DEBUG_KERNEL
    	suspend_console();
   +#endif
    	if ((error = device_suspend(PMSG_SUSPEND))) {
    		printk(KERN_ERR "Some devices failed to suspend\n");
    		goto Finish;

I'd like also sending this patch to the Linux main tree, where should I send it? I found nothing useful in MAINTAINERS file... :-o

Ciao,

Rodolfo

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
#6 lore raw
Quoted 22 lines · Rodolfo Giometti
Quoted 4 lines

The first strange thing is that this time the kernel messages stop after "au1xxx_pm_prepare: state = 3" and not after "au_sleep: Zzz..." as before the merge! Maybe something as changed in serial console magement?

Yes, something as changed... here the patch to remove the problem.

   diff --git a/kernel/power/main.c b/kernel/power/main.c
   index 6d295c7..10bf859 100644
   --- a/kernel/power/main.c
   +++ b/kernel/power/main.c
   @@ -86,7 +86,9 @@ static int suspend_prepare(suspend_state
    			goto Thaw;
    	}
    
   +#ifndef CONFIG_DEBUG_KERNEL
    	suspend_console();
   +#endif
    	if ((error = device_suspend(PMSG_SUSPEND))) {
    		printk(KERN_ERR "Some devices failed to suspend\n");
    		goto Finish;
Quoted 2 lines

I'd like also sending this patch to the Linux main tree, where should I send it? I found nothing useful in MAINTAINERS file... :-o

You missed the last entry in MAINTAINERS ;-) Send such stuff to [email protected].

Ralf

#7 lore raw

PATCH 1/1 au1000_eth.c power management and driver registration support

In reply to Rodolfo Giometti

Hello,

Attached you can find my patch to add power managament and driver registration to the new version of file "drivers/net/au1000_eth.c" that implements the PHY-layer support.

Ciao,

Rodolfo Giometti

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
arch/mips/au1000/common/au1xxx_irqmap.c +2 -2
index 7acfe9b..d94bde1 100644
@@ -117,7 +117,7 @@ #elif defined(CONFIG_SOC_AU1500)
 	{ 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 },
 
@@ -151,7 +151,7 @@ #elif defined(CONFIG_SOC_AU1100)
 	{ 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 },
arch/mips/au1000/common/platform.c +79 -0

92 lines not on this page · raw message

drivers/net/Kconfig +2 -2
index 27d465f..47c624b 100644
@@ -453,13 +453,13 @@ config MIPS_GT96100ETH
 	  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 PHYLIB
 	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"
drivers/net/au1000_eth.c +324 -215

658 lines not on this page · raw message

drivers/net/au1000_eth.h +0 -1
index 41c2f84..056ecdc 100644
@@ -27,7 +27,6 @@
  */
 
 
-#define MAC_IOSIZE 0x10000
 #define NUM_RX_DMA 4       /* Au1x00 has 4 rx hardware descriptors */
 #define NUM_TX_DMA 4       /* Au1x00 has 4 tx hardware descriptors */
 
include/asm-mips/mach-au1x00/au1000.h +24 -23

95 lines not on this page · raw message