static irqreturn_t ariadne_interrupt(int irq, void *data) { struct net_device *dev = (struct net_device *)data; volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr; struct ariadne_private *priv; int csr0, boguscnt; int handled = 0; lance->RAP = CSR0; /* PCnet-ISA Controller Status */ if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ return IRQ_NONE; /* generated by the board */ priv = netdev_priv(dev); boguscnt = 10; while ((csr0 = lance->RDP) & (ERR | RINT | TINT) && --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP */ lance->RDP = csr0 & ~(INEA | TDMD | STOP | STRT | INIT); #ifdef DEBUG if (ariadne_debug > 5) { netdev_dbg(dev, "interrupt csr0=%#02x new csr=%#02x [", csr0, lance->RDP); if (csr0 & INTR) pr_cont(" INTR"); if (csr0 & INEA) pr_cont(" INEA"); if (csr0 & RXON) pr_cont(" RXON"); if (csr0 & TXON) pr_cont(" TXON"); if (csr0 & TDMD) pr_cont(" TDMD"); if (csr0 & STOP) pr_cont(" STOP"); if (csr0 & STRT) pr_cont(" STRT"); if (csr0 & INIT) pr_cont(" INIT"); if (csr0 & ERR) pr_cont(" ERR"); if (csr0 & BABL) pr_cont(" BABL"); if (csr0 & CERR) pr_cont(" CERR"); if (csr0 & MISS) pr_cont(" MISS"); if (csr0 & MERR) pr_cont(" MERR"); if (csr0 & RINT) pr_cont(" RINT"); if (csr0 & TINT) pr_cont(" TINT"); if (csr0 & IDON) pr_cont(" IDON"); pr_cont(" ]\n"); } #endif if (csr0 & RINT) { /* Rx interrupt */ handled = 1; ariadne_rx(dev); } if (csr0 & TINT) { /* Tx-done interrupt */ int dirty_tx = priv->dirty_tx; handled = 1; while (dirty_tx < priv->cur_tx) { int entry = dirty_tx % TX_RING_SIZE; int status = lowb(priv->tx_ring[entry]->TMD1); if (status & TF_OWN) break; /* It still hasn't been Txed */ priv->tx_ring[entry]->TMD1 &= 0xff00; if (status & TF_ERR) { /* There was an major error, log it */ int err_status = priv->tx_ring[entry]->TMD3; dev->stats.tx_errors++; if (err_status & EF_RTRY) dev->stats.tx_aborted_errors++; if (err_status & EF_LCAR) dev->stats.tx_carrier_errors++; if (err_status & EF_LCOL) dev->stats.tx_window_errors++; if (err_status & EF_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */ dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */ netdev_err(dev, "Tx FIFO error! Status %04x\n", csr0); /* Restart the chip */ lance->RDP = STRT; } } else { if (status & (TF_MORE | TF_ONE)) dev->stats.collisions++; dev->stats.tx_packets++; } dirty_tx++; } #ifndef final_version if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) { netdev_err(dev, "out-of-sync dirty pointer, %d vs. %d, full=%d\n", dirty_tx, priv->cur_tx, priv->tx_full); dirty_tx += TX_RING_SIZE; } #endif if (priv->tx_full && netif_queue_stopped(dev) && dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full */ priv->tx_full = 0; netif_wake_queue(dev); } priv->dirty_tx = dirty_tx; } /* Log misc errors */ if (csr0 & BABL) { handled = 1; dev->stats.tx_errors++; /* Tx babble */ } if (csr0 & MISS) { handled = 1; dev->stats.rx_errors++; /* Missed a Rx frame */ } if (csr0 & MERR) { handled = 1; netdev_err(dev, "Bus master arbitration failure, status %04x\n", csr0); /* Restart the chip */ lance->RDP = STRT; } } /* Clear any other interrupt, and set interrupt enable */ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ lance->RDP = INEA | BABL | CERR | MISS | MERR | IDON; if (ariadne_debug > 4) netdev_dbg(dev, "exiting interrupt, csr%d=%#04x\n", lance->RAP, lance->RDP); return IRQ_RETVAL(handled); }
void add(int i, int v){ for (; i < n; val[i] += v, i += lowb(i)); }
static int ariadne_rx(struct net_device *dev) { struct ariadne_private *priv = netdev_priv(dev); int entry = priv->cur_rx % RX_RING_SIZE; int i; /* If we own the next entry, it's a new packet. Send it up */ while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) { int status = lowb(priv->rx_ring[entry]->RMD1); if (status != (RF_STP | RF_ENP)) { /* There was an error */ /* There is a tricky error noted by * John Murphy <*****@*****.**> to Russ Nelson: * Even with full-sized buffers it's possible for a * jabber packet to use two buffers, with only the * last correctly noting the error */ /* Only count a general error at the end of a packet */ if (status & RF_ENP) dev->stats.rx_errors++; if (status & RF_FRAM) dev->stats.rx_frame_errors++; if (status & RF_OFLO) dev->stats.rx_over_errors++; if (status & RF_CRC) dev->stats.rx_crc_errors++; if (status & RF_BUFF) dev->stats.rx_fifo_errors++; priv->rx_ring[entry]->RMD1 &= 0xff00 | RF_STP | RF_ENP; } else { /* Malloc up new buffer, compatible with net-3 */ short pkt_len = swapw(priv->rx_ring[entry]->RMD3); struct sk_buff *skb; skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) { netdev_warn(dev, "Memory squeeze, deferring packet\n"); for (i = 0; i < RX_RING_SIZE; i++) if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN) break; if (i > RX_RING_SIZE - 2) { dev->stats.rx_dropped++; priv->rx_ring[entry]->RMD1 |= RF_OWN; priv->cur_rx++; } break; } skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, pkt_len); /* Make room */ skb_copy_to_linear_data(skb, (const void *)priv->rx_buff[entry], pkt_len); skb->protocol = eth_type_trans(skb, dev); netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n", ((u_short *)skb->data)[6], skb->data + 6, skb->data, (int)skb->data, (int)skb->len); netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } priv->rx_ring[entry]->RMD1 |= RF_OWN; entry = (++priv->cur_rx) % RX_RING_SIZE; } priv->cur_rx = priv->cur_rx % RX_RING_SIZE; /* We should check that at least two ring entries are free. * If not, we should free one and mark stats->rx_dropped++ */ return 0; }
typev query(int i){ typev s = 0; for (; i > 0; s += val[i], i -= lowb(i)); return s; }