Exemple #1
0
void msnd_init_queue(unsigned long base, int start, int size)
{
	isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
	isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
	isa_writew(0, base + JQS_wHead);
	isa_writew(0, base + JQS_wTail);
}
Exemple #2
0
static void el16_tx_timeout (struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	int ioaddr = dev->base_addr;
	unsigned long shmem = dev->mem_start;

	if (net_debug > 1)
		printk ("%s: transmit timed out, %s?  ", dev->name,
			isa_readw (shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
			"network cable problem");
	/* Try to restart the adaptor. */
	if (lp->last_restart == lp->stats.tx_packets) {
		if (net_debug > 1)
			printk ("Resetting board.\n");
		/* Completely reset the adaptor. */
		init_82586_mem (dev);
		lp->tx_pkts_in_ring = 0;
	} else {
		/* Issue the channel attention signal and hope it "gets better". */
		if (net_debug > 1)
			printk ("Kicking board.\n");
		isa_writew (0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
		outb (0, ioaddr + SIGNAL_CA);	/* Issue channel-attn. */
		lp->last_restart = lp->stats.tx_packets;
	}
	dev->trans_start = jiffies;
	netif_wake_queue (dev);
}
Exemple #3
0
static int el16_close(struct net_device *dev)
{
	int ioaddr = dev->base_addr;
	unsigned long shmem = dev->mem_start;

	netif_stop_queue(dev);

	/* Flush the Tx and disable Rx. */
	isa_writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
	outb(0, ioaddr + SIGNAL_CA);

	/* Disable the 82586's input to the interrupt line. */
	outb(0x80, ioaddr + MISC_CTRL);

	/* We always physically use the IRQ line, so we don't do free_irq(). */

	/* Update the statistics here. */

	return 0;
}
Exemple #4
0
static void el16_rx(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *)dev->priv;
	unsigned long shmem = dev->mem_start;
	ushort rx_head = lp->rx_head;
	ushort rx_tail = lp->rx_tail;
	ushort boguscount = 10;
	short frame_status;

	while ((frame_status = isa_readw(shmem+rx_head)) < 0) {   /* Command complete */
		unsigned long read_frame = dev->mem_start + rx_head;
		ushort rfd_cmd = isa_readw(read_frame+2);
		ushort next_rx_frame = isa_readw(read_frame+4);
		ushort data_buffer_addr = isa_readw(read_frame+6);
		unsigned long data_frame = dev->mem_start + data_buffer_addr;
		ushort pkt_len = isa_readw(data_frame);

		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
			|| (pkt_len & 0xC000) != 0xC000) {
			printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
				   "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
				   frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
				   pkt_len);
		} else if ((frame_status & 0x2000) == 0) {
			/* Frame Rxed, but with error. */
			lp->stats.rx_errors++;
			if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
			if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
			if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
			if (frame_status & 0x0100) lp->stats.rx_over_errors++;
			if (frame_status & 0x0080) lp->stats.rx_length_errors++;
		} else {
			/* Malloc up new buffer. */
			struct sk_buff *skb;

			pkt_len &= 0x3fff;
			skb = dev_alloc_skb(pkt_len+2);
			if (skb == NULL) {
				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
				lp->stats.rx_dropped++;
				break;
			}

			skb_reserve(skb,2);
			skb->dev = dev;

			/* 'skb->data' points to the start of sk_buff data area. */
			isa_memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);

			skb->protocol=eth_type_trans(skb,dev);
			netif_rx(skb);
			dev->last_rx = jiffies;
			lp->stats.rx_packets++;
			lp->stats.rx_bytes += pkt_len;
		}

		/* Clear the status word and set End-of-List on the rx frame. */
		isa_writew(0,read_frame);
		isa_writew(0xC000,read_frame+2);
		/* Clear the end-of-list on the prev. RFD. */
		isa_writew(0x0000,dev->mem_start + rx_tail + 2);

		rx_tail = rx_head;
		rx_head = next_rx_frame;
		if (--boguscount == 0)
			break;
	}

	lp->rx_head = rx_head;
	lp->rx_tail = rx_tail;
}
Exemple #5
0
static void hardware_send_packet(struct net_device *dev, void *buf, short length)
{
	struct net_local *lp = (struct net_local *)dev->priv;
	short ioaddr = dev->base_addr;
	ushort tx_block = lp->tx_head;
	unsigned long write_ptr = dev->mem_start + tx_block;

	/* Set the write pointer to the Tx block, and put out the header. */
	isa_writew(0x0000,write_ptr);			/* Tx status */
	isa_writew(CMD_INTR|CmdTx,write_ptr+=2);		/* Tx command */
	isa_writew(tx_block+16,write_ptr+=2);		/* Next command is a NoOp. */
	isa_writew(tx_block+8,write_ptr+=2);			/* Data Buffer offset. */

	/* Output the data buffer descriptor. */
	isa_writew(length | 0x8000,write_ptr+=2);		/* Byte count parameter. */
	isa_writew(-1,write_ptr+=2);			/* No next data buffer. */
	isa_writew(tx_block+22+SCB_BASE,write_ptr+=2);	/* Buffer follows the NoOp command. */
	isa_writew(0x0000,write_ptr+=2);			/* Buffer address high bits (always zero). */

	/* Output the Loop-back NoOp command. */
	isa_writew(0x0000,write_ptr+=2);			/* Tx status */
	isa_writew(CmdNOp,write_ptr+=2);			/* Tx command */
	isa_writew(tx_block+16,write_ptr+=2);		/* Next is myself. */

	/* Output the packet at the write pointer. */
	isa_memcpy_toio(write_ptr+2, buf, length);

	/* Set the old command link pointing to this send packet. */
	isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);
	lp->tx_cmd_link = tx_block + 20;

	/* Set the next free tx region. */
	lp->tx_head = tx_block + TX_BUF_SIZE;
	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
		lp->tx_head = TX_BUF_START;

	if (net_debug > 4) {
		printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
			   dev->name, ioaddr, length, tx_block, lp->tx_head);
	}

	/* Grimly block further packets if there has been insufficient reaping. */
	if (++lp->tx_pkts_in_ring < NUM_TX_BUFS) 
		netif_wake_queue(dev);
}
Exemple #6
0
/* Initialize the Rx-block list. */
static void init_rx_bufs(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *)dev->priv;
	unsigned long write_ptr;
	unsigned short SCB_base = SCB_BASE;

	int cur_rxbuf = lp->rx_head = RX_BUF_START;

	/* Initialize each Rx frame + data buffer. */
	do {	/* While there is room for one more. */

	  write_ptr = dev->mem_start + cur_rxbuf;

		isa_writew(0x0000,write_ptr);			/* Status */
		isa_writew(0x0000,write_ptr+=2);			/* Command */
		isa_writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);	/* Link */
		isa_writew(cur_rxbuf + 22,write_ptr+=2);		/* Buffer offset */
		isa_writew(0x0000,write_ptr+=2);			/* Pad for dest addr. */
		isa_writew(0x0000,write_ptr+=2);
		isa_writew(0x0000,write_ptr+=2);
		isa_writew(0x0000,write_ptr+=2);			/* Pad for source addr. */
		isa_writew(0x0000,write_ptr+=2);
		isa_writew(0x0000,write_ptr+=2);
		isa_writew(0x0000,write_ptr+=2);			/* Pad for protocol. */

		isa_writew(0x0000,write_ptr+=2);			/* Buffer: Actual count */
		isa_writew(-1,write_ptr+=2);			/* Buffer: Next (none). */
		isa_writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
		isa_writew(0x0000,write_ptr+=2);
		/* Finally, the number of bytes in the buffer. */
		isa_writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);

		lp->rx_tail = cur_rxbuf;
		cur_rxbuf += RX_BUF_SIZE;
	} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);

	/* Terminate the list by setting the EOL bit, and wrap the pointer to make
	   the list a ring. */
	write_ptr = dev->mem_start + lp->rx_tail + 2;
	isa_writew(0xC000,write_ptr);				/* Command, mark as last. */
	isa_writew(lp->rx_head,write_ptr+2);			/* Link */
}
Exemple #7
0
/*	The typical workload of the driver:
	Handle the network interface interrupts. */
