Пример #1
0
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);
}
Пример #2
0
 void add(int i, int v){
     for (; i < n; val[i] += v, i += lowb(i));
 }
Пример #3
0
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;
}
Пример #4
0
 typev query(int i){
     typev s = 0;
     for (; i > 0; s += val[i], i -= lowb(i));
     return s;
 }