/* * 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; }
/* * If we have a good packet(s), get it/them out of the buffers. */ static int ether3_rx(struct net_device *dev, unsigned int maxcnt) { unsigned int next_ptr = priv(dev)->rx_head, received = 0; ether3_ledon(dev); do { unsigned int this_ptr, status; unsigned char addrs[16]; /* * read the first 16 bytes from the buffer. * This contains the status bytes etc and ethernet addresses, * and we also check the source ethernet address to see if * it originated from us. */ { unsigned int temp_ptr; ether3_setbuffer(dev, buffer_read, next_ptr); temp_ptr = ether3_readword(dev); status = ether3_readword(dev); if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) != (RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr) break; this_ptr = next_ptr + 4; next_ptr = ntohs(temp_ptr); } ether3_setbuffer(dev, buffer_read, this_ptr); ether3_readbuffer(dev, addrs+2, 12); if (next_ptr < RX_START || next_ptr >= RX_END) { int i; printk("%s: bad next pointer @%04X: ", dev->name, priv(dev)->rx_head); printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8); for (i = 2; i < 14; i++) printk("%02X ", addrs[i]); printk("\n"); next_ptr = priv(dev)->rx_head; break; } /* * ignore our own packets... */ if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) && !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) { maxcnt ++; /* compensate for loopedback packet */ ether3_outw(next_ptr >> 8, REG_RECVEND); } else
/* * 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 {