// SPDX-License-Identifier: GPL-2.0-only /* * Lance ethernet driver for the MIPS processor based * DECstation family * * * adopted from sunlance.c by Richard van den Berg * * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, * Revision 1.2 * * History: * * v0.001: The kernel accepts the code and it shows the hardware address. * * v0.002: Removed most sparc stuff, left only some module and dma stuff. * * v0.003: Enhanced base address calculation from proposals by * Harald Koerfgen and Thomas Riemer. * * v0.004: lance-regs is pointing at the right addresses, added prom * check. First start of address mapping and DMA. * * v0.005: started to play around with LANCE-DMA. This driver will not * work for non IOASIC lances. HK * * v0.006: added pointer arrays to lance_private and setup routine for * them in dec_lance_init. HK * * v0.007: Big shit. The LANCE seems to use a different DMA mechanism to * access the init block. This looks like one (short) word at a * time, but the smallest amount the IOASIC can transfer is a * (long) word. So we have a 2-2 padding here. Changed * lance_init_block accordingly. The 16-16 padding for the buffers * seems to be correct. HK * * v0.008: mods to make PMAX_LANCE work. 01/09/1999 triemer * * v0.009: Module support fixes, multiple interfaces support, various * bits. macro * * v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the * PMAX requirement to only use halfword accesses to the * buffer. macro * * v0.011: Converted the PMAD to the driver model. macro
*/
/* * The DS2100/3100 have a linear 64 kB buffer which supports halfword * accesses only. Each halfword of the buffer is word-aligned in the * CPU address space. * * The PMAD-AA has a 128 kB buffer on-board. * * The IOASIC LANCE devices use a shared memory region. This region * as seen from the CPU is (max) 128 kB long and has to be on an 128 kB * boundary. The LANCE sees this as a 64 kB long continuous memory * region. * * The LANCE's DMA address is used as an index in this buffer and DMA * takes place in bursts of eight 16-bit words which are packed into * four 32-bit words by the IOASIC. This leads to a strange padding: * 16 bytes of valid data followed by a 16 byte gap :-(.
*/
struct lance_rx_desc { unsignedshort rmd0; /* low address of packet */ unsignedshort rmd1; /* high address of packet
and descriptor bits */ short length; /* 2s complement (negative!)
of buffer length */ unsignedshort mblength; /* actual number of bytes received */
};
struct lance_tx_desc { unsignedshort tmd0; /* low address of packet */ unsignedshort tmd1; /* high address of packet
and descriptor bits */ short length; /* 2s complement (negative!)
of buffer length */ unsignedshort misc;
};
/* First part of the LANCE initialization block, described in databook. */ struct lance_init_block { unsignedshort mode; /* pre-set mode (reg. 15) */
/* Receive and transmit ring base, along with extra bits. */ unsignedshort rx_ptr; /* receive descriptor addr */ unsignedshort rx_len; /* receive len and high addr */ unsignedshort tx_ptr; /* transmit descriptor addr */ unsignedshort tx_len; /* transmit len and high addr */
/* The lance control ports are at an absolute address, machine and tc-slot * dependent. * DECstations do only 32-bit access and the LANCE uses 16 bit addresses, * so we have to give the structure an extra member making rap pointing * at the right address
*/ struct lance_regs { volatileunsignedshort rdp; /* register data port */ unsignedshort pad; volatileunsignedshort rap; /* register address port */
};
/* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) {
dev->stats.rx_over_errors++;
dev->stats.rx_errors++;
} elseif (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning
*/ if (bits & LE_R1_BUF)
dev->stats.rx_fifo_errors++; if (bits & LE_R1_CRC)
dev->stats.rx_crc_errors++; if (bits & LE_R1_OFL)
dev->stats.rx_over_errors++; if (bits & LE_R1_FRA)
dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP)
dev->stats.rx_errors++;
} else {
len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4;
skb = netdev_alloc_skb(dev, len + 2);
staticvoid lance_tx(struct net_device *dev)
{ struct lance_private *lp = netdev_priv(dev); volatile u16 *ib = (volatile u16 *)dev->mem_start; volatilestruct lance_regs *ll = lp->ll; volatile u16 *td; int i, j; int status;
j = lp->tx_old;
spin_lock(&lp->lock);
for (i = j; i != lp->tx_new; i = j) {
td = lib_ptr(ib, btx_ring[i], lp->type); /* If we hit a packet not owned by us, stop */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_OWN) break;
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) {
status = *tds_ptr(td, misc, lp->type);
dev->stats.tx_errors++; if (status & LE_T3_RTY)
dev->stats.tx_aborted_errors++; if (status & LE_T3_LCOL)
dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
dev->stats.tx_carrier_errors++;
printk("%s: Carrier Lost\n", dev->name); /* Stop the lance */
writereg(&ll->rap, LE_CSR0);
writereg(&ll->rdp, LE_C0_STOP);
lance_init_ring(dev);
load_csrs(lp);
init_restart_lance(lp); goto out;
} /* Buffer errors and underflows turn off the * transmitter, restart the adapter.
*/ if (status & (LE_T3_BUF | LE_T3_UFL)) {
dev->stats.tx_fifo_errors++;
printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name); /* Stop the lance */
writereg(&ll->rap, LE_CSR0);
writereg(&ll->rdp, LE_C0_STOP);
lance_init_ring(dev);
load_csrs(lp);
init_restart_lance(lp); goto out;
}
} elseif ((*tds_ptr(td, tmd1, lp->type) & LE_T1_POK) ==
LE_T1_POK) { /* * So we don't count the packet more than once.
*/
*tds_ptr(td, tmd1, lp->type) &= ~(LE_T1_POK);
/* One collision before packet was sent. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE)
dev->stats.collisions++;
/* More than one collision, be optimistic. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE)
dev->stats.collisions += 2;
/* Stop the Lance */
writereg(&ll->rap, LE_CSR0);
writereg(&ll->rdp, LE_C0_STOP);
/* Set mode and clear multicast filter only at device open, * so that lance_init_ring() called at any error will not * forget multicast filters. * * BTW it is common bug in all lance drivers! --ANK
*/
*lib_ptr(ib, mode, lp->type) = 0;
*lib_ptr(ib, filter[0], lp->type) = 0;
*lib_ptr(ib, filter[1], lp->type) = 0;
*lib_ptr(ib, filter[2], lp->type) = 0;
*lib_ptr(ib, filter[3], lp->type) = 0;
lance_init_ring(dev);
load_csrs(lp);
netif_start_queue(dev);
/* Associate IRQ with lance_interrupt */ if (request_irq(dev->irq, lance_interrupt, 0, "lance", dev)) {
printk("%s: Can't get IRQ %d\n", dev->name, dev->irq); return -EAGAIN;
} if (lp->dma_irq >= 0) { unsignedlong flags;
/* prom checks */ /* First, check for test pattern */ if (esar[0x60] != 0xff && esar[0x64] != 0x00 &&
esar[0x68] != 0x55 && esar[0x6c] != 0xaa) {
printk(KERN_ERR "%s: Ethernet station address prom not found!\n",
name);
ret = -ENODEV; goto err_out_resource;
} /* Check the prom contents */ for (i = 0; i < 8; i++) { if (esar[i * 4] != esar[0x3c - i * 4] &&
esar[i * 4] != esar[0x40 + i * 4] &&
esar[0x3c - i * 4] != esar[0x40 + i * 4]) {
printk(KERN_ERR "%s: Something is wrong with the " "ethernet station address prom!\n", name);
ret = -ENODEV; goto err_out_resource;
}
}
/* Copy the ethernet address to the device structure, later to the * lance initialization block so the lance gets it every time it's * (re)initialized.
*/ switch (type) { case ASIC_LANCE:
desc = "IOASIC onboard LANCE"; break; case PMAD_LANCE:
desc = "PMAD-AA"; break; case PMAX_LANCE:
desc = "PMAX onboard LANCE"; break;
} for (i = 0; i < 6; i++)
addr[i] = esar[i * 4];
eth_hw_addr_set(dev, addr);
/* lp->ll is the location of the registers for lance card */
lp->ll = ll;
/* busmaster_regval (CSR3) should be zero according to the PMAD-AA * specification.
*/
lp->busmaster_regval = 0;
dev->dma = 0;
/* We cannot sleep if the chip is busy during a * multicast list update event, because such events * can occur from interrupts (ex. IPv6). So we * use a timer to try again later when necessary. -DaveM
*/
lp->dev = dev;
timer_setup(&lp->multicast_timer, lance_set_multicast_retry, 0);
ret = register_netdev(dev); if (ret) {
printk(KERN_ERR "%s: Unable to register netdev, aborting.\n", name); goto err_out_resource;
}
if (!bdev) {
lp->next = root_lance_dev;
root_lance_dev = dev;
}
printk("%s: registered as %s.\n", name, dev->name); return 0;
err_out_resource: if (bdev)
release_mem_region(start, len);
err_out_dev:
free_netdev(dev);
err_out: return ret;
}
/* Find all the lance cards on the system and initialize them */ staticint __init dec_lance_platform_probe(void)
{ int count = 0;
if (dec_interrupt[DEC_IRQ_LANCE] >= 0) { if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) { if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
count++;
} elseif (!TURBOCHANNEL) { if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
count++;
}
}
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.