static void smc_tx(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int saved_packet, packet_no, tx_status, pkt_len; DBG(3, "%s: %s\n", dev->name, __func__); packet_no = SMC_GET_TXFIFO(lp); if (unlikely(packet_no & TXFIFO_TEMPTY)) { PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); return; } saved_packet = SMC_GET_PN(lp); SMC_SET_PN(lp, packet_no); SMC_SET_PTR(lp, PTR_AUTOINC | PTR_READ); SMC_GET_PKT_HDR(lp, tx_status, pkt_len); DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n", dev->name, tx_status, packet_no); if (!(tx_status & ES_TX_SUC)) dev->stats.tx_errors++; if (tx_status & ES_LOSTCARR) dev->stats.tx_carrier_errors++; if (tx_status & (ES_LATCOL | ES_16COL)) { PRINTK("%s: %s occurred on last xmit\n", dev->name, (tx_status & ES_LATCOL) ? "late collision" : "too many collisions"); dev->stats.tx_window_errors++; if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { printk(KERN_INFO "%s: unexpectedly large number of " "bad collisions. Please check duplex " "setting.\n", dev->name); } } SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_FREEPKT); SMC_WAIT_MMU_BUSY(lp); SMC_SET_PN(lp, saved_packet); SMC_SELECT_BANK(lp, 0); SMC_SET_TCR(lp, lp->tcr_cur_mode); SMC_SELECT_BANK(lp, 2); }
static void smc_hardware_send_pkt(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; struct sk_buff *skb; unsigned int packet_no, len; unsigned char *buf; unsigned long flags; DBG(3, "%s: %s\n", dev->name, __func__); if (!smc_special_trylock(&lp->lock, flags)) { netif_stop_queue(dev); tasklet_schedule(&lp->tx_task); return; } skb = lp->pending_tx_skb; if (unlikely(!skb)) { smc_special_unlock(&lp->lock, flags); return; } lp->pending_tx_skb = NULL; packet_no = SMC_GET_AR(lp); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); dev->stats.tx_errors++; dev->stats.tx_fifo_errors++; smc_special_unlock(&lp->lock, flags); goto done; } SMC_SET_PN(lp, packet_no); SMC_SET_PTR(lp, PTR_AUTOINC); buf = skb->data; len = skb->len; DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", dev->name, packet_no, len, len, buf); PRINT_PKT(buf, len); SMC_PUT_PKT_HDR(lp, 0, len + 6); SMC_PUSH_DATA(lp, buf, len & ~1); SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp)); if (THROTTLE_TX_PKTS) netif_stop_queue(dev); SMC_SET_MMU_CMD(lp, MC_ENQUEUE); smc_special_unlock(&lp->lock, flags); dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += len; SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT); done: if (!THROTTLE_TX_PKTS) netif_wake_queue(dev); dev_kfree_skb(skb); }
/* * This is called to actually send a packet to the chip. */ static void smc_hardware_send_pkt(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; struct sk_buff *skb; unsigned int packet_no, len; unsigned char *buf; unsigned long flags; DBG(3, "%s: %s\n", dev->name, __func__); if (!smc_special_trylock(&lp->lock, flags)) { netif_stop_queue(dev); tasklet_schedule(&lp->tx_task); return; } skb = lp->pending_tx_skb; if (unlikely(!skb)) { smc_special_unlock(&lp->lock, flags); return; } lp->pending_tx_skb = NULL; packet_no = SMC_GET_AR(lp); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); dev->stats.tx_errors++; dev->stats.tx_fifo_errors++; smc_special_unlock(&lp->lock, flags); goto done; } /* point to the beginning of the packet */ SMC_SET_PN(lp, packet_no); SMC_SET_PTR(lp, PTR_AUTOINC); buf = skb->data; len = skb->len; DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", dev->name, packet_no, len, len, buf); PRINT_PKT(buf, len); /* * Send the packet length (+6 for status words, length, and ctl. * The card will pad to 64 bytes with zeroes if packet is too small. */ SMC_PUT_PKT_HDR(lp, 0, len + 6); /* send the actual data */ SMC_PUSH_DATA(lp, buf, len & ~1); /* Send final ctl word with the last byte if there is one */ SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp)); /* * If THROTTLE_TX_PKTS is set, we stop the queue here. This will * have the effect of having at most one packet queued for TX * in the chip's memory at all time. * * If THROTTLE_TX_PKTS is not set then the queue is stopped only * when memory allocation (MC_ALLOC) does not succeed right away. */ if (THROTTLE_TX_PKTS) netif_stop_queue(dev); /* queue the packet for TX */ SMC_SET_MMU_CMD(lp, MC_ENQUEUE); smc_special_unlock(&lp->lock, flags); dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += len; SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT); done: if (!THROTTLE_TX_PKTS) netif_wake_queue(dev); dev_kfree_skb(skb); }
static inline void smc_rcv(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int packet_number, status, packet_len; DBG(3, "%s: %s\n", dev->name, __func__); packet_number = SMC_GET_RXFIFO(lp); if (unlikely(packet_number & RXFIFO_REMPTY)) { PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); return; } SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC); SMC_GET_PKT_HDR(lp, status, packet_len); packet_len &= 0x07ff; DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", dev->name, packet_number, status, packet_len, packet_len); back: if (unlikely(packet_len < 6 || status & RS_ERRORS)) { if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) { status &= ~RS_TOOLONG; goto back; } if (packet_len < 6) { printk(KERN_ERR "%s: fubar (rxlen %u status %x\n", dev->name, packet_len, status); status |= RS_TOOSHORT; } SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); dev->stats.rx_errors++; if (status & RS_ALGNERR) dev->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) dev->stats.rx_length_errors++; if (status & RS_BADCRC) dev->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; unsigned int data_len; if (status & RS_MULTICAST) dev->stats.multicast++; skb = dev_alloc_skb(packet_len); if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", dev->name); SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); dev->stats.rx_dropped++; return; } skb_reserve(skb, 2); if (lp->version == 0x90) status |= RS_ODDFRAME; data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); data = skb_put(skb, data_len); SMC_PULL_DATA(lp, data, packet_len - 4); SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); PRINT_PKT(data, packet_len - 4); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += data_len; } }
/* * This is the procedure to handle the receipt of a packet. */ static inline void smc_rcv(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int packet_number, status, packet_len; DBG(3, "%s: %s\n", dev->name, __func__); packet_number = SMC_GET_RXFIFO(lp); if (unlikely(packet_number & RXFIFO_REMPTY)) { PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); return; } /* read from start of packet */ SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC); /* First two words are status and packet length */ SMC_GET_PKT_HDR(lp, status, packet_len); packet_len &= 0x07ff; /* mask off top bits */ DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", dev->name, packet_number, status, packet_len, packet_len); back: if (unlikely(packet_len < 6 || status & RS_ERRORS)) { if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) { /* accept VLAN packets */ status &= ~RS_TOOLONG; goto back; } if (packet_len < 6) { /* bloody hardware */ printk(KERN_ERR "%s: fubar (rxlen %u status %x\n", dev->name, packet_len, status); status |= RS_TOOSHORT; } SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); dev->stats.rx_errors++; if (status & RS_ALGNERR) dev->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) dev->stats.rx_length_errors++; if (status & RS_BADCRC) dev->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; unsigned int data_len; /* set multicast stats */ if (status & RS_MULTICAST) dev->stats.multicast++; /* * Actual payload is packet_len - 6 (or 5 if odd byte). * We want skb_reserve(2) and the final ctrl word * (2 bytes, possibly containing the payload odd byte). * Furthermore, we add 2 bytes to allow rounding up to * multiple of 4 bytes on 32 bit buses. * Hence packet_len - 6 + 2 + 2 + 2. */ skb = dev_alloc_skb(packet_len); if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", dev->name); SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); dev->stats.rx_dropped++; return; } /* Align IP header to 32 bits */ skb_reserve(skb, 2); /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ if (lp->version == 0x90) status |= RS_ODDFRAME; /* * If odd length: packet_len - 5, * otherwise packet_len - 6. * With the trailing ctrl byte it's packet_len - 4. */ data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); data = skb_put(skb, data_len); SMC_PULL_DATA(lp, data, packet_len - 4); SMC_WAIT_MMU_BUSY(lp); SMC_SET_MMU_CMD(lp, MC_RELEASE); PRINT_PKT(data, packet_len - 4); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += data_len; } }