📄 em86xx_eth.c
字号:
if (em86xx_set_mac(dev)) return(-EIO); /* stop MAC engine */ em86xx_write_reg(EM86XX_CR_REG, 0x0); #ifndef USE_HW_FILTERING /* set up multicast hash table to MCHTHR MCHTLR */ /* set multicast hash table to accept all */ em86xx_write_reg(EM86XX_MCHTHR_REG, 0xffffffff); em86xx_write_reg(EM86XX_MCHTLR_REG, 0xffffffff); #else /* clear hash table */ em86xx_write_reg( EM86XX_MCHTHR_REG, 0 ); em86xx_write_reg( EM86XX_MCHTLR_REG, 0 ); /* set the broadcast address */ n = em86xx_hash(broadcast_addr); if( n >= 32 ) em86xx_write_reg(EM86XX_MCHTHR_REG, 1 << (n-32) ); else em86xx_write_reg(EM86XX_MCHTLR_REG, 1 << n );#endif /* resetting descriptors */#ifdef BOOTLOADER if (em86xx_eth_reset_desc(dev, &reset_flag))#else if (em86xx_eth_reset_desc(&em86xx_eth_dev, &reset_flag))#endif return(-EIO); /* configure IFR with PHY and speed, as well as PHY */ em86xx_link_config(dev, max_link_loop); return 0;}#ifndef BOOTLOADER/* Monitor the status of link, re-do link initialization if necessary. */static void em86xx_eth_link_monitor(unsigned long dummy){ unsigned long link_status; struct net_device *dev = (struct net_device *)dummy; int res; /* Setup the link/configuration is not done so. */ if ((link_up == 0) || (link_configured == 0)) { res = em86xx_eth_hw_init(dev); } /* Get link status and adjust the delay loop accordingly */ link_status = (em86xx_mii_read(1, GEN_sts) & LINK) ; if (link_status) { if ((link_configured != 0) && (link_up != 0)) { if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); /* Up and running, turn netif on */ max_link_loop = DEF_LINK_LOOP; ld_count >>= 2; if (ld_count == 0) ld_count = 1; } } else { ld_count <<= 1; max_link_loop = ld_count * DEF_LINK_LOOP; if (max_link_loop > DEF_MAX_LINK_LOOP) max_link_loop = DEF_MAX_LINK_LOOP; netif_carrier_off(dev); link_configured = 0; } } else { MSG_PRINT("%s: detected link down.\n", dev->name); ld_count <<= 1; max_link_loop = ld_count * DEF_LINK_LOOP; if (max_link_loop > DEF_MAX_LINK_LOOP) max_link_loop = DEF_MAX_LINK_LOOP; netif_carrier_off(dev); link_up = link_configured = 0; } /* Schedule for the next time */ mod_timer(ð_timer, jiffies + HZ*5); }#endif/* Setting rx/tx descriptors */static void em86xx_eth_setup_desc(void){ register int i; struct em86xx_desc *desc_ptr = NULL; unsigned long base_addr = 0; /* Setup rx descriptor */ desc_ptr = (struct em86xx_desc *)(rxdsc); for (i = 0; i < (num_rxdesc - 1); i++, desc_ptr++) { desc_ptr->desc3 = (unsigned long)(desc_ptr + 1); desc_ptr->desc1 = (DescChain | R_BUF_SIZE); desc_ptr->desc0 = DescOwnByDma; } desc_ptr->desc3 = (unsigned long)(rxdsc); desc_ptr->desc1 = (DescChain | DescEndOfRing | R_BUF_SIZE); desc_ptr->desc0 = DescOwnByDma; /* Setup tx descriptor */ desc_ptr = (struct em86xx_desc *)(txdsc); for (i =0; i < (num_txdesc - 1); i++, desc_ptr++) { desc_ptr->desc3 = (unsigned long)(desc_ptr + 1); desc_ptr->desc1 = (TX_DESC1_FLAGS | T_BUF_SIZE); desc_ptr->desc0 = DescOwnByCPU; } desc_ptr->desc3 = (unsigned long)(txdsc); desc_ptr->desc1 = (TX_DESC1_FLAGS | DescEndOfRing | T_BUF_SIZE); desc_ptr->desc0 = DescOwnByCPU; /* Point rx descriptor to buffer */ desc_ptr = (struct em86xx_desc *)(rxdsc); base_addr = (unsigned long)(rxbuf); for (i = 0; i < num_rxdesc; i++, desc_ptr++, base_addr += R_BUF_SIZE) desc_ptr->desc2 = base_addr; /* Point tx descriptor to buffer */ desc_ptr = (struct em86xx_desc *)(txdsc); base_addr = (unsigned long)(txbuf); for (i = 0; i < num_txdesc; i++, desc_ptr++, base_addr += T_BUF_SIZE) desc_ptr->desc2 = base_addr;}/* Starting up the ethernet device */static int em86xx_eth_open(struct net_device *dev){ EM86XX_ETH_PRIV *private = (EM86XX_ETH_PRIV *)dev->priv; if ((dev == NULL) || (private == NULL)) return(-EIO); DBG_PRINT("%s: starting interface.\n", dev->name);#ifdef BOOTLOADER em86xx_eth_hw_init(dev); dev->state = NETDEV_UP;#else /* Schedule timer for monitoring link status */ init_timer(ð_timer); eth_timer.function = em86xx_eth_link_monitor; eth_timer.data = (unsigned long)dev; mod_timer(ð_timer, jiffies + HZ); netif_start_queue(dev);#endif /*BOOTLOADER*/ return 0;}/* Stopping the ethernet device */static int em86xx_eth_close(struct net_device *dev){ if (dev == NULL) return(-EIO); /* Turn off IRQ and stop receive/transmit */ em86xx_write_reg(EM86XX_CR_REG, 0); em86xx_write_reg(EM86XX_IER_REG, 0);#ifdef BOOTLOADER dev->state = NETDEV_DOWN;#else /* Kill timer */ del_timer_sync(ð_timer); /* Stop the transmit queue */ netif_stop_queue(dev); link_up = link_configured = 0;#endif /*BOOTLOADER*/ return 0;}#ifndef BOOTLOADER/* Setup multicast list */static void em86xx_eth_set_multicast_list(struct net_device *dev){ /* Multicast hash filter */ u32 mc_filter[2]; int i, rx_mode; rx_mode = em86xx_read_reg(EM86XX_MACCR_REG); DBG_PRINT(KERN_DEBUG"%s: set_rx_mode(0x%x) done -- rx_mode=0x%x.\n", dev->name, dev->flags, rx_mode); if (dev->flags & IFF_PROMISC) { printk("%s: Promiscuous mode enabled.\n", dev->name); rx_mode |= MacPromiscuousModeOn; mc_filter[1] = mc_filter[0] = 0xffffffff; } else { struct dev_mc_list *mclist; rx_mode &= ~MacPromiscuousModeOn; mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next){ int n = 0; n = em86xx_hash(mclist->dmi_addr); if( n >= 32 ) mc_filter[1] |= 1 << (n-32) ; else mc_filter[0] |= 1 << n ; } } em86xx_write_reg(EM86XX_MACCR_REG, rx_mode ); em86xx_write_reg(EM86XX_MCHTLR_REG, mc_filter[0]); em86xx_write_reg(EM86XX_MCHTHR_REG, mc_filter[1]); return;}#endif/* Transmit a packet */#ifdef BOOTLOADERstatic int em86xx_eth_tx(struct sk_buff *skb, struct net_device *dev, int async)#elsestatic int em86xx_eth_tx(struct sk_buff *skb, struct net_device *dev)#endif{ EM86XX_ETH_PRIV *private = NULL; volatile struct em86xx_desc *desc_ptr = NULL; struct net_device_stats *stats = NULL; unsigned long length = 0; //int j; if ((skb == NULL) || (dev == NULL)) { DBG_PRINT("em86xx_eth_tx: null dev\n"); return(-EIO); } else if ((link_up == 0) || (link_configured == 0)) { DBG_PRINT("em86xx_eth_tx: link is not up yet\n");#ifndef BOOTLOADER netif_carrier_off(dev);#endif return(-EIO); } else if ((length = ((ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN)) > T_BUF_SIZE) { DBG_PRINT("em86xx_eth_tx: too big\n"); return(-ENOMEM); } private = (EM86XX_ETH_PRIV *)dev->priv; stats = &(private->stats); /* Send packet to device */ desc_ptr = (volatile struct em86xx_desc *)(&txdsc[private->next_txidx]); if (desc_ptr->desc0 & DescOwnByDma) { stats->tx_dropped++; ERR_PRINT("%s desc_ptr=0x%x: tx error (descriptor not owned by CPU).\n", dev->name, (u32)desc_ptr); return(-EIO); } /* Check if previous transmission has error */ if (desc_ptr->desc0 & TX_ERROR_FLAGS) { ERR_PRINT("%s: tx error 0x%08lx\n", dev->name, desc_ptr->desc0); /* Update stats */ stats->tx_errors++; stats->tx_packets--; stats->tx_bytes -= (desc_ptr->desc1 & DescSize1Mask); } /* Copy packet data to tx buffer */ DBG_PRINT("tx copy data from skb->data=0x%x to desc2=0x%x length=0x%lx\n", (u32)skb->data, desc_ptr->desc2, length ); memcpy((unsigned char *)(desc_ptr->desc2), skb->data, length); /* Setup tx descriptor */ desc_ptr->desc1 = ( TX_DESC1_FLAGS | length ); if (private->next_txidx == (num_txdesc - 1)) desc_ptr->desc1 |= DescEndOfRing ; desc_ptr->desc0 |= DescOwnByDma;#ifdef BOOTLOADER private->next_txidx = imodulus((private->next_txidx + 1), num_txdesc);#else dev->trans_start = jiffies; private->next_txidx = ((private->next_txidx + 1) % num_txdesc);#endif /* Start transmission (should be in suspend mode already) */ em86xx_write_reg(EM86XX_TPDR_REG, 0x0); /* Update stats */ stats->tx_packets++; stats->tx_bytes += length; /* Free up socket buffer */#ifdef BOOTLOADER async = 0; skb_free(skb);#else dev_kfree_skb(skb);#endif return 0;}static inline int is_sw_filtered_packet(struct net_device *dev, unsigned char *data){#ifdef USE_SW_FILTERING if (((data[0] & 0x80) == 0) && (dev->dev_addr[5] != data[5])) return 1; else return 0;#else return 0;#endif}/* Receiving packet(s) */static int em86xx_eth_rx(struct net_device *dev){ EM86XX_ETH_PRIV *private = NULL; struct sk_buff *skb = NULL; struct net_device_stats *stats = NULL; unsigned char *data = NULL; volatile struct em86xx_desc *desc_ptr = NULL; unsigned long length = 0; unsigned long dsc = 0; unsigned long count = 0, cnt = 0; if (dev == NULL) return(-EIO); else { private = (EM86XX_ETH_PRIV *)dev->priv; stats = &(private->stats); } /* Go thru descriptors list until we ran out or encounterred the one being processed by DMA */#ifdef BOOTLOADER for (cnt = 0, count = private->last_rxidx; cnt < num_rxdesc; cnt++, count = imodulus(count + 1, num_rxdesc)) {#else for (cnt = 0, count = private->last_rxidx; cnt < num_rxdesc; cnt++, count = ((count + 1) % num_rxdesc)) {#endif desc_ptr = (volatile struct em86xx_desc *)(&rxdsc[count]); dsc = desc_ptr->desc0; if (dsc & DescOwnByDma) { /* DMA is processing this one, break out the loop */ break; } /*filter out those are not for me */ data = (unsigned char *)(desc_ptr->desc2); if (is_sw_filtered_packet(dev, data)) { ERR_PRINT("%s: mac mismatched, dropped.\n", dev->name); } else if ( dsc & RX_ERROR_FLAGS ) { ERR_PRINT("%s: rx error 0x%08lx:%ld desc1=0x%08x\n", dev->name, dsc, count, (u32)desc_ptr->desc1); /* We dropped any error packet */ stats->rx_errors++; } else if ((dsc & MP_FRAME_FLAGS) != MP_FRAME_FLAGS) { ERR_PRINT("%s: multi-packet frame detected 0x%08lx\n", dev->name, dsc); /* We don't handle multi-packet frame, for now */ stats->rx_dropped++; } else if ((length = ((dsc & DescFrameLengthMask) >> DescFrameLengthShift)) > R_BUF_SIZE) { ERR_PRINT("%s: rx dropped (size too large: %ld)\n", dev->name, length); stats->rx_dropped++;#ifdef BOOTLOADER } else if ((skb = skb_alloc(length)) == NULL) {#else } else if ((skb = dev_alloc_skb(length + 2)) == NULL) {#endif ERR_PRINT("%s: rx dropped (memory unavailable)\n", dev->name); stats->rx_dropped++; } else { skb->dev = dev;#ifdef BOOTLOADER skb->len = length - 4; memcpy(skb->data, data, length-4); skb_put(skb); /* Update stats */ stats->rx_packets++; stats->rx_bytes += length;#else skb_reserve(skb, 2); memcpy(skb_put(skb, length), data, length-4); skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* Send the packet to kernel */ netif_rx(skb); /* Update stats */ stats->rx_packets++; stats->rx_bytes += length; dev->last_rx = jiffies;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -