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); }
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); }
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; }
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; }
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); }
/* 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 */ }
/* 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); }