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; } }