// SPDX-License-Identifier: GPL-2.0-or-later #define VERSION "0.23" /* ns83820.c by Benjamin LaHaise with contributions. * * Questions/comments/discussion to linux-ns83820@kvack.org. * * $Revision: 1.34.2.23 $ * * Copyright 2001 Benjamin LaHaise. * Copyright 2001, 2002 Red Hat. * * Mmmm, chocolate vanilla mocha... * * ChangeLog * ========= * 20010414 0.1 - created * 20010622 0.2 - basic rx and tx. * 20010711 0.3 - added duplex and link state detection support. * 20010713 0.4 - zero copy, no hangs. * 0.5 - 64 bit dma support (davem will hate me for this) * - disable jumbo frames to avoid tx hangs * - work around tx deadlocks on my 1.02 card via * fiddling with TXCFG * 20010810 0.6 - use pci dma api for ringbuffers, work on ia64 * 20010816 0.7 - misc cleanups * 20010826 0.8 - fix critical zero copy bugs * 0.9 - internal experiment * 20010827 0.10 - fix ia64 unaligned access. * 20010906 0.11 - accept all packets with checksum errors as * otherwise fragments get lost * - fix >> 32 bugs * 0.12 - add statistics counters * - add allmulti/promisc support * 20011009 0.13 - hotplug support, other smaller pci api cleanups * 20011204 0.13a - optical transceiver support added * by Michael Clark <michael@metaparadigm.com> * 20011205 0.13b - call register_netdev earlier in initialization * suppress duplicate link status messages * 20011117 0.14 - ethtool GDRVINFO, GLINK support from jgarzik * 20011204 0.15 get ppc (big endian) working * 20011218 0.16 various cleanups * 20020310 0.17 speedups * 20020610 0.18 - actually use the pci dma api for highmem * - remove pci latency register fiddling * 0.19 - better bist support * - add ihr and reset_phy parameters * - gmii bus probing * - fix missed txok introduced during performance * tuning * 0.20 - fix stupid RFEN thinko. i am such a smurf. * 20040828 0.21 - add hardware vlan accleration * by Neil Horman <nhorman@redhat.com> * 20050406 0.22 - improved DAC ifdefs from Andi Kleen * - removal of dead code from Adrian Bunk * - fix half duplex collision behaviour * Driver Overview * =============== * * This driver was originally written for the National Semiconductor * 83820 chip, a 10/100/1000 Mbps 64 bit PCI ethernet NIC. Hopefully * this code will turn out to be a) clean, b) correct, and c) fast. * With that in mind, I'm aiming to split the code up as much as * reasonably possible. At present there are X major sections that * break down into a) packet receive, b) packet transmit, c) link * management, d) initialization and configuration. Where possible, * these code paths are designed to run in parallel. * * This driver has been tested and found to work with the following * cards (in no particular order): * * Cameo SOHO-GA2000T SOHO-GA2500T * D-Link DGE-500T * PureData PDP8023Z-TG * SMC SMC9452TX SMC9462TX * Netgear GA621 * * Special thanks to SMC for providing hardware to test this driver on. * * Reports of success or failure would be greatly appreciated.
*/ //#define dprintk printk #define dprintk(x...) do { } while (0)
/* Global parameters. See module_param near the bottom. */ staticint ihr = 2; staticint reset_phy = 0; staticint lnksts = 0; /* CFG_LNKSTS bit polarity */
/* Dprintk is used for more interesting debug events */ #undef Dprintk #define Dprintk dprintk
/* Must not exceed ~65000. */ #define NR_RX_DESC 64 #define NR_TX_DESC 128
/* not tunable */ #define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14) /* rx/tx mac addr + type */
#define MIN_TX_DESC_FREE 8
/* register defines */ #define CFGCS 0x04
#define CR_TXE 0x00000001 #define CR_TXD 0x00000002 /* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE * The Receive engine skips one descriptor and moves
* onto the next one!! */ #define CR_RXE 0x00000004 #define CR_RXD 0x00000008 #define CR_TXR 0x00000010 #define CR_RXR 0x00000020 #define CR_SWI 0x00000080 #define CR_RST 0x00000100
/* Packet Receiver * * The hardware supports linked lists of receive descriptors for * which ownership is transferred back and forth by means of an * ownership bit. While the hardware does support the use of a * ring for receive descriptors, we only make use of a chain in * an attempt to reduce bus traffic under heavy load scenarios. * This will also make bugs a bit more obvious. The current code * only makes use of a single rx chain; I hope to implement * priority based rx for version 1.0. Goal: even under overload * conditions, still route realtime traffic with as low jitter as * possible.
*/ staticinlinevoid build_rx_desc(struct ns83820 *dev, __le32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts)
{
desc_addr_set(desc + DESC_LINK, link);
desc_addr_set(desc + DESC_BUFPTR, buf);
desc[DESC_EXTSTS] = cpu_to_le32(extsts);
mb();
desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
}
ret = rx_refill(ndev, GFP_KERNEL); if (!ret) {
dprintk("starting receiver\n"); /* prevent the interrupt handler from stomping on us */
spin_lock_irq(&dev->rx_info.lock);
dma_unmap_single(&dev->pci_dev->dev, bufptr, RX_BUF_SIZE,
DMA_FROM_DEVICE);
len = cmdsts & CMDSTS_LEN_MASK; #ifdef NS83820_VLAN_ACCEL_SUPPORT /* NH: As was mentioned below, this chip is kinda * brain dead about vlan tag stripping. Frames * that are 64 bytes with a vlan header appended * like arp frames, or pings, are flagged as Runts * when the tag is stripped and hardware. This * also means that the OK bit in the descriptor * is cleared when the frame comes in so we have * to do a specific length check here to make sure * the frame would have been ok, had we not stripped * the tag.
*/ if (likely((CMDSTS_OK & cmdsts) ||
((cmdsts & CMDSTS_RUNT) && len >= 56))) { #else if (likely(CMDSTS_OK & cmdsts)) { #endif
skb_put(skb, len); if (unlikely(!skb)) {
ndev->stats.rx_dropped++; goto netdev_mangle_me_harder_failed;
} if (cmdsts & CMDSTS_DEST_MULTI)
ndev->stats.multicast++;
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += len; if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
skb_checksum_none_assert(skb);
}
skb->protocol = eth_type_trans(skb, ndev); #ifdef NS83820_VLAN_ACCEL_SUPPORT if(extsts & EXTSTS_VPKT) { unsignedshort tag;
/* Allow network stack to resume queueing packets after we've * finished transmitting at least 1/4 of the packets in the queue.
*/ if (netif_queue_stopped(ndev) && start_tx_okay(dev)) {
dprintk("start_queue(%p)\n", ndev);
netif_start_queue(ndev);
netif_wake_queue(ndev);
}
}
/* transmit routine. This code relies on the network layer serializing * its calls in, but will run happily in parallel with the interrupt * handler. This code currently has provisions for fragmenting tx buffers * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN).
*/ static netdev_tx_t ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ struct ns83820 *dev = PRIV(ndev);
u32 free_idx, cmdsts, extsts; int nr_free, nr_frags; unsigned tx_done_idx, last_idx;
dma_addr_t buf; unsigned len;
skb_frag_t *frag; int stopped = 0; int do_intr = 0; volatile __le32 *first_desc;
dprintk("ns83820_hard_start_xmit\n");
nr_frags = skb_shinfo(skb)->nr_frags;
again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) {
netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) return NETDEV_TX_BUSY;
netif_start_queue(ndev);
}
/* Check again: we may have raced with a tx done irq */ if (dev->tx_done_idx != tx_done_idx) {
dprintk("restart queue(%p)\n", ndev);
netif_start_queue(ndev); goto again;
} return NETDEV_TX_BUSY;
}
#ifdef NS83820_VLAN_ACCEL_SUPPORT if (skb_vlan_tag_present(skb)) { /* fetch the vlan tag info out of the * ancillary data if the vlan code * is using hw vlan acceleration
*/ short tag = skb_vlan_tag_get(skb);
extsts |= (EXTSTS_VPKT | htons(tag));
} #endif
len = skb->len; if (nr_frags)
len -= skb->data_len;
buf = dma_map_single(&dev->pci_dev->dev, skb->data, len,
DMA_TO_DEVICE);
/* Check again: we may have raced with a tx done irq */ if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))
netif_start_queue(ndev);
/* this function is called in irq context from the ISR */ staticvoid ns83820_mib_isr(struct ns83820 *dev)
{ unsignedlong flags;
spin_lock_irqsave(&dev->misc_lock, flags);
ns83820_update_stats(dev);
spin_unlock_irqrestore(&dev->misc_lock, flags);
}
if (unlikely(ISR_RXSOVR & isr)) { //printk("overrun: rxsovr\n");
ndev->stats.rx_fifo_errors++;
}
if (unlikely(ISR_RXORN & isr)) { //printk("overrun: rxorn\n");
ndev->stats.rx_fifo_errors++;
}
if ((ISR_RXRCMP & isr) && dev->rx_info.up)
writel(CR_RXE, dev->base + CR);
if (ISR_TXIDLE & isr) {
u32 txdp;
txdp = readl(dev->base + TXDP);
dprintk("txdp: %08x\n", txdp);
txdp -= dev->tx_phy_descs;
dev->tx_idx = txdp / (DESC_SIZE * 4); if (dev->tx_idx >= NR_TX_DESC) {
printk(KERN_ALERT "%s: BUG -- txdp out of range\n", ndev->name);
dev->tx_idx = 0;
} /* The may have been a race between a pci originated read * and the descriptor update from the cpu. Just in case, * kick the transmitter if the hardware thinks it is on a * different descriptor than we are.
*/ if (dev->tx_idx != dev->tx_free_idx)
kick_tx(dev);
}
/* Defer tx ring processing until more than a minimum amount of * work has accumulated
*/ if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
spin_lock_irqsave(&dev->tx_lock, flags);
do_tx_done(ndev);
spin_unlock_irqrestore(&dev->tx_lock, flags);
/* Disable TxOk if there are no outstanding tx packets.
*/ if ((dev->tx_done_idx == dev->tx_free_idx) &&
(dev->IMR_cache & ISR_TXOK)) {
spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
spin_unlock_irqrestore(&dev->misc_lock, flags);
}
}
/* The TxIdle interrupt can come in before the transmit has * completed. Normally we reap packets off of the combination * of TxDesc and TxIdle and leave TxOk disabled (since it * occurs on every packet), but when no further irqs of this * nature are expected, we must enable TxOk.
*/ if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache |= ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
spin_unlock_irqrestore(&dev->misc_lock, flags);
}
/* MIB interrupt: one of the statistics counters is about to overflow */ if (unlikely(ISR_MIB & isr))
ns83820_mib_isr(dev);
/* PHY: Link up/down/negotiation state change */ if (unlikely(ISR_PHY & isr))
phy_intr(ndev);
#if 0 /* Still working on the interrupt mitigation strategy */ if (dev->ihr)
writel(dev->ihr, dev->base + IHR); #endif
}
/* Read from the perfect match memory: this is loaded by * the chip from the EEPROM via the EELOAD self test.
*/
writel(i*2, dev->base + RFCR);
data = readl(dev->base + RFDR);
/* enable output, set bit */
dev->MEAR_cache |= MEAR_MDDIR; if (bit)
dev->MEAR_cache |= MEAR_MDIO; else
dev->MEAR_cache &= ~MEAR_MDIO;
/* set the output bit */
writel(dev->MEAR_cache, dev->base + MEAR);
readl(dev->base + MEAR);
/* Wait. Max clock rate is 2.5MHz, this way we come in under 1MHz */
udelay(1);
/* drive MDC high causing the data bit to be latched */
dev->MEAR_cache |= MEAR_MDC;
writel(dev->MEAR_cache, dev->base + MEAR);
readl(dev->base + MEAR);
/* Wait again... */
udelay(1);
}
staticint ns83820_mii_read_bit(struct ns83820 *dev)
{ int bit;
/* Wait. Max clock rate is 2.5MHz, this way we come in under 1MHz */
udelay(1);
/* drive MDC high causing the data bit to be latched */
bit = (readl(dev->base + MEAR) & MEAR_MDIO) ? 1 : 0;
dev->MEAR_cache |= MEAR_MDC;
writel(dev->MEAR_cache, dev->base + MEAR);
/* Wait again... */
udelay(1);
return bit;
}
staticunsigned ns83820_mii_read_reg(struct ns83820 *dev, unsigned phy, unsigned reg)
{ unsigned data = 0; int i;
/* read some garbage so that we eventually sync up */ for (i=0; i<64; i++)
ns83820_mii_read_bit(dev);
staticint ns83820_init_one(struct pci_dev *pci_dev, conststruct pci_device_id *id)
{ struct net_device *ndev; struct ns83820 *dev; long addr; int err; int using_dac = 0;
/* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 &&
!dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64))) {
using_dac = 1;
} elseif (!dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
using_dac = 0;
} else {
dev_warn(&pci_dev->dev, "dma_set_mask failed!\n"); return -ENODEV;
}
/* * FIXME: we are holding rtnl_lock() over obscenely long area only * because some of the setup code uses dev->name. It's Wrong(tm) - * we should be using driver-specific names for all that stuff. * For now that will do, but we really need to come back and kill * most of the dev_alloc_name() users later.
*/
rtnl_lock();
err = dev_alloc_name(ndev, ndev->name); if (err < 0) {
dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err); goto out_free_irq;
}
/* When compiled with 64 bit addressing, we must always enable * the 64 bit descriptor format.
*/ if (sizeof(dma_addr_t) == 8)
dev->CFG_cache |= CFG_M64ADDR; if (using_dac)
dev->CFG_cache |= CFG_T64ADDR;
/* Big endian mode does not seem to do what the docs suggest */
dev->CFG_cache &= ~CFG_BEM;
/* setup optical transceiver if we have one */ if (dev->CFG_cache & CFG_TBI_EN) {
printk(KERN_INFO "%s: enabling optical transceiver\n",
ndev->name);
writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
#if 0 /* Huh? This sets the PCI latency register. Should be done via * the PCI layer. FIXME.
*/ if (readl(dev->base + SRR))
writel(readl(dev->base+0x20c) | 0xfe00, dev->base + 0x20c); #endif
/* Note! The DMA burst size interacts with packet * transmission, such that the largest packet that * can be transmitted is 8192 - FLTH - burst size. * If only the transmit fifo was larger...
*/ /* Ramit : 1024 DMA is not a good idea, it ends up banging
* some DELL and COMPAQ SMP systems */
writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
| ((1600 / 32) * 0x100),
dev->base + TXCFG);
/* Set Rx to full duplex, don't accept runt, errored, long or length * range errored packets. Use 512 byte DMA.
*/ /* Ramit : 1024 DMA is not a good idea, it ends up banging * some DELL and COMPAQ SMP systems
* Turn on ALP, only we are accepting Jumbo Packets */
writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
| RXCFG_STRIPCRC //| RXCFG_ALP
| (RXCFG_MXDMA512) | 0, dev->base + RXCFG);
/* Enable IP checksum validation and detetion of VLAN headers. * Note: do not set the reject options as at least the 0x102 * revision of the chip does not properly accept IP fragments * at least for UDP.
*/ /* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since * the MAC it calculates the packetsize AFTER stripping the VLAN * header, and if a VLAN Tagged packet of 64 bytes is received (like * a ping with a VLAN header) then the card, strips the 4 byte VLAN * tag and then checks the packet size, so if RXCFG_ARP is not enabled, * it discrards it!. These guys...... * also turn on tag stripping if hardware acceleration is enabled
*/ #ifdef NS83820_VLAN_ACCEL_SUPPORT #define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN) #else #define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN) #endif
writel(VRCR_INIT_VALUE, dev->base + VRCR);
/* Enable per-packet TCP/UDP/IP checksumming * and per packet vlan tag insertion if * vlan hardware acceleration is enabled
*/ #ifdef NS83820_VLAN_ACCEL_SUPPORT #define VTCR_INIT_VALUE (VTCR_PPCHK|VTCR_VPPTI) #else #define VTCR_INIT_VALUE VTCR_PPCHK #endif
writel(VTCR_INIT_VALUE, dev->base + VTCR);
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.