/* The user-configurable values.
These may be modified when a driver module is loaded.*/
staticint debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ staticint max_interrupt_work = 20; /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The '840 uses a 64 element hash table based on the Ethernet CRC. */ staticint multicast_filter_limit = 32;
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1518 effectively disables this feature. */ staticint rx_copybreak;
/* Used to pass the media type, etc. Both'options[]'and'full_duplex[]'shouldexistfordriver interoperability. Themediatypeisusuallypassedin'options[]'.
*/ #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};
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency. Thecompilerwillconvert<unsigned>'%'<2^N>intoabitmask. MakingtheTxringtoolargedecreasestheeffectivenessofchannel bondingandpacketpriority.
There are no ill effects from too-large receive rings. */ #define TX_QUEUE_LEN 10/* Limit ring entries actually used. */ #define TX_QUEUE_LEN_RESTART 5
#define TX_BUFLIMIT (1024-128)
/* The presumed FIFO size for working around the Tx-FIFO-overflow bug. Toavoidoverflowingwedon'tqueueagainuntilwehaveroomfora full-sizepacket.
*/ #define TX_FIFO_SIZE (2048) #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
/* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ)
/* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/rtnetlink.h> #include <linux/crc32.h> #include <linux/bitops.h> #include <linux/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/io.h> #include <asm/irq.h>
#include"tulip.h"
#undef PKT_BUF_SZ /* tulip.h also defines this */ #define PKT_BUF_SZ 1536/* Size of each temporary Rx buffer.*/
#define MII_CNT 1/* winbond only supports one MII */ struct netdev_private { struct w840_rx_desc *rx_ring;
dma_addr_t rx_addr[RX_RING_SIZE]; struct w840_tx_desc *tx_ring;
dma_addr_t tx_addr[TX_RING_SIZE];
dma_addr_t ring_dma_addr; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */
spinlock_t lock; int chip_id, drv_flags; struct pci_dev *pci_dev; int csr6; struct w840_rx_desc *rx_head_desc; unsignedint cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsignedint rx_buf_sz; /* Based on MTU+slack. */ unsignedint cur_tx, dirty_tx; unsignedint tx_q_bytes; unsignedint tx_full; /* The Tx queue is full. */ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ unsignedchar phys[MII_CNT]; /* MII device addresses, but only the first is used */
u32 mii; struct mii_if_info mii_if; void __iomem *base_addr;
};
staticint w840_probe1(struct pci_dev *pdev, conststruct pci_device_id *ent)
{ struct net_device *dev; struct netdev_private *np; staticint find_cnt; int chip_idx = ent->driver_data; int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
__le16 addr[ETH_ALEN / 2]; void __iomem *ioaddr;
i = pcim_enable_device(pdev); if (i) return i;
pci_set_master(pdev);
irq = pdev->irq;
if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
pr_warn("Device %s disabled due to DMA limitations\n",
pci_name(pdev)); return -EIO;
}
dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM;
SET_NETDEV_DEV(dev, &pdev->dev);
if (pcim_request_all_regions(pdev, DRV_NAME)) goto err_out_netdev;
ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size); if (!ioaddr) goto err_out_netdev;
for (i = 0; i < 3; i++)
addr[i] = cpu_to_le16(eeprom_read(ioaddr, i));
eth_hw_addr_set(dev, (u8 *)addr);
/* Reset the chip to erase previous misconfiguration.
No hold time required! */
iowrite32(0x00000001, ioaddr + PCIBusCfg);
/* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200)
np->mii_if.full_duplex = 1; if (option & 15)
dev_info(&dev->dev, "ignoring user supplied media type %d",
option & 15);
} if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
np->mii_if.full_duplex = 1;
if (np->mii_if.full_duplex)
np->mii_if.force_media = 1;
/* The chip-specific entries in the device structure. */
dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
i = register_netdev(dev); if (i) goto err_out_cleardev;
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are oftenserialbitstreamsgeneratedbythehostprocessor.
The example below is for the common 93c46 EEPROM, 64 16 bit words. */
/* MII transceiver control section. ReadandwritetheMIIregistersusingsoftware-generatedserial MDIOprotocol.SeetheMIIspecificationsorDP83840Adatasheet fordetails.
Themaximumdataclockrateis2.5Mhz.Theminimumtimingisusually
met by back-to-back 33Mhz PCI cycles. */ #define mdio_delay(mdio_addr) ioread32(mdio_addr)
/* Set iff a MII transceiver on any interface requires mdio preamble. Thisonlysetwitholdertransceivers,sotheextra
code size of a per-interface flag is not worthwhile. */ staticchar mii_preamble_required = 1;
/* Generate the preamble required for initial synchronization and
a few older transceivers. */ staticvoid mdio_sync(void __iomem *mdio_addr)
{ int bits = 32;
/* Establish sync by sending at least 32 logic ones. */ while (--bits >= 0) {
iowrite32(MDIO_WRITE1, mdio_addr);
mdio_delay(mdio_addr);
iowrite32(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
mdio_delay(mdio_addr);
}
}
staticint mdio_read(struct net_device *dev, int phy_id, int location)
{ struct netdev_private *np = netdev_priv(dev); void __iomem *mdio_addr = np->base_addr + MIICtrl; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0;
if (mii_preamble_required)
mdio_sync(mdio_addr);
/* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
iowrite32(dataval, mdio_addr);
mdio_delay(mdio_addr);
iowrite32(dataval | MDIO_ShiftClk, mdio_addr);
mdio_delay(mdio_addr);
} /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 20; i > 0; i--) {
iowrite32(MDIO_EnbIn, mdio_addr);
mdio_delay(mdio_addr);
retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DataIn) ? 1 : 0);
iowrite32(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
mdio_delay(mdio_addr);
} return (retval>>1) & 0xffff;
}
staticvoid mdio_write(struct net_device *dev, int phy_id, int location, int value)
{ struct netdev_private *np = netdev_priv(dev); void __iomem *mdio_addr = np->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i;
netif_start_queue(dev); if (debug > 2)
netdev_dbg(dev, "Done %s()\n", __func__);
/* Set the timer to check for link beat. */
timer_setup(&np->timer, netdev_timer, 0);
np->timer.expires = jiffies + 1*HZ;
add_timer(&np->timer); return0;
out_err:
netif_device_attach(dev); return i;
}
if (mii_reg == 0xffff) return np->csr6; /* reread: the link status bit is sticky */
mii_reg = mdio_read(dev, np->phys[0], MII_BMSR); if (!(mii_reg & 0x4)) { if (netif_carrier_ok(dev)) { if (debug)
dev_info(&dev->dev, "MII #%d reports no link. Disabling watchdog\n",
np->phys[0]);
netif_carrier_off(dev);
} return np->csr6;
} if (!netif_carrier_ok(dev)) { if (debug)
dev_info(&dev->dev, "MII #%d link is back. Enabling watchdog\n",
np->phys[0]);
netif_carrier_on(dev);
}
if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) { /* If the link partner doesn't support autonegotiation *theMIIdetectsit'sabilitieswiththe"paralleldetection". *SomeMIIsupdatetheLPAregistertotheresultoftheparallel *detection,somedon't. *TheDavicomPHY[atleast0181b800]doesn't. *Insteadbit9and13oftheBMCRareupdatedtotheresult *ofthenegotiation..
*/
mii_reg = mdio_read(dev, np->phys[0], MII_BMCR);
duplex = mii_reg & BMCR_FULLDPLX;
fasteth = mii_reg & BMCR_SPEED100;
} else { int negotiated;
mii_reg = mdio_read(dev, np->phys[0], MII_LPA);
negotiated = mii_reg & np->mii_if.advertising;
duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
fasteth = negotiated & 0x380;
}
duplex |= np->mii_if.force_media; /* remove fastether and fullduplex */
result = np->csr6 & ~0x20000200; if (duplex)
result |= 0x200; if (fasteth)
result |= 0x20000000; if (result != np->csr6 && debug)
dev_info(&dev->dev, "Setting %dMBit-%s-duplex based on MII#%d\n",
fasteth ? 100 : 10, duplex ? "full" : "half",
np->phys[0]); return result;
}
if (!netif_device_present(dev)) new = 0; if (new==np->csr6) return; /* stop both Tx and Rx processes */
iowrite32(np->csr6 & ~0x2002, ioaddr + NetworkConfig); /* wait until they have really stopped */ for (;;) { int csr5 = ioread32(ioaddr + IntrStatus); int t;
t = (csr5 >> 17) & 0x07; if (t==0||t==1) { /* rx stopped */
t = (csr5 >> 20) & 0x07; if (t==0||t==1) break;
}
limit--; if(!limit) {
dev_info(&dev->dev, "couldn't stop rxtx, IntrStatus %xh\n", csr5); break;
}
udelay(1);
}
np->csr6 = new; /* and restart them with the new configuration */
iowrite32(np->csr6, ioaddr + NetworkConfig); if (new & 0x200)
np->mii_if.full_duplex = 1;
}
/* Initial all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].length = np->rx_buf_sz;
np->rx_ring[i].status = 0;
np->rx_skbuff[i] = NULL;
} /* Mark the last entry as wrapping the ring. */
np->rx_ring[i-1].length |= DescEndRing;
/* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = netdev_alloc_skb(dev, np->rx_buf_sz);
np->rx_skbuff[i] = skb; if (skb == NULL) break;
np->rx_addr[i] = dma_map_single(&np->pci_dev->dev, skb->data,
np->rx_buf_sz,
DMA_FROM_DEVICE);
staticvoid free_rxtx_rings(struct netdev_private* np)
{ int i; /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].status = 0; if (np->rx_skbuff[i]) {
dma_unmap_single(&np->pci_dev->dev, np->rx_addr[i],
np->rx_skbuff[i]->len,
DMA_FROM_DEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
}
np->rx_skbuff[i] = NULL;
} for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) {
dma_unmap_single(&np->pci_dev->dev, np->tx_addr[i],
np->tx_skbuff[i]->len, DMA_TO_DEVICE);
dev_kfree_skb(np->tx_skbuff[i]);
}
np->tx_skbuff[i] = NULL;
}
}
for (i = 0; i < 6; i++)
iowrite8(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */ #ifdef __BIG_ENDIAN
i = (1<<20); /* Big-endian descriptors */ #else
i = 0; #endif
i |= (0x04<<2); /* skip length 4 u32 */
i |= 0x02; /* give Rx priority */
/* Configure the PCI bus bursts and FIFO thresholds. 486:Set8longwordcachealignment,8longwordburst. 586:Set16longwordcachealignment,noburstlimit. Cachealignmentbits15:14Burstlength13:8 0000<notallowed>0000aligntocache08008longwords 40008longwords01001longword100016longwords 800016longwords02002longwords200032longwords
C000 32 longwords 0400 4 longwords */
#ifdefined (__i386__) && !defined(MODULE) && !defined(CONFIG_UML) /* When not a module we can work around broken '486 PCI boards. */ if (boot_cpu_data.x86 <= 4) {
i |= 0x4800;
dev_info(&dev->dev, "This is a 386/486 PCI system, setting cache alignment to 8 longwords\n");
} else {
i |= 0xE000;
} #elifdefined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
i |= 0xE000; #elifdefined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM)
i |= 0x4800; #else
dev_warn(&dev->dev, "unknown CPU architecture, using default csr0 setting\n");
i |= 0x4800; #endif
iowrite32(i, ioaddr + PCIBusCfg);
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ staticint alloc_ringdesc(struct net_device *dev)
{ struct netdev_private *np = netdev_priv(dev);
/* Now acquire the irq spinlock. *Thedifficultraceistheorderingbetween *increasingnp->cur_txandsettingDescOwned: *-ifnp->cur_txisincreasedfirsttheinterrupt *handlercouldconsiderthepacketastransmitted *sinceDescOwnediscleared. *-IfDescOwnedissetfirsttheNICcouldreportthe *packetassent,buttheinterrupthandlerwouldignoreit *sincethenp->cur_txwasnotyetincreased.
*/
spin_lock_irq(&np->lock);
np->cur_tx++;
wmb(); /* flush length, buffer1, buffer2 */
np->tx_ring[entry].status = DescOwned;
wmb(); /* flush status and kick the hardware */
iowrite32(0, np->base_addr + TxStartDemand);
np->tx_q_bytes += skb->len; /* Work around horrible bug in the chip by marking the queue as full
when we do not have FIFO room for a maximum sized packet. */ if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN ||
((np->drv_flags & HasBrokenTx) && np->tx_q_bytes > TX_BUG_FIFO_LIMIT)) {
netif_stop_queue(dev);
wmb();
np->tx_full = 1;
}
spin_unlock_irq(&np->lock);
if (debug > 4) {
netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
np->cur_tx, entry);
} return NETDEV_TX_OK;
}
staticvoid netdev_tx_done(struct net_device *dev)
{ struct netdev_private *np = netdev_priv(dev); for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; int tx_status = np->tx_ring[entry].status;
if (tx_status < 0) break; if (tx_status & 0x8000) { /* There was an error, log it. */ #ifndef final_version if (debug > 1)
netdev_dbg(dev, "Transmit error, Tx status %08x\n",
tx_status); #endif
np->stats.tx_errors++; if (tx_status & 0x0104) np->stats.tx_aborted_errors++; if (tx_status & 0x0C80) np->stats.tx_carrier_errors++; if (tx_status & 0x0200) np->stats.tx_window_errors++; if (tx_status & 0x0002) np->stats.tx_fifo_errors++; if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
np->stats.tx_heartbeat_errors++;
} else { #ifndef final_version if (debug > 3)
netdev_dbg(dev, "Transmit slot %d ok, Tx status %08x\n",
entry, tx_status); #endif
np->stats.tx_bytes += np->tx_skbuff[entry]->len;
np->stats.collisions += (tx_status >> 3) & 15;
np->stats.tx_packets++;
} /* Free the original skb. */
dma_unmap_single(&np->pci_dev->dev, np->tx_addr[entry],
np->tx_skbuff[entry]->len, DMA_TO_DEVICE);
np->tx_q_bytes -= np->tx_skbuff[entry]->len;
dev_kfree_skb_irq(np->tx_skbuff[entry]);
np->tx_skbuff[entry] = NULL;
} if (np->tx_full &&
np->cur_tx - np->dirty_tx < TX_QUEUE_LEN_RESTART &&
np->tx_q_bytes < TX_BUG_FIFO_LIMIT) { /* The ring is no longer full, clear tbusy. */
np->tx_full = 0;
wmb();
netif_wake_queue(dev);
}
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */ static irqreturn_t intr_handler(int irq, void *dev_instance)
{ struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base_addr; int work_limit = max_interrupt_work; int handled = 0;
if (!netif_device_present(dev)) return IRQ_NONE; do {
u32 intr_status = ioread32(ioaddr + IntrStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus);
if (debug > 4)
netdev_dbg(dev, "Interrupt, status %04x\n", intr_status);
if ((intr_status & (NormalIntr|AbnormalIntr)) == 0) break;
handled = 1;
if (intr_status & (RxIntr | RxNoBuf))
netdev_rx(dev); if (intr_status & RxNoBuf)
iowrite32(0, ioaddr + RxStartDemand);
if (--work_limit < 0) {
dev_warn(&dev->dev, "Too much work at interrupt, status=0x%04x\n",
intr_status); /* Set the timer to re-enable the other interrupts after
10*82usec ticks. */
spin_lock(&np->lock); if (netif_device_present(dev)) {
iowrite32(AbnormalIntr | TimerInt, ioaddr + IntrEnable);
iowrite32(10, ioaddr + GPTimer);
}
spin_unlock(&np->lock); break;
}
} while (1);
/* This routine is logically part of the interrupt handler, but separated
for clarity and better register allocation. */ staticint netdev_rx(struct net_device *dev)
{ struct netdev_private *np = netdev_priv(dev); int entry = np->cur_rx % RX_RING_SIZE; int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
netdev_dbg(dev, " In netdev_rx(), entry %d status %04x\n",
entry, np->rx_ring[entry].status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */ while (--work_limit >= 0) { struct w840_rx_desc *desc = np->rx_head_desc;
s32 status = desc->status;
if (debug > 4)
netdev_dbg(dev, " netdev_rx() status was %08x\n",
status); if (status < 0) break; if ((status & 0x38008300) != 0x0300) { if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) {
dev_warn(&dev->dev, "Oversized Ethernet frame spanned multiple buffers, entry %#x status %04x!\n",
np->cur_rx, status);
np->stats.rx_length_errors++;
}
} elseif (status & 0x8000) { /* There was a fatal error. */ if (debug > 2)
netdev_dbg(dev, "Receive error, Rx status %08x\n",
status);
np->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) np->stats.rx_length_errors++; if (status & 0x004C) np->stats.rx_frame_errors++; if (status & 0x0002) np->stats.rx_crc_errors++;
}
} else { struct sk_buff *skb; /* Omit the four octet CRC from the length. */ int pkt_len = ((status >> 16) & 0x7ff) - 4;
#ifndef final_version if (debug > 4)
netdev_dbg(dev, " netdev_rx() normal Rx pkt length %d status %x\n",
pkt_len, status); #endif /* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak &&
(skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* 16 byte align the IP header */
dma_sync_single_for_cpu(&np->pci_dev->dev,
np->rx_addr[entry],
np->rx_skbuff[entry]->len,
DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
dma_sync_single_for_device(&np->pci_dev->dev,
np->rx_addr[entry],
np->rx_skbuff[entry]->len,
DMA_FROM_DEVICE);
} else {
dma_unmap_single(&np->pci_dev->dev,
np->rx_addr[entry],
np->rx_skbuff[entry]->len,
DMA_FROM_DEVICE);
skb_put(skb = np->rx_skbuff[entry], pkt_len);
np->rx_skbuff[entry] = NULL;
} #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5)
netdev_dbg(dev, " Rx data %pM %pM %02x%02x %pI4\n",
&skb->data[0], &skb->data[6],
skb->data[12], skb->data[13],
&skb->data[14]); #endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
np->stats.rx_packets++;
np->stats.rx_bytes += pkt_len;
}
entry = (++np->cur_rx) % RX_RING_SIZE;
np->rx_head_desc = &np->rx_ring[entry];
}
switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = ((struct netdev_private *)netdev_priv(dev))->phys[0] & 0x1f;
fallthrough;
case SIOCGMIIREG: /* Read MII PHY register. */
spin_lock_irq(&np->lock);
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
spin_unlock_irq(&np->lock); return0;
printk(KERN_DEBUG" Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++)
printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
i, np->tx_ring[i].length,
np->tx_ring[i].status, np->tx_ring[i].buffer1);
printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) {
printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
i, np->rx_ring[i].length,
np->rx_ring[i].status, np->rx_ring[i].buffer1);
}
} #endif/* __i386__ debugging only */
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.