162306a36Sopenharmony_ci/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 262306a36Sopenharmony_ci * driver for linux. 362306a36Sopenharmony_ci * Written 1996 by Russell Nelson, with reference to skeleton.c 462306a36Sopenharmony_ci * written 1993-1994 by Donald Becker. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software may be used and distributed according to the terms 762306a36Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * The author may be reached at nelson@crynwr.com, Crynwr 1062306a36Sopenharmony_ci * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Other contributors: 1362306a36Sopenharmony_ci * Mike Cruse : mcruse@cti-ltd.com 1462306a36Sopenharmony_ci * Russ Nelson 1562306a36Sopenharmony_ci * Melody Lee : ethernet@crystal.cirrus.com 1662306a36Sopenharmony_ci * Alan Cox 1762306a36Sopenharmony_ci * Andrew Morton 1862306a36Sopenharmony_ci * Oskar Schirmer : oskar@scara.com 1962306a36Sopenharmony_ci * Deepak Saxena : dsaxena@plexity.net 2062306a36Sopenharmony_ci * Dmitry Pervushin : dpervushin@ru.mvista.com 2162306a36Sopenharmony_ci * Deepak Saxena : dsaxena@plexity.net 2262306a36Sopenharmony_ci * Domenico Andreoli : cavokz@gmail.com 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Set this to zero to disable DMA code 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' 3062306a36Sopenharmony_ci * module options so we don't break any startup scripts. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#ifndef CONFIG_ISA_DMA_API 3362306a36Sopenharmony_ci#define ALLOW_DMA 0 3462306a36Sopenharmony_ci#else 3562306a36Sopenharmony_ci#define ALLOW_DMA 1 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Set this to zero to remove all the debug statements via 4062306a36Sopenharmony_ci * dead code elimination 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define DEBUGGING 1 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Sources: 4562306a36Sopenharmony_ci * Crynwr packet driver epktisa. 4662306a36Sopenharmony_ci * Crystal Semiconductor data sheets. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include <linux/module.h> 5262306a36Sopenharmony_ci#include <linux/printk.h> 5362306a36Sopenharmony_ci#include <linux/errno.h> 5462306a36Sopenharmony_ci#include <linux/netdevice.h> 5562306a36Sopenharmony_ci#include <linux/etherdevice.h> 5662306a36Sopenharmony_ci#include <linux/of.h> 5762306a36Sopenharmony_ci#include <linux/platform_device.h> 5862306a36Sopenharmony_ci#include <linux/kernel.h> 5962306a36Sopenharmony_ci#include <linux/types.h> 6062306a36Sopenharmony_ci#include <linux/fcntl.h> 6162306a36Sopenharmony_ci#include <linux/interrupt.h> 6262306a36Sopenharmony_ci#include <linux/ioport.h> 6362306a36Sopenharmony_ci#include <linux/in.h> 6462306a36Sopenharmony_ci#include <linux/jiffies.h> 6562306a36Sopenharmony_ci#include <linux/skbuff.h> 6662306a36Sopenharmony_ci#include <linux/spinlock.h> 6762306a36Sopenharmony_ci#include <linux/string.h> 6862306a36Sopenharmony_ci#include <linux/init.h> 6962306a36Sopenharmony_ci#include <linux/bitops.h> 7062306a36Sopenharmony_ci#include <linux/delay.h> 7162306a36Sopenharmony_ci#include <linux/gfp.h> 7262306a36Sopenharmony_ci#include <linux/io.h> 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#include <net/Space.h> 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#include <asm/irq.h> 7762306a36Sopenharmony_ci#include <linux/atomic.h> 7862306a36Sopenharmony_ci#if ALLOW_DMA 7962306a36Sopenharmony_ci#include <asm/dma.h> 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#include "cs89x0.h" 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define cs89_dbg(val, level, fmt, ...) \ 8562306a36Sopenharmony_cido { \ 8662306a36Sopenharmony_ci if (val <= net_debug) \ 8762306a36Sopenharmony_ci pr_##level(fmt, ##__VA_ARGS__); \ 8862306a36Sopenharmony_ci} while (0) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic char version[] __initdata = 9162306a36Sopenharmony_ci "v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton"; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define DRV_NAME "cs89x0" 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* First, a few definitions that the brave might change. 9662306a36Sopenharmony_ci * A zero-terminated list of I/O addresses to be probed. Some special flags.. 9762306a36Sopenharmony_ci * Addr & 1 = Read back the address port, look for signature and reset 9862306a36Sopenharmony_ci * the page window before probing 9962306a36Sopenharmony_ci * Addr & 3 = Reset the page window and probe 10062306a36Sopenharmony_ci * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space, 10162306a36Sopenharmony_ci * but it is possible that a Cirrus board could be plugged into the ISA 10262306a36Sopenharmony_ci * slots. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps 10562306a36Sopenharmony_ci * them to system IRQ numbers. This mapping is card specific and is set to 10662306a36Sopenharmony_ci * the configuration of the Cirrus Eval board for this chip. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_ISA) 10962306a36Sopenharmony_cistatic unsigned int netcard_portlist[] __used __initdata = { 11062306a36Sopenharmony_ci 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 11162306a36Sopenharmony_ci 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_cistatic unsigned int cs8900_irq_map[] = { 11462306a36Sopenharmony_ci 10, 11, 12, 5 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci#endif 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#if DEBUGGING 11962306a36Sopenharmony_cistatic unsigned int net_debug = DEBUGGING; 12062306a36Sopenharmony_ci#else 12162306a36Sopenharmony_ci#define net_debug 0 /* gcc will remove all the debug code for us */ 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* The number of low I/O ports used by the ethercard. */ 12562306a36Sopenharmony_ci#define NETCARD_IO_EXTENT 16 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* we allow the user to override various values normally set in the EEPROM */ 12862306a36Sopenharmony_ci#define FORCE_RJ45 0x0001 /* pick one of these three */ 12962306a36Sopenharmony_ci#define FORCE_AUI 0x0002 13062306a36Sopenharmony_ci#define FORCE_BNC 0x0004 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define FORCE_AUTO 0x0010 /* pick one of these three */ 13362306a36Sopenharmony_ci#define FORCE_HALF 0x0020 13462306a36Sopenharmony_ci#define FORCE_FULL 0x0030 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* Information that need to be kept for each board. */ 13762306a36Sopenharmony_cistruct net_local { 13862306a36Sopenharmony_ci int chip_type; /* one of: CS8900, CS8920, CS8920M */ 13962306a36Sopenharmony_ci char chip_revision; /* revision letter of the chip ('A'...) */ 14062306a36Sopenharmony_ci int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */ 14162306a36Sopenharmony_ci int auto_neg_cnf; /* auto-negotiation word from EEPROM */ 14262306a36Sopenharmony_ci int adapter_cnf; /* adapter configuration from EEPROM */ 14362306a36Sopenharmony_ci int isa_config; /* ISA configuration from EEPROM */ 14462306a36Sopenharmony_ci int irq_map; /* IRQ map from EEPROM */ 14562306a36Sopenharmony_ci int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */ 14662306a36Sopenharmony_ci int curr_rx_cfg; /* a copy of PP_RxCFG */ 14762306a36Sopenharmony_ci int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. */ 14862306a36Sopenharmony_ci int send_underrun; /* keep track of how many underruns in a row we get */ 14962306a36Sopenharmony_ci int force; /* force various values; see FORCE* above. */ 15062306a36Sopenharmony_ci spinlock_t lock; 15162306a36Sopenharmony_ci void __iomem *virt_addr;/* CS89x0 virtual address. */ 15262306a36Sopenharmony_ci#if ALLOW_DMA 15362306a36Sopenharmony_ci int use_dma; /* Flag: we're using dma */ 15462306a36Sopenharmony_ci int dma; /* DMA channel */ 15562306a36Sopenharmony_ci int dmasize; /* 16 or 64 */ 15662306a36Sopenharmony_ci unsigned char *dma_buff; /* points to the beginning of the buffer */ 15762306a36Sopenharmony_ci unsigned char *end_dma_buff; /* points to the end of the buffer */ 15862306a36Sopenharmony_ci unsigned char *rx_dma_ptr; /* points to the next packet */ 15962306a36Sopenharmony_ci#endif 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* Example routines you must write ;->. */ 16362306a36Sopenharmony_ci#define tx_done(dev) 1 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * Permit 'cs89x0_dma=N' in the kernel boot environment 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci#if !defined(MODULE) 16962306a36Sopenharmony_ci#if ALLOW_DMA 17062306a36Sopenharmony_cistatic int g_cs89x0_dma; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int __init dma_fn(char *str) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci g_cs89x0_dma = simple_strtol(str, NULL, 0); 17562306a36Sopenharmony_ci return 1; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci__setup("cs89x0_dma=", dma_fn); 17962306a36Sopenharmony_ci#endif /* ALLOW_DMA */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int g_cs89x0_media__force; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int __init media_fn(char *str) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci if (!strcmp(str, "rj45")) 18662306a36Sopenharmony_ci g_cs89x0_media__force = FORCE_RJ45; 18762306a36Sopenharmony_ci else if (!strcmp(str, "aui")) 18862306a36Sopenharmony_ci g_cs89x0_media__force = FORCE_AUI; 18962306a36Sopenharmony_ci else if (!strcmp(str, "bnc")) 19062306a36Sopenharmony_ci g_cs89x0_media__force = FORCE_BNC; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 1; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci__setup("cs89x0_media=", media_fn); 19662306a36Sopenharmony_ci#endif 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void readwords(struct net_local *lp, int portno, void *buf, int length) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u8 *buf8 = (u8 *)buf; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci do { 20362306a36Sopenharmony_ci u16 tmp16; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci tmp16 = ioread16(lp->virt_addr + portno); 20662306a36Sopenharmony_ci *buf8++ = (u8)tmp16; 20762306a36Sopenharmony_ci *buf8++ = (u8)(tmp16 >> 8); 20862306a36Sopenharmony_ci } while (--length); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void writewords(struct net_local *lp, int portno, void *buf, int length) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci u8 *buf8 = (u8 *)buf; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci do { 21662306a36Sopenharmony_ci u16 tmp16; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci tmp16 = *buf8++; 21962306a36Sopenharmony_ci tmp16 |= (*buf8++) << 8; 22062306a36Sopenharmony_ci iowrite16(tmp16, lp->virt_addr + portno); 22162306a36Sopenharmony_ci } while (--length); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic u16 22562306a36Sopenharmony_cireadreg(struct net_device *dev, u16 regno) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci iowrite16(regno, lp->virt_addr + ADD_PORT); 23062306a36Sopenharmony_ci return ioread16(lp->virt_addr + DATA_PORT); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void 23462306a36Sopenharmony_ciwritereg(struct net_device *dev, u16 regno, u16 value) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci iowrite16(regno, lp->virt_addr + ADD_PORT); 23962306a36Sopenharmony_ci iowrite16(value, lp->virt_addr + DATA_PORT); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int __init 24362306a36Sopenharmony_ciwait_eeprom_ready(struct net_device *dev) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci unsigned long timeout = jiffies; 24662306a36Sopenharmony_ci /* check to see if the EEPROM is ready, 24762306a36Sopenharmony_ci * a timeout is used just in case EEPROM is ready when 24862306a36Sopenharmony_ci * SI_BUSY in the PP_SelfST is clear 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci while (readreg(dev, PP_SelfST) & SI_BUSY) 25162306a36Sopenharmony_ci if (time_after_eq(jiffies, timeout + 40)) 25262306a36Sopenharmony_ci return -1; 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int __init 25762306a36Sopenharmony_ciget_eeprom_data(struct net_device *dev, int off, int len, int *buffer) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci int i; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci cs89_dbg(3, info, "EEPROM data from %x for %x:", off, len); 26262306a36Sopenharmony_ci for (i = 0; i < len; i++) { 26362306a36Sopenharmony_ci if (wait_eeprom_ready(dev) < 0) 26462306a36Sopenharmony_ci return -1; 26562306a36Sopenharmony_ci /* Now send the EEPROM read command and EEPROM location to read */ 26662306a36Sopenharmony_ci writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD); 26762306a36Sopenharmony_ci if (wait_eeprom_ready(dev) < 0) 26862306a36Sopenharmony_ci return -1; 26962306a36Sopenharmony_ci buffer[i] = readreg(dev, PP_EEData); 27062306a36Sopenharmony_ci cs89_dbg(3, cont, " %04x", buffer[i]); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci cs89_dbg(3, cont, "\n"); 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int __init 27762306a36Sopenharmony_ciget_eeprom_cksum(int off, int len, int *buffer) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int i, cksum; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci cksum = 0; 28262306a36Sopenharmony_ci for (i = 0; i < len; i++) 28362306a36Sopenharmony_ci cksum += buffer[i]; 28462306a36Sopenharmony_ci cksum &= 0xffff; 28562306a36Sopenharmony_ci if (cksum == 0) 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci return -1; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void 29162306a36Sopenharmony_ciwrite_irq(struct net_device *dev, int chip_type, int irq) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci int i; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (chip_type == CS8900) { 29662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_ISA) 29762306a36Sopenharmony_ci /* Search the mapping table for the corresponding IRQ pin. */ 29862306a36Sopenharmony_ci for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++) 29962306a36Sopenharmony_ci if (cs8900_irq_map[i] == irq) 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci /* Not found */ 30262306a36Sopenharmony_ci if (i == ARRAY_SIZE(cs8900_irq_map)) 30362306a36Sopenharmony_ci i = 3; 30462306a36Sopenharmony_ci#else 30562306a36Sopenharmony_ci /* INTRQ0 pin is used for interrupt generation. */ 30662306a36Sopenharmony_ci i = 0; 30762306a36Sopenharmony_ci#endif 30862306a36Sopenharmony_ci writereg(dev, PP_CS8900_ISAINT, i); 30962306a36Sopenharmony_ci } else { 31062306a36Sopenharmony_ci writereg(dev, PP_CS8920_ISAINT, irq); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void 31562306a36Sopenharmony_cicount_rx_errors(int status, struct net_device *dev) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci dev->stats.rx_errors++; 31862306a36Sopenharmony_ci if (status & RX_RUNT) 31962306a36Sopenharmony_ci dev->stats.rx_length_errors++; 32062306a36Sopenharmony_ci if (status & RX_EXTRA_DATA) 32162306a36Sopenharmony_ci dev->stats.rx_length_errors++; 32262306a36Sopenharmony_ci if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA | RX_RUNT))) 32362306a36Sopenharmony_ci /* per str 172 */ 32462306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 32562306a36Sopenharmony_ci if (status & RX_DRIBBLE) 32662306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/********************************* 33062306a36Sopenharmony_ci * This page contains DMA routines 33162306a36Sopenharmony_ci *********************************/ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci#if ALLOW_DMA 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci#define dma_page_eq(ptr1, ptr2) ((long)(ptr1) >> 17 == (long)(ptr2) >> 17) 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void 33862306a36Sopenharmony_ciget_dma_channel(struct net_device *dev) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (lp->dma) { 34362306a36Sopenharmony_ci dev->dma = lp->dma; 34462306a36Sopenharmony_ci lp->isa_config |= ISA_RxDMA; 34562306a36Sopenharmony_ci } else { 34662306a36Sopenharmony_ci if ((lp->isa_config & ANY_ISA_DMA) == 0) 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci dev->dma = lp->isa_config & DMA_NO_MASK; 34962306a36Sopenharmony_ci if (lp->chip_type == CS8900) 35062306a36Sopenharmony_ci dev->dma += 5; 35162306a36Sopenharmony_ci if (dev->dma < 5 || dev->dma > 7) { 35262306a36Sopenharmony_ci lp->isa_config &= ~ANY_ISA_DMA; 35362306a36Sopenharmony_ci return; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void 35962306a36Sopenharmony_ciwrite_dma(struct net_device *dev, int chip_type, int dma) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 36262306a36Sopenharmony_ci if ((lp->isa_config & ANY_ISA_DMA) == 0) 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci if (chip_type == CS8900) 36562306a36Sopenharmony_ci writereg(dev, PP_CS8900_ISADMA, dma - 5); 36662306a36Sopenharmony_ci else 36762306a36Sopenharmony_ci writereg(dev, PP_CS8920_ISADMA, dma); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void 37162306a36Sopenharmony_ciset_dma_cfg(struct net_device *dev) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (lp->use_dma) { 37662306a36Sopenharmony_ci if ((lp->isa_config & ANY_ISA_DMA) == 0) { 37762306a36Sopenharmony_ci cs89_dbg(3, err, "set_dma_cfg(): no DMA\n"); 37862306a36Sopenharmony_ci return; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci if (lp->isa_config & ISA_RxDMA) { 38162306a36Sopenharmony_ci lp->curr_rx_cfg |= RX_DMA_ONLY; 38262306a36Sopenharmony_ci cs89_dbg(3, info, "set_dma_cfg(): RX_DMA_ONLY\n"); 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */ 38562306a36Sopenharmony_ci cs89_dbg(3, info, "set_dma_cfg(): AUTO_RX_DMA\n"); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int 39162306a36Sopenharmony_cidma_bufcfg(struct net_device *dev) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 39462306a36Sopenharmony_ci if (lp->use_dma) 39562306a36Sopenharmony_ci return (lp->isa_config & ANY_ISA_DMA) ? RX_DMA_ENBL : 0; 39662306a36Sopenharmony_ci else 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int 40162306a36Sopenharmony_cidma_busctl(struct net_device *dev) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci int retval = 0; 40462306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 40562306a36Sopenharmony_ci if (lp->use_dma) { 40662306a36Sopenharmony_ci if (lp->isa_config & ANY_ISA_DMA) 40762306a36Sopenharmony_ci retval |= RESET_RX_DMA; /* Reset the DMA pointer */ 40862306a36Sopenharmony_ci if (lp->isa_config & DMA_BURST) 40962306a36Sopenharmony_ci retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */ 41062306a36Sopenharmony_ci if (lp->dmasize == 64) 41162306a36Sopenharmony_ci retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */ 41262306a36Sopenharmony_ci retval |= MEMORY_ON; /* we need memory enabled to use DMA. */ 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci return retval; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void 41862306a36Sopenharmony_cidma_rx(struct net_device *dev) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 42162306a36Sopenharmony_ci struct sk_buff *skb; 42262306a36Sopenharmony_ci int status, length; 42362306a36Sopenharmony_ci unsigned char *bp = lp->rx_dma_ptr; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci status = bp[0] + (bp[1] << 8); 42662306a36Sopenharmony_ci length = bp[2] + (bp[3] << 8); 42762306a36Sopenharmony_ci bp += 4; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci cs89_dbg(5, debug, "%s: receiving DMA packet at %lx, status %x, length %x\n", 43062306a36Sopenharmony_ci dev->name, (unsigned long)bp, status, length); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if ((status & RX_OK) == 0) { 43362306a36Sopenharmony_ci count_rx_errors(status, dev); 43462306a36Sopenharmony_ci goto skip_this_frame; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Malloc up new buffer. */ 43862306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, length + 2); 43962306a36Sopenharmony_ci if (skb == NULL) { 44062306a36Sopenharmony_ci dev->stats.rx_dropped++; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* AKPM: advance bp to the next frame */ 44362306a36Sopenharmony_ciskip_this_frame: 44462306a36Sopenharmony_ci bp += (length + 3) & ~3; 44562306a36Sopenharmony_ci if (bp >= lp->end_dma_buff) 44662306a36Sopenharmony_ci bp -= lp->dmasize * 1024; 44762306a36Sopenharmony_ci lp->rx_dma_ptr = bp; 44862306a36Sopenharmony_ci return; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci skb_reserve(skb, 2); /* longword align L3 header */ 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (bp + length > lp->end_dma_buff) { 45362306a36Sopenharmony_ci int semi_cnt = lp->end_dma_buff - bp; 45462306a36Sopenharmony_ci skb_put_data(skb, bp, semi_cnt); 45562306a36Sopenharmony_ci skb_put_data(skb, lp->dma_buff, length - semi_cnt); 45662306a36Sopenharmony_ci } else { 45762306a36Sopenharmony_ci skb_put_data(skb, bp, length); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci bp += (length + 3) & ~3; 46062306a36Sopenharmony_ci if (bp >= lp->end_dma_buff) 46162306a36Sopenharmony_ci bp -= lp->dmasize*1024; 46262306a36Sopenharmony_ci lp->rx_dma_ptr = bp; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci cs89_dbg(3, info, "%s: received %d byte DMA packet of type %x\n", 46562306a36Sopenharmony_ci dev->name, length, 46662306a36Sopenharmony_ci ((skb->data[ETH_ALEN + ETH_ALEN] << 8) | 46762306a36Sopenharmony_ci skb->data[ETH_ALEN + ETH_ALEN + 1])); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 47062306a36Sopenharmony_ci netif_rx(skb); 47162306a36Sopenharmony_ci dev->stats.rx_packets++; 47262306a36Sopenharmony_ci dev->stats.rx_bytes += length; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void release_dma_buff(struct net_local *lp) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci if (lp->dma_buff) { 47862306a36Sopenharmony_ci free_pages((unsigned long)(lp->dma_buff), 47962306a36Sopenharmony_ci get_order(lp->dmasize * 1024)); 48062306a36Sopenharmony_ci lp->dma_buff = NULL; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci#endif /* ALLOW_DMA */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void 48762306a36Sopenharmony_cicontrol_dc_dc(struct net_device *dev, int on_not_off) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 49062306a36Sopenharmony_ci unsigned int selfcontrol; 49162306a36Sopenharmony_ci unsigned long timenow = jiffies; 49262306a36Sopenharmony_ci /* control the DC to DC convertor in the SelfControl register. 49362306a36Sopenharmony_ci * Note: This is hooked up to a general purpose pin, might not 49462306a36Sopenharmony_ci * always be a DC to DC convertor. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ 49862306a36Sopenharmony_ci if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) 49962306a36Sopenharmony_ci selfcontrol |= HCB1; 50062306a36Sopenharmony_ci else 50162306a36Sopenharmony_ci selfcontrol &= ~HCB1; 50262306a36Sopenharmony_ci writereg(dev, PP_SelfCTL, selfcontrol); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Wait for the DC/DC converter to power up - 500ms */ 50562306a36Sopenharmony_ci while (time_before(jiffies, timenow + HZ)) 50662306a36Sopenharmony_ci ; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* send a test packet - return true if carrier bits are ok */ 51062306a36Sopenharmony_cistatic int 51162306a36Sopenharmony_cisend_test_pkt(struct net_device *dev) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 51462306a36Sopenharmony_ci char test_packet[] = { 51562306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51662306a36Sopenharmony_ci 0, 46, /* A 46 in network order */ 51762306a36Sopenharmony_ci 0, 0, /* DSAP=0 & SSAP=0 fields */ 51862306a36Sopenharmony_ci 0xf3, 0 /* Control (Test Req + P bit set) */ 51962306a36Sopenharmony_ci }; 52062306a36Sopenharmony_ci unsigned long timenow = jiffies; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci memcpy(test_packet, dev->dev_addr, ETH_ALEN); 52562306a36Sopenharmony_ci memcpy(test_packet + ETH_ALEN, dev->dev_addr, ETH_ALEN); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci iowrite16(TX_AFTER_ALL, lp->virt_addr + TX_CMD_PORT); 52862306a36Sopenharmony_ci iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Test to see if the chip has allocated memory for the packet */ 53162306a36Sopenharmony_ci while (time_before(jiffies, timenow + 5)) 53262306a36Sopenharmony_ci if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW) 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci if (time_after_eq(jiffies, timenow + 5)) 53562306a36Sopenharmony_ci return 0; /* this shouldn't happen */ 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* Write the contents of the packet */ 53862306a36Sopenharmony_ci writewords(lp, TX_FRAME_PORT, test_packet, (ETH_ZLEN + 1) >> 1); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cs89_dbg(1, debug, "Sending test packet "); 54162306a36Sopenharmony_ci /* wait a couple of jiffies for packet to be received */ 54262306a36Sopenharmony_ci for (timenow = jiffies; time_before(jiffies, timenow + 3);) 54362306a36Sopenharmony_ci ; 54462306a36Sopenharmony_ci if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { 54562306a36Sopenharmony_ci cs89_dbg(1, cont, "succeeded\n"); 54662306a36Sopenharmony_ci return 1; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci cs89_dbg(1, cont, "failed\n"); 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci#define DETECTED_NONE 0 55362306a36Sopenharmony_ci#define DETECTED_RJ45H 1 55462306a36Sopenharmony_ci#define DETECTED_RJ45F 2 55562306a36Sopenharmony_ci#define DETECTED_AUI 3 55662306a36Sopenharmony_ci#define DETECTED_BNC 4 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int 55962306a36Sopenharmony_cidetect_tp(struct net_device *dev) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 56262306a36Sopenharmony_ci unsigned long timenow = jiffies; 56362306a36Sopenharmony_ci int fdx; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* If connected to another full duplex capable 10-Base-T card 56862306a36Sopenharmony_ci * the link pulses seem to be lost when the auto detect bit in 56962306a36Sopenharmony_ci * the LineCTL is set. To overcome this the auto detect bit will 57062306a36Sopenharmony_ci * be cleared whilst testing the 10-Base-T interface. This would 57162306a36Sopenharmony_ci * not be necessary for the sparrow chip but is simpler to do it 57262306a36Sopenharmony_ci * anyway. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci writereg(dev, PP_LineCTL, lp->linectl & ~AUI_ONLY); 57562306a36Sopenharmony_ci control_dc_dc(dev, 0); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Delay for the hardware to work out if the TP cable is present 57862306a36Sopenharmony_ci * - 150ms 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_ci for (timenow = jiffies; time_before(jiffies, timenow + 15);) 58162306a36Sopenharmony_ci ; 58262306a36Sopenharmony_ci if ((readreg(dev, PP_LineST) & LINK_OK) == 0) 58362306a36Sopenharmony_ci return DETECTED_NONE; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (lp->chip_type == CS8900) { 58662306a36Sopenharmony_ci switch (lp->force & 0xf0) { 58762306a36Sopenharmony_ci#if 0 58862306a36Sopenharmony_ci case FORCE_AUTO: 58962306a36Sopenharmony_ci pr_info("%s: cs8900 doesn't autonegotiate\n", 59062306a36Sopenharmony_ci dev->name); 59162306a36Sopenharmony_ci return DETECTED_NONE; 59262306a36Sopenharmony_ci#endif 59362306a36Sopenharmony_ci /* CS8900 doesn't support AUTO, change to HALF*/ 59462306a36Sopenharmony_ci case FORCE_AUTO: 59562306a36Sopenharmony_ci lp->force &= ~FORCE_AUTO; 59662306a36Sopenharmony_ci lp->force |= FORCE_HALF; 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci case FORCE_HALF: 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case FORCE_FULL: 60162306a36Sopenharmony_ci writereg(dev, PP_TestCTL, 60262306a36Sopenharmony_ci readreg(dev, PP_TestCTL) | FDX_8900); 60362306a36Sopenharmony_ci break; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci fdx = readreg(dev, PP_TestCTL) & FDX_8900; 60662306a36Sopenharmony_ci } else { 60762306a36Sopenharmony_ci switch (lp->force & 0xf0) { 60862306a36Sopenharmony_ci case FORCE_AUTO: 60962306a36Sopenharmony_ci lp->auto_neg_cnf = AUTO_NEG_ENABLE; 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci case FORCE_HALF: 61262306a36Sopenharmony_ci lp->auto_neg_cnf = 0; 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case FORCE_FULL: 61562306a36Sopenharmony_ci lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX; 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { 62262306a36Sopenharmony_ci pr_info("%s: negotiating duplex...\n", dev->name); 62362306a36Sopenharmony_ci while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { 62462306a36Sopenharmony_ci if (time_after(jiffies, timenow + 4000)) { 62562306a36Sopenharmony_ci pr_err("**** Full / half duplex auto-negotiation timed out ****\n"); 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci if (fdx) 63362306a36Sopenharmony_ci return DETECTED_RJ45F; 63462306a36Sopenharmony_ci else 63562306a36Sopenharmony_ci return DETECTED_RJ45H; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int 63962306a36Sopenharmony_cidetect_bnc(struct net_device *dev) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: Attempting BNC\n", dev->name); 64462306a36Sopenharmony_ci control_dc_dc(dev, 1); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (send_test_pkt(dev)) 64962306a36Sopenharmony_ci return DETECTED_BNC; 65062306a36Sopenharmony_ci else 65162306a36Sopenharmony_ci return DETECTED_NONE; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int 65562306a36Sopenharmony_cidetect_aui(struct net_device *dev) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: Attempting AUI\n", dev->name); 66062306a36Sopenharmony_ci control_dc_dc(dev, 0); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (send_test_pkt(dev)) 66562306a36Sopenharmony_ci return DETECTED_AUI; 66662306a36Sopenharmony_ci else 66762306a36Sopenharmony_ci return DETECTED_NONE; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/* We have a good packet(s), get it/them out of the buffers. */ 67162306a36Sopenharmony_cistatic void 67262306a36Sopenharmony_cinet_rx(struct net_device *dev) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 67562306a36Sopenharmony_ci struct sk_buff *skb; 67662306a36Sopenharmony_ci int status, length; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci status = ioread16(lp->virt_addr + RX_FRAME_PORT); 67962306a36Sopenharmony_ci length = ioread16(lp->virt_addr + RX_FRAME_PORT); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if ((status & RX_OK) == 0) { 68262306a36Sopenharmony_ci count_rx_errors(status, dev); 68362306a36Sopenharmony_ci return; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Malloc up new buffer. */ 68762306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, length + 2); 68862306a36Sopenharmony_ci if (skb == NULL) { 68962306a36Sopenharmony_ci dev->stats.rx_dropped++; 69062306a36Sopenharmony_ci return; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci skb_reserve(skb, 2); /* longword align L3 header */ 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci readwords(lp, RX_FRAME_PORT, skb_put(skb, length), length >> 1); 69562306a36Sopenharmony_ci if (length & 1) 69662306a36Sopenharmony_ci skb->data[length-1] = ioread16(lp->virt_addr + RX_FRAME_PORT); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci cs89_dbg(3, debug, "%s: received %d byte packet of type %x\n", 69962306a36Sopenharmony_ci dev->name, length, 70062306a36Sopenharmony_ci (skb->data[ETH_ALEN + ETH_ALEN] << 8) | 70162306a36Sopenharmony_ci skb->data[ETH_ALEN + ETH_ALEN + 1]); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 70462306a36Sopenharmony_ci netif_rx(skb); 70562306a36Sopenharmony_ci dev->stats.rx_packets++; 70662306a36Sopenharmony_ci dev->stats.rx_bytes += length; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci/* The typical workload of the driver: 71062306a36Sopenharmony_ci * Handle the network interface interrupts. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic irqreturn_t net_interrupt(int irq, void *dev_id) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct net_device *dev = dev_id; 71662306a36Sopenharmony_ci struct net_local *lp; 71762306a36Sopenharmony_ci int status; 71862306a36Sopenharmony_ci int handled = 0; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci lp = netdev_priv(dev); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* we MUST read all the events out of the ISQ, otherwise we'll never 72362306a36Sopenharmony_ci * get interrupted again. As a consequence, we can't have any limit 72462306a36Sopenharmony_ci * on the number of times we loop in the interrupt handler. The 72562306a36Sopenharmony_ci * hardware guarantees that eventually we'll run out of events. Of 72662306a36Sopenharmony_ci * course, if you're on a slow machine, and packets are arriving 72762306a36Sopenharmony_ci * faster than you can read them off, you're screwed. Hasta la 72862306a36Sopenharmony_ci * vista, baby! 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci while ((status = ioread16(lp->virt_addr + ISQ_PORT))) { 73162306a36Sopenharmony_ci cs89_dbg(4, debug, "%s: event=%04x\n", dev->name, status); 73262306a36Sopenharmony_ci handled = 1; 73362306a36Sopenharmony_ci switch (status & ISQ_EVENT_MASK) { 73462306a36Sopenharmony_ci case ISQ_RECEIVER_EVENT: 73562306a36Sopenharmony_ci /* Got a packet(s). */ 73662306a36Sopenharmony_ci net_rx(dev); 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci case ISQ_TRANSMITTER_EVENT: 73962306a36Sopenharmony_ci dev->stats.tx_packets++; 74062306a36Sopenharmony_ci netif_wake_queue(dev); /* Inform upper layers. */ 74162306a36Sopenharmony_ci if ((status & (TX_OK | 74262306a36Sopenharmony_ci TX_LOST_CRS | 74362306a36Sopenharmony_ci TX_SQE_ERROR | 74462306a36Sopenharmony_ci TX_LATE_COL | 74562306a36Sopenharmony_ci TX_16_COL)) != TX_OK) { 74662306a36Sopenharmony_ci if ((status & TX_OK) == 0) 74762306a36Sopenharmony_ci dev->stats.tx_errors++; 74862306a36Sopenharmony_ci if (status & TX_LOST_CRS) 74962306a36Sopenharmony_ci dev->stats.tx_carrier_errors++; 75062306a36Sopenharmony_ci if (status & TX_SQE_ERROR) 75162306a36Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 75262306a36Sopenharmony_ci if (status & TX_LATE_COL) 75362306a36Sopenharmony_ci dev->stats.tx_window_errors++; 75462306a36Sopenharmony_ci if (status & TX_16_COL) 75562306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci break; 75862306a36Sopenharmony_ci case ISQ_BUFFER_EVENT: 75962306a36Sopenharmony_ci if (status & READY_FOR_TX) { 76062306a36Sopenharmony_ci /* we tried to transmit a packet earlier, 76162306a36Sopenharmony_ci * but inexplicably ran out of buffers. 76262306a36Sopenharmony_ci * That shouldn't happen since we only ever 76362306a36Sopenharmony_ci * load one packet. Shrug. Do the right 76462306a36Sopenharmony_ci * thing anyway. 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_ci netif_wake_queue(dev); /* Inform upper layers. */ 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci if (status & TX_UNDERRUN) { 76962306a36Sopenharmony_ci cs89_dbg(0, err, "%s: transmit underrun\n", 77062306a36Sopenharmony_ci dev->name); 77162306a36Sopenharmony_ci lp->send_underrun++; 77262306a36Sopenharmony_ci if (lp->send_underrun == 3) 77362306a36Sopenharmony_ci lp->send_cmd = TX_AFTER_381; 77462306a36Sopenharmony_ci else if (lp->send_underrun == 6) 77562306a36Sopenharmony_ci lp->send_cmd = TX_AFTER_ALL; 77662306a36Sopenharmony_ci /* transmit cycle is done, although 77762306a36Sopenharmony_ci * frame wasn't transmitted - this 77862306a36Sopenharmony_ci * avoids having to wait for the upper 77962306a36Sopenharmony_ci * layers to timeout on us, in the 78062306a36Sopenharmony_ci * event of a tx underrun 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci netif_wake_queue(dev); /* Inform upper layers. */ 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci#if ALLOW_DMA 78562306a36Sopenharmony_ci if (lp->use_dma && (status & RX_DMA)) { 78662306a36Sopenharmony_ci int count = readreg(dev, PP_DmaFrameCnt); 78762306a36Sopenharmony_ci while (count) { 78862306a36Sopenharmony_ci cs89_dbg(5, debug, 78962306a36Sopenharmony_ci "%s: receiving %d DMA frames\n", 79062306a36Sopenharmony_ci dev->name, count); 79162306a36Sopenharmony_ci if (count > 1) 79262306a36Sopenharmony_ci cs89_dbg(2, debug, 79362306a36Sopenharmony_ci "%s: receiving %d DMA frames\n", 79462306a36Sopenharmony_ci dev->name, count); 79562306a36Sopenharmony_ci dma_rx(dev); 79662306a36Sopenharmony_ci if (--count == 0) 79762306a36Sopenharmony_ci count = readreg(dev, PP_DmaFrameCnt); 79862306a36Sopenharmony_ci if (count > 0) 79962306a36Sopenharmony_ci cs89_dbg(2, debug, 80062306a36Sopenharmony_ci "%s: continuing with %d DMA frames\n", 80162306a36Sopenharmony_ci dev->name, count); 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci#endif 80562306a36Sopenharmony_ci break; 80662306a36Sopenharmony_ci case ISQ_RX_MISS_EVENT: 80762306a36Sopenharmony_ci dev->stats.rx_missed_errors += (status >> 6); 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci case ISQ_TX_COL_EVENT: 81062306a36Sopenharmony_ci dev->stats.collisions += (status >> 6); 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci return IRQ_RETVAL(handled); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/* Open/initialize the board. This is called (in the current kernel) 81862306a36Sopenharmony_ci sometime after booting when the 'ifconfig' program is run. 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci This routine should set everything up anew at each open, even 82162306a36Sopenharmony_ci registers that "should" only need to be set once at boot, so that 82262306a36Sopenharmony_ci there is non-reboot way to recover if something goes wrong. 82362306a36Sopenharmony_ci*/ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/* AKPM: do we need to do any locking here? */ 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic int 82862306a36Sopenharmony_cinet_open(struct net_device *dev) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 83162306a36Sopenharmony_ci int result = 0; 83262306a36Sopenharmony_ci int i; 83362306a36Sopenharmony_ci int ret; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (dev->irq < 2) { 83662306a36Sopenharmony_ci /* Allow interrupts to be generated by the chip */ 83762306a36Sopenharmony_ci/* Cirrus' release had this: */ 83862306a36Sopenharmony_ci#if 0 83962306a36Sopenharmony_ci writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); 84062306a36Sopenharmony_ci#endif 84162306a36Sopenharmony_ci/* And 2.3.47 had this: */ 84262306a36Sopenharmony_ci writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci for (i = 2; i < CS8920_NO_INTS; i++) { 84562306a36Sopenharmony_ci if ((1 << i) & lp->irq_map) { 84662306a36Sopenharmony_ci if (request_irq(i, net_interrupt, 0, dev->name, 84762306a36Sopenharmony_ci dev) == 0) { 84862306a36Sopenharmony_ci dev->irq = i; 84962306a36Sopenharmony_ci write_irq(dev, lp->chip_type, i); 85062306a36Sopenharmony_ci /* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */ 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (i >= CS8920_NO_INTS) { 85762306a36Sopenharmony_ci writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ 85862306a36Sopenharmony_ci pr_err("can't get an interrupt\n"); 85962306a36Sopenharmony_ci ret = -EAGAIN; 86062306a36Sopenharmony_ci goto bad_out; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci } else { 86362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_ISA) 86462306a36Sopenharmony_ci if (((1 << dev->irq) & lp->irq_map) == 0) { 86562306a36Sopenharmony_ci pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", 86662306a36Sopenharmony_ci dev->name, dev->irq, lp->irq_map); 86762306a36Sopenharmony_ci ret = -EAGAIN; 86862306a36Sopenharmony_ci goto bad_out; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci#endif 87162306a36Sopenharmony_ci/* FIXME: Cirrus' release had this: */ 87262306a36Sopenharmony_ci writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ); 87362306a36Sopenharmony_ci/* And 2.3.47 had this: */ 87462306a36Sopenharmony_ci#if 0 87562306a36Sopenharmony_ci writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); 87662306a36Sopenharmony_ci#endif 87762306a36Sopenharmony_ci write_irq(dev, lp->chip_type, dev->irq); 87862306a36Sopenharmony_ci ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev); 87962306a36Sopenharmony_ci if (ret) { 88062306a36Sopenharmony_ci pr_err("request_irq(%d) failed\n", dev->irq); 88162306a36Sopenharmony_ci goto bad_out; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci#if ALLOW_DMA 88662306a36Sopenharmony_ci if (lp->use_dma && (lp->isa_config & ANY_ISA_DMA)) { 88762306a36Sopenharmony_ci unsigned long flags; 88862306a36Sopenharmony_ci lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, 88962306a36Sopenharmony_ci get_order(lp->dmasize * 1024)); 89062306a36Sopenharmony_ci if (!lp->dma_buff) { 89162306a36Sopenharmony_ci pr_err("%s: cannot get %dK memory for DMA\n", 89262306a36Sopenharmony_ci dev->name, lp->dmasize); 89362306a36Sopenharmony_ci goto release_irq; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: dma %lx %lx\n", 89662306a36Sopenharmony_ci dev->name, 89762306a36Sopenharmony_ci (unsigned long)lp->dma_buff, 89862306a36Sopenharmony_ci (unsigned long)isa_virt_to_bus(lp->dma_buff)); 89962306a36Sopenharmony_ci if ((unsigned long)lp->dma_buff >= MAX_DMA_ADDRESS || 90062306a36Sopenharmony_ci !dma_page_eq(lp->dma_buff, 90162306a36Sopenharmony_ci lp->dma_buff + lp->dmasize * 1024 - 1)) { 90262306a36Sopenharmony_ci pr_err("%s: not usable as DMA buffer\n", dev->name); 90362306a36Sopenharmony_ci goto release_irq; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */ 90662306a36Sopenharmony_ci if (request_dma(dev->dma, dev->name)) { 90762306a36Sopenharmony_ci pr_err("%s: cannot get dma channel %d\n", 90862306a36Sopenharmony_ci dev->name, dev->dma); 90962306a36Sopenharmony_ci goto release_irq; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci write_dma(dev, lp->chip_type, dev->dma); 91262306a36Sopenharmony_ci lp->rx_dma_ptr = lp->dma_buff; 91362306a36Sopenharmony_ci lp->end_dma_buff = lp->dma_buff + lp->dmasize * 1024; 91462306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 91562306a36Sopenharmony_ci disable_dma(dev->dma); 91662306a36Sopenharmony_ci clear_dma_ff(dev->dma); 91762306a36Sopenharmony_ci set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */ 91862306a36Sopenharmony_ci set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff)); 91962306a36Sopenharmony_ci set_dma_count(dev->dma, lp->dmasize * 1024); 92062306a36Sopenharmony_ci enable_dma(dev->dma); 92162306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci#endif /* ALLOW_DMA */ 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* set the Ethernet address */ 92662306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN / 2; i++) 92762306a36Sopenharmony_ci writereg(dev, PP_IA + i * 2, 92862306a36Sopenharmony_ci (dev->dev_addr[i * 2] | 92962306a36Sopenharmony_ci (dev->dev_addr[i * 2 + 1] << 8))); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* while we're testing the interface, leave interrupts disabled */ 93262306a36Sopenharmony_ci writereg(dev, PP_BusCTL, MEMORY_ON); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */ 93562306a36Sopenharmony_ci if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && 93662306a36Sopenharmony_ci (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) 93762306a36Sopenharmony_ci lp->linectl = LOW_RX_SQUELCH; 93862306a36Sopenharmony_ci else 93962306a36Sopenharmony_ci lp->linectl = 0; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* check to make sure that they have the "right" hardware available */ 94262306a36Sopenharmony_ci switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) { 94362306a36Sopenharmony_ci case A_CNF_MEDIA_10B_T: 94462306a36Sopenharmony_ci result = lp->adapter_cnf & A_CNF_10B_T; 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci case A_CNF_MEDIA_AUI: 94762306a36Sopenharmony_ci result = lp->adapter_cnf & A_CNF_AUI; 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci case A_CNF_MEDIA_10B_2: 95062306a36Sopenharmony_ci result = lp->adapter_cnf & A_CNF_10B_2; 95162306a36Sopenharmony_ci break; 95262306a36Sopenharmony_ci default: 95362306a36Sopenharmony_ci result = lp->adapter_cnf & (A_CNF_10B_T | 95462306a36Sopenharmony_ci A_CNF_AUI | 95562306a36Sopenharmony_ci A_CNF_10B_2); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci if (!result) { 95862306a36Sopenharmony_ci pr_err("%s: EEPROM is configured for unavailable media\n", 95962306a36Sopenharmony_ci dev->name); 96062306a36Sopenharmony_cirelease_dma: 96162306a36Sopenharmony_ci#if ALLOW_DMA 96262306a36Sopenharmony_ci free_dma(dev->dma); 96362306a36Sopenharmony_cirelease_irq: 96462306a36Sopenharmony_ci release_dma_buff(lp); 96562306a36Sopenharmony_ci#endif 96662306a36Sopenharmony_ci writereg(dev, PP_LineCTL, 96762306a36Sopenharmony_ci readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); 96862306a36Sopenharmony_ci free_irq(dev->irq, dev); 96962306a36Sopenharmony_ci ret = -EAGAIN; 97062306a36Sopenharmony_ci goto bad_out; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* set the hardware to the configured choice */ 97462306a36Sopenharmony_ci switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) { 97562306a36Sopenharmony_ci case A_CNF_MEDIA_10B_T: 97662306a36Sopenharmony_ci result = detect_tp(dev); 97762306a36Sopenharmony_ci if (result == DETECTED_NONE) { 97862306a36Sopenharmony_ci pr_warn("%s: 10Base-T (RJ-45) has no cable\n", 97962306a36Sopenharmony_ci dev->name); 98062306a36Sopenharmony_ci if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ 98162306a36Sopenharmony_ci result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */ 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci break; 98462306a36Sopenharmony_ci case A_CNF_MEDIA_AUI: 98562306a36Sopenharmony_ci result = detect_aui(dev); 98662306a36Sopenharmony_ci if (result == DETECTED_NONE) { 98762306a36Sopenharmony_ci pr_warn("%s: 10Base-5 (AUI) has no cable\n", dev->name); 98862306a36Sopenharmony_ci if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ 98962306a36Sopenharmony_ci result = DETECTED_AUI; /* Yes! I don't care if I see a carrier */ 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci break; 99262306a36Sopenharmony_ci case A_CNF_MEDIA_10B_2: 99362306a36Sopenharmony_ci result = detect_bnc(dev); 99462306a36Sopenharmony_ci if (result == DETECTED_NONE) { 99562306a36Sopenharmony_ci pr_warn("%s: 10Base-2 (BNC) has no cable\n", dev->name); 99662306a36Sopenharmony_ci if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ 99762306a36Sopenharmony_ci result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */ 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci case A_CNF_MEDIA_AUTO: 100162306a36Sopenharmony_ci writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); 100262306a36Sopenharmony_ci if (lp->adapter_cnf & A_CNF_10B_T) { 100362306a36Sopenharmony_ci result = detect_tp(dev); 100462306a36Sopenharmony_ci if (result != DETECTED_NONE) 100562306a36Sopenharmony_ci break; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci if (lp->adapter_cnf & A_CNF_AUI) { 100862306a36Sopenharmony_ci result = detect_aui(dev); 100962306a36Sopenharmony_ci if (result != DETECTED_NONE) 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci if (lp->adapter_cnf & A_CNF_10B_2) { 101362306a36Sopenharmony_ci result = detect_bnc(dev); 101462306a36Sopenharmony_ci if (result != DETECTED_NONE) 101562306a36Sopenharmony_ci break; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci pr_err("%s: no media detected\n", dev->name); 101862306a36Sopenharmony_ci goto release_dma; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci switch (result) { 102162306a36Sopenharmony_ci case DETECTED_NONE: 102262306a36Sopenharmony_ci pr_err("%s: no network cable attached to configured media\n", 102362306a36Sopenharmony_ci dev->name); 102462306a36Sopenharmony_ci goto release_dma; 102562306a36Sopenharmony_ci case DETECTED_RJ45H: 102662306a36Sopenharmony_ci pr_info("%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci case DETECTED_RJ45F: 102962306a36Sopenharmony_ci pr_info("%s: using full-duplex 10Base-T (RJ-45)\n", dev->name); 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci case DETECTED_AUI: 103262306a36Sopenharmony_ci pr_info("%s: using 10Base-5 (AUI)\n", dev->name); 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci case DETECTED_BNC: 103562306a36Sopenharmony_ci pr_info("%s: using 10Base-2 (BNC)\n", dev->name); 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* Turn on both receive and transmit operations */ 104062306a36Sopenharmony_ci writereg(dev, PP_LineCTL, 104162306a36Sopenharmony_ci readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* Receive only error free packets addressed to this card */ 104462306a36Sopenharmony_ci lp->rx_mode = 0; 104562306a36Sopenharmony_ci writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (lp->isa_config & STREAM_TRANSFER) 105062306a36Sopenharmony_ci lp->curr_rx_cfg |= RX_STREAM_ENBL; 105162306a36Sopenharmony_ci#if ALLOW_DMA 105262306a36Sopenharmony_ci set_dma_cfg(dev); 105362306a36Sopenharmony_ci#endif 105462306a36Sopenharmony_ci writereg(dev, PP_RxCFG, lp->curr_rx_cfg); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci writereg(dev, PP_TxCFG, (TX_LOST_CRS_ENBL | 105762306a36Sopenharmony_ci TX_SQE_ERROR_ENBL | 105862306a36Sopenharmony_ci TX_OK_ENBL | 105962306a36Sopenharmony_ci TX_LATE_COL_ENBL | 106062306a36Sopenharmony_ci TX_JBR_ENBL | 106162306a36Sopenharmony_ci TX_ANY_COL_ENBL | 106262306a36Sopenharmony_ci TX_16_COL_ENBL)); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci writereg(dev, PP_BufCFG, (READY_FOR_TX_ENBL | 106562306a36Sopenharmony_ci RX_MISS_COUNT_OVRFLOW_ENBL | 106662306a36Sopenharmony_ci#if ALLOW_DMA 106762306a36Sopenharmony_ci dma_bufcfg(dev) | 106862306a36Sopenharmony_ci#endif 106962306a36Sopenharmony_ci TX_COL_COUNT_OVRFLOW_ENBL | 107062306a36Sopenharmony_ci TX_UNDERRUN_ENBL)); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* now that we've got our act together, enable everything */ 107362306a36Sopenharmony_ci writereg(dev, PP_BusCTL, (ENABLE_IRQ 107462306a36Sopenharmony_ci | (dev->mem_start ? MEMORY_ON : 0) /* turn memory on */ 107562306a36Sopenharmony_ci#if ALLOW_DMA 107662306a36Sopenharmony_ci | dma_busctl(dev) 107762306a36Sopenharmony_ci#endif 107862306a36Sopenharmony_ci )); 107962306a36Sopenharmony_ci netif_start_queue(dev); 108062306a36Sopenharmony_ci cs89_dbg(1, debug, "net_open() succeeded\n"); 108162306a36Sopenharmony_ci return 0; 108262306a36Sopenharmony_cibad_out: 108362306a36Sopenharmony_ci return ret; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci/* The inverse routine to net_open(). */ 108762306a36Sopenharmony_cistatic int 108862306a36Sopenharmony_cinet_close(struct net_device *dev) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci#if ALLOW_DMA 109162306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 109262306a36Sopenharmony_ci#endif 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci netif_stop_queue(dev); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci writereg(dev, PP_RxCFG, 0); 109762306a36Sopenharmony_ci writereg(dev, PP_TxCFG, 0); 109862306a36Sopenharmony_ci writereg(dev, PP_BufCFG, 0); 109962306a36Sopenharmony_ci writereg(dev, PP_BusCTL, 0); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci free_irq(dev->irq, dev); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci#if ALLOW_DMA 110462306a36Sopenharmony_ci if (lp->use_dma && lp->dma) { 110562306a36Sopenharmony_ci free_dma(dev->dma); 110662306a36Sopenharmony_ci release_dma_buff(lp); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci#endif 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Update the statistics here. */ 111162306a36Sopenharmony_ci return 0; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci/* Get the current statistics. 111562306a36Sopenharmony_ci * This may be called with the card open or closed. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_cistatic struct net_device_stats * 111862306a36Sopenharmony_cinet_get_stats(struct net_device *dev) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 112162306a36Sopenharmony_ci unsigned long flags; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 112462306a36Sopenharmony_ci /* Update the statistics from the device registers. */ 112562306a36Sopenharmony_ci dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); 112662306a36Sopenharmony_ci dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6); 112762306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci return &dev->stats; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic void net_timeout(struct net_device *dev, unsigned int txqueue) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci /* If we get here, some higher level has decided we are broken. 113562306a36Sopenharmony_ci There should really be a "kick me" function call instead. */ 113662306a36Sopenharmony_ci cs89_dbg(0, err, "%s: transmit timed out, %s?\n", 113762306a36Sopenharmony_ci dev->name, 113862306a36Sopenharmony_ci tx_done(dev) ? "IRQ conflict" : "network cable problem"); 113962306a36Sopenharmony_ci /* Try to restart the adaptor. */ 114062306a36Sopenharmony_ci netif_wake_queue(dev); 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 114662306a36Sopenharmony_ci unsigned long flags; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci cs89_dbg(3, debug, "%s: sent %d byte packet of type %x\n", 114962306a36Sopenharmony_ci dev->name, skb->len, 115062306a36Sopenharmony_ci ((skb->data[ETH_ALEN + ETH_ALEN] << 8) | 115162306a36Sopenharmony_ci skb->data[ETH_ALEN + ETH_ALEN + 1])); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* keep the upload from being interrupted, since we 115462306a36Sopenharmony_ci * ask the chip to start transmitting before the 115562306a36Sopenharmony_ci * whole packet has been completely uploaded. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 115962306a36Sopenharmony_ci netif_stop_queue(dev); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* initiate a transmit sequence */ 116262306a36Sopenharmony_ci iowrite16(lp->send_cmd, lp->virt_addr + TX_CMD_PORT); 116362306a36Sopenharmony_ci iowrite16(skb->len, lp->virt_addr + TX_LEN_PORT); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* Test to see if the chip has allocated memory for the packet */ 116662306a36Sopenharmony_ci if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { 116762306a36Sopenharmony_ci /* Gasp! It hasn't. But that shouldn't happen since 116862306a36Sopenharmony_ci * we're waiting for TxOk, so return 1 and requeue this packet. 116962306a36Sopenharmony_ci */ 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 117262306a36Sopenharmony_ci cs89_dbg(0, err, "Tx buffer not free!\n"); 117362306a36Sopenharmony_ci return NETDEV_TX_BUSY; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci /* Write the contents of the packet */ 117662306a36Sopenharmony_ci writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1); 117762306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 117862306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 117962306a36Sopenharmony_ci dev_consume_skb_any(skb); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* We DO NOT call netif_wake_queue() here. 118262306a36Sopenharmony_ci * We also DO NOT call netif_start_queue(). 118362306a36Sopenharmony_ci * 118462306a36Sopenharmony_ci * Either of these would cause another bottom half run through 118562306a36Sopenharmony_ci * net_send_packet() before this packet has fully gone out. 118662306a36Sopenharmony_ci * That causes us to hit the "Gasp!" above and the send is rescheduled. 118762306a36Sopenharmony_ci * it runs like a dog. We just return and wait for the Tx completion 118862306a36Sopenharmony_ci * interrupt handler to restart the netdevice layer 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci return NETDEV_TX_OK; 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 119762306a36Sopenharmony_ci unsigned long flags; 119862306a36Sopenharmony_ci u16 cfg; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 120162306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 120262306a36Sopenharmony_ci lp->rx_mode = RX_ALL_ACCEPT; 120362306a36Sopenharmony_ci else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) 120462306a36Sopenharmony_ci /* The multicast-accept list is initialized to accept-all, 120562306a36Sopenharmony_ci * and we rely on higher-level filtering for now. 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_ci lp->rx_mode = RX_MULTCAST_ACCEPT; 120862306a36Sopenharmony_ci else 120962306a36Sopenharmony_ci lp->rx_mode = 0; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* in promiscuous mode, we accept errored packets, 121462306a36Sopenharmony_ci * so we have to enable interrupts on them also 121562306a36Sopenharmony_ci */ 121662306a36Sopenharmony_ci cfg = lp->curr_rx_cfg; 121762306a36Sopenharmony_ci if (lp->rx_mode == RX_ALL_ACCEPT) 121862306a36Sopenharmony_ci cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL; 121962306a36Sopenharmony_ci writereg(dev, PP_RxCFG, cfg); 122062306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic int set_mac_address(struct net_device *dev, void *p) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci int i; 122662306a36Sopenharmony_ci struct sockaddr *addr = p; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (netif_running(dev)) 122962306a36Sopenharmony_ci return -EBUSY; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci eth_hw_addr_set(dev, addr->sa_data); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci cs89_dbg(0, debug, "%s: Setting MAC address to %pM\n", 123462306a36Sopenharmony_ci dev->name, dev->dev_addr); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* set the Ethernet address */ 123762306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN / 2; i++) 123862306a36Sopenharmony_ci writereg(dev, PP_IA + i * 2, 123962306a36Sopenharmony_ci (dev->dev_addr[i * 2] | 124062306a36Sopenharmony_ci (dev->dev_addr[i * 2 + 1] << 8))); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 124662306a36Sopenharmony_ci/* 124762306a36Sopenharmony_ci * Polling receive - used by netconsole and other diagnostic tools 124862306a36Sopenharmony_ci * to allow network i/o with interrupts disabled. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_cistatic void net_poll_controller(struct net_device *dev) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci disable_irq(dev->irq); 125362306a36Sopenharmony_ci net_interrupt(dev->irq, dev); 125462306a36Sopenharmony_ci enable_irq(dev->irq); 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci#endif 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic const struct net_device_ops net_ops = { 125962306a36Sopenharmony_ci .ndo_open = net_open, 126062306a36Sopenharmony_ci .ndo_stop = net_close, 126162306a36Sopenharmony_ci .ndo_tx_timeout = net_timeout, 126262306a36Sopenharmony_ci .ndo_start_xmit = net_send_packet, 126362306a36Sopenharmony_ci .ndo_get_stats = net_get_stats, 126462306a36Sopenharmony_ci .ndo_set_rx_mode = set_multicast_list, 126562306a36Sopenharmony_ci .ndo_set_mac_address = set_mac_address, 126662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 126762306a36Sopenharmony_ci .ndo_poll_controller = net_poll_controller, 126862306a36Sopenharmony_ci#endif 126962306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 127062306a36Sopenharmony_ci}; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic void __init reset_chip(struct net_device *dev) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci#if !defined(CONFIG_MACH_MX31ADS) 127562306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 127662306a36Sopenharmony_ci unsigned long reset_start_time; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* wait 30 ms */ 128162306a36Sopenharmony_ci msleep(30); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (lp->chip_type != CS8900) { 128462306a36Sopenharmony_ci /* Hardware problem requires PNP registers to be reconfigured after a reset */ 128562306a36Sopenharmony_ci iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT); 128662306a36Sopenharmony_ci iowrite8(dev->irq, lp->virt_addr + DATA_PORT); 128762306a36Sopenharmony_ci iowrite8(0, lp->virt_addr + DATA_PORT + 1); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci iowrite16(PP_CS8920_ISAMemB, lp->virt_addr + ADD_PORT); 129062306a36Sopenharmony_ci iowrite8((dev->mem_start >> 16) & 0xff, 129162306a36Sopenharmony_ci lp->virt_addr + DATA_PORT); 129262306a36Sopenharmony_ci iowrite8((dev->mem_start >> 8) & 0xff, 129362306a36Sopenharmony_ci lp->virt_addr + DATA_PORT + 1); 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* Wait until the chip is reset */ 129762306a36Sopenharmony_ci reset_start_time = jiffies; 129862306a36Sopenharmony_ci while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && 129962306a36Sopenharmony_ci time_before(jiffies, reset_start_time + 2)) 130062306a36Sopenharmony_ci ; 130162306a36Sopenharmony_ci#endif /* !CONFIG_MACH_MX31ADS */ 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci/* This is the real probe routine. 130562306a36Sopenharmony_ci * Linux has a history of friendly device probes on the ISA bus. 130662306a36Sopenharmony_ci * A good device probes avoids doing writes, and 130762306a36Sopenharmony_ci * verifies that the correct device exists and functions. 130862306a36Sopenharmony_ci * Return 0 on success. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_cistatic int __init 131162306a36Sopenharmony_cics89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 131462306a36Sopenharmony_ci int i; 131562306a36Sopenharmony_ci int tmp; 131662306a36Sopenharmony_ci unsigned rev_type = 0; 131762306a36Sopenharmony_ci int eeprom_buff[CHKSUM_LEN]; 131862306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 131962306a36Sopenharmony_ci int retval; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* Initialize the device structure. */ 132262306a36Sopenharmony_ci if (!modular) { 132362306a36Sopenharmony_ci memset(lp, 0, sizeof(*lp)); 132462306a36Sopenharmony_ci spin_lock_init(&lp->lock); 132562306a36Sopenharmony_ci#ifndef MODULE 132662306a36Sopenharmony_ci#if ALLOW_DMA 132762306a36Sopenharmony_ci if (g_cs89x0_dma) { 132862306a36Sopenharmony_ci lp->use_dma = 1; 132962306a36Sopenharmony_ci lp->dma = g_cs89x0_dma; 133062306a36Sopenharmony_ci lp->dmasize = 16; /* Could make this an option... */ 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci#endif 133362306a36Sopenharmony_ci lp->force = g_cs89x0_media__force; 133462306a36Sopenharmony_ci#endif 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci pr_debug("PP_addr at %p[%x]: 0x%x\n", 133862306a36Sopenharmony_ci ioaddr, ADD_PORT, ioread16(ioaddr + ADD_PORT)); 133962306a36Sopenharmony_ci iowrite16(PP_ChipID, ioaddr + ADD_PORT); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci tmp = ioread16(ioaddr + DATA_PORT); 134262306a36Sopenharmony_ci if (tmp != CHIP_EISA_ID_SIG) { 134362306a36Sopenharmony_ci pr_debug("%s: incorrect signature at %p[%x]: 0x%x!=" 134462306a36Sopenharmony_ci CHIP_EISA_ID_SIG_STR "\n", 134562306a36Sopenharmony_ci dev->name, ioaddr, DATA_PORT, tmp); 134662306a36Sopenharmony_ci retval = -ENODEV; 134762306a36Sopenharmony_ci goto out1; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci lp->virt_addr = ioaddr; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* get the chip type */ 135362306a36Sopenharmony_ci rev_type = readreg(dev, PRODUCT_ID_ADD); 135462306a36Sopenharmony_ci lp->chip_type = rev_type & ~REVISON_BITS; 135562306a36Sopenharmony_ci lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Check the chip type and revision in order to set the correct 135862306a36Sopenharmony_ci * send command. CS8920 revision C and CS8900 revision F can use 135962306a36Sopenharmony_ci * the faster send. 136062306a36Sopenharmony_ci */ 136162306a36Sopenharmony_ci lp->send_cmd = TX_AFTER_381; 136262306a36Sopenharmony_ci if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') 136362306a36Sopenharmony_ci lp->send_cmd = TX_NOW; 136462306a36Sopenharmony_ci if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') 136562306a36Sopenharmony_ci lp->send_cmd = TX_NOW; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci pr_info_once("%s\n", version); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci pr_info("%s: cs89%c0%s rev %c found at %p ", 137062306a36Sopenharmony_ci dev->name, 137162306a36Sopenharmony_ci lp->chip_type == CS8900 ? '0' : '2', 137262306a36Sopenharmony_ci lp->chip_type == CS8920M ? "M" : "", 137362306a36Sopenharmony_ci lp->chip_revision, 137462306a36Sopenharmony_ci lp->virt_addr); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci reset_chip(dev); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* Here we read the current configuration of the chip. 137962306a36Sopenharmony_ci * If there is no Extended EEPROM then the idea is to not disturb 138062306a36Sopenharmony_ci * the chip configuration, it should have been correctly setup by 138162306a36Sopenharmony_ci * automatic EEPROM read on reset. So, if the chip says it read 138262306a36Sopenharmony_ci * the EEPROM the driver will always do *something* instead of 138362306a36Sopenharmony_ci * complain that adapter_cnf is 0. 138462306a36Sopenharmony_ci */ 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == 138762306a36Sopenharmony_ci (EEPROM_OK | EEPROM_PRESENT)) { 138862306a36Sopenharmony_ci /* Load the MAC. */ 138962306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN / 2; i++) { 139062306a36Sopenharmony_ci unsigned int Addr; 139162306a36Sopenharmony_ci Addr = readreg(dev, PP_IA + i * 2); 139262306a36Sopenharmony_ci addr[i * 2] = Addr & 0xFF; 139362306a36Sopenharmony_ci addr[i * 2 + 1] = Addr >> 8; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* Load the Adapter Configuration. 139862306a36Sopenharmony_ci * Note: Barring any more specific information from some 139962306a36Sopenharmony_ci * other source (ie EEPROM+Schematics), we would not know 140062306a36Sopenharmony_ci * how to operate a 10Base2 interface on the AUI port. 140162306a36Sopenharmony_ci * However, since we do read the status of HCB1 and use 140262306a36Sopenharmony_ci * settings that always result in calls to control_dc_dc(dev,0) 140362306a36Sopenharmony_ci * a BNC interface should work if the enable pin 140462306a36Sopenharmony_ci * (dc/dc converter) is on HCB1. 140562306a36Sopenharmony_ci * It will be called AUI however. 140662306a36Sopenharmony_ci */ 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci lp->adapter_cnf = 0; 140962306a36Sopenharmony_ci i = readreg(dev, PP_LineCTL); 141062306a36Sopenharmony_ci /* Preserve the setting of the HCB1 pin. */ 141162306a36Sopenharmony_ci if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL)) 141262306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_DC_DC_POLARITY; 141362306a36Sopenharmony_ci /* Save the sqelch bit */ 141462306a36Sopenharmony_ci if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH) 141562306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH; 141662306a36Sopenharmony_ci /* Check if the card is in 10Base-t only mode */ 141762306a36Sopenharmony_ci if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0) 141862306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T; 141962306a36Sopenharmony_ci /* Check if the card is in AUI only mode */ 142062306a36Sopenharmony_ci if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY) 142162306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI; 142262306a36Sopenharmony_ci /* Check if the card is in Auto mode. */ 142362306a36Sopenharmony_ci if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET) 142462306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T | 142562306a36Sopenharmony_ci A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci cs89_dbg(1, info, "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n", 142862306a36Sopenharmony_ci dev->name, i, lp->adapter_cnf); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* IRQ. Other chips already probe, see below. */ 143162306a36Sopenharmony_ci if (lp->chip_type == CS8900) 143262306a36Sopenharmony_ci lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci pr_cont("[Cirrus EEPROM] "); 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci pr_cont("\n"); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci /* First check to see if an EEPROM is attached. */ 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) 144262306a36Sopenharmony_ci pr_warn("No EEPROM, relying on command line....\n"); 144362306a36Sopenharmony_ci else if (get_eeprom_data(dev, START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) { 144462306a36Sopenharmony_ci pr_warn("EEPROM read failed, relying on command line\n"); 144562306a36Sopenharmony_ci } else if (get_eeprom_cksum(START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) { 144662306a36Sopenharmony_ci /* Check if the chip was able to read its own configuration starting 144762306a36Sopenharmony_ci at 0 in the EEPROM*/ 144862306a36Sopenharmony_ci if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) != 144962306a36Sopenharmony_ci (EEPROM_OK | EEPROM_PRESENT)) 145062306a36Sopenharmony_ci pr_warn("Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n"); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci } else { 145362306a36Sopenharmony_ci /* This reads an extended EEPROM that is not documented 145462306a36Sopenharmony_ci * in the CS8900 datasheet. 145562306a36Sopenharmony_ci */ 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* get transmission control word but keep the autonegotiation bits */ 145862306a36Sopenharmony_ci if (!lp->auto_neg_cnf) 145962306a36Sopenharmony_ci lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET / 2]; 146062306a36Sopenharmony_ci /* Store adapter configuration */ 146162306a36Sopenharmony_ci if (!lp->adapter_cnf) 146262306a36Sopenharmony_ci lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET / 2]; 146362306a36Sopenharmony_ci /* Store ISA configuration */ 146462306a36Sopenharmony_ci lp->isa_config = eeprom_buff[ISA_CNF_OFFSET / 2]; 146562306a36Sopenharmony_ci dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET / 2] << 8; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ 146862306a36Sopenharmony_ci /* store the initial memory base address */ 146962306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN / 2; i++) { 147062306a36Sopenharmony_ci addr[i * 2] = eeprom_buff[i]; 147162306a36Sopenharmony_ci addr[i * 2 + 1] = eeprom_buff[i] >> 8; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 147462306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: new adapter_cnf: 0x%x\n", 147562306a36Sopenharmony_ci dev->name, lp->adapter_cnf); 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci /* allow them to force multiple transceivers. If they force multiple, autosense */ 147962306a36Sopenharmony_ci { 148062306a36Sopenharmony_ci int count = 0; 148162306a36Sopenharmony_ci if (lp->force & FORCE_RJ45) { 148262306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_10B_T; 148362306a36Sopenharmony_ci count++; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci if (lp->force & FORCE_AUI) { 148662306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_AUI; 148762306a36Sopenharmony_ci count++; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci if (lp->force & FORCE_BNC) { 149062306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_10B_2; 149162306a36Sopenharmony_ci count++; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci if (count > 1) 149462306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_MEDIA_AUTO; 149562306a36Sopenharmony_ci else if (lp->force & FORCE_RJ45) 149662306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_MEDIA_10B_T; 149762306a36Sopenharmony_ci else if (lp->force & FORCE_AUI) 149862306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_MEDIA_AUI; 149962306a36Sopenharmony_ci else if (lp->force & FORCE_BNC) 150062306a36Sopenharmony_ci lp->adapter_cnf |= A_CNF_MEDIA_10B_2; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci cs89_dbg(1, debug, "%s: after force 0x%x, adapter_cnf=0x%x\n", 150462306a36Sopenharmony_ci dev->name, lp->force, lp->adapter_cnf); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* FIXME: we don't set the Ethernet address on the command line. Use 151162306a36Sopenharmony_ci * ifconfig IFACE hw ether AABBCCDDEEFF 151262306a36Sopenharmony_ci */ 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci pr_info("media %s%s%s", 151562306a36Sopenharmony_ci (lp->adapter_cnf & A_CNF_10B_T) ? "RJ-45," : "", 151662306a36Sopenharmony_ci (lp->adapter_cnf & A_CNF_AUI) ? "AUI," : "", 151762306a36Sopenharmony_ci (lp->adapter_cnf & A_CNF_10B_2) ? "BNC," : ""); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci lp->irq_map = 0xffff; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* If this is a CS8900 then no pnp soft */ 152262306a36Sopenharmony_ci if (lp->chip_type != CS8900 && 152362306a36Sopenharmony_ci /* Check if the ISA IRQ has been set */ 152462306a36Sopenharmony_ci (i = readreg(dev, PP_CS8920_ISAINT) & 0xff, 152562306a36Sopenharmony_ci (i != 0 && i < CS8920_NO_INTS))) { 152662306a36Sopenharmony_ci if (!dev->irq) 152762306a36Sopenharmony_ci dev->irq = i; 152862306a36Sopenharmony_ci } else { 152962306a36Sopenharmony_ci i = lp->isa_config & INT_NO_MASK; 153062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_ISA) 153162306a36Sopenharmony_ci if (lp->chip_type == CS8900) { 153262306a36Sopenharmony_ci /* Translate the IRQ using the IRQ mapping table. */ 153362306a36Sopenharmony_ci if (i >= ARRAY_SIZE(cs8900_irq_map)) 153462306a36Sopenharmony_ci pr_err("invalid ISA interrupt number %d\n", i); 153562306a36Sopenharmony_ci else 153662306a36Sopenharmony_ci i = cs8900_irq_map[i]; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */ 153962306a36Sopenharmony_ci } else { 154062306a36Sopenharmony_ci int irq_map_buff[IRQ_MAP_LEN/2]; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA, 154362306a36Sopenharmony_ci IRQ_MAP_LEN / 2, 154462306a36Sopenharmony_ci irq_map_buff) >= 0) { 154562306a36Sopenharmony_ci if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT) 154662306a36Sopenharmony_ci lp->irq_map = ((irq_map_buff[0] >> 8) | 154762306a36Sopenharmony_ci (irq_map_buff[1] << 8)); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci#endif 155162306a36Sopenharmony_ci if (!dev->irq) 155262306a36Sopenharmony_ci dev->irq = i; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci pr_cont(" IRQ %d", dev->irq); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci#if ALLOW_DMA 155862306a36Sopenharmony_ci if (lp->use_dma) { 155962306a36Sopenharmony_ci get_dma_channel(dev); 156062306a36Sopenharmony_ci pr_cont(", DMA %d", dev->dma); 156162306a36Sopenharmony_ci } else 156262306a36Sopenharmony_ci#endif 156362306a36Sopenharmony_ci pr_cont(", programmed I/O"); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci /* print the ethernet address. */ 156662306a36Sopenharmony_ci pr_cont(", MAC %pM\n", dev->dev_addr); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci dev->netdev_ops = &net_ops; 156962306a36Sopenharmony_ci dev->watchdog_timeo = HZ; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci cs89_dbg(0, info, "cs89x0_probe1() successful\n"); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci retval = register_netdev(dev); 157462306a36Sopenharmony_ci if (retval) 157562306a36Sopenharmony_ci goto out2; 157662306a36Sopenharmony_ci return 0; 157762306a36Sopenharmony_ciout2: 157862306a36Sopenharmony_ci iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT); 157962306a36Sopenharmony_ciout1: 158062306a36Sopenharmony_ci return retval; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_ISA) 158462306a36Sopenharmony_ci/* 158562306a36Sopenharmony_ci * This function converts the I/O port address used by the cs89x0_probe() and 158662306a36Sopenharmony_ci * init_module() functions to the I/O memory address used by the 158762306a36Sopenharmony_ci * cs89x0_probe1() function. 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_cistatic int __init 159062306a36Sopenharmony_cics89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modular) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev); 159362306a36Sopenharmony_ci int ret; 159462306a36Sopenharmony_ci void __iomem *io_mem; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (!lp) 159762306a36Sopenharmony_ci return -ENOMEM; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci dev->base_addr = ioport; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) { 160262306a36Sopenharmony_ci ret = -EBUSY; 160362306a36Sopenharmony_ci goto out; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci io_mem = ioport_map(ioport & ~3, NETCARD_IO_EXTENT); 160762306a36Sopenharmony_ci if (!io_mem) { 160862306a36Sopenharmony_ci ret = -ENOMEM; 160962306a36Sopenharmony_ci goto release; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* if they give us an odd I/O address, then do ONE write to 161362306a36Sopenharmony_ci * the address port, to get it back to address zero, where we 161462306a36Sopenharmony_ci * expect to find the EISA signature word. An IO with a base of 0x3 161562306a36Sopenharmony_ci * will skip the test for the ADD_PORT. 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci if (ioport & 1) { 161862306a36Sopenharmony_ci cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport); 161962306a36Sopenharmony_ci if ((ioport & 2) != 2) { 162062306a36Sopenharmony_ci if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) != 162162306a36Sopenharmony_ci ADD_SIG) { 162262306a36Sopenharmony_ci pr_err("%s: bad signature 0x%x\n", 162362306a36Sopenharmony_ci dev->name, ioread16(io_mem + ADD_PORT)); 162462306a36Sopenharmony_ci ret = -ENODEV; 162562306a36Sopenharmony_ci goto unmap; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci ret = cs89x0_probe1(dev, io_mem, modular); 163162306a36Sopenharmony_ci if (!ret) 163262306a36Sopenharmony_ci goto out; 163362306a36Sopenharmony_ciunmap: 163462306a36Sopenharmony_ci ioport_unmap(io_mem); 163562306a36Sopenharmony_cirelease: 163662306a36Sopenharmony_ci release_region(ioport, NETCARD_IO_EXTENT); 163762306a36Sopenharmony_ciout: 163862306a36Sopenharmony_ci return ret; 163962306a36Sopenharmony_ci} 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci#ifndef MODULE 164262306a36Sopenharmony_ci/* Check for a network adaptor of this type, and return '0' iff one exists. 164362306a36Sopenharmony_ci * If dev->base_addr == 0, probe all likely locations. 164462306a36Sopenharmony_ci * If dev->base_addr == 1, always return failure. 164562306a36Sopenharmony_ci * If dev->base_addr == 2, allocate space for the device and return success 164662306a36Sopenharmony_ci * (detachable devices only). 164762306a36Sopenharmony_ci * Return 0 on success. 164862306a36Sopenharmony_ci */ 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistruct net_device * __init cs89x0_probe(int unit) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); 165362306a36Sopenharmony_ci unsigned *port; 165462306a36Sopenharmony_ci int err = 0; 165562306a36Sopenharmony_ci int irq; 165662306a36Sopenharmony_ci int io; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (!dev) 165962306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci sprintf(dev->name, "eth%d", unit); 166262306a36Sopenharmony_ci netdev_boot_setup_check(dev); 166362306a36Sopenharmony_ci io = dev->base_addr; 166462306a36Sopenharmony_ci irq = dev->irq; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci if (io > 0x1ff) { /* Check a single specified location. */ 166962306a36Sopenharmony_ci err = cs89x0_ioport_probe(dev, io, 0); 167062306a36Sopenharmony_ci } else if (io != 0) { /* Don't probe at all. */ 167162306a36Sopenharmony_ci err = -ENXIO; 167262306a36Sopenharmony_ci } else { 167362306a36Sopenharmony_ci for (port = netcard_portlist; *port; port++) { 167462306a36Sopenharmony_ci if (cs89x0_ioport_probe(dev, *port, 0) == 0) 167562306a36Sopenharmony_ci break; 167662306a36Sopenharmony_ci dev->irq = irq; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci if (!*port) 167962306a36Sopenharmony_ci err = -ENODEV; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci if (err) 168262306a36Sopenharmony_ci goto out; 168362306a36Sopenharmony_ci return dev; 168462306a36Sopenharmony_ciout: 168562306a36Sopenharmony_ci free_netdev(dev); 168662306a36Sopenharmony_ci pr_warn("no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); 168762306a36Sopenharmony_ci return ERR_PTR(err); 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci#else 169062306a36Sopenharmony_cistatic struct net_device *dev_cs89x0; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci/* Support the 'debug' module parm even if we're compiled for non-debug to 169362306a36Sopenharmony_ci * avoid breaking someone's startup scripts 169462306a36Sopenharmony_ci */ 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cistatic int io; 169762306a36Sopenharmony_cistatic int irq; 169862306a36Sopenharmony_cistatic int debug; 169962306a36Sopenharmony_cistatic char media[8]; 170062306a36Sopenharmony_cistatic int duplex = -1; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cistatic int use_dma; /* These generate unused var warnings if ALLOW_DMA = 0 */ 170362306a36Sopenharmony_cistatic int dma; 170462306a36Sopenharmony_cistatic int dmasize = 16; /* or 64 */ 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_cimodule_param_hw(io, int, ioport, 0); 170762306a36Sopenharmony_cimodule_param_hw(irq, int, irq, 0); 170862306a36Sopenharmony_cimodule_param(debug, int, 0); 170962306a36Sopenharmony_cimodule_param_string(media, media, sizeof(media), 0); 171062306a36Sopenharmony_cimodule_param(duplex, int, 0); 171162306a36Sopenharmony_cimodule_param_hw(dma , int, dma, 0); 171262306a36Sopenharmony_cimodule_param(dmasize , int, 0); 171362306a36Sopenharmony_cimodule_param(use_dma , int, 0); 171462306a36Sopenharmony_ciMODULE_PARM_DESC(io, "cs89x0 I/O base address"); 171562306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "cs89x0 IRQ number"); 171662306a36Sopenharmony_ci#if DEBUGGING 171762306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)"); 171862306a36Sopenharmony_ci#else 171962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "(ignored)"); 172062306a36Sopenharmony_ci#endif 172162306a36Sopenharmony_ciMODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)"); 172262306a36Sopenharmony_ci/* No other value than -1 for duplex seems to be currently interpreted */ 172362306a36Sopenharmony_ciMODULE_PARM_DESC(duplex, "(ignored)"); 172462306a36Sopenharmony_ci#if ALLOW_DMA 172562306a36Sopenharmony_ciMODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0"); 172662306a36Sopenharmony_ciMODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0"); 172762306a36Sopenharmony_ciMODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)"); 172862306a36Sopenharmony_ci#else 172962306a36Sopenharmony_ciMODULE_PARM_DESC(dma , "(ignored)"); 173062306a36Sopenharmony_ciMODULE_PARM_DESC(dmasize , "(ignored)"); 173162306a36Sopenharmony_ciMODULE_PARM_DESC(use_dma , "(ignored)"); 173262306a36Sopenharmony_ci#endif 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ciMODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton"); 173562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci/* 173862306a36Sopenharmony_ci * media=t - specify media type 173962306a36Sopenharmony_ci * or media=2 174062306a36Sopenharmony_ci * or media=aui 174162306a36Sopenharmony_ci * or medai=auto 174262306a36Sopenharmony_ci * duplex=0 - specify forced half/full/autonegotiate duplex 174362306a36Sopenharmony_ci * debug=# - debug level 174462306a36Sopenharmony_ci * 174562306a36Sopenharmony_ci * Default Chip Configuration: 174662306a36Sopenharmony_ci * DMA Burst = enabled 174762306a36Sopenharmony_ci * IOCHRDY Enabled = enabled 174862306a36Sopenharmony_ci * UseSA = enabled 174962306a36Sopenharmony_ci * CS8900 defaults to half-duplex if not specified on command-line 175062306a36Sopenharmony_ci * CS8920 defaults to autoneg if not specified on command-line 175162306a36Sopenharmony_ci * Use reset defaults for other config parameters 175262306a36Sopenharmony_ci * 175362306a36Sopenharmony_ci * Assumptions: 175462306a36Sopenharmony_ci * media type specified is supported (circuitry is present) 175562306a36Sopenharmony_ci * if memory address is > 1MB, then required mem decode hw is present 175662306a36Sopenharmony_ci * if 10B-2, then agent other than driver will enable DC/DC converter 175762306a36Sopenharmony_ci * (hw or software util) 175862306a36Sopenharmony_ci */ 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic int __init cs89x0_isa_init_module(void) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct net_device *dev; 176362306a36Sopenharmony_ci struct net_local *lp; 176462306a36Sopenharmony_ci int ret = 0; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci#if DEBUGGING 176762306a36Sopenharmony_ci net_debug = debug; 176862306a36Sopenharmony_ci#else 176962306a36Sopenharmony_ci debug = 0; 177062306a36Sopenharmony_ci#endif 177162306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct net_local)); 177262306a36Sopenharmony_ci if (!dev) 177362306a36Sopenharmony_ci return -ENOMEM; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci dev->irq = irq; 177662306a36Sopenharmony_ci dev->base_addr = io; 177762306a36Sopenharmony_ci lp = netdev_priv(dev); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci#if ALLOW_DMA 178062306a36Sopenharmony_ci if (use_dma) { 178162306a36Sopenharmony_ci lp->use_dma = use_dma; 178262306a36Sopenharmony_ci lp->dma = dma; 178362306a36Sopenharmony_ci lp->dmasize = dmasize; 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci#endif 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci spin_lock_init(&lp->lock); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* boy, they'd better get these right */ 179062306a36Sopenharmony_ci if (!strcmp(media, "rj45")) 179162306a36Sopenharmony_ci lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; 179262306a36Sopenharmony_ci else if (!strcmp(media, "aui")) 179362306a36Sopenharmony_ci lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; 179462306a36Sopenharmony_ci else if (!strcmp(media, "bnc")) 179562306a36Sopenharmony_ci lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; 179662306a36Sopenharmony_ci else 179762306a36Sopenharmony_ci lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (duplex == -1) 180062306a36Sopenharmony_ci lp->auto_neg_cnf = AUTO_NEG_ENABLE; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (io == 0) { 180362306a36Sopenharmony_ci pr_err("Module autoprobing not allowed\n"); 180462306a36Sopenharmony_ci pr_err("Append io=0xNNN\n"); 180562306a36Sopenharmony_ci ret = -EPERM; 180662306a36Sopenharmony_ci goto out; 180762306a36Sopenharmony_ci } else if (io <= 0x1ff) { 180862306a36Sopenharmony_ci ret = -ENXIO; 180962306a36Sopenharmony_ci goto out; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci#if ALLOW_DMA 181362306a36Sopenharmony_ci if (use_dma && dmasize != 16 && dmasize != 64) { 181462306a36Sopenharmony_ci pr_err("dma size must be either 16K or 64K, not %dK\n", 181562306a36Sopenharmony_ci dmasize); 181662306a36Sopenharmony_ci ret = -EPERM; 181762306a36Sopenharmony_ci goto out; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci#endif 182062306a36Sopenharmony_ci ret = cs89x0_ioport_probe(dev, io, 1); 182162306a36Sopenharmony_ci if (ret) 182262306a36Sopenharmony_ci goto out; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci dev_cs89x0 = dev; 182562306a36Sopenharmony_ci return 0; 182662306a36Sopenharmony_ciout: 182762306a36Sopenharmony_ci free_netdev(dev); 182862306a36Sopenharmony_ci return ret; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_cimodule_init(cs89x0_isa_init_module); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cistatic void __exit cs89x0_isa_cleanup_module(void) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci struct net_local *lp = netdev_priv(dev_cs89x0); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci unregister_netdev(dev_cs89x0); 183762306a36Sopenharmony_ci iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT); 183862306a36Sopenharmony_ci ioport_unmap(lp->virt_addr); 183962306a36Sopenharmony_ci release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); 184062306a36Sopenharmony_ci free_netdev(dev_cs89x0); 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_cimodule_exit(cs89x0_isa_cleanup_module); 184362306a36Sopenharmony_ci#endif /* MODULE */ 184462306a36Sopenharmony_ci#endif /* CONFIG_CS89x0_ISA */ 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CS89x0_PLATFORM) 184762306a36Sopenharmony_cistatic int __init cs89x0_platform_probe(struct platform_device *pdev) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); 185062306a36Sopenharmony_ci void __iomem *virt_addr; 185162306a36Sopenharmony_ci int err; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (!dev) 185462306a36Sopenharmony_ci return -ENOMEM; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci dev->irq = platform_get_irq(pdev, 0); 185762306a36Sopenharmony_ci if (dev->irq < 0) { 185862306a36Sopenharmony_ci err = dev->irq; 185962306a36Sopenharmony_ci goto free; 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci virt_addr = devm_platform_ioremap_resource(pdev, 0); 186362306a36Sopenharmony_ci if (IS_ERR(virt_addr)) { 186462306a36Sopenharmony_ci err = PTR_ERR(virt_addr); 186562306a36Sopenharmony_ci goto free; 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci err = cs89x0_probe1(dev, virt_addr, 0); 186962306a36Sopenharmony_ci if (err) { 187062306a36Sopenharmony_ci dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n"); 187162306a36Sopenharmony_ci goto free; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci platform_set_drvdata(pdev, dev); 187562306a36Sopenharmony_ci return 0; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cifree: 187862306a36Sopenharmony_ci free_netdev(dev); 187962306a36Sopenharmony_ci return err; 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cistatic int cs89x0_platform_remove(struct platform_device *pdev) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* This platform_get_resource() call will not return NULL, because 188762306a36Sopenharmony_ci * the same call in cs89x0_platform_probe() has returned a non NULL 188862306a36Sopenharmony_ci * value. 188962306a36Sopenharmony_ci */ 189062306a36Sopenharmony_ci unregister_netdev(dev); 189162306a36Sopenharmony_ci free_netdev(dev); 189262306a36Sopenharmony_ci return 0; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused cs89x0_match[] = { 189662306a36Sopenharmony_ci { .compatible = "cirrus,cs8900", }, 189762306a36Sopenharmony_ci { .compatible = "cirrus,cs8920", }, 189862306a36Sopenharmony_ci { }, 189962306a36Sopenharmony_ci}; 190062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs89x0_match); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_cistatic struct platform_driver cs89x0_driver = { 190362306a36Sopenharmony_ci .driver = { 190462306a36Sopenharmony_ci .name = DRV_NAME, 190562306a36Sopenharmony_ci .of_match_table = of_match_ptr(cs89x0_match), 190662306a36Sopenharmony_ci }, 190762306a36Sopenharmony_ci .remove = cs89x0_platform_remove, 190862306a36Sopenharmony_ci}; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_cimodule_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci#endif /* CONFIG_CS89x0_PLATFORM */ 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 191562306a36Sopenharmony_ciMODULE_DESCRIPTION("Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 network driver"); 191662306a36Sopenharmony_ciMODULE_AUTHOR("Russell Nelson <nelson@crynwr.com>"); 1917