Subject: dbau1200 ethernet driver?

From: "Ruslan V.Pisarev" <[email-masked]>
Date: Fri, 6 May 2005 15:53:22 +0300

Hi!

 I compiled last 2.6 kernel (2-3 weeks ago from cvs@linux-mips) and
trying to start it on DBAu1200 development board. First problem I
discovered with "nfsroot" configuration - is that kernel cannot find
network interface at boot-time.
 There is a smc91c111 network chip on board, so my question is - what
driver is suitable with him? Is it "MIPS AU1000 Ethernet support"
which fails to compile with "error: `NUM_ETH_INTERFACES' undeclared"
(and it must be?) or something different? It seems that I have enabled
all other options for ethernet functionality.

the part of boot log is:

loop: loaded (max 8 devices)
nbd: registered device at major 43
NET: Registered protocol family 2
IP: routing cache hash table of 2048 buckets, 16Kbytes
TCP established hash table entries: 16384 (order: 5, 131072 bytes)
TCP bind hash table entries: 16384 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 16384 bind 16384)
NET: Registered protocol family 1
NET: Registered protocol family 17
IP-Config: No network devices available.
Looking up port of RPC 100003/2 on 192.168.0.30
RPC: sendmsg returned error 128
portmap: RPC call returned error 128
Root-NFS: Unable to get nfsd port number from server, using default
Looking up port of RPC 100005/1 on 192.168.0.30
RPC: sendmsg returned error 128
portmap: RPC call returned error 128
Root-NFS: Unable to get mountd port number from server, using default
RPC: sendmsg returned error 128
mount: RPC call returned error 128

   ()_()
--( °,° )---[21398845]-[jerry¤wicomtechnologies.com]-
  (") (")                 -<The Bat! 3.0.1.33>- -<06/05/2005 15:35>-

---

From: [email-masked]
Date: Fri, 6 May 2005 08:32:23 -0500 (CDT)

> all other options for ethernet functionality.
Without having access to a source tree currently, how about you grep
through the 'arch/mips/au1000' directory and friends for the string
NUM_ETH_INTERFACES. I think you will find that each board-specific
setup file is responsible for defining it. Either that, or look in
'include/asm-mips'. In the future, make sure you grep through all of
the source to find other possible uses or examples.

-Steve

---

From: "Ruslan V.Pisarev" <[email-masked]>
Date: Fri, 6 May 2005 17:12:59 +0300

>[In reply to "dbau1200 ethernet driver?" from [email-masked] <[email-masked]> to Ruslan V.Pisarev <[email-masked]>  06/05/2005 16:32]

>> all other options for ethernet functionality.
src> Without having access to a source tree currently, how about you grep
src> through the 'arch/mips/au1000' directory and friends for the string
src> NUM_ETH_INTERFACES. I think you will find that each board-specific
src> setup file is responsible for defining it. Either that, or look in
src> 'include/asm-mips'. In the future, make sure you grep through all of
src> the source to find other possible uses or examples.

Well, problem is something more complicated... At least for me :)

NUM_ETH_INTERFACES is defined /include/asm-mips/mach-au1x00/au1000.h
for all machines (au1000 au1100 au1500 au1550) except au1200. I dont
think that someone forgot to add NUM_ETH_INTERFACES for au1200. And
even what it means? All these machines have "on-board" ethernet
controller in processor core, so I think there's no external chip on
development board. au1200 haven't internal controller and has
dedicated chip on board...

 Furtermore, I found now, that Linux 2.4.26 distributed by AMD has an
additional option CONFIG_AU1XXX_SMC91111 in config for DBAu1200 which
controls compiling drivers/net/smc91111.c.
 In 2.6 this file disappeared but we have drivers/net/smc91x.c which
configures in some arm, ppc, and superh architectures. MIPS knows
nothing about him. Is it the right file? I suppose it is, but...

 Am I first who put 2.6 kernel on this board and see that is there no
drivers for it ? :)

   ()_()
--( °,° )---[21398845]-[jerry¤wicomtechnologies.com]-
  (") (")                 -<The Bat! 3.0.1.33>- -<06/05/2005 16:38>-

---

From: Pete Popov <[email-masked]>
Date: Fri, 06 May 2005 08:46:40 -0700

On Fri, 2005-05-06 at 15:53 +0300, Ruslan V.Pisarev wrote:
> driver is suitable with him?

The smc91x.c driver. However, I don't remember if that driver was
tested.  The board was tested with a different smc driver which I
couldn't push in the tree because it was old and would conflict with the
smc91x.c.

>  Is it "MIPS AU1000 Ethernet support"

Well, that's a different driver.