static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct net_device *dev = dev_id;
	struct net_local *lp;
	int ioaddr, status, boguscount = 0;
	ushort ack_cmd = 0;
	unsigned long shmem;

	if (dev == NULL) {
		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
		return;
	}

	ioaddr = dev->base_addr;
	lp = (struct net_local *)dev->priv;
	shmem = dev->mem_start;

	spin_lock(&lp->lock);

	status = isa_readw(shmem+iSCB_STATUS);

	if (net_debug > 4) {
		printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
	}

	/* Disable the 82586's input to the interrupt line. */
	outb(0x80, ioaddr + MISC_CTRL);

	/* Reap the Tx packet buffers. */
	while (lp->tx_pkts_in_ring) {
	  unsigned short tx_status = isa_readw(shmem+lp->tx_reap);
	  if (!(tx_status & 0x8000)) {
		if (net_debug > 5) 
			printk("Tx command incomplete (%#x).\n", lp->tx_reap);
		break;
	  }
	  /* Tx unsuccessful or some interesting status bit set. */
	  if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
		lp->stats.tx_errors++;
		if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
		if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
		if (!(tx_status & 0x0040))  lp->stats.tx_heartbeat_errors++;
		if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
		lp->stats.collisions += tx_status & 0xf;
	  }
	  lp->stats.tx_packets++;
	  if (net_debug > 5)
		  printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
	  lp->tx_reap += TX_BUF_SIZE;
	  if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
		lp->tx_reap = TX_BUF_START;

	  lp->tx_pkts_in_ring--;
	  /* There is always more space in the Tx ring buffer now. */
	  netif_wake_queue(dev);

	  if (++boguscount > 10)
		break;
	}

	if (status & 0x4000) { /* Packet received. */
		if (net_debug > 5)
			printk("Received packet, rx_head %04x.\n", lp->rx_head);
		el16_rx(dev);
	}

	/* Acknowledge the interrupt sources. */
	ack_cmd = status & 0xf000;

	if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
		if (net_debug)
			printk("%s: Command unit stopped, status %04x, restarting.\n",
				   dev->name, status);
		/* If this ever occurs we should really re-write the idle loop, reset
		   the Tx list, and do a complete restart of the command unit.
		   For now we rely on the Tx timeout if the resume doesn't work. */
		ack_cmd |= CUC_RESUME;
	}

	if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
		static void init_rx_bufs(struct net_device *);
		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
		   initializing the rx buffers, and issuing an Rx start command. */
		if (net_debug)
			printk("%s: Rx unit stopped, status %04x, restarting.\n",
				   dev->name, status);
		init_rx_bufs(dev);
		isa_writew(RX_BUF_START,shmem+iSCB_RFA);
		ack_cmd |= RX_START;
	}

	isa_writew(ack_cmd,shmem+iSCB_CMD);
	outb(0, ioaddr + SIGNAL_CA);			/* Issue channel-attn. */

	/* Clear the latched interrupt. */
	outb(0, ioaddr + RESET_IRQ);

	/* Enable the 82586's interrupt input. */
	outb(0x84, ioaddr + MISC_CTRL);
	spin_unlock(&lp->lock);
}