/* * 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
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); }
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; }
static int __init ether3_init_2(struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; int i; priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC; priv->regs.command = 0; /* * Set up our hardware address */ ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); for (i = 0; i < 6; i++) ether3_outb(dev->dev_addr[i], REG_BUFWIN); if (dev->flags & IFF_PROMISC) priv->regs.config1 |= CFG1_RECVPROMISC; else if (dev->flags & IFF_MULTICAST) priv->regs.config1 |= CFG1_RECVSPECBRMULTI; else priv->regs.config1 |= CFG1_RECVSPECBROAD; /* * There is a problem with the NQ8005 in that it occasionally loses the * last two bytes. To get round this problem, we receive the CRC as * well. That way, if we do loose the last two, then it doesn't matter. */ 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(0, REG_TRANSMITPTR); ether3_outw(priv->rx_head >> 8, REG_RECVEND); ether3_outw(priv->regs.config2, REG_CONFIG2); ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); ether3_outw(priv->regs.command, REG_COMMAND); i = ether3_ramtest(dev, 0x5A); if(i) return i; i = ether3_ramtest(dev, 0x1E); if(i) return i; ether3_setbuffer(dev, buffer_write, 0); ether3_writelong(dev, 0); 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 {