Pete

---

From: Pete Popov <[email-masked]>
Date: Fri, 06 May 2005 09:17:50 -0700

Here you go, courtesy of AMD:

----
here's the driver and patch and instructions that we use...

# On AMD Alchemy Au1200 eval boards, the SMSC LAN91C111 is the
# network chipset.
unzip -a ../linux26-patches/LAN91C111_Linux_V201.zip smc91111.c -d
drivers/net
unzip -a ../linux26-patches/LAN91C111_Linux_V201.zip smc91111.h -d
drivers/net
patch -p1 < ../linux26-patches/smslan91c111.patch

----

Pete

>   (") (")                 -<The Bat! 3.0.1.33>- -<06/05/2005 16:38>-
This patch changes the SMSC-authored LAN91C111 Linux Ethernet driver
to work with the AMD Alchemy Au1x00 SOCs, utilizing the static bus
controller.

This patch is developed against SMSC LAN91C111 Linux driver 2.01,
which was obtained here:

  http://www.smsc.com/main/catalog/lan91c111.html

--- linux26.cvs/drivers/net/Kconfig	2005-01-24 22:28:23.000000000 -0600
+++ linux26.amd/drivers/net/Kconfig	2005-02-24 15:45:40.000000000 -0600
@@ -472,6 +472,14 @@ config MIPS_AU1X00_ENET
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
+config MIPS_SMSCLAN91C111_ENET
+	bool "SMSC LAN91C111 on AMD Alchemy Static Bus support"
+	depends on NET_ETHERNET && SOC_AU1X00
+	select CRC32
+	help
+	  Use SMSC LAN91C111 with AMD Alchemy Statis Bus
+	  say Y.  Otherwise, say N.
+
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
 	depends on NET_ETHERNET && PCI && SGI_IP27

--- linux26.cvs/drivers/net/Makefile	2005-01-13 08:06:10.000000000 -0600
+++ linux26.amd/drivers/net/Makefile	2005-02-24 15:46:18.000000000 -0600
@@ -166,6 +166,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
+obj-$(CONFIG_MIPS_SMSCLAN91C111_ENET) += smc91111.o
 obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o

--- linux.org/drivers/net/smc91111.c	2004-12-13 13:32:50.000000000 -0600
+++ linux.amd/drivers/net/smc91111.c	2005-03-03 10:40:43.000000000 -0600
@@ -64,11 +64,11 @@
 static const char version[] =
 "SMSC LAN91C111 Driver (v2.01), (Linux Kernel 2.4 + Support for Odd Byte) 12/13/04\n\n";
 
-#ifdef MODULE
+#include <linux/config.h>
 #include <linux/module.h>
+#ifdef MODULE
 #include <linux/version.h>
 #endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -95,6 +95,65 @@ static const char version[] =
 #include <linux/sysctl.h>
 #endif
 
+#if defined(CONFIG_SOC_AU1X00)
+#define SMC_DEBUG 1 // Must be defined in makefile
+
+#ifdef CONFIG_MIPS_PB1550
+#include <asm/mach-pb1x00/pb1550.h>
+#endif
+#ifdef CONFIG_MIPS_PB1200
+#include <asm/mach-pb1x00/pb1200.h>
+#endif
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#endif
+#ifdef CONFIG_MIPS_FICMMP
+#include <asm/mach-pb1x00/ficmmp.h>
+#endif
+
+#include <asm/mach-au1x00/au1000.h>
+#undef inb
+#undef inw
+#undef outb
+#undef outw
+
+#define inb(x)		au_readb(x)
+#define inw(x)		au_readw(x)
+#define outb(d,x)	au_writeb(d,x)
+#define outw(d,x)	au_writew(d,x)
+
+/* Can't use io.h version since it inlines incorrect inw() and outw() */
+#undef insw
+#define insw auinsw
+static inline void auinsw(unsigned long port, void *addr, unsigned int count)
+{
+    while (count--) {
+        *(u16 *)addr = inw(port);
+        addr += 2;
+    }
+}
+
+#undef outsw
+#define outsw auoutsw
+static inline void auoutsw(unsigned long port, void *addr, unsigned int count)
+{
+    while (count--) {
+        outw(*(u16 *)addr, port);
+        addr += 2;
+    }
+}
+
+/* extern functions */
+extern int get_ethernet_addr(char *ethenet_addr);
+
+/* Compiled-in defaults can be over-ridden at boot-time by board setup code */
+uint32_t au1xxx_smc91111_base = KSEG1ADDR(AU1XXX_SMC91111_PHYS_ADDR);
+int au1xxx_smc91111_irq = AU1XXX_SMC91111_IRQ;
+int au1xxx_smc91111_nowait = 1;
+
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100_10 << RPC_LSXA_SHFT) | (RPC_LED_TX_RX << RPC_LSXB_SHFT))
+#endif /* end CONFIG_SOC_AU1X00 */
+
 #include "smc91111.h"
 /*------------------------------------------------------------------------
  .
@@ -106,7 +165,9 @@ static const char version[] =
  . Do you want to use 32 bit xfers?  This should work on all chips, as
  . the chipset is designed to accommodate them.
 */
