static int i596_open(struct device *dev) { int i; if (i596_debug > 1) printk("%s: i596_open() irq %d.\n", dev->name, dev->irq); if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", NULL)) return -EAGAIN; irq2dev_map[dev->irq] = dev; i = init_rx_bufs(dev, RX_RING_SIZE); if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE) printk("%s: only able to allocate %d receive buffers\n", dev->name, i); if (i < 4) { free_irq(dev->irq, NULL); irq2dev_map[dev->irq] = 0; return -EAGAIN; } dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; /* Initialize the 82596 memory */ init_i596_mem(dev); return 0; /* Always succeed */ }
static void init_82586_mem(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; /* Enable loopback to protect the wire while starting up, and hold the 586 in reset during the memory initialization. */ outb(0x20, ioaddr + MISC_CTRL); /* Fix the ISCP address and base. */ init_words[3] = SCB_BASE; init_words[7] = SCB_BASE; /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ isa_memcpy_toio(dev->mem_end-10, init_words, 10); /* Write the words at 0x0000. */ isa_memcpy_toio(dev->mem_start, init_words + 5, sizeof(init_words) - 10); /* Fill in the station address. */ isa_memcpy_toio(dev->mem_start+SA_OFFSET, dev->dev_addr, sizeof(dev->dev_addr)); /* The Tx-block list is written as needed. We just set up the values. */ lp->tx_cmd_link = IDLELOOP + 4; lp->tx_head = lp->tx_reap = TX_BUF_START; init_rx_bufs(dev); /* Start the 586 by releasing the reset line, but leave loopback. */ outb(0xA0, ioaddr + MISC_CTRL); /* This was time consuming to track down: you need to give two channel attention signals to reliably start up the i82586. */ outb(0, ioaddr + SIGNAL_CA); { int boguscnt = 50; while (isa_readw(shmem+iSCB_STATUS) == 0) if (--boguscnt == 0) { printk("%s: i82586 initialization timed out with status %04x," "cmd %04x.\n", dev->name, isa_readw(shmem+iSCB_STATUS), isa_readw(shmem+iSCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start. */ outb(0, ioaddr + SIGNAL_CA); } /* Disable loopback and enable interrupts. */ outb(0x84, ioaddr + MISC_CTRL); if (net_debug > 4) printk("%s: Initialized 82586, status %04x.\n", dev->name, isa_readw(shmem+iSCB_STATUS)); return; }
static void init_82586_mem(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; /* Enable loopback to protect the wire while starting up. This is Superstition From Crynwr. */ outb(inb(ioaddr + Config) | 0x02, ioaddr + Config); /* Hold the 586 in reset during the memory initialization. */ outb(_586_RESET, ioaddr + EEPROM_Ctrl); /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */ outw(0xfff6, ioaddr + WRITE_PTR); outsw(ioaddr, init_words, sizeof(init_words)>>1); /* Fill in the station address. */ outw(SA_OFFSET, ioaddr + WRITE_PTR); outsw(ioaddr, dev->dev_addr, 3); /* The Tx-block list is written as needed. We just set up the values. */ #ifdef initial_text_tx lp->tx_cmd_link = DUMP_DATA + 4; #else lp->tx_cmd_link = IDLELOOP + 4; #endif lp->tx_head = lp->tx_reap = TX_BUF_START; init_rx_bufs(dev); /* Start the 586 by releasing the reset line. */ outb(0x00, ioaddr + EEPROM_Ctrl); /* This was time consuming to track down: you need to give two channel attention signals to reliably start up the i82586. */ outb(0, ioaddr + SIGNAL_CA); { int boguscnt = 50; while (inw(ioaddr + SCB_STATUS) == 0) if (--boguscnt == 0) { printk("%s: i82586 initialization timed out with status %04x, cmd %04x.\n", dev->name, inw(ioaddr + SCB_STATUS), inw(ioaddr + SCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start without it. */ outb(0, ioaddr + SIGNAL_CA); } /* Disable loopback. */ outb(inb(ioaddr + Config) & ~0x02, ioaddr + Config); if (net_debug > 4) printk("%s: Initialized 82586, status %04x.\n", dev->name, inw(ioaddr + SCB_STATUS)); return; }
/* 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); }
/* The typical workload of the driver: Handle the network interface interrupts. */ static void eexp_interrupt(int reg_ptr) { int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; int ioaddr, status, boguscount = 0; short ack_cmd; if (dev == NULL) { printk ("net_interrupt(): irq %d for unknown device.\n", irq); return; } dev->interrupt = 1; ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; status = inw(ioaddr + SCB_STATUS); if (net_debug > 4) { printk("%s: EExp interrupt, status %4.4x.\n", dev->name, status); } /* Disable the 82586's input to the interrupt line. */ outb(irqrmap[dev->irq], ioaddr + SET_IRQ); /* Reap the Tx packet buffers. */ while (lp->tx_reap != lp->tx_head) { /* if (status & 0x8000) */ unsigned short tx_status; outw(lp->tx_reap, ioaddr + READ_PTR); tx_status = inw(ioaddr); if (tx_status == 0) { if (net_debug > 5) printk("Couldn't reap %#x.\n", lp->tx_reap); break; } if (tx_status & 0x2000) { lp->stats.tx_packets++; lp->stats.collisions += tx_status & 0xf; dev->tbusy = 0; mark_bh(NET_BH); /* Inform upper layers. */ } else { 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++; } 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 > TX_BUF_END - TX_BUF_SIZE) lp->tx_reap = TX_BUF_START; if (++boguscount > 4) break; } if (status & 0x4000) { /* Packet received. */ if (net_debug > 5) printk("Received packet, rx_head %04x.\n", lp->rx_head); eexp_rx(dev); } /* Acknowledge the interrupt sources. */ ack_cmd = status & 0xf000; if ((status & 0x0700) != 0x0200 && dev->start) { short saved_write_ptr = inw(ioaddr + WRITE_PTR); if (net_debug > 1) printk("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); /* If this ever occurs we must re-write the idle loop, reset the Tx list, and do a complete restart of the command unit. */ outw(IDLELOOP, ioaddr + WRITE_PTR); outw(0, ioaddr); outw(CmdNOp, ioaddr); outw(IDLELOOP, ioaddr); outw(IDLELOOP, SCB_CBL); lp->tx_cmd_link = IDLELOOP + 4; lp->tx_head = lp->tx_reap = TX_BUF_START; /* Restore the saved write pointer. */ outw(saved_write_ptr, ioaddr + WRITE_PTR); ack_cmd |= CUC_START; } if ((status & 0x0070) != 0x0040 && dev->start) { short saved_write_ptr = inw(ioaddr + WRITE_PTR); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ lp->stats.rx_errors++; if (net_debug > 1) { int cur_rxbuf = RX_BUF_START; printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n", dev->name, status, lp->rx_head, lp->rx_tail); while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) { int i; printk(" Rx buf at %04x:", cur_rxbuf); outw(cur_rxbuf, ioaddr + READ_PTR); for (i = 0; i < 0x20; i += 2) printk(" %04x", inw(ioaddr)); printk(".\n"); cur_rxbuf += RX_BUF_SIZE; } } init_rx_bufs(dev); outw(RX_BUF_START, SCB_RFA); outw(saved_write_ptr, ioaddr + WRITE_PTR); ack_cmd |= RX_START; } outw(ack_cmd, ioaddr + SCB_CMD); outb(0, ioaddr + SIGNAL_CA); if (net_debug > 5) { printk("%s: EExp exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + SCB_CMD)); } /* Enable the 82586's input to the interrupt line. */ outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ); return; }