/* These define the number of Rx and Tx buffers as log2. (Only powers *oftwoarevalid) *Muchmorerxbuffers(32)arereservedthantxbuffers(8),sincereceiving *ismoretimecriticalthensendingandpacketsmayhavetoremaininthe *board'smemorywhenmainmemoryislow.
*/
/* 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 *initblockandthering *descriptorsandarelocated
* at runtime */
};
/* This is a default address for the old RieblCards without a battery *thathavenoethernetaddressatboottime.00:00:36:04isthe *prefixforRieblcards,the00:00attheendisarbitrary.
*/
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 avoidconflictwithROM
(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 ); return0;
}
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" ); return0;
} if (request_irq(irq, lance_interrupt, 0, "Riebl-VME Ethernet",
dev)) {
printk( "Lance: request for irq %u failed\n", irq ); return0;
}
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>toRussNelson:Evenwithfull-sized buffersit'spossibleforajabberpackettousetwo
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;
return0;
}
/* Set or clear the multicast filter for this adaptor. num_addrs==-1Promiscuousmode,receiveallpackets num_addrs==0Normalmode,clearmulticastlist num_addrs>0Multicastmode,receivenormalandMCpackets,anddo best-effortfiltering.
*/
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.