/* The user-configurable values.
These may be modified when a driver module is loaded.*/
staticint debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ staticint max_interrupt_work = 20; staticint mtu; #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ /* System-wide count of bogus-rx frames. */ staticint bogus_rx; staticint dma_ctrl = 0x004A0263; /* Constrained by errata */ staticint fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ #elifdefined(YF_NEW) /* A future perfect board :->. */ staticint dma_ctrl = 0x00CAC277; /* Override when loading module! */ staticint fifo_cfg = 0x0028; #else staticconstint dma_ctrl = 0x004A0263; /* Constrained by errata */ staticconstint fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ #endif
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1514 effectively disables this feature. */ staticint rx_copybreak;
/* Used to pass the media type, etc. Nomediatypesarecurrentlydefined.Theseexistfordriver interoperability.
*/ #define MAX_UNITS 8/* More are supported, limit only on options */ staticint options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; staticint full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* Do ugly workaround for GX server chipset errata. */ staticint gx_fix;
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for efficiency. MakingtheTxringtoolongdecreasestheeffectivenessofchannel bondingandpacketpriority.
There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_SIZE 12/* Must be > 4 && <= TX_RING_SIZE */ #define RX_RING_SIZE 64 #define STATUS_TOTAL_SIZE TX_RING_SIZE*sizeof(struct tx_status_words) #define TX_TOTAL_SIZE 2*TX_RING_SIZE*sizeof(struct yellowfin_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct yellowfin_desc)
/* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) #define PKT_BUF_SZ 1536/* Size of each temporary Rx buffer.*/
/* These identify the driver base version and may not be removed. */ staticconstchar version[] =
KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n" " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
enum capability_flags {
HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
HasMACAddrBug=32, /* Only on early revs. */
DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
};
/* The PCI I/O space extent. */ enum {
YELLOWFIN_SIZE = 0x100,
};
struct pci_id_info { constchar *name; struct match_info { int pci, pci_mask, subsystem, subsystem_mask; int revision, revision_mask; /* Only 8 bits. */
} id; int drv_flags; /* Driver use, intended as capability flags. */
};
/* The Yellowfin Rx and Tx buffer descriptors.
Elements are written as 32 bit for endian portability. */ struct yellowfin_desc {
__le32 dbdma_cmd;
__le32 addr;
__le32 branch_addr;
__le32 result_status;
};
struct timer_list timer; /* Media selection timer. */ /* Frequently used and paired value: keep adjacent for cache effect. */ int chip_id, drv_flags; struct pci_dev *pci_dev; unsignedint cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsignedint rx_buf_sz; /* Based on MTU+slack. */ struct tx_status_words *tx_tail_desc; unsignedint cur_tx, dirty_tx; int tx_threshold; unsignedint tx_full:1; /* The Tx queue is full. */ unsignedint full_duplex:1; /* Full-duplex operation requested. */ unsignedint duplex_lock:1; unsignedint medialock:1; /* Do not sense media. */ unsignedint default_port:4; /* Last dev->if_port value. */ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */ unsignedchar phys[MII_CNT]; /* MII device addresses, only first one used */
spinlock_t lock; void __iomem *base;
};
staticint yellowfin_init_one(struct pci_dev *pdev, conststruct pci_device_id *ent)
{ struct net_device *dev; struct yellowfin_private *np; int irq; int chip_idx = ent->driver_data; staticint find_cnt; void __iomem *ioaddr; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; int drv_flags = pci_id_tbl[chip_idx].drv_flags; void *ring_space;
dma_addr_t ring_dma; #ifdef USE_IO_OPS int bar = 0; #else int bar = 1; #endif
u8 addr[ETH_ALEN];
/* when built into the kernel, we only print version if device is found */ #ifndef MODULE staticint printed_version; if (!printed_version++)
printk(version); #endif
i = pci_enable_device(pdev); if (i) return i;
dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM;
SET_NETDEV_DEV(dev, &pdev->dev);
np = netdev_priv(dev);
if (pci_request_regions(pdev, DRV_NAME)) goto err_out_free_netdev;
pci_set_master (pdev);
ioaddr = pci_iomap(pdev, bar, YELLOWFIN_SIZE); if (!ioaddr) goto err_out_free_res;
irq = pdev->irq;
if (drv_flags & DontUseEeprom) for (i = 0; i < 6; i++)
addr[i] = ioread8(ioaddr + StnAddr + i); else { int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); for (i = 0; i < 6; i++)
addr[i] = read_eeprom(ioaddr, ee_offset + i);
}
eth_hw_addr_set(dev, addr);
/* Reset the chip. */
iowrite32(0x80000000, ioaddr + DMACtrl);
/* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200)
np->full_duplex = 1;
np->default_port = option & 15; if (np->default_port)
np->medialock = 1;
} if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
np->full_duplex = 1;
if (np->full_duplex)
np->duplex_lock = 1;
/* The Yellowfin-specific entries in the device structure. */
dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = ðtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
if (mtu)
dev->mtu = mtu;
i = register_netdev(dev); if (i) goto err_out_unmap_status;
netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n",
pci_id_tbl[chip_idx].name,
ioread32(ioaddr + ChipRev), ioaddr,
dev->dev_addr, irq);
if (np->drv_flags & HasMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
np->advertising = mdio_read(ioaddr, phy, 4);
netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n",
phy, mii_status, np->advertising);
}
}
np->mii_cnt = phy_idx;
}
for (i = 0; i < 6; i++)
iowrite8(dev->dev_addr[i], ioaddr + StnAddr + i);
/* Set up various condition 'select' registers.
There are no options here. */
iowrite32(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */
iowrite32(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */
iowrite32(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */
iowrite32(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */
iowrite32(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */
iowrite32(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */
/* Initialize other registers: with so many this eventually this will
converted to an offset/value list. */
iowrite32(dma_ctrl, ioaddr + DMACtrl);
iowrite16(fifo_cfg, ioaddr + FIFOcfg); /* Enable automatic generation of flow control frames, period 0xffff. */
iowrite32(0x0030FFFF, ioaddr + FlowCtrl);
/* Set the timer to check for link beat. */
timer_setup(&yp->timer, yellowfin_timer, 0);
yp->timer.expires = jiffies + 3*HZ;
add_timer(&yp->timer);
out: return rc;
if (yellowfin_debug > 3) {
netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n",
ioread16(ioaddr + IntrStatus));
}
if (yp->mii_cnt) { int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR); int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA); int negotiated = lpa & yp->advertising; if (yellowfin_debug > 1)
netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n",
yp->phys[0], bmsr, lpa);
netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n",
yp->cur_tx, yp->dirty_tx,
ioread32(ioaddr + TxStatus),
ioread32(ioaddr + RxStatus));
/* Note: these should be KERN_DEBUG. */ if (yellowfin_debug) { int i;
pr_warn(" Rx ring %p: ", yp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++)
pr_cont(" %08x", yp->rx_ring[i].result_status);
pr_cont("\n");
pr_warn(" Tx ring %p: ", yp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++)
pr_cont(" %04x /%08x",
yp->tx_status[i].tx_errs,
yp->tx_ring[i].result_status);
pr_cont("\n");
}
/* If the hardware is found to hang regularly, we will update the code
to reinitialize the chip here. */
dev->if_port = 0;
/* Wake the potentially-idle transmit channel. */
iowrite32(0x10001000, yp->base + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
netif_wake_queue (dev); /* Typical path */
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ staticint yellowfin_init_ring(struct net_device *dev)
{ struct yellowfin_private *yp = netdev_priv(dev); int i, j;
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
{ struct net_device *dev = dev_instance; struct yellowfin_private *yp; void __iomem *ioaddr; int boguscnt = max_interrupt_work; unsignedint handled = 0;
yp = netdev_priv(dev);
ioaddr = yp->base;
spin_lock (&yp->lock);
do {
u16 intr_status = ioread16(ioaddr + IntrClear);
if (yellowfin_debug > 4)
netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n",
intr_status);
if (intr_status == 0) break;
handled = 1;
if (intr_status & (IntrRxDone | IntrEarlyRx)) {
yellowfin_rx(dev);
iowrite32(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */
}
#ifdef NO_TXSTATS for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) { int entry = yp->dirty_tx % TX_RING_SIZE; struct sk_buff *skb;
if (yp->tx_ring[entry].result_status == 0) break;
skb = yp->tx_skbuff[entry];
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; /* Free the original skb. */
dma_unmap_single(&yp->pci_dev->dev,
le32_to_cpu(yp->tx_ring[entry].addr),
skb->len, DMA_TO_DEVICE);
dev_consume_skb_irq(skb);
yp->tx_skbuff[entry] = NULL;
} if (yp->tx_full &&
yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { /* The ring is no longer full, clear tbusy. */
yp->tx_full = 0;
netif_wake_queue(dev);
} #else if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) { unsigned dirty_tx = yp->dirty_tx;
/* This routine is logically part of the interrupt handler, but separated
for clarity and better register allocation. */ staticint yellowfin_rx(struct net_device *dev)
{ struct yellowfin_private *yp = netdev_priv(dev); int entry = yp->cur_rx % RX_RING_SIZE; int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
if (yellowfin_debug > 4) {
printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n",
entry, yp->rx_ring[entry].result_status);
printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n",
entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
yp->rx_ring[entry].result_status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */ while (1) { struct yellowfin_desc *desc = &yp->rx_ring[entry]; struct sk_buff *rx_skb = yp->rx_skbuff[entry];
s16 frame_status;
u16 desc_status; int data_size, __maybe_unused yf_size;
u8 *buf_addr;
/* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) {
yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (yp->rx_skbuff[i]) {
dev_kfree_skb(yp->rx_skbuff[i]);
}
yp->rx_skbuff[i] = NULL;
} for (i = 0; i < TX_RING_SIZE; i++) {
dev_kfree_skb(yp->tx_skbuff[i]);
yp->tx_skbuff[i] = NULL;
}
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ if (yellowfin_debug > 0) {
netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n",
bogus_rx);
} #endif
return0;
}
/* Set or clear the multicast filter for this adaptor. */
/* Stop the Rx process to change any value. */
iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
iowrite16(0x000F, ioaddr + AddrMode);
} elseif ((netdev_mc_count(dev) > 64) ||
(dev->flags & IFF_ALLMULTI)) { /* Too many to filter well, or accept all multicasts. */
iowrite16(0x000B, ioaddr + AddrMode);
} elseif (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */ struct netdev_hw_addr *ha;
u16 hash_table[4]; int i;
staticint __init yellowfin_init (void)
{ /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE
printk(version); #endif return pci_register_driver(&yellowfin_driver);
}
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.