/* * 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 int __devinit ether3_ramtest(struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); int i,ret = 0; int max_errors = 4; int bad = -1; if (!buffer) return 1; memset(buffer, byte, RX_END); ether3_setbuffer(dev, buffer_write, 0); ether3_writebuffer(dev, buffer, TX_END); ether3_setbuffer(dev, buffer_write, RX_START); ether3_writebuffer(dev, buffer + RX_START, RX_LEN); memset(buffer, byte ^ 0xff, RX_END); ether3_setbuffer(dev, buffer_read, 0); ether3_readbuffer(dev, buffer, TX_END); ether3_setbuffer(dev, buffer_read, RX_START); ether3_readbuffer(dev, buffer + RX_START, RX_LEN); for (i = 0; i < RX_END; i++) { if (buffer[i] != byte) { if (max_errors > 0 && bad != buffer[i]) { printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X", dev->name, buffer[i], byte, i); ret = 2; max_errors--; bad = i; } } else { if (bad != -1) { if (bad != i - 1) printk(" - 0x%04X\n", i - 1); printk("\n"); bad = -1; } } } if (bad != -1) printk(" - 0xffff\n"); kfree(buffer); return ret; }
/* * 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 {