int tulip_poll(struct napi_struct *napi, int budget)
{ struct tulip_private *tp = container_of(napi, struct tulip_private, napi); struct net_device *dev = tp->dev; int entry = tp->cur_rx % RX_RING_SIZE; int work_done = 0; #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION int received = 0; #endif
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* that one buffer is needed for mit activation; or might be a
bug in the ring buffer code; check later -- JHS*/
if (budget >=RX_RING_SIZE) budget--; #endif
if (tulip_debug > 4)
netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n",
entry, tp->rx_ring[entry].status);
do { if (ioread32(tp->base_addr + CSR5) == 0xffffffff) {
netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); break;
} /* Acknowledge current RX interrupt sources. */
iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5);
/* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status); short pkt_len;
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) break;
if (tulip_debug > 5)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, status);
if ((status & (RxLengthOver2047 |
RxDescCRCError |
RxDescCollisionSeen |
RxDescRunt |
RxDescDescErr |
RxWholePkt)) != RxWholePkt ||
pkt_len > 1518) { if ((status & (RxLengthOver2047 |
RxWholePkt)) != RxWholePkt) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1)
dev_warn(&dev->dev, "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
dev->stats.rx_length_errors++;
}
} else { /* There was a fatal error. */ if (tulip_debug > 2)
netdev_dbg(dev, "Receive error, Rx status %08x\n",
status);
dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 ||
(status & RxDescRunt))
dev->stats.rx_length_errors++;
if (status & 0x0004)
dev->stats.rx_frame_errors++; if (status & 0x0002)
dev->stats.rx_crc_errors++; if (status & 0x0001)
dev->stats.rx_fifo_errors++;
}
} else { struct sk_buff *skb;
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */ if (pkt_len < tulip_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(&tp->pdev->dev,
tp->rx_buffers[entry].mapping,
pkt_len,
DMA_FROM_DEVICE); #if ! defined(__alpha__)
skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
pkt_len);
skb_put(skb, pkt_len); #else
skb_put_data(skb,
tp->rx_buffers[entry].skb->data,
pkt_len); #endif
dma_sync_single_for_device(&tp->pdev->dev,
tp->rx_buffers[entry].mapping,
pkt_len,
DMA_FROM_DEVICE);
} else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
pkt_len);
#ifndef final_version if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
dev_err(&dev->dev, "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n",
le32_to_cpu(tp->rx_ring[entry].buffer1),
(unsignedlonglong)tp->rx_buffers[entry].mapping,
skb->head, temp);
} #endif
/* New ack strategy... irq does not ack Rx any longer
hopefully this helps */
/* Really bad things can happen here... If new packet arrives *andanirqarrives(txorjustduetooccasionallyunset *mask),itwillbeackedbyirqhandler,butnewthread *isnotscheduled.Itismajorholeindesign. *Noideahowtofixthisif"playingwithfire"willfail *tomorrow(night011029).Ifitwillnotfail,wewon
* finally: amount of IO did not increase at all. */
} while ((ioread32(tp->base_addr + CSR5) & RxIntr));
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* We use this simplistic scheme for IM. It's proven by reallifeinstallations.WecanhaveIMenabled continueslybutthiswouldcauseunnecessarylatency. Unfortunelywecan'tusealltheNET_RX_*feedbackhere. ThiswouldturnonIMfordevicesthatisnotcontributing tobacklogcongestionwithunnecessarylatency.
/* The last op happens after poll completion. Which means the following: *1.itcanracewithdisablingirqsinirqhandler *2.itcanracewithdise/enablingirqsinotherpollthreads *3.ifanirqraisedafterbeginningloop,itwillbeimmediately *triggeredhere. * *Summarizing:thelogicresultsinsomeredundantirqsboth *duetoracesinmaskingandduetotoolateackingofalready *processedirqs.Butitmustnotresultinlosingevents.
*/
if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
return work_done;
oom: /* Executed with RX ints disabled */
/* Start timer, stop polling, but do not enable rx interrupts. */
mod_timer(&tp->oom_timer, jiffies+1);
/* Think: timer_pending() was an explicit signature of bug. *Timercanbependingnowbutfiredandcompleted
* before we did napi_complete(). See? We would lose it. */
/* remove ourselves from the polling list */
napi_complete_done(napi, work_done);
return work_done;
}
#else/* CONFIG_TULIP_NAPI */
staticint tulip_rx(struct net_device *dev)
{ struct tulip_private *tp = netdev_priv(dev); int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; int received = 0;
if (tulip_debug > 4)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status); short pkt_len;
if (tulip_debug > 5)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, status); if (--rx_work_limit < 0) break;
if ((status & (RxLengthOver2047 |
RxDescCRCError |
RxDescCollisionSeen |
RxDescRunt |
RxDescDescErr |
RxWholePkt)) != RxWholePkt ||
pkt_len > 1518) { if ((status & (RxLengthOver2047 |
RxWholePkt)) != RxWholePkt) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1)
netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
dev->stats.rx_length_errors++;
}
} else { /* There was a fatal error. */ if (tulip_debug > 2)
netdev_dbg(dev, "Receive error, Rx status %08x\n",
status);
dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 ||
(status & RxDescRunt))
dev->stats.rx_length_errors++; if (status & 0x0004)
dev->stats.rx_frame_errors++; if (status & 0x0002)
dev->stats.rx_crc_errors++; if (status & 0x0001)
dev->stats.rx_fifo_errors++;
}
} else { struct sk_buff *skb;
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */ if (pkt_len < tulip_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(&tp->pdev->dev,
tp->rx_buffers[entry].mapping,
pkt_len,
DMA_FROM_DEVICE); #if ! defined(__alpha__)
skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
pkt_len);
skb_put(skb, pkt_len); #else
skb_put_data(skb,
tp->rx_buffers[entry].skb->data,
pkt_len); #endif
dma_sync_single_for_device(&tp->pdev->dev,
tp->rx_buffers[entry].mapping,
pkt_len,
DMA_FROM_DEVICE);
} else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
pkt_len);
#ifndef final_version if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
dev_err(&dev->dev, "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n",
le32_to_cpu(tp->rx_ring[entry].buffer1),
(longlong)tp->rx_buffers[entry].mapping,
skb->head, temp);
} #endif
if (csr12 != tp->csr12_shadow) { /* ack interrupt */
iowrite32(csr12 | 0x02, tp->base_addr + CSR12);
tp->csr12_shadow = csr12; /* do link change stuff */
spin_lock(&tp->lock);
tulip_check_duplex(dev);
spin_unlock(&tp->lock); /* clear irq ack bit */
iowrite32(csr12 & ~0x02, tp->base_addr + CSR12);
return1;
} #endif
return0;
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
irqreturn_t tulip_interrupt(int irq, void *dev_instance)
{ struct net_device *dev = (struct net_device *)dev_instance; struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int csr5; int missed; int rx = 0; int tx = 0; int oi = 0; int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; #ifdef CONFIG_TULIP_NAPI int rxd = 0; #else int entry; #endif unsignedint work_count = tulip_max_interrupt_work; unsignedint handled = 0;
/* Let's see whether the interrupt really is for us */
csr5 = ioread32(ioaddr + CSR5);
if (tp->flags & HAS_PHY_IRQ)
handled = phy_interrupt (dev);
if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) return IRQ_RETVAL(handled);
tp->nir++;
do {
#ifdef CONFIG_TULIP_NAPI
if (!rxd && (csr5 & (RxIntr | RxNoBuf))) {
rxd++; /* Mask RX intrs and add the device to poll list. */
iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
napi_schedule(&tp->napi);
if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break;
}
/* Acknowledge the interrupt sources we handle here ASAP
the poll function does Rx and RxNoBuf acking */
iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5);
#else /* Acknowledge all of the current interrupt sources ASAP. */
iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5);
for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status);
if (status < 0) break; /* It still has not been Txed */
/* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping)
dma_unmap_single(&tp->pdev->dev,
tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame),
DMA_TO_DEVICE); continue;
}
if (status & 0x8000) { /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1)
netdev_dbg(dev, "Transmit error, Tx status %08x\n",
status); #endif
dev->stats.tx_errors++; if (status & 0x4104)
dev->stats.tx_aborted_errors++; if (status & 0x0C00)
dev->stats.tx_carrier_errors++; if (status & 0x0200)
dev->stats.tx_window_errors++; if (status & 0x0002)
dev->stats.tx_fifo_errors++; if ((status & 0x0080) && tp->full_duplex == 0)
dev->stats.tx_heartbeat_errors++;
} else {
dev->stats.tx_bytes +=
tp->tx_buffers[entry].skb->len;
dev->stats.collisions += (status >> 3) & 15;
dev->stats.tx_packets++;
}
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.