1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216 |
- /*
- net-3-driver for the SKNET MCA-based cards
- This is an extension to the Linux operating system, and is covered by the
- same GNU General Public License that covers that work.
- Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
- alfred.arnold@lancom.de)
- This driver is based both on the 3C523 driver and the SK_G16 driver.
- paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
- Hans-Peter Messmer for the basic Microchannel stuff
-
- 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
- for help on Ethernet driver programming
- 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
- for documentation on the AM7990 LANCE
- 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
- for documentation on the Junior board
- 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
- documentation on the MC2 bord
-
- A big thank you to the S&K support for providing me so quickly with
- documentation!
- Also see http://www.syskonnect.com/
- Missing things:
- -> set debug level via ioctl instead of compile-time switches
- -> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
- are probably nonsense
- History:
- May 16th, 1999
- startup
- May 22st, 1999
- added private structure, methods
- begun building data structures in RAM
- May 23nd, 1999
- can receive frames, send frames
- May 24th, 1999
- modularized initialization of LANCE
- loadable as module
- still Tx problem :-(
- May 26th, 1999
- MC2 works
- support for multiple devices
- display media type for MC2+
- May 28th, 1999
- fixed problem in GetLANCE leaving interrupts turned off
- increase TX queue to 4 packets to improve send performance
- May 29th, 1999
- a few corrections in statistics, caught rcvr overruns
- reinitialization of LANCE/board in critical situations
- MCA info implemented
- implemented LANCE multicast filter
- Jun 6th, 1999
- additions for Linux 2.2
- Dec 25th, 1999
- unfortunately there seem to be newer MC2+ boards that react
- on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
- in questionable cases...
- Dec 28th, 1999
- integrated patches from David Weinehall & Bill Wendling for 2.3
- kernels (isa_...functions). Things are defined in a way that
- it still works with 2.0.x 8-)
- Dec 30th, 1999
- added handling of the remaining interrupt conditions. That
- should cure the spurious hangs.
- Jan 30th, 2000
- newer kernels automatically probe more than one board, so the
- 'startslot' as a variable is also needed here
- June 1st, 2000
- added changes for recent 2.3 kernels
- *************************************************************************/
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/time.h>
- #include <linux/mca-legacy.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
- #include <linux/bitops.h>
- #include <asm/processor.h>
- #include <asm/io.h>
- #define _SK_MCA_DRIVER_
- #include "sk_mca.h"
- /* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
- static char *MediaNames[Media_Count] =
- { "10Base2", "10BaseT", "10Base5", "Unknown" };
- static unsigned char poly[] =
- { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
- };
- /* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
- /* dump parts of shared memory - only needed during debugging */
- #ifdef DEBUG
- static void dumpmem(struct net_device *dev, u32 start, u32 len)
- {
- skmca_priv *priv = netdev_priv(dev);
- int z;
- for (z = 0; z < len; z++) {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(priv->base + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
- }
- /* print exact time - ditto */
- static void PrTime(void)
- {
- struct timeval tv;
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
- }
- #endif
- /* deduce resources out of POS registers */
- static void __init getaddrs(int slot, int junior, int *base, int *irq,
- skmca_medium * medium)
- {
- u_char pos0, pos1, pos2;
- if (junior) {
- pos0 = mca_read_stored_pos(slot, 2);
- *base = ((pos0 & 0x0e) << 13) + 0xc0000;
- *irq = ((pos0 & 0x10) >> 4) + 10;
- *medium = Media_Unknown;
- } else {
- /* reset POS 104 Bits 0+1 so the shared memory region goes to the
- configured area between 640K and 1M. Afterwards, enable the MC2.
- I really don't know what rode SK to do this... */
- mca_write_pos(slot, 4,
- mca_read_stored_pos(slot, 4) & 0xfc);
- mca_write_pos(slot, 2,
- mca_read_stored_pos(slot, 2) | 0x01);
- pos1 = mca_read_stored_pos(slot, 3);
- pos2 = mca_read_stored_pos(slot, 4);
- *base = ((pos1 & 0x07) << 14) + 0xc0000;
- switch (pos2 & 0x0c) {
- case 0:
- *irq = 3;
- break;
- case 4:
- *irq = 5;
- break;
- case 8:
- *irq = -10;
- break;
- case 12:
- *irq = -11;
- break;
- }
- *medium = (pos2 >> 6) & 3;
- }
- }
- /* check for both cards:
- When the MC2 is turned off, it was configured for more than 15MB RAM,
- is disabled and won't get detected using the standard probe. We
- therefore have to scan the slots manually :-( */
- static int __init dofind(int *junior, int firstslot)
- {
- int slot;
- unsigned int id;
- for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
- id = mca_read_stored_pos(slot, 0)
- + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
- *junior = 0;
- if (id == SKNET_MCA_ID)
- return slot;
- *junior = 1;
- if (id == SKNET_JUNIOR_MCA_ID)
- return slot;
- }
- return MCA_NOTFOUND;
- }
- /* reset the whole board */
- static void ResetBoard(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- writeb(CTRL_RESET_ON, priv->ctrladdr);
- udelay(10);
- writeb(CTRL_RESET_OFF, priv->ctrladdr);
- }
- /* wait for LANCE interface to become not busy */
- static int WaitLANCE(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- int t = 0;
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
- STAT_IO_BUSY) {
- udelay(1);
- if (++t > 1000) {
- printk("%s: LANCE access timeout", dev->name);
- return 0;
- }
- }
- return 1;
- }
- /* set LANCE register - must be atomic */
- static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
- {
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
- /* disable interrupts */
- spin_lock_irqsave(&priv->lock, flags);
- /* wait until no transfer is pending */
- WaitLANCE(dev);
- /* transfer register address to RAP */
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- /* transfer data to register */
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
- writew(value, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- /* reenable interrupts */
- spin_unlock_irqrestore(&priv->lock, flags);
- }
- /* get LANCE register */
- static u16 GetLANCE(struct net_device *dev, u16 addr)
- {
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
- unsigned int res;
- /* disable interrupts */
- spin_lock_irqsave(&priv->lock, flags);
- /* wait until no transfer is pending */
- WaitLANCE(dev);
- /* transfer register address to RAP */
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- /* transfer data from register */
- writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- res = readw(priv->ioregaddr);
- /* reenable interrupts */
- spin_unlock_irqrestore(&priv->lock, flags);
- return res;
- }
- /* build up descriptors in shared RAM */
- static void InitDscrs(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- u32 bufaddr;
- /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
- are always 0. */
- bufaddr = RAM_DATABASE;
- {
- LANCE_TxDescr descr;
- int z;
- for (z = 0; z < TXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = 0;
- descr.Len = 0xf000;
- descr.Status = 0;
- memcpy_toio(priv->base + RAM_TXBASE +
- (z * sizeof(LANCE_TxDescr)), &descr,
- sizeof(LANCE_TxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
- /* do the same for the Rx descriptors */
- {
- LANCE_RxDescr descr;
- int z;
- for (z = 0; z < RXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = RXDSCR_FLAGS_OWN;
- descr.MaxLen = -RAM_BUFSIZE;
- descr.Len = 0;
- memcpy_toio(priv->base + RAM_RXBASE +
- (z * sizeof(LANCE_RxDescr)), &descr,
- sizeof(LANCE_RxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
- }
- /* calculate the hash bit position for a given multicast address
- taken more or less directly from the AMD datasheet... */
- static void UpdateCRC(unsigned char *CRC, int bit)
- {
- int j;
- /* shift CRC one bit */
- memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
- CRC[0] = 0;
- /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
- if (bit ^ CRC[32])
- for (j = 0; j < 32; j++)
- CRC[j] ^= poly[j];
- }
- static unsigned int GetHash(char *address)
- {
- unsigned char CRC[33];
- int i, byte, hashcode;
- /* a multicast address has bit 0 in the first byte set */
- if ((address[0] & 1) == 0)
- return -1;
- /* initialize CRC */
- memset(CRC, 1, sizeof(CRC));
- /* loop through address bits */
- for (byte = 0; byte < 6; byte++)
- for (i = 0; i < 8; i++)
- UpdateCRC(CRC, (address[byte] >> i) & 1);
- /* hashcode is the 6 least significant bits of the CRC */
- hashcode = 0;
- for (i = 0; i < 6; i++)
- hashcode = (hashcode << 1) + CRC[i];
- return hashcode;
- }
- /* feed ready-built initialization block into LANCE */
- static void InitLANCE(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- /* build up descriptors. */
- InitDscrs(dev);
- /* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
- reset out pointers too. */
- priv->nextrx = 0;
- /* no TX descriptors active */
- priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
- /* set up the LANCE bus control register - constant for SKnet boards */
- SetLANCE(dev, LANCE_CSR3,
- CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
- /* write address of initialization block into LANCE */
- SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
- SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
- /* we don't get ready until the LANCE has read the init block */
- netif_stop_queue(dev);
- /* let LANCE read the initialization block. LANCE is ready
- when we receive the corresponding interrupt. */
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
- }
- /* stop the LANCE so we can reinitialize it */
- static void StopLANCE(struct net_device *dev)
- {
- /* can't take frames any more */
- netif_stop_queue(dev);
- /* disable interrupts, stop it */
- SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
- }
- /* initialize card and LANCE for proper operation */
- static void InitBoard(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
- /* Lay out the shared RAM - first we create the init block for the LANCE.
- We do not overwrite it later because we need it again when we switch
- promiscous mode on/off. */
- block.Mode = 0;
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- memcpy(block.PAdr, dev->dev_addr, 6);
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
- block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
- /* initialize LANCE. Implicitly sets up other structures in RAM. */
- InitLANCE(dev);
- }
- /* deinitialize card and LANCE */
- static void DeinitBoard(struct net_device *dev)
- {
- /* stop LANCE */
- StopLANCE(dev);
- /* reset board */
- ResetBoard(dev);
- }
- /* probe for device's irq */
- static int __init ProbeIRQ(struct net_device *dev)
- {
- unsigned long imaskval, njiffies, irq;
- u16 csr0val;
- /* enable all interrupts */
- imaskval = probe_irq_on();
- /* initialize the board. Wait for interrupt 'Initialization done'. */
- ResetBoard(dev);
- InitBoard(dev);
- njiffies = jiffies + HZ;
- do {
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
- /* turn of interrupts again */
- irq = probe_irq_off(imaskval);
- /* if we found something, ack the interrupt */
- if (irq)
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
- /* back to idle state */
- DeinitBoard(dev);
- return irq;
- }
- /* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
- /* LANCE has read initialization block -> start it */
- static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
- {
- /* now we're ready to transmit */
- netif_wake_queue(dev);
- /* reset IDON bit, start LANCE */
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
- return GetLANCE(dev, LANCE_CSR0);
- }
- /* did we lose blocks due to a FIFO overrun ? */
- static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
- {
- skmca_priv *priv = netdev_priv(dev);
- /* update statistics */
- priv->stat.rx_fifo_errors++;
- /* reset MISS bit */
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
- return GetLANCE(dev, LANCE_CSR0);
- }
- /* receive interrupt */
- static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
- {
- skmca_priv *priv = netdev_priv(dev);
- LANCE_RxDescr descr;
- unsigned int descraddr;
- /* run through queue until we reach a descriptor we do not own */
- descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
- while (1) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_RxDescr));
- /* if we reach a descriptor we do not own, we're done */
- if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
- break;
- #ifdef DEBUG
- PrTime();
- printk("Receive packet on descr %d len %d\n", priv->nextrx,
- descr.Len);
- #endif
- /* erroneous packet ? */
- if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
- priv->stat.rx_errors++;
- if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_crc_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_frame_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
- priv->stat.rx_fifo_errors++;
- }
- /* good packet ? */
- else {
- struct sk_buff *skb;
- skb = dev_alloc_skb(descr.Len + 2);
- if (skb == NULL)
- priv->stat.rx_dropped++;
- else {
- memcpy_fromio(skb_put(skb, descr.Len),
- priv->base +
- descr.LowAddr, descr.Len);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += descr.Len;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
- }
- /* give descriptor back to LANCE */
- descr.Len = 0;
- descr.Flags |= RXDSCR_FLAGS_OWN;
- /* update descriptor in shared RAM */
- memcpy_toio(priv->base + descraddr, &descr,
- sizeof(LANCE_RxDescr));
- /* go to next descriptor */
- priv->nextrx++;
- descraddr += sizeof(LANCE_RxDescr);
- if (priv->nextrx >= RXCOUNT) {
- priv->nextrx = 0;
- descraddr = RAM_RXBASE;
- }
- }
- /* reset RINT bit */
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
- return GetLANCE(dev, LANCE_CSR0);
- }
- /* transmit interrupt */
- static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
- {
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int descraddr;
- /* check descriptors at most until no busy one is left */
- descraddr =
- RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
- while (priv->txbusy > 0) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_TxDescr));
- /* if the LANCE still owns this one, we've worked out all sent packets */
- if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
- break;
- #ifdef DEBUG
- PrTime();
- printk("Send packet done on descr %d\n", priv->nexttxdone);
- #endif
- /* update statistics */
- if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
- priv->stat.tx_packets++;
- priv->stat.tx_bytes++;
- } else {
- priv->stat.tx_errors++;
- if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
- priv->stat.tx_fifo_errors++;
- InitLANCE(dev);
- }
- else
- if ((descr.Status & TXDSCR_STATUS_LCOL) !=
- 0) priv->stat.tx_window_errors++;
- else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
- priv->stat.tx_carrier_errors++;
- else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
- priv->stat.tx_aborted_errors++;
- }
- /* go to next descriptor */
- priv->nexttxdone++;
- descraddr += sizeof(LANCE_TxDescr);
- if (priv->nexttxdone >= TXCOUNT) {
- priv->nexttxdone = 0;
- descraddr = RAM_TXBASE;
- }
- priv->txbusy--;
- }
- /* reset TX interrupt bit */
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
- oldcsr0 = GetLANCE(dev, LANCE_CSR0);
- /* at least one descriptor is freed. Therefore we can accept
- a new one */
- /* inform upper layers we're in business again */
- netif_wake_queue(dev);
- return oldcsr0;
- }
- /* general interrupt entry */
- static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
- {
- struct net_device *dev = (struct net_device *) device;
- u16 csr0val;
- /* read CSR0 to get interrupt cause */
- csr0val = GetLANCE(dev, LANCE_CSR0);
- /* in case we're not meant... */
- if ((csr0val & CSR0_INTR) == 0)
- return IRQ_NONE;
- #if 0
- set_bit(LINK_STATE_RXSEM, &dev->state);
- #endif
- /* loop through the interrupt bits until everything is clear */
- do {
- if ((csr0val & CSR0_IDON) != 0)
- csr0val = irqstart_handler(dev, csr0val);
- if ((csr0val & CSR0_RINT) != 0)
- csr0val = irqrx_handler(dev, csr0val);
- if ((csr0val & CSR0_MISS) != 0)
- csr0val = irqmiss_handler(dev, csr0val);
- if ((csr0val & CSR0_TINT) != 0)
- csr0val = irqtx_handler(dev, csr0val);
- if ((csr0val & CSR0_MERR) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- if ((csr0val & CSR0_BABL) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- }
- while ((csr0val & CSR0_INTR) != 0);
- #if 0
- clear_bit(LINK_STATE_RXSEM, &dev->state);
- #endif
- return IRQ_HANDLED;
- }
- /* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
- /* MCA info */
- static int skmca_getinfo(char *buf, int slot, void *d)
- {
- int len = 0, i;
- struct net_device *dev = (struct net_device *) d;
- skmca_priv *priv;
- /* can't say anything about an uninitialized device... */
- if (dev == NULL)
- return len;
- priv = netdev_priv(dev);
- /* print info */
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len +=
- sprintf(buf + len, "Transceiver: %s\n",
- MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i++)
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- buf[len++] = '\n';
- buf[len] = 0;
- return len;
- }
- /* open driver. Means also initialization and start of LANCE */
- static int skmca_open(struct net_device *dev)
- {
- int result;
- skmca_priv *priv = netdev_priv(dev);
- /* register resources - only necessary for IRQ */
- result =
- request_irq(priv->realirq, irq_handler,
- SA_SHIRQ | SA_SAMPLE_RANDOM, "sk_mca", dev);
- if (result != 0) {
- printk("%s: failed to register irq %d\n", dev->name,
- dev->irq);
- return result;
- }
- dev->irq = priv->realirq;
- /* set up the card and LANCE */
- InitBoard(dev);
- /* set up flags */
- netif_start_queue(dev);
- return 0;
- }
- /* close driver. Shut down board and free allocated resources */
- static int skmca_close(struct net_device *dev)
- {
- /* turn off board */
- DeinitBoard(dev);
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
- return 0;
- }
- /* transmit a block. */
- static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int address;
- int tmplen, retval = 0;
- unsigned long flags;
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
- our card is stuck an we should reset it. We'll do this completely: */
- if (skb == NULL) {
- DeinitBoard(dev);
- InitBoard(dev);
- return 0; /* don't try to free the block here ;-) */
- }
- /* is there space in the Tx queue ? If no, the upper layer gave us a
- packet in spite of us not being ready and is really in trouble.
- We'll do the dropping for him: */
- if (priv->txbusy >= TXCOUNT) {
- priv->stat.tx_dropped++;
- retval = -EIO;
- goto tx_done;
- }
- /* get TX descriptor */
- address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
- memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
- /* enter packet length as 2s complement - assure minimum length */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- descr.Len = 65536 - tmplen;
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger... */
- if (tmplen > skb->len) {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = 0, l = strlen(fill);
- while (destoffs < tmplen) {
- memcpy_toio(priv->base + descr.LowAddr +
- destoffs, fill, l);
- destoffs += l;
- }
- }
- /* do the real data copying */
- memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
- /* hand descriptor over to LANCE - this is the first and last chunk */
- descr.Flags =
- TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
- #ifdef DEBUG
- PrTime();
- printk("Send packet on descr %d len %d\n", priv->nexttxput,
- skb->len);
- #endif
- /* one more descriptor busy */
- spin_lock_irqsave(&priv->lock, flags);
- priv->nexttxput++;
- if (priv->nexttxput >= TXCOUNT)
- priv->nexttxput = 0;
- priv->txbusy++;
- /* are we saturated ? */
- if (priv->txbusy >= TXCOUNT)
- netif_stop_queue(dev);
- /* write descriptor back to RAM */
- memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
- /* if no descriptors were active, give the LANCE a hint to read it
- immediately */
- if (priv->txbusy == 0)
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
- spin_unlock_irqrestore(&priv->lock, flags);
- tx_done:
- dev_kfree_skb(skb);
- return retval;
- }
- /* return pointer to Ethernet statistics */
- static struct net_device_stats *skmca_stats(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- return &(priv->stat);
- }
- /* switch receiver mode. We use the LANCE's multicast filter to prefilter
- multicast addresses. */
- static void skmca_set_multicast_list(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
- /* first stop the LANCE... */
- StopLANCE(dev);
- /* ...then modify the initialization block... */
- memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- else
- block.Mode &= ~LANCE_INIT_PROM;
- if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */
- memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
- } else { /* get selected/no multicasts */
- struct dev_mc_list *mptr;
- int code;
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
- code = GetHash(mptr->dmi_addr);
- block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
- }
- }
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
- /* ...then reinit LANCE with the correct flags */
- InitLANCE(dev);
- }
- /* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
- static int startslot; /* counts through slots when probing multiple devices */
- static void cleanup_card(struct net_device *dev)
- {
- skmca_priv *priv = netdev_priv(dev);
- DeinitBoard(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- iounmap(priv->base);
- mca_mark_as_unused(priv->slot);
- mca_set_adapter_procfn(priv->slot, NULL, NULL);
- }
- struct net_device * __init skmca_probe(int unit)
- {
- struct net_device *dev;
- int force_detect = 0;
- int junior, slot, i;
- int base = 0, irq = 0;
- skmca_priv *priv;
- skmca_medium medium;
- int err;
- /* can't work without an MCA bus ;-) */
- if (MCA_bus == 0)
- return ERR_PTR(-ENODEV);
- dev = alloc_etherdev(sizeof(skmca_priv));
- if (!dev)
- return ERR_PTR(-ENOMEM);
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
- SET_MODULE_OWNER(dev);
- /* start address of 1 --> forced detection */
- if (dev->mem_start == 1)
- force_detect = 1;
- /* search through slots */
- base = dev->mem_start;
- irq = dev->base_addr;
- for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
- /* deduce card addresses */
- getaddrs(slot, junior, &base, &irq, &medium);
- /* slot already in use ? */
- if (mca_is_adapter_used(slot))
- continue;
- /* were we looking for something different ? */
- if (dev->irq && dev->irq != irq)
- continue;
- if (dev->mem_start && dev->mem_start != base)
- continue;
- /* found something that matches */
- break;
- }
- /* nothing found ? */
- if (slot == -1) {
- free_netdev(dev);
- return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
- }
- /* make procfs entries */
- if (junior)
- mca_set_adapter_name(slot,
- "SKNET junior MC2 Ethernet Adapter");
- else
- mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
- mca_mark_as_used(slot);
- /* announce success */
- printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
- junior ? "Junior MC2" : "MC2+", slot + 1);
- priv = netdev_priv(dev);
- priv->base = ioremap(base, 0x4000);
- if (!priv->base) {
- mca_set_adapter_procfn(slot, NULL, NULL);
- mca_mark_as_unused(slot);
- free_netdev(dev);
- return ERR_PTR(-ENOMEM);
- }
- priv->slot = slot;
- priv->macbase = priv->base + 0x3fc0;
- priv->ioregaddr = priv->base + 0x3ff0;
- priv->ctrladdr = priv->base + 0x3ff2;
- priv->cmdaddr = priv->base + 0x3ff3;
- priv->medium = medium;
- memset(&priv->stat, 0, sizeof(struct net_device_stats));
- spin_lock_init(&priv->lock);
- /* set base + irq for this device (irq not allocated so far) */
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + 0x4000;
- /* autoprobe ? */
- if (irq < 0) {
- int nirq;
- printk
- ("%s: ambigous POS bit combination, must probe for IRQ...\n",
- dev->name);
- nirq = ProbeIRQ(dev);
- if (nirq <= 0)
- printk("%s: IRQ probe failed, assuming IRQ %d",
- dev->name, priv->realirq = -irq);
- else
- priv->realirq = nirq;
- } else
- priv->realirq = irq;
- /* set methods */
- dev->open = skmca_open;
- dev->stop = skmca_close;
- dev->hard_start_xmit = skmca_tx;
- dev->do_ioctl = NULL;
- dev->get_stats = skmca_stats;
- dev->set_multicast_list = skmca_set_multicast_list;
- dev->flags |= IFF_MULTICAST;
- /* copy out MAC address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(priv->macbase + (i << 1));
- /* print config */
- printk("%s: IRQ %d, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
- /* reset board */
- ResetBoard(dev);
- startslot = slot + 1;
- err = register_netdev(dev);
- if (err) {
- cleanup_card(dev);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
- }
- /* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
- #ifdef MODULE
- MODULE_LICENSE("GPL");
- #define DEVMAX 5
- static struct net_device *moddevs[DEVMAX];
- int init_module(void)
- {
- int z;
- startslot = 0;
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = skmca_probe(-1);
- if (IS_ERR(dev))
- break;
- moddevs[z] = dev;
- }
- if (!z)
- return -EIO;
- return 0;
- }
- void cleanup_module(void)
- {
- int z;
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = moddevs[z];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
- }
- #endif /* MODULE */
|