+#if !defined(CONFIG_SOC_AU1X00)
 #define USE_32_BIT 1
+#endif

 /*
@@ -368,7 +429,7 @@ static void smc_phy_configure(struct net
 /*
  . Handles the actual interrupt
 */
-static void smc_interrupt(int irq, void *, struct pt_regs *regs);
+static irqreturn_t smc_interrupt(int irq, void *, struct pt_regs *regs);
 /*
  . This is a separate procedure to handle the receipt of a packet, to
  . leave the interrupt code looking slightly cleaner
@@ -546,7 +607,7 @@ static void smc_reset( struct net_device
 */
 static void smc_enable( struct net_device *dev )
 {
-	unsigned short ioaddr 	= dev->base_addr;
+	unsigned int ioaddr 	= dev->base_addr;
 	struct smc_local *lp 	= (struct smc_local *)dev->priv;
 
 	PRINTK2("%s:smc_enable\n", dev->name);
@@ -701,7 +762,7 @@ static int crc32( char * s, int length )
 static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
 {
 	struct smc_local *lp 	= (struct smc_local *)dev->priv;
-	unsigned short ioaddr 	= dev->base_addr;
+	unsigned int ioaddr 	= dev->base_addr;
 	word 			length;
 	unsigned short 		numPages;
 	word			time_out;
@@ -823,7 +884,7 @@ static void smc_hardware_send_packet( st
 	byte	 		packet_no;
 	struct sk_buff * 	skb = lp->saved_skb;
 	word			length;
-	unsigned short		ioaddr;
+	unsigned int	ioaddr;
 	byte			* buf;
 
 	PRINTK3("%s:smc_hardware_send_packet\n", dev->name);
@@ -935,7 +996,7 @@ static void smc_hardware_send_packet( st
 int __init smc_init(struct net_device *dev)
 {
 	int i;
-	int base_addr = dev ? dev->base_addr : 0;
+	unsigned int base_addr = dev ? dev->base_addr : 0;
 
 	PRINTK2("CARDNAME:smc_init\n");
 
@@ -1118,6 +1179,7 @@ static int __init smc_probe(struct net_d
 	   so I can access the base address register */
 	SMC_SELECT_BANK(1);
 	base_address_register = inw( ioaddr + BASE_REG );
+#ifndef CONFIG_SOC_AU1X00
 	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )
 	{
 		printk("CARDNAME: IOADDR %x doesn't match configuration (%x)."
@@ -1128,6 +1190,7 @@ static int __init smc_probe(struct net_d
 		retval = -ENODEV;
 		goto err_out;
 	}
+#endif
 
 	/*  check if the revision register is something that I recognize.
 	    These might need to be added to later, as future revisions
@@ -1157,6 +1220,7 @@ static int __init smc_probe(struct net_d
 	/*
  	 . Get the MAC address ( bank 1, regs 4 - 9 )
 	*/
+#ifndef CONFIG_SOC_AU1X00
 	SMC_SELECT_BANK( 1 );
 	for ( i = 0; i < 6; i += 2 )
 	{
@@ -1166,6 +1230,10 @@ static int __init smc_probe(struct net_d
 		dev->dev_addr[ i + 1] = address >> 8;
 		dev->dev_addr[ i ] = address & 0xFF;
 	}
+#else
+		/* Obtain address from Boot PROM (no EEPROM) */
+		get_ethernet_addr(dev->dev_addr);
+#endif
 
 	/* get the memory information */
 
@@ -1445,7 +1513,7 @@ static void smc_timeout (struct net_devi
  .   and finally restore state.
  .
  ---------------------------------------------------------------------*/
-static void smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)
+static irqreturn_t smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)
 {
 	struct net_device *dev 	= dev_id;
 	int ioaddr 		= dev->base_addr;
@@ -1466,7 +1534,7 @@ static void smc_interrupt(int irq, void 
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n",
 			dev->name, irq);
-		return;
+		return IRQ_RETVAL(1);
 	}
 
 /* will Linux let this happen ??  If not, this costs some speed
@@ -1490,6 +1558,18 @@ static void smc_interrupt(int irq, void 
 	outb( 0, ioaddr + IM_REG );

+	#if defined(CONFIG_MIPS_FICMMP)
+		//Check if the unit is still docked
+		if(((*((u32*)0xB170000C)) >> 15 & 0x01) == 0)
+		//if(au1xxx_gpio_read(215) == 0)	//Ugh!  why isn't this symbol getting exported?!?!?
+		{
+			//Disable the ethernet IRQ.  Removing from dock pulls IRQ high (always on!)
+			free_irq(devSMC91111.irq, &devSMC91111);
+			mask = 0;
+			goto no_device;
+		}
+	#endif
+
 	/* set a timeout value, so I don't stay here forever */
 	timeout = 4;
 
@@ -1500,6 +1580,9 @@ static void smc_interrupt(int irq, void 
 		if (!status )
 			break;
 
+		// Acknowledge the interrupt
+		outb(status, ioaddr + INT_REG );
+
 		PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n",
 			dev->name, status);
 
@@ -1512,8 +1595,6 @@ static void smc_interrupt(int irq, void 
 			PRINTK2(KERN_WARNING "%s: TX ERROR handled\n",
 				dev->name);
 			smc_tx(dev);
-			// Acknowledge the interrupt
-			outb(IM_TX_INT, ioaddr + INT_REG );
 		} else if (status & IM_TX_EMPTY_INT ) {
 			/* update stats */
 			SMC_SELECT_BANK( 0 );
@@ -1534,8 +1615,6 @@ static void smc_interrupt(int irq, void 
 			SMC_SELECT_BANK( 2 );
 			PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",
 				dev->name);
-			// Acknowledge the interrupt
-			outb( IM_TX_EMPTY_INT, ioaddr + INT_REG );
 			mask &= ~IM_TX_EMPTY_INT;
 			lp->stats.tx_packets += lp->packets_waiting;
 			lp->packets_waiting = 0;
@@ -1559,25 +1638,22 @@ static void smc_interrupt(int irq, void 
 		} else if (status & IM_RX_OVRN_INT ) {
 			lp->stats.rx_errors++;
 			lp->stats.rx_fifo_errors++;
-			// Acknowledge the interrupt
-			outb( IM_RX_OVRN_INT, ioaddr + INT_REG );
 		} else if (status & IM_EPH_INT ) {
 			PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n",
 				dev->name);
 		} else if (status & IM_MDINT ) {
 			smc_phy_interrupt(dev);
-			// Acknowledge the interrupt
-			outb(IM_MDINT, ioaddr + INT_REG );
 		} else if (status & IM_ERCV_INT ) {
 			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n",
 				dev->name);
-			// Acknowledge the interrupt
-			outb( IM_ERCV_INT, ioaddr + INT_REG );
 		}
 	} while ( timeout -- );

 	/* restore register states */
+#if defined(CONFIG_MIPS_FICMMP)
+no_device:
+#endif
 
 	SMC_SELECT_BANK( 2 );
 
@@ -1590,7 +1666,7 @@ static void smc_interrupt(int irq, void 
 
 	//dev->interrupt = 0;
 	PRINTK3("%s: Interrupt done\n", dev->name);
-	return;
+	return IRQ_RETVAL(1);
 }
 
 /*-------------------------------------------------------------
@@ -1874,7 +1950,7 @@ static struct net_device_stats* smc_quer
 */
 static void smc_set_multicast_list(struct net_device *dev)
 {
-	short ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
 	PRINTK2("%s:smc_set_multicast_list\n", dev->name);
 
@@ -1930,7 +2006,7 @@ static void smc_set_multicast_list(struc
 	}
 }
 
-#ifdef MODULE
+//#ifdef MODULE
 
 static struct net_device devSMC91111;
 int io = 0;
@@ -1944,7 +2020,7 @@ MODULE_PARM(nowait, "i");
 /*------------------------------------------------------------
  . Module initialization function
  .-------------------------------------------------------------*/
-int init_module(void)
+int __init smc91111_init_module(void)
 {
 	int result;
 
@@ -1954,9 +2030,21 @@ int init_module(void)
 		CARDNAME": You shouldn't use auto-probing with insmod!\n" );
 
 	/* copy the parameters from insmod into the device structure */
+#ifdef CONFIG_SOC_AU1X00
+	if (au1xxx_smc91111_base == 0)
+	{
+		printk(KERN_WARNING
+		CARDNAME": Wrong SMC91111 Base Address!\n" );
+		return -ENODEV;
+	}
+	devSMC91111.base_addr	= au1xxx_smc91111_base;
+	devSMC91111.irq		= au1xxx_smc91111_irq;
+	devSMC91111.dma		= au1xxx_smc91111_nowait;
+#else
 	devSMC91111.base_addr	= io;
 	devSMC91111.irq		= irq;
 	devSMC91111.dma		= nowait; // Use DMA field for nowait		
+#endif
 	devSMC91111.init	= smc_init;/* Kernel 2.4 Changes - Pramod */
 	if ((result = register_netdev(&devSMC91111)) != 0)
 		return result;
@@ -1967,7 +2055,7 @@ int init_module(void)
 /*------------------------------------------------------------
  . Cleanup when module is removed with rmmod
  .-------------------------------------------------------------*/
-void cleanup_module(void)
+void __exit smc91111_cleanup_module(void)
 {
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	unregister_netdev(&devSMC91111);
@@ -1979,8 +2067,10 @@ void cleanup_module(void)
 		kfree(devSMC91111.priv); /* Kernel 2.4 Changes - Pramod */
 }
 
-#endif /* MODULE */
+//#endif /* MODULE */
 
+module_init(smc91111_init_module);
+module_exit(smc91111_cleanup_module);
 
 #ifdef CONFIG_SYSCTL
 
@@ -2065,7 +2155,7 @@ static const char smc_info_string[] =
  . Sysctl handler for all integer parameters
  .-------------------------------------------------------------*/
 static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
-				void *buffer, size_t *lenp)
+				void *buffer, size_t *lenp, loff_t *fpos)
 {
 	struct net_device *dev = (struct net_device*)ctl->extra1;
 	struct smc_local *lp = (struct smc_local *)ctl->extra2;
@@ -2294,7 +2384,7 @@ static int smc_sysctl_handler(ctl_table 
 	val = *valp;
 
 	// Perform the generic integer operation	
-	if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
+	if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp, fpos)) != 0)
 		return(ret);
 
 	// Write changes out to the registers

--- linux.org/drivers/net/smc91111.h	2005-03-02 13:48:34.000000000 -0600
+++ linux.amd/drivers/net/smc91111.h	2005-03-02 13:48:48.000000000 -0600
@@ -89,7 +89,7 @@ typedef unsigned long int 		dword;
 #define	TCR_CLEAR	0	/* do NOTHING */
 /* the default settings for the TCR register : */ 
 /* QUESTION: do I want to enable padding of short packets ? */
-#define	TCR_DEFAULT  	TCR_ENABLE 
+#define	TCR_DEFAULT  	(TCR_ENABLE | TCR_SWFDUP)

 // EPH Status Register
@@ -151,7 +151,9 @@ typedef unsigned long int 		dword;
 #define RPC_LED_100	(0x05)	// LED = 100Mbps link dectect
 #define RPC_LED_TX	(0x06)	// LED = TX packet occurred
 #define RPC_LED_RX	(0x07)	// LED = RX packet occurred
+#ifndef RPC_DEFAULT
 #define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+#endif
 
 /* Bank 0 0x000C is reserved */

---

From: "Ruslan V.Pisarev" <[email-masked]>
Date: Fri, 6 May 2005 19:19:49 +0300

>[In reply to "dbau1200 ethernet driver?" from Pete Popov <[email-masked]> to Ruslan V.Pisarev <[email-masked]>  06/05/2005 18:46]

PP> The smc91x.c driver. However, I don't remember if that driver was
PP> tested.  The board was tested with a different smc driver which I
PP> couldn't push in the tree because it was old and would conflict with the
PP> smc91x.c.

Ok. But as I replied earlier, this driver is not in MIPS architecture
tree. And I suspect it needs some additional configurations and
modifications..
May I expect any solution in the near future or better do some digging by
myself? (alas I have not much expirience with this stuff)

   ()_()
--( °,° )---[21398845]-[jerry¤wicomtechnologies.com]-
  (") (")                 -<The Bat! 3.0.1.33>- -<06/05/2005 19:07>-

---

From: "Bogdan Vacaliuc" <[email-masked]>
Date: Sat, 7 May 2005 09:08:36 -0400

On Friday, May 06, 2005 11:47 AM, Pete Popov wrote:

>> network interface at boot-time.  There is a smc91c111 network chip on
>> board, so my question is - what driver is suitable with him?
> 
> couldn't push in the tree because it was old and would conflict with
> the smc91x.c.   
> 
>> (and it must be?) or something different? It seems that I have
>> enabled all other options for ethernet functionality.
> 

Yes, and not for Au1200.  The Au1200 does not have an integrated MAC; access to the MAC/PHY is through the static memory controller.

-bogdan