static int ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) { int timeout = 1000; ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { if (!timeout--) { printk("%s: setbuffer broken\n", dev->name); priv(dev)->broken = 1; return 1; } udelay(1); } if (read == buffer_read) { ether3_outw(start, REG_DMAADDR); ether3_outw(priv(dev)->regs.command | CMD_FIFOREAD, REG_COMMAND); } else { ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); ether3_outw(start, REG_DMAADDR); } return 0; }
static irqreturn_t ether3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; unsigned int status, handled = IRQ_NONE; #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("eth3irq: %d ", irq); #endif status = ether3_inw(REG_STATUS); if (status & STAT_INTRX) { ether3_outw(CMD_ACKINTRX | priv(dev)->regs.command, REG_COMMAND); ether3_rx(dev, 12); handled = IRQ_HANDLED; } if (status & STAT_INTTX) { ether3_outw(CMD_ACKINTTX | priv(dev)->regs.command, REG_COMMAND); ether3_tx(dev); handled = IRQ_HANDLED; } #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("done\n"); #endif return handled; }
static void ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; struct dev_priv *priv; unsigned int status; #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("eth3irq: %d ", irq); #endif priv = (struct dev_priv *)dev->priv; status = ether3_inw(REG_STATUS); if (status & STAT_INTRX) { ether3_outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND); ether3_rx(dev, priv, 12); } if (status & STAT_INTTX) { ether3_outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND); ether3_tx(dev, priv); } #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("done\n"); #endif }
/* * Transmit a packet */ static int ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; length = (length + 1) & ~1; if (priv->broken) { dev_kfree_skb(skb); priv->stats.tx_dropped ++; netif_start_queue(dev); return 0; } next_ptr = (priv->tx_head + 1) & 15; save_flags_cli(flags); if (priv->tx_tail == next_ptr) { restore_flags(flags); return 1; /* unable to queue */ } dev->trans_start = jiffies; ptr = 0x600 * priv->tx_head; priv->tx_head = next_ptr; next_ptr *= 0x600; #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) ether3_setbuffer(dev, buffer_write, next_ptr); ether3_writelong(dev, 0); ether3_setbuffer(dev, buffer_write, ptr); ether3_writelong(dev, 0); ether3_writebuffer(dev, skb->data, length); ether3_writeword(dev, htons(next_ptr)); ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); ether3_setbuffer(dev, buffer_write, ptr); ether3_writeword(dev, htons((ptr + length + 4))); ether3_writeword(dev, TXHDR_FLAGS >> 16); ether3_ledon(dev, priv); if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { ether3_outw(ptr, REG_TRANSMITPTR); ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND); } next_ptr = (priv->tx_head + 1) & 15; restore_flags(flags); dev_kfree_skb(skb); if (priv->tx_tail == next_ptr) netif_stop_queue(dev); return 0; }
static inline int ether3_probe_bus_16(struct net_device *dev, int val) { int read_val; ether3_outw(val, REG_RECVPTR); read_val = ether3_inw(REG_RECVPTR); printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val); return read_val == val; }
static void ether3_timeout(struct net_device *dev) { unsigned long flags; del_timer(&priv(dev)->timer); local_irq_save(flags); printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, priv(dev)->tx_head, priv(dev)->tx_tail); ether3_setbuffer(dev, buffer_read, priv(dev)->tx_tail); printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); local_irq_restore(flags); priv(dev)->regs.config2 |= CFG2_CTRLO; dev->stats.tx_errors += 1; ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); priv(dev)->tx_head = priv(dev)->tx_tail = 0; netif_wake_queue(dev); }
/* * The inverse routine to ether3_open(). */ static int ether3_close(struct net_device *dev) { netif_stop_queue(dev); disable_irq(dev->irq); ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); priv(dev)->regs.command = 0; while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)) barrier(); ether3_outb(0x80, REG_CONFIG2 + 4); ether3_outw(0, REG_COMMAND); free_irq(dev->irq, dev); return 0; }
/* * The inverse routine to ether3_open(). */ static int ether3_close(struct device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; dev->tbusy = 1; dev->start = 0; disable_irq(dev->irq); ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); priv->regs.command = 0; while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)); ether3_outb(0x80, REG_CONFIG2 + 1); ether3_outw(0, REG_COMMAND); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return 0; }
static void ether3_init_for_open(struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; int i; memset(&priv->stats, 0, sizeof(struct net_device_stats)); /* Reset the chip */ ether3_outw(CFG2_RESET, REG_CONFIG2); udelay(4); priv->regs.command = 0; ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)); ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); for (i = 0; i < 6; i++) ether3_outb(dev->dev_addr[i], REG_BUFWIN); priv->tx_head = 0; priv->tx_tail = 0; priv->regs.config2 |= CFG2_CTRLO; priv->rx_head = RX_START; ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); ether3_outw((TX_END>>8) - 1, REG_BUFWIN); ether3_outw(priv->rx_head, REG_RECVPTR); ether3_outw(priv->rx_head >> 8, REG_RECVEND); ether3_outw(0, REG_TRANSMITPTR); ether3_outw(priv->regs.config2, REG_CONFIG2); ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); ether3_setbuffer(dev, buffer_write, 0); ether3_writelong(dev, 0); priv->regs.command = CMD_ENINTRX | CMD_ENINTTX; ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND); }
/* * Transmit a packet */ static int ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; if (priv(dev)->broken) { dev_kfree_skb(skb); dev->stats.tx_dropped++; netif_start_queue(dev); return NETDEV_TX_OK; } length = (length + 1) & ~1; if (length != skb->len) { if (skb_padto(skb, length)) goto out; } next_ptr = (priv(dev)->tx_head + 1) & 15; local_irq_save(flags); if (priv(dev)->tx_tail == next_ptr) { local_irq_restore(flags); return NETDEV_TX_BUSY; /* unable to queue */ } ptr = 0x600 * priv(dev)->tx_head; priv(dev)->tx_head = next_ptr; next_ptr *= 0x600; #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) ether3_setbuffer(dev, buffer_write, next_ptr); ether3_writelong(dev, 0); ether3_setbuffer(dev, buffer_write, ptr); ether3_writelong(dev, 0); ether3_writebuffer(dev, skb->data, length); ether3_writeword(dev, htons(next_ptr)); ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); ether3_setbuffer(dev, buffer_write, ptr); ether3_writeword(dev, htons((ptr + length + 4))); ether3_writeword(dev, TXHDR_FLAGS >> 16); ether3_ledon(dev); if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { ether3_outw(ptr, REG_TRANSMITPTR); ether3_outw(priv(dev)->regs.command | CMD_TXON, REG_COMMAND); } next_ptr = (priv(dev)->tx_head + 1) & 15; local_irq_restore(flags); dev_kfree_skb(skb); if (priv(dev)->tx_tail == next_ptr) netif_stop_queue(dev); out: return NETDEV_TX_OK; }
/* * Transmit a packet */ static int ether3_sendpacket(struct sk_buff *skb, struct device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; retry: if (!dev->tbusy) { /* Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (!test_and_set_bit(0, (void *)&dev->tbusy)) { unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; length = (length + 1) & ~1; if (priv->broken) { dev_kfree_skb(skb); priv->stats.tx_dropped ++; dev->tbusy = 0; return 0; } next_ptr = (priv->tx_head + 1) & 15; save_flags_cli(flags); if (priv->tx_tail == next_ptr) { restore_flags(flags); return 1; /* unable to queue */ } dev->trans_start = jiffies; ptr = 0x600 * priv->tx_head; priv->tx_head = next_ptr; next_ptr *= 0x600; #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) ether3_setbuffer(dev, buffer_write, next_ptr); ether3_writelong(dev, 0); ether3_setbuffer(dev, buffer_write, ptr); ether3_writelong(dev, 0); ether3_writebuffer(dev, skb->data, length); ether3_writeword(dev, htons(next_ptr)); ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); ether3_setbuffer(dev, buffer_write, ptr); ether3_writeword(dev, htons((ptr + length + 4))); ether3_writeword(dev, TXHDR_FLAGS >> 16); ether3_ledon(dev, priv); if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { ether3_outw(ptr, REG_TRANSMITPTR); ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND); } next_ptr = (priv->tx_head + 1) & 15; if (priv->tx_tail != next_ptr) dev->tbusy = 0; restore_flags(flags); dev_kfree_skb(skb); return 0; } else {