📄 eth8186.c
字号:
drop_frag: if (frag_skb) { dev_kfree_skb_irq(frag_skb); cp->frag_skb = NULL; } if (last_frag) { cp->net_stats.rx_dropped++; cp->dropping_frag = 0; } return; } copy_skb->dev = cp->dev; skb_reserve(copy_skb, RX_OFFSET); skb_put(copy_skb, target_len); if (frag_skb) { memcpy(copy_skb->data, frag_skb->data, orig_len); dev_kfree_skb_irq(frag_skb); } memcpy(copy_skb->data + orig_len, skb->data, len); copy_skb->ip_summed = CHECKSUM_NONE; if (last_frag) { if (status & (RxError)) { rtl8186_rx_err_acct(cp, rx_tail, status, len); dev_kfree_skb_irq(copy_skb); } else rtl8186_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]); cp->frag_skb = NULL; } else { cp->frag_skb = copy_skb; }}static inline unsigned int rtl8186_rx_csum_ok(u32 status){ unsigned int protocol = (status >> 16) & 0x3; if (likely((protocol == RxProtoTCP) && (!(status & TCPFail)))) return 1; else if ((protocol == RxProtoUDP) && (!(status & UDPFail))) return 1; else if ((protocol == RxProtoIP) && (!(status & IPFail))) return 1; return 0;}static inline void rtl8186_rx(unsigned long task_priv){ struct re_private *cp = (struct re_private *)task_priv; unsigned rx_tail = cp->rx_tail; unsigned rx_work = 100; u32 status, len; dma_addr_t mapping; struct sk_buff *skb, *new_skb; DMA_DESC *desc; unsigned buflen; while (rx_work--) { skb = cp->rx_skb[rx_tail].skb; if (!skb) BUG(); desc = &cp->rx_ring[rx_tail]; status = desc->opts1; if (status & DescOwn) break; // ethernet CRC-4 bytes- are padding after the payload len = (status & 0x0fff) - 4; mapping = cp->rx_skb[rx_tail].mapping; if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) { rtl8186_rx_frag(cp, rx_tail, skb, status, len); goto rx_next; } if (status & (RxError)) { rtl8186_rx_err_acct(cp, rx_tail, status, len); goto rx_next; } if (netif_msg_rx_status(cp)) printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n", cp->dev->name, rx_tail, status, len); buflen = cp->rx_buf_sz + RX_OFFSET; new_skb = dev_alloc_skb (buflen); if (!new_skb) { cp->net_stats.rx_dropped++; goto rx_next; } if ((u32)new_skb->data &0x3) printk(KERN_DEBUG "new_skb->data unaligment %8x\n",(u32)new_skb->data); /*skb_reserve(new_skb, RX_OFFSET);*/ new_skb->dev = cp->dev; /* Handle checksum offloading for incoming packets. */ if (rtl8186_rx_csum_ok(status)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; skb_reserve(skb, RX_OFFSET); skb_put(skb, len); mapping = cp->rx_skb[rx_tail].mapping = (u32)new_skb->tail | UNCACHE_MASK; rtl8186_rx_skb(cp, skb, desc); cp->rx_skb[rx_tail].skb = new_skb; cp->rx_ring[rx_tail].addr = virt_to_bus((void *)mapping);rx_next: if (rx_tail == (RTL8186_RX_RING_SIZE - 1)) desc->opts1 = (DescOwn | RingEnd | cp->rx_buf_sz); else desc->opts1 = (DescOwn | cp->rx_buf_sz); cp->rx_ring[rx_tail].opts2 = 0; rx_tail = NEXT_RX(rx_tail); } r3k_flush_dcache_range(0,0); if (!rx_work) printk(KERN_WARNING "%s: rx work limit reached\n", cp->dev->name); cp->rx_tail = rx_tail;#ifdef DELAY_RX if (RTL_R16(IMR) == 0) { RTL_W16(IMR, rtl8186_intr_mask); // re-accept all interrupt RTL_R16(IMR); }#endif}static inline void rtl8186_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = dev_instance; struct re_private *cp = dev->priv; u16 status; spin_lock(&cp->lock); status = RTL_R16(ISR); RTL_W16(ISR,status); //printk("%s: intr, status %04x cmd %02x \n",dev->name,status,RTL_R8(CMD)); if (!status || (status == 0xFFFF)) return; //if (status & LINK_CHG) // printk("%s: Link change\n",dev->name); if (netif_msg_intr(cp)) printk(KERN_DEBUG "%s: intr, status %04x cmd %02x \n", dev->name, status, RTL_R8(CMD)); if (status & (RX_OK | RX_ERR | RX_EMPTY | RX_FIFOOVR)) {#if 0 if(!(status & RX_OK)) printk("%s rx error =%x\n",dev->name,status); if(status & RX_EMPTY) printk("eRDU "); if(status & RX_FIFOOVR) printk("eFIFO ");#endif#ifndef DELAY_RX rtl8186_rx((unsigned long)cp);#else if (eth_flag & 1) rtl8186_rx((unsigned long)cp); else { RTL_W16(IMR, 0); // disable ISR tasklet_hi_schedule(&cp->rx_tasklet); }#endif } if (status & (TX_OK | TX_ERR | TX_EMPTY | SW_INT)) { if (!(status & TX_OK) && !(status & TX_EMPTY)) printk("%s tx error =%x\n", dev->name, status); rtl8186_tx(cp); } spin_unlock(&cp->lock);}static inline void rtl8186_tx(struct re_private *cp){ unsigned tx_head = cp->tx_hqhead; unsigned tx_tail = cp->tx_hqtail; while (tx_tail != tx_head) { struct sk_buff *skb; u32 status; status = (cp->tx_hqring[tx_tail].opts1); if (status & DescOwn) break; skb = cp->tx_skb[tx_tail].skb; cp->tx_hqring[tx_tail].addr = 0x0; cp->tx_hqring[tx_tail].opts1 = 0x0; if (!skb) BUG(); cp->net_stats.tx_packets++; cp->net_stats.tx_bytes += skb->len; if (netif_msg_tx_done(cp)) printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail); dev_kfree_skb_irq(skb); cp->tx_skb[tx_tail].skb = NULL; tx_tail = NEXT_TX(tx_tail); } cp->tx_hqtail = tx_tail; if (netif_queue_stopped(cp->dev) && (TX_HQBUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))) netif_wake_queue(cp->dev);}static int rtl8186_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct re_private *cp = dev->priv; unsigned entry; u32 eor;#if CP_VLAN_TAG_USED u32 vlan_tag = 0;#endif#ifdef VLAN_QOS struct qos_node *pbuf;#endif#ifdef DRIVER_SPEEDUP struct Qdisc *q=dev->qdisc; int deq_loop=0; unsigned int flags;dequeue_label: if (deq_loop) { save_flags(flags);cli(); // fetch a new skb for tx if ((skb = q->dequeue(q)) == NULL) { // polling TX RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL); restore_flags(flags); return 0; } restore_flags(flags); //printk("next tx skb\n"); }#endif spin_lock_irq(&cp->lock); /* This is a hard error, log it. */ if (TX_HQBUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irq(&cp->lock);// printk(KERN_ERR PFX "%s: Tx Ring full when queue awake!\n",// dev->name);#ifdef DRIVER_SPEEDUP if (deq_loop) { q->ops->requeue(skb, q); netif_schedule(dev); } RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL);#endif return 0; }#if CP_VLAN_TAG_USED if (cp->vlgrp && vlan_tx_tag_present(skb)) vlan_tag = TxVlanTag | vlan_tx_tag_get(skb);#endif#if 0 //sc_yang if ( (skb->len>1514) ) for(;;) { printk("error tx len = %d \n",skb->len); }#endif entry = cp->tx_hqhead; eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0; // if skb contains a full/single packet if (skb_shinfo(skb)->nr_frags == 0) { DMA_DESC *txd = &cp->tx_hqring[entry]; u32 mapping, len; len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0; CP_VLAN_TX_TAG(txd, vlan_tag); mapping = (u32)skb->data|UNCACHE_MASK; txd->addr = virt_to_bus((void *)mapping); cp->tx_skb[entry].skb = skb; cp->tx_skb[entry].mapping = mapping; cp->tx_skb[entry].frag = 0; txd->opts1 = (eor | len | DescOwn | FirstFrag | LastFrag | TxCRC);#ifdef VLAN_QOS pbuf = qosnode_lookup(cp, skb->data); if ((pbuf == 0) || (pbuf->vlan_tagged == 0)) txd->opts2 = 0; else txd->opts2 = TxVlanTag | ((skb->cb[0] & 0x07) << 5) | pbuf->vlan_id_h | (pbuf->vlan_id_l << 8);#endif entry = NEXT_TX(entry); } else { // fragmented packet DMA_DESC *txd; u32 first_len, first_mapping; int frag, first_entry = entry; /* We must give this initial chunk to the device last. * Otherwise we could race with the device. */ first_len = skb->len - skb->data_len; first_mapping = (u32)skb->data|UNCACHE_MASK; cp->tx_skb[entry].skb = skb; cp->tx_skb[entry].mapping = first_mapping; cp->tx_skb[entry].frag = 1; entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; u32 len, mapping; u32 ctrl; len = this_frag->size; mapping = (u32)this_frag->page_offset|UNCACHE_MASK; eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0; ctrl = eor | len | DescOwn | TxCRC; if (frag == skb_shinfo(skb)->nr_frags - 1) ctrl |= LastFrag; txd = &cp->tx_hqring[entry]; CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr = virt_to_bus((void *)mapping); txd->opts1 = (ctrl); cp->tx_skb[entry].skb = skb; cp->tx_skb[entry].mapping = mapping; cp->tx_skb[entry].frag = frag + 2; entry = NEXT_TX(entry); } txd = &cp->tx_hqring[first_entry]; CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr = virt_to_bus((void *)first_mapping); eor = (first_entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0; txd->opts1 = (first_len | FirstFrag | DescOwn|TxCRC|eor); } cp->tx_hqhead = entry; if (netif_msg_tx_queued(cp)) printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); if (TX_HQBUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); spin_unlock_irq(&cp->lock);#ifndef DRIVER_SPEEDUP RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL);#else deq_loop++; goto dequeue_label;#endif dev->trans_start = jiffies; return 0;}/* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */static void __rtl8186_set_rx_mode(struct net_device *dev){ //struct re_private *cp = dev->priv; u8 mc_filter[8]; /* Multicast hash filter */ int i, rx_mode; //u32 tmp;// printk("%s: %s %d Still Unimplemented !!!!!!!\n",__FILE__,__FUNCTION__,__LINE__); return; /* Note: do not reorder, GCC is clever about common statements. */ if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; for (i=0;i<8;i++) mc_filter[i] = 0xff; } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; for (i=0;i<8;i++) mc_filter[i] = 0xff; } else { struct dev_mc_list *mclist; rx_mode = AcceptBroadcast | AcceptMyPhys; for (i=0;i<8;i++) mc_filter[i] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {#if 0 int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;#endif#if 0 // arthur int bit_nr = 0; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast;#endif } }}static void rtl8186_set_rx_mode(struct net_device *dev){ unsigned long flags; struct re_private *cp = dev->priv; spin_lock_irqsave (&cp->lock, flags); __rtl8186_set_rx_mode(dev); spin_unlock_irqrestore (&cp->lock, flags);}static void __rtl8186_get_stats(struct re_private *cp){ /* XXX implement */}static struct net_device_stats *rtl8186_get_stats(struct net_device *dev){ struct re_private *cp = dev->priv; /* The chip only need report frame silently dropped. */ spin_lock_irq(&cp->lock); if (netif_running(dev) && netif_device_present(dev)) __rtl8186_get_stats(cp); spin_unlock_irq(&cp->lock); return &cp->net_stats;}/* * Disable TX/RX through IO_CMD register */static void rtl8186_stop_hw(struct net_device *dev, struct re_private *cp){ RTL_W16(IMR, 0); RTL_W16(ISR, 0xffff); RTL_W32(IO_CMD, 0); /* timer rx int 1 packets */ synchronize_irq(); udelay(10); cp->rx_tail = 0; cp->tx_hqhead = cp->tx_hqtail = 0;}static void rtl8186_reset_hw(struct re_private *cp){ unsigned work = 1000; RTL_W8(CMD, 0x1); /* Reset */ while (work--) { if (!(RTL_R8(CMD) & 0x1)) return; set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(10); } printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);}static inline void rtl8186_start_hw(struct re_private *cp){ // set TX/RX setting/enable TX/RX RTL_W32(IO_CMD, CMD_CONFIG);}static void rtl8186_init_hw(struct re_private *cp){ struct net_device *dev = cp->dev; u8 status; rtl8186_reset_hw(cp);#ifdef RTL8186_CHECKSUM_OFFLOAD RTL_W8(CMD, 0x2);#endif#ifdef VLAN_QOS RTL_W8(CMD, RTL_R8(CMD)|0x4);#endif RTL_W16(ISR, 0xffff); RTL_W16(IMR, rtl8186_intr_mask); RTL_W32(RxFDP, virt_to_bus((void *)(cp->rx_ring)));#if DEBUG writecheck = RTL_R32(RxFDP); if (writecheck != ((u32)cp->rx_ring)) for (;;);#endif RTL_W16(RxCDO, 0); RTL_W32(TxFDP1, virt_to_bus((void *)(cp->tx_hqring)));#if DEBUG writecheck = RTL_R32(TxFDP1); if (writecheck != ((u32)cp->tx_hqring)) for (;;);#endif RTL_W16(TxCDO1, 0); RTL_W32(TxFDP2, (u32)cp->tx_lqring); RTL_W16(TxCDO2, 0); RTL_W32(RCR, AcceptAll); RTL_W32(TCR, (u32)(0xC00)); RTL_W8(RxRingSize, RINGSIZE); status = RTL_R8(MSR); status = status & ~(TXFCE | RXFCE); RTL_W8(MSR, status); mdelay(200); RTL_W32(MIIAR, BIT(26)|0x30000); // read PHY type mdelay(200); if ((RTL_R32(MIIAR)&0x0000ffff) == 0x8201) { // if PHY == 8201 printk("%s:phy is 8201\n", dev->name); RTL_W32(MIIAR, BIT(31)|BIT(26)|0x3300); // Reset/re-auto-nego } else { // should be 8305 printk("%s:phy is 8305\n", dev->name); if(dev->base_addr == 0xbd200000) RTL_W32(MIIAR, BIT(31)|BIT(30)|0x3300); // LAN MII is open else RTL_W32(MIIAR, BIT(31)|BIT(28)|0x1300); // WAN is port 4 (5th port) } mdelay(200); RTL_W8(IDR0, dev->dev_addr[0]); RTL_W8(IDR1, dev->dev_addr[1]); RTL_W8(IDR2, dev->dev_addr[2]); RTL_W8(IDR3, dev->dev_addr[3]); RTL_W8(IDR4, dev->dev_addr[4]); RTL_W8(IDR5, dev->dev_addr[5]); rtl8186_start_hw(cp); __rtl8186_set_rx_mode(dev);}static int rtl8186_refill_rx(struct re_private *cp){ unsigned i; for (i = 0; i < RTL8186_RX_RING_SIZE; i++) { struct sk_buff *skb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -