/*------------------------------------------------------------------------ . smc91x.c . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. . . Copyright (C) 1996 by Erik Stahlman . Copyright (C) 2001 Standard Microsystems Corporation . Developed by Simple Network Magic Corporation . Copyright (C) 2003 Monta Vista Software, Inc. . Unified SMC91x driver by Nicolas Pitre . . This program is free software; you can redistribute it and/or modify . it under the terms of the GNU General Public License as published by . the Free Software Foundation; either version 2 of the License, or . (at your option) any later version. . . This program is distributed in the hope that it will be useful, . but WITHOUT ANY WARRANTY; without even the implied warranty of . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the . GNU General Public License for more details. . . You should have received a copy of the GNU General Public License . along with this program; if not, write to the Free Software . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA . . Arguments: . io = for the base address . irq = for the IRQ . nowait = 0 for normal wait states, 1 eliminates additional wait states . . original author: . Erik Stahlman . . hardware multicast code: . Peter Cammaert . . contributors: . Daris A Nevil . Nicolas Pitre . . History: . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" . 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 . 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 . 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 . 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support . 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, . more bus abstraction, big cleanup, etc. ----------------------------------------------------------------------------*/ static const char version[] = "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre \n"; /* Debugging level */ #ifndef SMC_DEBUG #define SMC_DEBUG 0 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_PM #include #endif #include #include #include #include static u_int16_t smc91c111_mii_get_2(unsigned long); static void smc91c111_mii_set_2(unsigned long, u_int16_t); static unsigned long smc91_base; #define _INCLUDE_ONCE_smc91c111 1 #include "smc-91c111-mac+phy.hail.h" #if 1 #define SMC_CAN_USE_ISA 0 #define SMC_IOADDR (VIPER_ETH_PHYS + 0x300) #define SMC_DATACSADDR (VIPER_ETH_DATA_PHYS) #define SMC_IRQ VIPER_ETH_IRQ #define SMC_USE_DATACS 0 #define SMC_NOWAIT 1 #define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup #define MII_MDOE 0x0008 // MII Output Enable #define MII_MCLK 0x0004 // MII Clock, pin MDCLK #define MII_MDI 0x0002 // MII Input, pin MDI #define MII_MDO 0x0001 // MII Output, pin MDO /* when to use datacs */ //#undef SMC_USE_DATACS_RX //#undef SMC_USE_DATACS_TX //#undef SMC_USE_DATACS_BOTH #define SMC_USE_DATACS_RX 1 #define SMC_USE_DATACS_TX 2 #define SMC_USE_DATACS_BOTH 3 //#undef SMC_IO_EXTENT //#undef SMC_DATA_EXTENT //#undef SMC_IO_SHIFT #define SMC_IO_SHIFT 0 #define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) #define SMC_DATA_EXTENT 4 // Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low //#undef CONFIG_DEFAULT #define CONFIG_DEFAULT CR_EPH_Power_EN_VAL(1) #define TCR_CLEAR 0 /* do NOTHING */ /* the default settings for the TCR register : */ #define TCR_DEFAULT (TCR_TXENA_VAL(1) | TCR_PAD_EN_VAL(1)) /* the normal settings for the RCR register : */ #define RCR_DEFAULT (RCR_STRIP_CRC_VAL(1) | RCR_RXEN_VAL(1)) #define RCR_CLEAR 0x0 // set it to a base state //#undef RPC_DEFAULT #define RPC_DEFAULT (RPCR_ANEG_VAL(1) | RPCR_LEDA_VAL(RPCR_LINK10or100) | RPCR_LEDB_VAL(RPCR_FDX) | RPCR_SPEED_VAL(1) | RPCR_DPLX_VAL(1)) #define CHIP_9192 3 #define CHIP_9194 4 #define CHIP_9195 5 #define CHIP_9196 6 #define CHIP_91100 7 #define CHIP_91100FD 8 #define CHIP_91111FD 9 static const char * chip_ids[ 16 ] = { NULL, NULL, NULL, /* 3 */ "SMC91C90/91C92", /* 4 */ "SMC91C94", /* 5 */ "SMC91C95", /* 6 */ "SMC91C96", /* 7 */ "SMC91C100", /* 8 */ "SMC91C100FD", /* 9 */ "SMC91C11xFD", NULL, NULL, NULL, NULL, NULL, NULL}; /* . Transmit status bits */ #define TS_SUCCESS 0x0001 #define TS_LOSTCAR 0x0400 #define TS_LATCOL 0x0200 #define TS_16COL 0x0010 /* . Receive status bits */ #define RS_ALGNERR 0x8000 #define RS_BRODCAST 0x4000 #define RS_BADCRC 0x2000 #define RS_ODDFRAME 0x1000 #define RS_TOOLONG 0x0800 #define RS_TOOSHORT 0x0400 #define RS_MULTICAST 0x0001 #define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) // PHY Types enum { PHY_LAN83C183 = 1, // LAN91C111 Internal PHY PHY_LAN83C180 }; // PHY Register Addresses (LAN91C111 Internal PHY) // these are unused when using HAIL // PHY Control Register //#define PHY_CNTL_REG 0x00 //#define PHY_CNTL_RST 0x8000 // 1=PHY Reset //#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback //#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs //#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation //#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode //#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled //#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate //#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex //#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test // PHY Status Register //#define PHY_STAT_REG 0x01 //#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable //#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable //#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable //#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable //#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable //#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble //#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed //#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected //#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable //#define PHY_STAT_LINK 0x0004 // 1=valid link //#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition //#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented // PHY Identifier Registers //#define PHY_ID1_REG 0x02 // PHY Identifier 1 //#define PHY_ID2_REG 0x03 // PHY Identifier 2 // PHY Auto-Negotiation Advertisement Register //#define PHY_AD_REG 0x04 //#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page //#define PHY_AD_ACK 0x4000 // 1=got link code word from remote //#define PHY_AD_RF 0x2000 // 1=advertise remote fault //#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4 //#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX //#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX //#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX //#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX //#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA // PHY Auto-negotiation Remote End Capability Register //#define PHY_RMT_REG 0x05 // Uses same bit definitions as PHY_AD_REG // PHY Configuration Register 1 //#define PHY_CFG1_REG 0x10 //#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled //#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled //#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down //#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler //#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable //#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled //#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) //#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db //#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust //#define PHY_CFG1_TLVL_MASK 0x003C //#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time // PHY Configuration Register 2 //#define PHY_CFG2_REG 0x11 //#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled //#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled //#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) //#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo // PHY Status Output (and Interrupt status) Register //#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) //#define PHY_INT_INT 0x8000 // 1=bits have changed since last read //#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected //#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync //#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx //#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx //#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx //#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected //#define PHY_INT_JAB 0x0100 // 1=Jabber detected //#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode //#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex // PHY Interrupt/Status Mask Register //#define PHY_MASK_REG 0x13 // Interrupt Mask // Uses the same bit definitions as PHY_INT_REG #endif #if 1 //#undef SMC_GET_MAC_ADDR #define SMC_GET_MAC_ADDR(addr) \ do { \ unsigned int __v; \ __v = get_IAR1_0(); \ addr[0] = __v; addr[1] = __v >> 8; \ __v = get_IAR3_2(); \ addr[2] = __v; addr[3] = __v >> 8; \ __v = get_IAR5_4(); \ addr[4] = __v; addr[5] = __v >> 8; \ } while (0) //#undef SMC_SET_MAC_ADDR #define SMC_SET_MAC_ADDR(addr) \ do { \ set_IAR1_0( addr[0]|(addr[1] << 8)); \ set_IAR3_2( addr[2]|(addr[3] << 8)); \ set_IAR5_4( addr[4]|(addr[5] << 8)); \ } while (0) //#undef SMC_CLEAR_MCAST #define SMC_CLEAR_MCAST() \ do { \ set_MT1_0(0); \ set_MT3_2(0); \ set_MT5_4(0); \ set_MT7_6(0); \ } while (0) //#undef SMC_SET_MCAST #define SMC_SET_MCAST(x) \ do { \ unsigned char *mt = (x); \ set_MT1_0( mt[0] | (mt[1] << 8)); \ set_MT3_2( mt[2] | (mt[3] << 8)); \ set_MT5_4( mt[4] | (mt[5] << 8)); \ set_MT7_6( mt[6] | (mt[7] << 8)); \ } while (0) //#undef SMC_PUT_PKT_HDR #define SMC_PUT_PKT_HDR(status, length) \ do { \ set_DATA( status); \ set_DATA( length); \ } while (0) //#undef SMC_GET_PKT_HDR #define SMC_GET_PKT_HDR(status, length) \ do { \ (status) = get_DATA(); \ (length) = get_DATA(); \ } while (0) //#undef SMC_ACK_INT #define SMC_ACK_INT(x) \ do { \ unsigned long __flags; \ int __mask; \ local_irq_save(__flags); \ __mask = get_MSK() & ~0xff; \ set_ACK( __mask | (x)); \ local_irq_restore(__flags); \ } while (0) //#undef SMC_PUSH_DATA #define SMC_PUSH_DATA(p, l) \ if ( lp->datacs && ( lp->use_datacs & SMC_USE_DATACS_TX ) ) { \ char *__ptr = (p); \ int __len = (l); \ if (__len >= 2 && (long)__ptr & 2) { \ __len -= 2; \ set_DATA( *((u16 *)__ptr)++);\ } \ outsl(lp->datacs, __ptr, __len >> 2); \ if (__len & 2) { \ __ptr += (__len & ~3); \ set_DATA( *((u16 *)__ptr)); \ } \ } else { \ /* _SMC_PUSH_DATA(p, l); */ \ outsw(smc91_base+8, p, (l)>>1); \ } /* HACK, jsun */ //#undef SMC_PULL_DATA #define SMC_PULL_DATA(p, l) \ if ( lp->datacs && ( lp->use_datacs & SMC_USE_DATACS_RX ) ) { \ char *__ptr = (p); \ int __len = (l); \ if ((long)__ptr & 2) { \ /* \ * We want 32bit alignment here. \ * Since some buses perform a full 32bit \ * fetch even for 16bit data we can't use \ * SMC_inw() here. Back both source (on chip \ * and destination) pointers of 2 bytes. \ */ \ (long)__ptr &= ~2; \ __len += 2; \ set_PTR( 2|PTR_READ_VAL(1)|PTR_RCV_VAL(1)|PTR_AUTO_INCR_VAL(1) ); \ } \ __len += 2; \ insl( lp->datacs, __ptr, __len >> 2); \ } else { \ /* _SMC_PULL_DATA(p, l); */ \ insw(smc91_base+8, p, (l)>>1);/* HACK, jsun */ \ } #endif #ifndef SMC_IOADDR # define SMC_IOADDR -1 #endif static int io = SMC_IOADDR; #ifndef SMC_DATACSADDR # define SMC_DATACSADDR 0 #endif static unsigned long datacs = SMC_DATACSADDR; #ifndef SMC_USE_DATACS # define SMC_USE_DATACS (SMC_USE_DATACS_RX|SMC_USE_DATACS_TX) #endif static int use_datacs = SMC_USE_DATACS; #ifndef SMC_IRQ # define SMC_IRQ -1 #endif static int irq = SMC_IRQ; #ifndef SMC_NOWAIT # define SMC_NOWAIT 0 #endif static int nowait = SMC_NOWAIT; MODULE_PARM(io, "i"); MODULE_PARM(datacs, "i"); MODULE_PARM(use_datacs, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(nowait, "i"); MODULE_PARM_DESC(io, "I/O base address"); MODULE_PARM_DESC(datacs, "DATACS base address"); MODULE_PARM_DESC(use_datacs, "How to use DATACS: 1=RX, 2=TX, 3=BOTH"); MODULE_PARM_DESC(irq, "IRQ number"); MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); MODULE_LICENSE("GPL"); /*------------------------------------------------------------------------ . . The internal workings of the driver. If you are changing anything . here with the SMC stuff, you should have the datasheet and know . what you are doing. . -------------------------------------------------------------------------*/ #define CARDNAME "LAN91x" // Use power-down feature of the chip #define POWER_DOWN 1 /* . Wait time for memory to be free. This probably shouldn't be . tuned that much, as waiting for this means nothing else happens . in the system */ #define MEMORY_WAIT_TIME 16 /* . This selects whether TX packets are sent one by one to the SMC91x internal . memory ans throttled until transmission completes. This may prevent . RX overruns a litle by keeping much of the memory free for RX packets . but to the expense of reduced TX throughput and increased IRQ overhead. . Note this is not a cure for a too slow data bus or too high IRQ latency. */ #define THROTTLE_TX_PKTS 0 /* store this information for the driver.. */ struct smc_local { // If I have to wait until memory is available to send // a packet, I will store the skbuff here, until I get the // desired memory. Then, I'll send it out and free it. struct sk_buff *saved_skb; // these are things that the kernel wants me to keep, so users // can find out semi-useless statistics of how well the card is // performing struct net_device_stats stats; // version/revision of the SMC91x chip int version; // Set to true during the auto-negotiation sequence int autoneg_active; // Address of our PHY port int phyaddr; // Type of PHY int phytype; // Last contents of PHY Register 18 int lastPhy18; // Contains the current active transmission mode // int tcr_cur_mode; unsigned short tcr_cur_mode; // Contains the current active receive mode unsigned short rcr_cur_mode; // Contains the current active receive/phy mode // int rpc_cur_mode; unsigned short rpc_cur_mode; int ctl_autoneg; int ctl_rfduplx; int ctl_rspeed; // base of datacs memory region unsigned long datacs; // when to use datacs int use_datacs; #ifdef CONFIG_PM struct pm_dev* pm; #endif }; #if SMC_DEBUG > 2 #define PRINTK3(args...) printk(args) #else #define PRINTK3(args...) do { } while(0) #endif #if SMC_DEBUG > 1 #define PRINTK2(args...) printk(args) #else #define PRINTK2(args...) do { } while(0) #endif #if SMC_DEBUG > 0 #define PRINTK1(args...) printk(args) #define PRINTK(args...) printk(args) #else #define PRINTK1(args...) do { } while(0) #define PRINTK(args...) printk(KERN_DEBUG args) #endif #if SMC_DEBUG > 3 static void PRINT_PKT(u_char *buf, int length) { int i; int remainder; int lines; lines = length / 16; remainder = length % 16; for (i = 0; i < lines ; i ++) { int cur; for (cur = 0; cur < 8; cur++) { u_char a, b; a = *buf++; b = *buf++; printk("%02x%02x ", a, b); } printk("\n"); } for (i = 0; i < remainder/2 ; i++) { u_char a, b; a = *buf++; b = *buf++; printk("%02x%02x ", a, b ); } printk("\n"); } #else #define PRINT_PKT(x...) do { } while(0) #endif /* this enables an interrupt in the interrupt mask register */ #define smc_ENABLE_INT(x) do { \ unsigned long flags; \ unsigned short mask; \ local_irq_save(flags); \ mask = get_MSK(); \ mask |= (x); \ set_MSK(mask & 0xff00); \ local_irq_restore(flags); \ } while (0) /* this disables an interrupt from the interrupt mask register */ #define smc_DISABLE_INT(x) do { \ unsigned long flags; \ unsigned short mask; \ local_irq_save(flags); \ mask = get_MSK(); \ mask &= ~(x); \ set_MSK(mask & 0xff00); \ local_irq_restore(flags); \ } while (0) /* wait while MMU is busy */ #define smc_WAIT_MMU_BUSY() do { \ if (get_MMUCR_BUSY() != 0 ) { \ unsigned long timeout = jiffies + 2; \ while (get_MMUCR_BUSY() !=0 ) { \ if (time_after(jiffies, timeout)) { \ PRINTK("%s: timeout %s line %d\n", \ dev->name, __FILE__, __LINE__); \ break; \ } \ } \ } \ } while (0) /* prototypes */ static int smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg); static void smc_write_phy_register( unsigned long ioaddr, int phyaddr, int phyreg, int phydata ); /* HAIL gated spec callback support */ //static u_int16_t smc91c111_mii_get_2(unsigned long); //static void smc91c111_mii_set_2(unsigned long, u_int16_t); static int smc91c111_mii_ioaddr; /* XXX HACK compensates for weak HAIL gated spec callback API */ static int smc91c111_mii_phyaddr; /* XXX " " " " " " " */ static u_int16_t smc91c111_mii_get_2(unsigned long regoff) { return smc_read_phy_register(smc91c111_mii_ioaddr, smc91c111_mii_phyaddr, regoff); } static void smc91c111_mii_set_2(unsigned long regoff, u_int16_t val) { smc_write_phy_register(smc91c111_mii_ioaddr, smc91c111_mii_phyaddr, regoff, val); } /* this does a soft reset on the device */ static void smc_reset(struct net_device *dev) { PRINTK2("%s: %s\n", dev->name, __FUNCTION__); /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ set_BSR_BANK( 0 ); set_RCR(RCR_SOFT_RST_VAL(1)); /* Setup the Configuration Register */ /* This is necessary because the CONFIG_REG is not affected */ /* by a soft reset */ set_BSR_BANK( 1 ); set_CR( CONFIG_DEFAULT ); /* Setup for fast accesses if requested */ /* If the card/system can't handle it then there will */ /* be no recovery except for a hard reset or power cycle */ if (nowait) set_CR_NO_WAIT(1); #ifdef POWER_DOWN { /* Release from possible power-down state */ /* Configuration register is not affected by Soft Reset */ set_BSR_BANK( 1 ); // set_CR( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN ); set_CR_EPH_Power_EN(1); set_Control_PDN(0); } #endif /* this should pause enough for the chip to be happy */ udelay(1); /* Disable transmit and receive functionality */ set_BSR_BANK( 0 ); set_RCR( RCR_CLEAR ); set_TCR( TCR_CLEAR ); /* set the control register to automatically release successfully transmitted packets, to make the best use out of our limited memory */ set_BSR_BANK( 1 ); #if ! THROTTLE_TX_PKTS //SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE ); set_CTR_AUTO_RELEASE(1); #else //SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE ); set_CTR_AUTO_RELEASE(0); #endif /* Disable all interrupts */ set_BSR_BANK( 2 ); set_MSK( 0 ); /* Reset the MMU */ set_MMUCR_CMD(MMUCR_MMU_RESET ); smc_WAIT_MMU_BUSY(); } /* Enable Interrupts, Receive, and Transmit */ static void smc_enable(struct net_device *dev) { // unsigned long ioaddr = dev->base_addr; struct smc_local *lp = (struct smc_local *)dev->priv; unsigned short mask=0; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); /* see the header file for options in TCR/RCR DEFAULT*/ set_BSR_BANK( 0 ); set_TCR( lp->tcr_cur_mode ); set_RCR( lp->rcr_cur_mode ); /* now, enable interrupts */ mem_set_MSK_EPH_INT(&mask, 1); mem_set_MSK_RX_OVRN_INT(&mask, 1); mem_set_MSK_RCV_INT(&mask, 1); if (lp->version >= 0x70) mem_set_MSK_MDINT(&mask,1); set_BSR_BANK( 2 ); set_MSK( mask ); } /* this puts the device in an inactive state */ static void smc_shutdown(struct net_device *dev) { PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); /* no more interrupts for me */ set_BSR_BANK( 2 ); set_MSK( 0 ); /* and tell the card to stay away from that nasty outside world */ set_BSR_BANK( 0 ); set_RCR( RCR_CLEAR ); set_TCR( TCR_CLEAR ); #ifdef POWER_DOWN set_Control_PDN(1); /* finally, shut the chip down */ set_BSR_BANK( 1 ); // set_CR( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN ); set_CR_EPH_Power_EN(0); #endif } /* This is the procedure to handle the receipt of a packet. */ static inline void smc_rcv(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; unsigned int packet_number, status, packet_len; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); packet_number = get_FIFO(); if (mem_get_FIFO_REMPTY(packet_number)) { printk(KERN_WARNING "%s: smc_rcv with nothing on FIFO.\n", dev->name); return; } packet_number = mem_get_FIFO_RX_FIFO_PACKET_NUMBER(packet_number); /* read from start of packet */ set_PTR(PTR_READ_VAL(1) | PTR_RCV_VAL(1) | PTR_AUTO_INCR_VAL(1) ); /* First two words are status and packet length */ SMC_GET_PKT_HDR(status, packet_len); packet_len &= 0x07ff; /* mask off top bits */ PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", dev->name, packet_number, status, packet_len, packet_len); if (unlikely(status & RS_ERRORS)) { lp->stats.rx_errors++; if (status & RS_ALGNERR) lp->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) lp->stats.rx_length_errors++; if (status & RS_BADCRC) lp->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; unsigned int data_len; /* set multicast stats */ if (status & RS_MULTICAST) lp->stats.multicast++; /* * Actual payload is packet_len - 4 (or 3 if odd byte). * We want skb_reserve(2) and the final ctrl word * (2 bytes, possibly containing the payload odd byte). * Ence packet_len - 4 + 2 + 2. */ skb = dev_alloc_skb(packet_len); if (unlikely(skb == NULL)) { printk(KERN_WARNING "%s: Low memory, packet dropped.\n", dev->name); lp->stats.rx_dropped++; goto done; } /* Align IP header to 32 bits */ skb_reserve(skb, 2); /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ if (lp->version == 0x90) status |= RS_ODDFRAME; /* * If odd length: packet_len - 3, * otherwise packet_len - 4. */ data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); data = skb_put(skb, data_len); SMC_PULL_DATA(data, packet_len - 2); PRINT_PKT(data, packet_len - 2); dev->last_rx = jiffies; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += data_len; } done: smc_WAIT_MMU_BUSY(); set_MMUCR_CMD(MMUCR_RX_FIFO_RnR); } /* * This is called to actually send a packet to the chip. * Returns non-zero when successful. */ static void smc_hardware_send_packet(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; struct sk_buff *skb = lp->saved_skb; unsigned int packet_no, len; unsigned char *buf; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); if (unlikely(!skb)) { printk (KERN_WARNING "%s: In XMIT with no packet to send\n", dev->name); return; } packet_no = get_ARR(); if (unlikely(mem_get_ARR_FAILED(packet_no)!=0)) { printk(KERN_WARNING "%s: Memory allocation failed.\n", dev->name); lp->saved_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; dev_kfree_skb_any(skb); return; } packet_no >>=8; /* FIXME, jsun */ /* point to the beginning of the packet */ set_PNR( packet_no ); set_PTR( PTR_AUTO_INCR_VAL(1) ); buf = skb->data; len = skb->len; PRINTK2("%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 9x%p\n", dev->name, packet_no, len, len, buf); PRINT_PKT(buf, len); /* * Send the packet length ( +6 for status words, length, and ctl. * The card will pad to 64 bytes with zeroes if packet is too small. */ SMC_PUT_PKT_HDR(0, len + 6); /* send the actual data */ SMC_PUSH_DATA(buf, len & ~1); /* Send final ctl word with the last byte if there is one */ set_DATA( ((len & 1) ? (0x2000 | buf[len-1]) : 0)); /* and let the chipset deal with it */ set_MMUCR_CMD( MMUCR_ENQUEUE_PNO); SMC_ACK_INT( ACK_TX_EMPTY_INT_VAL(1) ); dev->trans_start = jiffies; dev_kfree_skb_any(skb); lp->saved_skb = NULL; lp->stats.tx_packets++; lp->stats.tx_bytes += len; } /* . Since I am not sure if I will have enough room in the chip's ram . to store the packet, I call this routine which either sends it . now, or set the card to generates an interrupt when ready . for the packet. */ static int smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev ) { struct smc_local *lp = (struct smc_local *)dev->priv; unsigned int numPages, poll_count, status, saved_bank; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); if (unlikely(lp->saved_skb != NULL)) { /* THIS SHOULD NEVER HAPPEN. */ printk( KERN_CRIT "%s: Bad Craziness - sent packet while busy.\n", dev->name ); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; return 1; } lp->saved_skb = skb; /* ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** The 91C111 ignores the size bits, but the code is left intact ** for backwards and future compatibility. ** ** Pkt size for allocating is data length +6 (for additional status ** words, length and ctl!) ** ** If odd size then last byte is included in ctl word. */ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk(KERN_WARNING "%s: Far too big packet error.\n", dev->name); lp->saved_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } /* now, try to allocate the memory */ saved_bank = get_BSR_BANK(); set_BSR_BANK( 2 ); // SMC_SET_MMU_CMD( MC_ALLOC | numPages ); set_MMUCR( MMUCR_CMD_VAL(MMUCR_TX_ALLOC) | numPages ); /* * Poll the chip for a short amount of time in case the * allocation succeeds quickly. */ poll_count = MEMORY_WAIT_TIME; do { status = get_IST(); if (mem_get_IST_ALLOC_INT(status)) { SMC_ACK_INT( IST_ALLOC_INT_VAL(1) ); break; } } while (--poll_count); if (!poll_count) { /* oh well, wait until the chip finds memory later */ netif_stop_queue(dev); PRINTK2("%s: TX memory allocation deferred.\n", dev->name); smc_ENABLE_INT( MSK_ALLOC_INT_VAL(1) ); } else { /* Send current packet immediately.. */ #if THROTTLE_TX_PKTS netif_stop_queue(dev); #endif smc_hardware_send_packet(dev); smc_ENABLE_INT( MSK_TX_INT_VAL(1) | MSK_TX_EMPTY_INT_VAL(1) ); } set_BSR_BANK( saved_bank ); return 0; } /* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent or CTL_AUTO_RELEASE is not set. */ static void smc_tx(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; unsigned int saved_packet, packet_no, tx_status, pkt_len; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); /* If the TX FIFO is empty then nothing to do */ //packet_no = SMC_GET_TXFIFO(); packet_no = get_FIFO(); if (unlikely(mem_get_FIFO_TEMPTY(packet_no) != 0)) { PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); return; } packet_no &= 0xff; /* FIXME, jsun */ /* select packet to read from */ saved_packet = get_PNR(); set_PNR( packet_no ); /* read the first word (status word) from this packet */ set_PTR( PTR_AUTO_INCR_VAL(1) | PTR_READ_VAL(1) ); SMC_GET_PKT_HDR(tx_status, pkt_len); PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n", dev->name, tx_status, packet_no); if (!(tx_status & TS_SUCCESS)) lp->stats.tx_errors++; if (tx_status & TS_LOSTCAR) lp->stats.tx_carrier_errors++; if (tx_status & TS_LATCOL) { printk( KERN_DEBUG "%s: Late collision occurred on last xmit.\n", dev->name); lp->stats.tx_window_errors++; } /* kill the packet */ smc_WAIT_MMU_BUSY(); set_MMUCR_CMD( MMUCR_RELEASE_PNO); /* Don't restore Packet Number Reg until busy bit is cleared */ smc_WAIT_MMU_BUSY(); set_PNR( saved_packet ); /* re-enable transmit */ set_BSR_BANK( 0 ); set_TCR( lp->tcr_cur_mode ); set_BSR_BANK( 2 ); } //---PHY CONTROL AND CONFIGURATION----------------------------------------- /*------------------------------------------------------------ . Debugging function for viewing MII Management serial bitstream .-------------------------------------------------------------*/ #if SMC_DEBUG > 3 static void PRINT_MII_STREAM(u_char *bits, int size) { int i; printk("BIT#:"); for (i = 0; i < size; ++i) printk("%d", i%10); printk("\nMDOE:"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDOE) printk("1"); else printk("0"); } printk("\nMDO :"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDO) printk("1"); else printk("0"); } printk("\nMDI :"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDI) printk("1"); else printk("0"); } printk("\n"); } #else #define PRINT_MII_STREAM(x...) #endif /*------------------------------------------------------------ . Reads a register from the MII Management serial interface .-------------------------------------------------------------*/ static int smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg) { int oldBank; int i, mask, mii_reg; u_char bits[64]; int input_idx, phydata; int clk_idx = 0; // 32 consecutive ones on MDO to establish sync for (i = 0; i < 32; ++i) bits[clk_idx++] = MII_MDOE | MII_MDO; // Start code <01> bits[clk_idx++] = MII_MDOE; bits[clk_idx++] = MII_MDOE | MII_MDO; // Read command <10> bits[clk_idx++] = MII_MDOE | MII_MDO; bits[clk_idx++] = MII_MDOE; // Output the PHY address, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyaddr & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Output the phy register number, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyreg & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Tristate and turnaround (2 bit times) bits[clk_idx++] = 0; //bits[clk_idx++] = 0; // Input starts at this bit time input_idx = clk_idx; // Will input 16 bits for (i = 0; i < 16; ++i) bits[clk_idx++] = 0; // Final clock bit bits[clk_idx++] = 0; // Save the current bank oldBank = get_BSR_BANK(); // Select bank 3 set_BSR_BANK( 3 ); // Get the current MII register value mii_reg = get_MGMT(); // Turn off all MII Interface bits mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); // Clock all 64 cycles for (i = 0; i < sizeof bits; ++i) { // Clock Low - output data set_MGMT( mii_reg | bits[i] ); udelay(50); // Clock Hi - input data set_MGMT( mii_reg | bits[i] | MII_MCLK ); udelay(50); bits[i] |= get_MGMT() & MII_MDI; } // Return to idle state // Set clock to low, data to low, and output tristated set_MGMT( mii_reg ); udelay(50); // Restore original bank select set_BSR_BANK( oldBank ); // Recover input data phydata = 0; for (i = 0; i < 16; ++i) { phydata <<= 1; if (bits[input_idx++] & MII_MDI) phydata |= 0x0001; } PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); PRINT_MII_STREAM(bits, sizeof(bits)); return phydata; } /*------------------------------------------------------------ . Writes a register to the MII Management serial interface .-------------------------------------------------------------*/ static void smc_write_phy_register( unsigned long ioaddr, int phyaddr, int phyreg, int phydata ) { int oldBank; int i, mask, mii_reg; u_char bits[65]; int clk_idx = 0; // 32 consecutive ones on MDO to establish sync for (i = 0; i < 32; ++i) bits[clk_idx++] = MII_MDOE | MII_MDO; // Start code <01> bits[clk_idx++] = MII_MDOE; bits[clk_idx++] = MII_MDOE | MII_MDO; // Write command <01> bits[clk_idx++] = MII_MDOE; bits[clk_idx++] = MII_MDOE | MII_MDO; // Output the PHY address, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyaddr & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Output the phy register number, msb first mask = 0x10; for (i = 0; i < 5; ++i) { if (phyreg & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Tristate and turnaround (2 bit times) bits[clk_idx++] = 0; bits[clk_idx++] = 0; // Write out 16 bits of data, msb first mask = 0x8000; for (i = 0; i < 16; ++i) { if (phydata & mask) bits[clk_idx++] = MII_MDOE | MII_MDO; else bits[clk_idx++] = MII_MDOE; // Shift to next lowest bit mask >>= 1; } // Final clock bit (tristate) bits[clk_idx++] = 0; // Save the current bank oldBank = get_BSR_BANK(); // Select bank 3 set_BSR_BANK( 3 ); // Get the current MII register value mii_reg = get_MGMT(); // Turn off all MII Interface bits mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); // Clock all cycles for (i = 0; i < sizeof bits; ++i) { // Clock Low - output data set_MGMT( mii_reg | bits[i] ); udelay(50); // Clock Hi - input data set_MGMT( mii_reg | bits[i] | MII_MCLK ); udelay(50); bits[i] |= get_MGMT() & MII_MDI; } // Return to idle state // Set clock to low, data to low, and output tristated set_MGMT( mii_reg ); udelay(50); // Restore original bank select set_BSR_BANK( oldBank ); PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); PRINT_MII_STREAM(bits, sizeof(bits)); } /*------------------------------------------------------------ . Finds and reports the PHY address .-------------------------------------------------------------*/ static int smc_detect_phy(struct net_device* dev) { struct smc_local *lp = (struct smc_local *)dev->priv; int phy_id1, phy_id2; int phyaddr; int found = 0; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); // Scan all 32 PHY addresses if necessary for (phyaddr = 0; phyaddr < 32; ++phyaddr) { // Read the PHY identifiers phy_id1 = get_PHY_ID1(); phy_id2 = get_PHY_ID2(); PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n", dev->name, phy_id1, phy_id2); // Make sure it is a valid identifier if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) { if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) { // Save the PHY's address smc91c111_mii_phyaddr = lp->phyaddr = phyaddr; found = 1; break; } } } if (!found) { PRINTK("%s: No PHY found\n", dev->name); return(0); } // Set the PHY type if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) { lp->phytype = PHY_LAN83C183; PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name); } if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) { lp->phytype = PHY_LAN83C180; PRINTK("%s: PHY=LAN83C180\n", dev->name); } return 1; } /*------------------------------------------------------------ . Waits the specified number of milliseconds - kernel friendly .-------------------------------------------------------------*/ static void smc_wait_ms(unsigned int ms) { if (!in_interrupt()) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1 + ms * HZ / 1000); } else { /* if this happens it must be fixed */ printk( KERN_WARNING "%s: busy wait while in interrupt!\n", __FUNCTION__); mdelay(ms); } } /*------------------------------------------------------------ . Sets the PHY to a configuration as determined by the user .-------------------------------------------------------------*/ static int smc_phy_fixed(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; int my_fixed_caps; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); // Enter Link Disable state set_Config1_LNKDIS(1); // Set our fixed capabilities // Disable auto-negotiation my_fixed_caps = 0; if (lp->ctl_rfduplx) my_fixed_caps |= Control_DPLX_VAL(1); if (lp->ctl_rspeed == 100) my_fixed_caps |= Control_SPEED_VAL(1); // Write our capabilities to the phy control register set_Control(my_fixed_caps); // Re-Configure the Receive/Phy Control register set_RPCR( lp->rpc_cur_mode ); // Success return(1); } /*------------------------------------------------------------ . Configures the specified PHY through the MII management interface . using Autonegotiation. . Calls smc_phy_fixed() if the user has requested a certain config. .-------------------------------------------------------------*/ static void smc_phy_configure(struct net_device* dev) { struct smc_local *lp = (struct smc_local *)dev->priv; int timeout; int phyaddr; u_int16_t my_phy_caps; // My PHY capabilities u_int16_t my_ad_caps; // My Advertised capabilities int status; PRINTK3("%s:smc_program_phy()\n", dev->name); // Set the blocking flag lp->autoneg_active = 1; // Find the address and type of our phy if (!smc_detect_phy(dev)) goto smc_phy_configure_exit; // Get the detected phy address phyaddr = lp->phyaddr; // Reset the PHY, setting all other bits to zero set_Control(Control_RST_VAL(1)); // Wait for the reset to complete, or time out timeout = 6; // Wait up to 3 seconds while (timeout--) { if (! get_Control_RST()) // reset complete break; smc_wait_ms(500); // wait 500 millisecs if (signal_pending(current)) { // Exit anyway if signaled PRINTK("%s: PHY reset interrupted by signal\n", dev->name); timeout = 0; break; } } if (timeout < 1) { printk(KERN_WARNING "%s: PHY reset timed out\n", dev->name); goto smc_phy_configure_exit; } // Read PHY Register 18, Status Output lp->lastPhy18 = get_Status_Output(); // Enable PHY Interrupts (for register 18) // Interrupts listed here are disabled set_Mask(Mask_MLOSSSYN_VAL(1) | Mask_MCWRD_VAL(1) | Mask_MSSD_VAL(1) | Mask_MESD_VAL(1) | Mask_MRPOL_VAL(1) | Mask_MJAB_VAL(1) | Mask_MSPDDT_VAL(1) | Mask_MDPLDT_VAL(1)); /* Configure the Receive/Phy Control register */ set_BSR_BANK( 0 ); set_RPCR( lp->rpc_cur_mode ); // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG printk("We are here! _raw_read_CR_EXT_PHY() = %d, _raw_read_BSR_BANK() = %d\n", _raw_read_CR_EXT_PHY(), _raw_read_BSR_BANK()); my_phy_caps = get_Status(); // If the user requested no auto neg, then go set his request if (!(lp->ctl_autoneg)) { smc_phy_fixed(dev); goto smc_phy_configure_exit; } if(! mem_get_Status_CAP_ANEG(my_phy_caps)) { printk(KERN_INFO "Auto negotiation NOT supported\n"); smc_phy_fixed(dev); goto smc_phy_configure_exit; } my_ad_caps = ANA_CSMA_VAL(1); // I am CSMA capable if (mem_get_Status_CAP_T4(my_phy_caps)) mem_set_ANA_T4(&my_ad_caps, 1); if (mem_get_Status_CAP_TXF(my_phy_caps)) mem_set_ANA_TX_FDX(&my_ad_caps, 1); if (mem_get_Status_CAP_TXH(my_phy_caps)) mem_set_ANA_TX_HDX(&my_ad_caps, 1); if (mem_get_Status_CAP_TF(my_phy_caps)) mem_set_ANA_TEN_FDX(&my_ad_caps, 1); if (mem_get_Status_CAP_TH(my_phy_caps)) mem_set_ANA_TEN_HDX(&my_ad_caps, 1); // Disable capabilities not selected by our user if (lp->ctl_rspeed != 100) my_ad_caps &= ~(ANA_T4_VAL(1)|ANA_TX_FDX_VAL(1)|ANA_TX_HDX_VAL(1)); if (!lp->ctl_rfduplx) my_ad_caps &= ~(ANA_TX_FDX_VAL(1)|ANA_TEN_FDX_VAL(1)); // Update our Auto-Neg Advertisement Register set_ANA(my_ad_caps); // Read the register back. Without this, it appears that when // auto-negotiation is restarted, sometimes it isn't ready and // the link does not come up. status = get_ANA(); PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps); PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps); // Restart auto-negotiation process in order to advertise my caps set_Control(Control_ANEG_EN_VAL(1) | Control_ANEG_RST_VAL(1)); // Wait for the auto-negotiation to complete. This may take from // 2 to 3 seconds. // Wait for the reset to complete, or time out timeout = 20; // Wait up to 10 seconds while (timeout--) { if (get_ANREC_ACK()) // auto-negotiate complete break; // We need to check for remote fault (which clears it) // otherwise auto-negotiation never completes and we // wait for the entire timeout. There doesn't appear // to be any need to reset the PHY. status = get_Status(); if (mem_get_Status_ANEG_ACK(status)) /* Since we read it, we might as well check */ // auto-negotiate complete break; smc_wait_ms(500); // wait 500 millisecs if (signal_pending(current)) { // Exit anyway if signaled printk(KERN_DEBUG "%s: PHY auto-negotiate interrupted by signal\n", dev->name); timeout = 0; break; } if (mem_get_Status_REM_FLT(status)) { PRINTK(KERN_NOTICE "%s: PHY remote fault detected while waiting for auto-negotiate to complete\n", dev->name); set_Control(Control_ANEG_EN_VAL(1) | Control_ANEG_RST_VAL(1)); } } status = get_Status(); if (timeout < 1) { PRINTK(KERN_NOTICE "%s: PHY auto-negotiate timed out\n", dev->name); } // Fail if we detected an auto-negotiate remote fault if (mem_get_Status_REM_FLT(status)) { PRINTK(KERN_NOTICE "%s: PHY remote fault detected\n", dev->name); } // Wait for link. Once the link is up, phy18 should be up to date timeout = 200; do { udelay(100); status = get_Status(); } while ( (mem_get_Status_LINK(status)==0) && --timeout); if (mem_get_Status_LINK(status)) { PRINTK(KERN_NOTICE "%s: Ethernet Link Detected\n", dev->name); } // The smc_phy_interrupt() routine will be called to update lastPhy18 // Set our sysctl parameters to match auto-negotiation results if (mem_get_Status_Output_SPDDET(lp->lastPhy18)) { PRINTK("%s: PHY 100BaseT\n", dev->name); // lp->rpc_cur_mode |= RPC_SPEED; mem_set_RPCR_SPEED(&lp->rpc_cur_mode, 1); } else { PRINTK("%s: PHY 10BaseT\n", dev->name); // lp->rpc_cur_mode &= ~RPC_SPEED; mem_set_RPCR_SPEED(&lp->rpc_cur_mode, 0); } if (mem_get_Status_Output_DPLXDET(lp->lastPhy18)) { PRINTK("%s: PHY Full Duplex\n", dev->name); //lp->rpc_cur_mode |= RPC_DPLX; mem_set_RPCR_DPLX(&lp->rpc_cur_mode, 1); //lp->tcr_cur_mode |= TCR_SWFDUP; mem_set_TCR_SWFDUP(&lp->tcr_cur_mode, 1); } else { PRINTK("%s: PHY Half Duplex\n", dev->name); // lp->rpc_cur_mode &= ~RPC_DPLX; mem_set_RPCR_DPLX(&lp->rpc_cur_mode, 0); // lp->tcr_cur_mode &= ~TCR_SWFDUP; mem_set_TCR_SWFDUP(&lp->tcr_cur_mode, 0); } // Re-Configure the Receive/Phy Control register and TCR set_RPCR( lp->rpc_cur_mode ); set_TCR( lp->tcr_cur_mode ); smc_phy_configure_exit: // Exit auto-negotiation lp->autoneg_active = 0; } /************************************************************************* . smc_phy_interrupt . . Purpose: Handle interrupts relating to PHY register 18. This is . called from the "hard" interrupt handler. . ************************************************************************/ static void smc_phy_interrupt(struct net_device* dev) { struct smc_local *lp = (struct smc_local *)dev->priv; int phy18; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); for(;;) { // Read PHY Register 18, Status Output phy18 = get_Status_Output(); // Exit if not more changes if (phy18 == lp->lastPhy18) break; #if SMC_DEBUG > 1 PRINTK2("%s: phy18=0x%04x\n", dev->name, phy18); PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18); // Handle events if (mem_get_Status_Output_LNKFAIL(phy18) != mem_get_Status_Output_LNKFAIL(lp->lastPhy18)) PRINTK2("%s: PHY Link Fail=%x\n", dev->name, phy18 & Status_Output_LNKFAIL_VAL(1)); if (mem_get_Status_Output_LOSSSYNC(phy18) != mem_get_Status_Output_LOSSSYNC(lp->lastPhy18)) PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name, phy18 & Status_Output_LOSSSYNC_VAL(1)); if (mem_get_Status_Output_CWRD(phy18) != mem_get_Status_Output_CWRD(lp->lastPhy18)) PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name, phy18 & Status_Output_CWRD_VAL(1)); if (mem_get_Status_Output_SSD(phy18) != mem_get_Status_Output_SSD(lp->lastPhy18)) PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name, phy18 & Status_Output_SSD_VAL(1)); if (mem_get_Status_Output_ESD(phy18) != mem_get_Status_Output_ESD(lp->lastPhy18)) PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name, phy18 & Status_Output_ESD_VAL(1)); if (mem_get_Status_Output_RPOL(phy18) != mem_get_Status_Output_RPOL(lp->lastPhy18)) PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", dev->name, phy18 & Status_Output_RPOL_VAL(1)); if (mem_get_Status_Output_JAB(phy18) != mem_get_Status_Output_JAB(lp->lastPhy18)) PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name, phy18 & Status_Output_JAB_VAL(1)); if (mem_get_Status_Output_SPDDET(phy18) != mem_get_Status_Output_SPDDET(lp->lastPhy18)) PRINTK2("%s: PHY Speed Detect=%x\n", dev->name, phy18 & Status_Output_SPDDET_VAL(1)); if (mem_get_Status_Output_DPLXDET(phy18) != mem_get_Status_Output_DPLXDET(lp->lastPhy18)) PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name, phy18 & Status_Output_DPLXDET_VAL(1)); #endif // Update the last phy 18 variable lp->lastPhy18 = phy18; } } //--- END PHY CONTROL AND CONFIGURATION------------------------------------- /* * This is the main routine of the driver, to handle the device when * it needs some attention. */ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct smc_local *lp = (struct smc_local *)dev->priv; int status, timeout, card_stats; unsigned short mask; int saved_bank, saved_pointer; PRINTK3("%s: %s\n", dev->name, __FUNCTION__); saved_bank = get_BSR_BANK(); set_BSR_BANK(2); saved_pointer = get_PTR(); mask = get_MSK(); set_MSK( 0 ); /* set a timeout value, so I don't stay here forever */ timeout = 8; do { status = get_IST(); PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", dev->name, status, mask>>8, ({ int meminfo; set_BSR_BANK(0); meminfo = SMC_GET_MIR(); set_BSR_BANK(2); meminfo; }), get_FIFO()); status &= mask>>8; /* HACK, jsun */ if (!status) break; if (mem_get_IST_RCV_INT(status)) { PRINTK3("%s: RX irq\n", dev->name); smc_rcv(dev); } else if (mem_get_IST_TX_INT(status)) { PRINTK3("%s: TX int\n", dev->name); smc_tx(dev); SMC_ACK_INT( ACK_TX_INT_VAL(1) ); #if THROTTLE_TX_PKTS netif_wake_queue(dev); #endif } else if (mem_get_IST_ALLOC_INT(status)) { PRINTK3("%s: Allocation irq\n", dev->name); smc_hardware_send_packet(dev); mem_set_MSK_TX_INT(&mask, 1); mem_set_MSK_TX_EMPTY_INT(&mask, 1); mem_set_MSK_ALLOC_INT(&mask, 0); #if ! THROTTLE_TX_PKTS netif_wake_queue(dev); #endif } else if (mem_get_IST_TX_EMPTY_INT(status)) { PRINTK3("%s: TX empty\n", dev->name); mem_set_MSK_TX_EMPTY_INT(&mask, 0); /* update stats */ set_BSR_BANK( 0 ); card_stats = get_ECR(); set_BSR_BANK( 2 ); /* single collisions */ lp->stats.collisions += mem_get_ECR_COLN(card_stats); /* multiple collisions */ lp->stats.collisions += mem_get_ECR_MCOLN(card_stats); } else if (mem_get_IST_RX_OVRN_INT(status)) { PRINTK1( "%s: RX overrun\n", dev->name); SMC_ACK_INT( ACK_RX_OVRN_INT_VAL(1) ); lp->stats.rx_errors++; lp->stats.rx_fifo_errors++; } else if (mem_get_IST_EPH_INT(status)) { PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name); } else if (mem_get_IST_MDINT(status)) { SMC_ACK_INT( ACK_MDINT_VAL(1) ); smc_phy_interrupt(dev); } else if (mem_get_IST_ERCV_INT(status)) { SMC_ACK_INT( ACK_ERCV_INT_VAL(1) ); PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); } } while (--timeout); /* restore register states */ set_MSK( mask); set_PTR( saved_pointer ); set_BSR_BANK( saved_bank ); PRINTK3("%s: Interrupt done\n", dev->name); } /* Our watchdog timed out. Called by the networking layer */ static void smc_timeout(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); smc_reset(dev); smc_enable(dev); #if 1 // IJC: If we don't reset the PHY then the chip stops working /* Reconfiguring the PHY doesn't seem like a bad idea here, but * it introduced a problem. Now that this is a timeout routine, * we are getting called from within an interrupt context. * smc_phy_configure() calls smc_wait_ms() which calls * schedule_timeout() which calls schedule(). When schedule() * is called from an interrupt context, it prints out * "Scheduling in interrupt" and then calls BUG(). This is * obviously not desirable. This was worked around by removing * the call to smc_phy_configure() here because it didn't seem * absolutely necessary. Ultimately, if smc_wait_ms() is * supposed to be usable from an interrupt context (which it * looks like it thinks it should handle), it should be fixed. */ /* Reconfigure the PHY */ smc_phy_configure(dev); #endif /* clear anything saved */ if (lp->saved_skb != NULL) { dev_kfree_skb (lp->saved_skb); lp->saved_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; } dev->trans_start = jiffies; netif_wake_queue(dev); } /* * Finds the CRC32 of a set of bytes. * (from Peter Cammaert's code) */ static int crc32(char *s, int length) { /* indices */ int perByte; int perBit; /* crc polynomial for Ethernet */ const unsigned long poly = 0xedb88320; /* crc value - preinitialized to all 1's */ unsigned long crc_value = 0xffffffff; for ( perByte = 0; perByte < length; perByte ++ ) { unsigned char c; c = *(s++); for ( perBit = 0; perBit < 8; perBit++ ) { crc_value = (crc_value>>1)^ (((crc_value^c)&0x01)?poly:0); c >>= 1; } } return crc_value; } /* . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. . . The SMC chip uses a hash table where the high 6 bits of the CRC of . address are the offset into the table. If that bit is 1, then the . multicast packet is accepted. Otherwise, it's dropped silently. . . To use the 6 bits as an offset into the table, the high 3 bits are the . number of the 8 bit register, while the low 3 bits are the bit within . that register. . . This routine is based very heavily on the one provided by Peter Cammaert. */ static void smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs) { int i; unsigned char multicast_table[ 8 ]; struct dev_mc_list *cur_addr; /* table for flipping the order of 3 bits */ static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* start with a table of all zeros: reject all */ memset( multicast_table, 0, sizeof( multicast_table ) ); cur_addr = addrs; for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { int position; /* do we have a pointer here? */ if ( !cur_addr ) break; /* make sure this is a multicast address - shouldn't this be a given if we have it here ? */ if ( !( *cur_addr->dmi_addr & 1 ) ) continue; /* only use the low order bits */ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= (1<>3)&7]); } /* now, the table can be loaded into the chipset */ set_BSR_BANK( 3 ); SMC_SET_MCAST( multicast_table ); } /* . This routine will, depending on the values passed to it, . either make it accept multicast packets, go into . promiscuous mode ( for TCPDUMP and cousins ) or accept . a select set of multicast packets */ static void smc_set_multicast_list(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; unsigned long ioaddr = dev->base_addr; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); set_BSR_BANK(0); if ( dev->flags & IFF_PROMISC ) { PRINTK2("%s: RCR_PRMS\n", dev->name); // lp->rcr_cur_mode |= RCR_PRMS; mem_set_RCR_PRMS(&lp->rcr_cur_mode, 1); set_RCR( lp->rcr_cur_mode ); } /* BUG? I never disable promiscuous mode if multicasting was turned on. Now, I turn off promiscuous mode, but I don't do anything to multicasting when promiscuous mode is turned on. */ /* Here, I am setting this to accept all multicast packets. I don't need to zero the multicast table, because the flag is checked before the table is */ else if (dev->flags & IFF_ALLMULTI) { // lp->rcr_cur_mode |= RCR_ALMUL; mem_set_RCR_ALMUL(&lp->rcr_cur_mode, 1); set_RCR( lp->rcr_cur_mode ); PRINTK2("%s: RCR_ALMUL\n", dev->name); } /* We just get all multicast packets even if we only want them . from one source. This will be changed at some future . point. */ else if (dev->mc_count ) { /* support hardware multicasting */ /* be sure I get rid of flags I might have set */ // lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); mem_set_RCR_PRMS(&lp->rcr_cur_mode, 0); mem_set_RCR_ALMUL(&lp->rcr_cur_mode, 0); set_RCR( lp->rcr_cur_mode ); /* NOTE: this has to set the bank, so make sure it is the last thing called. The bank is set to zero at the top */ smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); } else { PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); // lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); mem_set_RCR_PRMS(&lp->rcr_cur_mode, 0); mem_set_RCR_ALMUL(&lp->rcr_cur_mode, 0); set_RCR( lp->rcr_cur_mode ); /* since I'm disabling all multicast entirely, I need to clear the multicast list */ set_BSR_BANK( 3 ); SMC_CLEAR_MCAST(); } } /* * Open and Initialize the board * * Set up everything, reset the card, etc .. */ static int smc_open(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; unsigned long datacs = lp->datacs; int use_datacs = lp->use_datacs; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); /* clear out all the junk that was put here before... */ memset(dev->priv, 0, sizeof(struct smc_local)); /* Restore the interesting bits */ lp->datacs = datacs; lp->use_datacs = use_datacs; // Setup the default Register Modes lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT; lp->rpc_cur_mode = RPC_DEFAULT; /* Set default parameters */ #ifdef CONFIG_ARCH_RAMSES lp->ctl_autoneg = 0; lp->ctl_rfduplx = 0; lp->ctl_rspeed = 10; #else lp->ctl_autoneg = 1; lp->ctl_rfduplx = 1; lp->ctl_rspeed = 100; #endif set_BSR_BANK(3); lp->version = get_REV() & 0xff; /* reset the hardware */ smc_reset(dev); smc_enable(dev); set_BSR_BANK( 1 ); SMC_SET_MAC_ADDR(dev->dev_addr); /* Configure the PHY */ if (lp->version >= 0x70) smc_phy_configure(dev); netif_start_queue(dev); return 0; } /*---------------------------------------------------- . smc_close . . this makes the board clean up everything that it can . and not talk to the outside world. Caused by . an 'ifconfig ethX down' . -----------------------------------------------------*/ static int smc_close(struct net_device *dev) { PRINTK2("%s: %s\n", dev->name, __FUNCTION__); netif_stop_queue(dev); /* clear everything */ smc_shutdown(dev); return 0; } /*------------------------------------------------------------ . Get the current statistics. . This may be called with the card open or closed. .-------------------------------------------------------------*/ static struct net_device_stats * smc_query_statistics(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; PRINTK2("%s: %s\n", dev->name, __FUNCTION__); return &lp->stats; } /*---------------------------------------------------------------------- . smc_findirq . . This routine has a simple purpose -- make the SMC chip generate an . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ int __init smc_findirq( unsigned long ioaddr ) { int timeout = 20; unsigned long cookie; PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); cookie = probe_irq_on(); /* * What I try to do here is trigger an ALLOC_INT. This is done * by allocating a small chunk of memory, which will give an interrupt * when done. */ /* enable ALLOCation interrupts ONLY */ set_BSR_BANK(2); set_MSK( MSK_ALLOC_INT_VAL(1) ); /* . Allocate 512 bytes of memory. Note that the chip was just . reset so all the memory is available */ set_MMUCR( MMUCR_CMD_VAL(MMUCR_TX_ALLOC) | 1 ); /* . Wait until positive that the interrupt has been generated */ do { // int int_status; udelay(10); // int_status = get_IST(); // if (int_status & IM_ALLOC_INT) /* FIXME< jsun */ if (get_IST_ALLOC_INT()!=0) break; /* got the interrupt */ } while (--timeout); /* there is really nothing that I can do here if timeout fails, as autoirq_report will return a 0 anyway, which is what I want in this case. Plus, the clean up is needed in both cases. */ /* and disable all interrupts again */ set_MSK( 0 ); /* and return what I found */ return probe_irq_off(cookie); } /*---------------------------------------------------------------------- . Function: smc_probe( unsigned long ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC91x chip. . Returns a 0 on success . . Algorithm: . (1) see if the high byte of BANK_SELECT is 0x33 . (2) compare the ioaddr with the base register's address . (3) see if I recognize the chip ID in the appropriate register . .--------------------------------------------------------------------- */ /*--------------------------------------------------------------- . Here I do typical initialization tasks. . . o Initialize the structure if needed . o print out my vanity message if not done so already . o print out what type of hardware is detected . o print out the ethernet address . o find the IRQ . o set up my private data . o configure the dev structure with my subroutines . o actually GRAB the irq. . o GRAB the region .----------------------------------------------------------------- */ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr, unsigned long datacs) { struct smc_local *lp = (struct smc_local *)dev->priv; static int version_printed = 0; int i, retval; unsigned int val, revision_register; const char *version_string; const char *datacs_desc[4] = { "", " [datacs/rx]", " [datacs/tx]", " [datacs]" }; PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; if ( datacs ) { if (!request_region((unsigned long)datacs, SMC_DATA_EXTENT, dev->name)) { retval = -EBUSY; goto err_out1; } } /* First, see if the high byte is 0x33 */ val = get_BSR(); PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val); if ( (val & 0xFF00) != 0x3300 ) { if ( (val & 0xFF) == 0x33 ) { printk( KERN_WARNING "%s: Detected possible byte-swapped interface" " at IOADDR 0x%lx\n", CARDNAME, ioaddr); } retval = -ENODEV; goto err_out; } /* The above MIGHT indicate a device, but I need to write to further test this. */ set_BSR_BANK(0); val = get_BSR(); if ( (val & 0xFF00 ) != 0x3300 ) { retval = -ENODEV; goto err_out; } /* well, we've already written once, so hopefully another time won't hurt. This time, I need to switch the bank register to bank 1, so I can access the base address register */ set_BSR_BANK(1); val = get_BAR(); val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; if ( (ioaddr & ((PAGE_SIZE-1)<base_addr = ioaddr; lp->datacs = datacs; lp->use_datacs = use_datacs; lp->version = revision_register & 0xff; /* Get the MAC address */ set_BSR_BANK( 1 ); SMC_GET_MAC_ADDR(dev->dev_addr); /* now, reset the chip, and put it into a known state */ smc_reset( dev ); /* . If dev->irq is 0, then the device has to be banged on to see . what the IRQ is. . . This banging doesn't always detect the IRQ, for unknown reasons. . a workaround is to reset the chip and try again. . . Interestingly, the DOS packet driver *SETS* the IRQ on the card to . be what is requested on the command line. I don't do that, mostly . because the card that I have uses a non-standard method of accessing . the IRQs, and because this _should_ work in most configurations. . . Specifying an IRQ is done with the assumption that the user knows . what (s)he is doing. No checking is done!!!! . */ if ( dev->irq < 1 ) { int trials; trials = 3; while ( trials-- ) { dev->irq = smc_findirq( ioaddr ); if ( dev->irq ) break; /* kick the card and try again */ smc_reset( dev ); } } if (dev->irq == 0 ) { printk(KERN_ERR "%s: Couldn't autodetect your IRQ. Use irq=xx.\n", dev->name); retval = -ENODEV; goto err_out; } dev->irq = irq_cannonicalize(dev->irq); /* now, print out the card info, in a short format.. */ printk(KERN_INFO "%s: %s (rev %d) at %#lx IRQ %d%s%s%s\n", dev->name, version_string, revision_register & 0x0f, ioaddr, dev->irq, nowait ? " [nowait]" : "", THROTTLE_TX_PKTS ? " [throttle_tx]" : "", datacs ? datacs_desc[lp->use_datacs] : ""); /* Print the Ethernet address */ printk(KERN_INFO "%s: Ethernet addr: ", dev->name); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x\n", dev->dev_addr[5] ); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); if (retval) { goto err_out; } dev->open = smc_open; dev->stop = smc_close; dev->hard_start_xmit = smc_hard_start_xmit; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = HZ/10; dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; return 0; err_out: release_region(datacs, SMC_DATA_EXTENT); err_out1: release_region(ioaddr, SMC_IO_EXTENT); return retval; } /*------------------------------------------------------------------------- | | smc_init( void ) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr > 0x1ff, this is the address to check | dev->base_addr == , return failure code | | Output: | 0 --> there is a device | anything else, error | --------------------------------------------------------------------------- */ static struct net_device *global_dev = NULL; /* needs to be fixed */ #ifdef CONFIG_PM static int smc_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) { struct net_device *dev = (struct net_device *)pdev->data; struct smc_local *lp = (struct smc_local *)dev->priv; if(!netif_running(dev)) return 0; switch (rqst) { case PM_SUSPEND: netif_device_detach(dev); smc_shutdown(dev); break; case PM_RESUME: smc_reset(dev); smc_enable(dev); set_BSR_BANK( 1 ); SMC_SET_MAC_ADDR(dev->dev_addr); if (lp->version >= 0x70) smc_phy_configure(dev); netif_device_attach(dev); break; } return 0; } #endif static int __init smc_init(void) { struct smc_local *lp; int ret; PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); #ifdef MODULE if (io == -1) printk( KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", CARDNAME ); #endif if (global_dev) { printk("%s: already initialized.\n", CARDNAME); return -EBUSY; } global_dev = init_etherdev(0, sizeof(struct smc_local)); if (!global_dev) { printk("%s: could not allocate device.\n", CARDNAME); return -ENOMEM; } lp = (struct smc_local *)global_dev->priv; SET_MODULE_OWNER(global_dev); /* copy the parameters from insmod into the device structure */ if (io != -1) global_dev->base_addr = io; if (irq != -1) global_dev->irq = irq; lp->datacs = datacs; #ifdef SMC91X_CAN_USE_ISA /* try a specific location */ if (global_dev->base_addr > 0x1ff) ret = smc_probe(global_dev, global_dev->base_addr, datacs); else if (global_dev->base_addr != 0) ret = -ENXIO; else { int i; /* check every ethernet address */ for (i = 0; smc_portlist[i]; i++) { ret = smc_probe(global_dev, smc_portlist[i], datacs); if (ret == 0) break; } } #elif defined(CONFIG_ARCH_LUBBOCK) { int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2); volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000); unsigned long flags; /* first reset, then enable the device. Sequence is critical */ local_irq_save(flags); attaddr[ECOR] |= ECOR_RESET; udelay(100); attaddr[ECOR] &= ~ECOR_RESET; attaddr[ECOR] |= ECOR_ENABLE; /* force 16-bit mode */ attaddr[ECSR] &= ~ECSR_IOIS8; mdelay(1); local_irq_restore(flags); global_dev->irq = LUBBOCK_ETH_IRQ; ret = smc_probe(global_dev, ioaddr, datacs); } #elif defined(CONFIG_ARCH_PXA_IDP) { int ioaddr = IDP_ETH_BASE + 0x300; global_dev->irq = SMC_IRQ; ret = smc_probe(global_dev, ioaddr, datacs); } #elif defined(CONFIG_ARCH_RAMSES) { int ioaddr = RAMSES_ETH_BASE + 0x300; global_dev->irq = SMC_IRQ; ret = smc_probe(global_dev, ioaddr, datacs); } #else if (global_dev->base_addr == -1) { printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME); ret = -ENXIO; } else { void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT); smc91_base = (unsigned long)ioaddr; printk("smc91_base = %08lx\n", smc91_base); void *datacs; if ( lp->datacs ) datacs = ioremap(lp->datacs, SMC_DATA_EXTENT); else datacs = NULL; ret = smc_probe(global_dev, (unsigned long)ioaddr, (unsigned long)datacs); if (ret != 0) { if ( datacs ) iounmap(datacs); iounmap(ioaddr); } } #endif #ifdef SMC_USE_PXA_DMA if (ret == 0) { int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW, smc_pxa_dma_irq, NULL); if (dma >= 0) { global_dev->dma = dma; PRINTK("%s: using DMA channel %d\n", global_dev->name, dma); } else { global_dev->dma = -1; } } #endif #ifdef CONFIG_PM if (ret == 0) { struct smc_local *lp = (struct smc_local *)global_dev->priv; lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback); if ( lp->pm ) lp->pm->data = global_dev; } #endif if (ret != 0) { printk("%s: not found.\n", CARDNAME); kfree(global_dev->priv); unregister_netdev(global_dev); kfree(global_dev); } return ret; } static void __exit smc_cleanup(void) { struct smc_local *lp = (struct smc_local *)global_dev->priv; unregister_netdev(global_dev); #ifdef CONFIG_PM { struct smc_local *lp = (struct smc_local *)global_dev->priv; pm_unregister(lp->pm); } #endif free_irq(global_dev->irq, global_dev); release_region(global_dev->base_addr, SMC_IO_EXTENT); #ifndef SMC91X_CAN_USE_ISA iounmap((void *)global_dev->base_addr); #endif if ( lp->datacs ) { release_region(lp->datacs, SMC_DATA_EXTENT); iounmap((void*)lp->datacs); } kfree(global_dev); global_dev = NULL; } module_init(smc_init); module_exit(smc_cleanup);