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 On Fri, 2005-05-06 at 17:12 +0300, Ruslan V.Pisarev wrote: > >[In reply to "dbau1200 ethernet driver?" from sjhill@xxxxxxxxxxxxxxxxxx <sjhill@xxxxxxxxxxxxxxxxxx> to Ruslan V.Pisarev <jerry@xxxxxxxxxxxxxxx> 06/05/2005 16:32] > > >> 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. > 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>- > >
Attachment:
LAN91C111_Linux_V201.zip
Description: Zip archive
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 */