/* atarilance.c: Ethernet driver for VME Lance cards on the Atari */ /* Written 1995/96 by Roman Hodek (Roman.Hodek@informatik.uni-erlangen.de)
This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference.
This drivers was written with the following sources of reference: - The driver for the Riebl Lance card by the TU Vienna. - The modified TUW driver for PAM's VME cards - The PC-Linux driver for Lance cards (but this is for bus master cards, not the shared memory ones) - The Amiga Ariadne driver
v1.0: (in 1.2.13pl4/0.9.13) Initial version v1.1: (in 1.2.13pl5) more comments deleted some debugging stuff optimized register access (keep AREG pointing to CSR0) following AMD, CSR0_STRT should be set only after IDON is detected use memcpy() for data transfers, that also employs long word moves better probe procedure for 24-bit systems non-VME-RieblCards need extra delays in memcpy must also do write test, since 0xfxe00000 may hit ROM use 8/32 tx/rx buffers, which should give better NFS performance; this is made possible by shifting the last packet buffer after the RieblCard reserved area v1.2: (in 1.2.13pl8) again fixed probing for the Falcon; 0xfe01000 hits phys. 0x00010000 and thus RAM, in case of no Lance found all memory contents have to be restored! Now possible to compile as module. v1.3: 03/30/96 Jes Sorensen, Roman (in 1.3) Several little 1.3 adaptions When the lance is stopped it jumps back into little-endian mode. It is therefore necessary to put it back where it belongs, in big endian mode, in order to make things work. This might be the reason why multicast-mode didn't work before, but I'm not able to test it as I only got an Amiga (we had similar problems with the A2065 driver).
/* These define the number of Rx and Tx buffers as log2. (Only powers * of two are valid) * Much more rx buffers (32) are reserved than tx buffers (8), since receiving * is more time critical then sending and packets may have to remain in the * board's memory when main memory is low.
*/
/* The LANCE Rx and Tx ring descriptors. */ struct lance_rx_head { unsignedshort base; /* Low word of base addr */ volatileunsignedchar flag; unsignedchar base_hi; /* High word of base addr (unused) */ short buf_length; /* This length is 2s complement! */ volatileshort msg_length; /* This length is "normal". */
};
struct lance_tx_head { unsignedshort base; /* Low word of base addr */ volatileunsignedchar flag; unsignedchar base_hi; /* High word of base addr (unused) */ short length; /* Length is 2s complement! */ volatileshort misc;
};
struct ringdesc { unsignedshort adr_lo; /* Low 16 bits of address */ unsignedchar len; /* Length bits */ unsignedchar adr_hi; /* High 8 bits of address (unused) */
};
/* The LANCE initialization block, described in databook. */ struct lance_init_block { unsignedshort mode; /* Pre-set mode */ unsignedchar hwaddr[6]; /* Physical ethernet address */ unsigned filter[2]; /* Multicast filter (unused). */ /* Receive and transmit ring base, along with length bits. */ struct ringdesc rx_ring; struct ringdesc tx_ring;
};
/* The whole layout of the Lance shared memory */ struct lance_memory { struct lance_init_block init; struct lance_tx_head tx_head[TX_RING_SIZE]; struct lance_rx_head rx_head[RX_RING_SIZE]; char packet_area[]; /* packet data follow after the * init block and the ring * descriptors and are located
* at runtime */
};
/* RieblCard specifics: * The original TOS driver for these cards reserves the area from offset * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the * Ethernet address there, and the magic for verifying the data's validity. * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe * is reserved for the interrupt vector number.
*/ #define RIEBL_RSVD_START 0xee70 #define RIEBL_RSVD_END 0xeec0 #define RIEBL_MAGIC 0x09051990 #define RIEBL_MAGIC_ADDR ((unsignedlong *)(((char *)MEM) + 0xee8a)) #define RIEBL_HWADDR_ADDR ((unsignedchar *)(((char *)MEM) + 0xee8e)) #define RIEBL_IVEC_ADDR ((unsignedshort *)(((char *)MEM) + 0xfffe))
/* This is a default address for the old RieblCards without a battery * that have no ethernet address at boot time. 00:00:36:04 is the * prefix for Riebl cards, the 00:00 at the end is arbitrary.
*/
struct lance_private { enum lance_type cardtype; struct lance_ioreg *iobase; struct lance_memory *mem; int cur_rx, cur_tx; /* The next free ring entry */ int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, constvoid *, size_t ); /* This must be long for set_bit() */ long tx_full;
spinlock_t devlock;
};
/* Definitions for packet buffer access: */ #define PKT_BUF_SZ 1544 /* Get the address of a packet buffer corresponding to a given buffer head */ #define PKTBUF_ADDR(head) (((unsignedchar *)(MEM)) + (head)->base)
/* Possible memory/IO addresses for probing */
staticstruct lance_addr { unsignedlong memaddr; unsignedlong ioaddr; int slow_flag;
} lance_addr_list[] = {
{ 0xfe010000, 0xfe00fff0, 0 }, /* RieblCard VME in TT */
{ 0xffc10000, 0xffc0fff0, 0 }, /* RieblCard VME in MegaSTE
(highest byte stripped) */
{ 0xffe00000, 0xffff7000, 1 }, /* RieblCard in ST
(highest byte stripped) */
{ 0xffd00000, 0xffff7000, 1 }, /* RieblCard in ST with hw modif. to avoid conflict with ROM
(highest byte stripped) */
{ 0xffcf0000, 0xffcffff0, 0 }, /* PAMCard VME in TT and MSTE
(highest byte stripped) */
{ 0xfecf0000, 0xfecffff0, 0 }, /* Rhotron's PAMCard VME in TT and MSTE
(highest byte stripped) */
};
#define N_LANCE_ADDR ARRAY_SIZE(lance_addr_list)
/* Definitions for the Lance */
/* tx_head flags */ #define TMD1_ENP 0x01 /* end of packet */ #define TMD1_STP 0x02 /* start of packet */ #define TMD1_DEF 0x04 /* deferred */ #define TMD1_ONE 0x08 /* one retry needed */ #define TMD1_MORE 0x10 /* more than one retry needed */ #define TMD1_ERR 0x40 /* error summary */ #define TMD1_OWN 0x80 /* ownership (set: chip owns) */
staticstruct net_device * __init atarilance_probe(void)
{ int i; staticint found; struct net_device *dev; int err = -ENODEV;
if (!MACH_IS_ATARI || found) /* Assume there's only one board possible... That seems true, since
* the Riebl/PAM board's address cannot be changed. */ return ERR_PTR(-ENODEV);
dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) return ERR_PTR(-ENOMEM);
for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) {
found = 1;
err = register_netdev(dev); if (!err) return dev;
free_irq(dev->irq, dev); break;
}
}
free_netdev(dev); return ERR_PTR(err);
}
/* Derived from hwreg_present() in atari/config.c: */
static noinline int __init addr_accessible(volatilevoid *regp, int wordflag, int writeflag)
{ int ret; unsignedlong flags; long *vbr, save_berr;
PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
(long)memaddr, (long)ioaddr ));
/* Test whether memory readable and writable */
PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" )); if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
/* Written values should come back... */
PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
save1 = *memaddr;
*memaddr = 0x0001; if (*memaddr != 0x0001) goto probe_fail;
PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
*memaddr = 0x0000; if (*memaddr != 0x0000) goto probe_fail;
*memaddr = save1;
/* First port should be readable and writable */
PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" )); if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
/* and written values should be readable */
PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
save2 = ioaddr[1];
ioaddr[1] = 0x0001; if (ioaddr[1] != 0x0001) goto probe_fail;
/* The CSR0_INIT bit should not be readable */
PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
save1 = ioaddr[0];
ioaddr[1] = CSR0;
ioaddr[0] = CSR0_INIT | CSR0_STOP; if (ioaddr[0] != CSR0_STOP) {
ioaddr[0] = save1;
ioaddr[1] = save2; goto probe_fail;
}
PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
ioaddr[0] = CSR0_STOP; if (ioaddr[0] != CSR0_STOP) {
ioaddr[0] = save1;
ioaddr[1] = save2; goto probe_fail;
}
/* Now test for type: If the eeprom I/O port is readable, it is a
* PAM card */ if (addr_accessible( &(IO->eeprom), 0, 0 )) { /* Switch back to Ram */
i = IO->mem;
lp->cardtype = PAM_CARD;
} elseif (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
lp->cardtype = NEW_RIEBL;
} else
lp->cardtype = OLD_RIEBL;
if (lp->cardtype == PAM_CARD ||
memaddr == (unsignedshort *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ if (request_irq(IRQ_AUTO_5, lance_interrupt, 0, "PAM,Riebl-ST Ethernet", dev)) {
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); return 0;
}
dev->irq = IRQ_AUTO_5;
} else { /* For VME-RieblCards, request a free VME int */ unsignedint irq = atari_register_vme_int(); if (!irq) {
printk( "Lance: request for VME interrupt failed\n" ); return 0;
} if (request_irq(irq, lance_interrupt, 0, "Riebl-VME Ethernet",
dev)) {
printk( "Lance: request for irq %u failed\n", irq ); return 0;
}
dev->irq = irq;
}
/* If the packet buffer at offset 'o' would conflict with the reserved area
* of RieblCards, advance it */ #define CHECK_OFFSET(o) \ do { \ if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) { \ if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
: (o) < RIEBL_RSVD_END) \
(o) = RIEBL_RSVD_END; \
} \
} while(0)
/* The old LANCE chips doesn't automatically pad buffers to min. size. */
len = skb->len; if (len < ETH_ZLEN)
len = ETH_ZLEN; /* PAM-Card has a bug: Can only send packets with even number of bytes! */ elseif (lp->cardtype == PAM_CARD && (len & 1))
++len;
if (len > skb->len) { if (skb_padto(skb, len)) return NETDEV_TX_OK;
}
netif_stop_queue (dev);
/* Fill in a Tx ring entry */ if (lance_debug >= 3) {
printk( "%s: TX pkt type 0x%04x from %pM to %pM" " data at 0x%08x len %d\n",
dev->name, ((u_short *)skb->data)[6],
&skb->data[6], skb->data,
(int)skb->data, (int)skb->len );
}
/* We're not prepared for the int until the last flags are set/reset. And
* the int may happen already after setting the OWN_CHIP... */
spin_lock_irqsave (&lp->devlock, flags);
/* Mask to ring buffer boundary. */
entry = lp->cur_tx & TX_RING_MOD_MASK;
head = &(MEM->tx_head[entry]);
/* Caution: the write order is important here, set the "ownership" bits * last.
*/
if (csr0 & CSR0_RINT) /* Rx interrupt */
lance_rx( dev );
if (csr0 & CSR0_TINT) { /* Tx-done interrupt */ int dirty_tx = lp->dirty_tx;
while( dirty_tx < lp->cur_tx) { int entry = dirty_tx & TX_RING_MOD_MASK; int status = MEM->tx_head[entry].flag;
if (status & TMD1_OWN_CHIP) break; /* It still hasn't been Txed */
MEM->tx_head[entry].flag = 0;
if (status & TMD1_ERR) { /* There was an major error, log it. */ int err_status = MEM->tx_head[entry].misc;
dev->stats.tx_errors++; if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++; if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++; if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++; if (err_status & TMD3_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */
dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */
DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
dev->name, csr0 )); /* Restart the chip. */
DREG = CSR0_STRT;
}
} else { if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
dev->stats.collisions++;
dev->stats.tx_packets++;
}
/* If we own the next entry, it's a new packet. Send it up. */ while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) { struct lance_rx_head *head = &(MEM->rx_head[entry]); int status = head->flag;
if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */ /* There is a tricky error noted by John Murphy, <murf@perftech.com> to Russ Nelson: Even with full-sized buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */ if (status & RMD1_ENP) /* Only count a general error at the */
dev->stats.rx_errors++; /* end of a packet.*/ if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; if (status & RMD1_OFLO) dev->stats.rx_over_errors++; if (status & RMD1_CRC) dev->stats.rx_crc_errors++; if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else { /* Malloc up new buffer, compatible with net-3. */ short pkt_len = head->msg_length & 0xfff; struct sk_buff *skb;
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
dev->stats.rx_errors++;
} else {
skb = netdev_alloc_skb(dev, pkt_len + 2); if (!skb) { for( i = 0; i < RX_RING_SIZE; i++ ) if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
RMD1_OWN_CHIP) break;
if (i > RX_RING_SIZE - 2) {
dev->stats.rx_dropped++;
head->flag |= RMD1_OWN_CHIP;
lp->cur_rx++;
} break;
}
if (lance_debug >= 3) {
u_char *data = PKTBUF_ADDR(head);
printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM " "data %8ph len %d\n",
dev->name, ((u_short *)data)[6],
&data[6], data, &data[15], pkt_len);
}
/* From lance.c (Donald Becker): */ /* We should check that at least two ring entries are free. If not,
we should free one and mark stats->rx_dropped++. */
DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, DREG ));
/* We stop the LANCE here -- it occasionally polls
memory if we don't. */
DREG = CSR0_STOP;
return 0;
}
/* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering.
*/
if (netif_running(dev)) /* Only possible if board is already started */ return;
/* We take the simple way out and always enable promiscuous mode. */
DREG = CSR0_STOP; /* Temporarily stop the lance. */
if (dev->flags & IFF_PROMISC) { /* Log any net taps. */
DPRINTK( 2, ( "%s: Promiscuous mode enabled.\n", dev->name ));
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else { short multicast_table[4]; int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer
* filtering. */
memset( multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table) ); for( i = 0; i < 4; i++ )
REGA( CSR8+i ) = multicast_table[i];
REGA( CSR15 ) = 0; /* Unset promiscuous mode */
}
/* * Always set BSWP after a STOP as STOP puts it back into * little endian mode.
*/
REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
/* Resume normal operation and reset AREG to CSR0 */
REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
}
/* This is needed for old RieblCards and possible for new RieblCards */
if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL) return -EOPNOTSUPP;
if (netif_running(dev)) { /* Only possible while card isn't started */
DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
dev->name )); return -EIO;
}
eth_hw_addr_set(dev, saddr->sa_data); for( i = 0; i < 6; i++ )
MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 ); /* set also the magic for future sessions */
*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.