mv643xx_eth.c
来自「linux 内核源代码」· C语言 代码 · 共 2,216 行 · 第 1/5 页
C
2,216 行
/* These are for big-endian machines. Little endian needs different * definitions. */#if defined(__BIG_ENDIAN)struct eth_rx_desc { u16 byte_cnt; /* Descriptor buffer byte count */ u16 buf_size; /* Buffer size */ u32 cmd_sts; /* Descriptor command status */ u32 next_desc_ptr; /* Next descriptor pointer */ u32 buf_ptr; /* Descriptor buffer pointer */};struct eth_tx_desc { u16 byte_cnt; /* buffer byte count */ u16 l4i_chk; /* CPU provided TCP checksum */ u32 cmd_sts; /* Command/status field */ u32 next_desc_ptr; /* Pointer to next descriptor */ u32 buf_ptr; /* pointer to buffer for this descriptor*/};#elif defined(__LITTLE_ENDIAN)struct eth_rx_desc { u32 cmd_sts; /* Descriptor command status */ u16 buf_size; /* Buffer size */ u16 byte_cnt; /* Descriptor buffer byte count */ u32 buf_ptr; /* Descriptor buffer pointer */ u32 next_desc_ptr; /* Next descriptor pointer */};struct eth_tx_desc { u32 cmd_sts; /* Command/status field */ u16 l4i_chk; /* CPU provided TCP checksum */ u16 byte_cnt; /* buffer byte count */ u32 buf_ptr; /* pointer to buffer for this descriptor*/ u32 next_desc_ptr; /* Pointer to next descriptor */};#else#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined#endif/* Unified struct for Rx and Tx operations. The user is not required to *//* be familier with neither Tx nor Rx descriptors. */struct pkt_info { unsigned short byte_cnt; /* Descriptor buffer byte count */ unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ unsigned int cmd_sts; /* Descriptor command status */ dma_addr_t buf_ptr; /* Descriptor buffer pointer */ struct sk_buff *return_info; /* User resource return information */};/* Ethernet port specific information */struct mv643xx_mib_counters { u64 good_octets_received; u32 bad_octets_received; u32 internal_mac_transmit_err; u32 good_frames_received; u32 bad_frames_received; u32 broadcast_frames_received; u32 multicast_frames_received; u32 frames_64_octets; u32 frames_65_to_127_octets; u32 frames_128_to_255_octets; u32 frames_256_to_511_octets; u32 frames_512_to_1023_octets; u32 frames_1024_to_max_octets; u64 good_octets_sent; u32 good_frames_sent; u32 excessive_collision; u32 multicast_frames_sent; u32 broadcast_frames_sent; u32 unrec_mac_control_received; u32 fc_sent; u32 good_fc_received; u32 bad_fc_received; u32 undersize_received; u32 fragments_received; u32 oversize_received; u32 jabber_received; u32 mac_receive_error; u32 bad_crc_event; u32 collision; u32 late_collision;};struct mv643xx_private { int port_num; /* User Ethernet port number */ u32 rx_sram_addr; /* Base address of rx sram area */ u32 rx_sram_size; /* Size of rx sram area */ u32 tx_sram_addr; /* Base address of tx sram area */ u32 tx_sram_size; /* Size of tx sram area */ int rx_resource_err; /* Rx ring resource error flag */ /* Tx/Rx rings managment indexes fields. For driver use */ /* Next available and first returning Rx resource */ int rx_curr_desc_q, rx_used_desc_q; /* Next available and first returning Tx resource */ int tx_curr_desc_q, tx_used_desc_q;#ifdef MV643XX_TX_FAST_REFILL u32 tx_clean_threshold;#endif struct eth_rx_desc *p_rx_desc_area; dma_addr_t rx_desc_dma; int rx_desc_area_size; struct sk_buff **rx_skb; struct eth_tx_desc *p_tx_desc_area; dma_addr_t tx_desc_dma; int tx_desc_area_size; struct sk_buff **tx_skb; struct work_struct tx_timeout_task; struct net_device *dev; struct napi_struct napi; struct net_device_stats stats; struct mv643xx_mib_counters mib_counters; spinlock_t lock; /* Size of Tx Ring per queue */ int tx_ring_size; /* Number of tx descriptors in use */ int tx_desc_count; /* Size of Rx Ring per queue */ int rx_ring_size; /* Number of rx descriptors in use */ int rx_desc_count; /* * Used in case RX Ring is empty, which can be caused when * system does not have resources (skb's) */ struct timer_list timeout; u32 rx_int_coal; u32 tx_int_coal; struct mii_if_info mii;};/* Static function declarations */static void eth_port_init(struct mv643xx_private *mp);static void eth_port_reset(unsigned int eth_port_num);static void eth_port_start(struct net_device *dev);static void ethernet_phy_reset(unsigned int eth_port_num);static void eth_port_write_smi_reg(unsigned int eth_port_num, unsigned int phy_reg, unsigned int value);static void eth_port_read_smi_reg(unsigned int eth_port_num, unsigned int phy_reg, unsigned int *value);static void eth_clear_mib_counters(unsigned int eth_port_num);static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, struct pkt_info *p_pkt_info);static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, struct pkt_info *p_pkt_info);static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);static void eth_port_set_multicast_list(struct net_device *);static void mv643xx_eth_port_enable_tx(unsigned int port_num, unsigned int queues);static void mv643xx_eth_port_enable_rx(unsigned int port_num, unsigned int queues);static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num);static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num);static int mv643xx_eth_open(struct net_device *);static int mv643xx_eth_stop(struct net_device *);static int mv643xx_eth_change_mtu(struct net_device *, int);static void eth_port_init_mac_tables(unsigned int eth_port_num);#ifdef MV643XX_NAPIstatic int mv643xx_poll(struct napi_struct *napi, int budget);#endifstatic int ethernet_phy_get(unsigned int eth_port_num);static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);static int ethernet_phy_detect(unsigned int eth_port_num);static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location);static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val);static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);static const struct ethtool_ops mv643xx_ethtool_ops;static char mv643xx_driver_name[] = "mv643xx_eth";static char mv643xx_driver_version[] = "1.0";static void __iomem *mv643xx_eth_base;/* used to protect SMI_REG, which is shared across ports */static DEFINE_SPINLOCK(mv643xx_eth_phy_lock);static inline u32 mv_read(int offset){ return readl(mv643xx_eth_base + offset);}static inline void mv_write(int offset, u32 data){ writel(data, mv643xx_eth_base + offset);}/* * Changes MTU (maximum transfer unit) of the gigabit ethenret port * * Input : pointer to ethernet interface network device structure * new mtu size * Output : 0 upon success, -EINVAL upon failure */static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu > 9500) || (new_mtu < 64)) return -EINVAL; dev->mtu = new_mtu; /* * Stop then re-open the interface. This will allocate RX skb's with * the new MTU. * There is a possible danger that the open will not successed, due * to memory is full, which might fail the open function. */ if (netif_running(dev)) { mv643xx_eth_stop(dev); if (mv643xx_eth_open(dev)) printk(KERN_ERR "%s: Fatal error on opening device\n", dev->name); } return 0;}/* * mv643xx_eth_rx_refill_descs * * Fills / refills RX queue on a certain gigabit ethernet port * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv643xx_eth_rx_refill_descs(struct net_device *dev){ struct mv643xx_private *mp = netdev_priv(dev); struct pkt_info pkt_info; struct sk_buff *skb; int unaligned; while (mp->rx_desc_count < mp->rx_ring_size) { skb = dev_alloc_skb(ETH_RX_SKB_SIZE + dma_get_cache_alignment()); if (!skb) break; mp->rx_desc_count++; unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); if (unaligned) skb_reserve(skb, dma_get_cache_alignment() - unaligned); pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; pkt_info.byte_cnt = ETH_RX_SKB_SIZE; pkt_info.buf_ptr = dma_map_single(NULL, skb->data, ETH_RX_SKB_SIZE, DMA_FROM_DEVICE); pkt_info.return_info = skb; if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { printk(KERN_ERR "%s: Error allocating RX Ring\n", dev->name); break; } skb_reserve(skb, ETH_HW_IP_ALIGN); } /* * If RX ring is empty of SKB, set a timer to try allocating * again at a later time. */ if (mp->rx_desc_count == 0) { printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); mp->timeout.expires = jiffies + (HZ / 10); /* 100 mSec */ add_timer(&mp->timeout); }}/* * mv643xx_eth_rx_refill_descs_timer_wrapper * * Timer routine to wake up RX queue filling task. This function is * used only in case the RX queue is empty, and all alloc_skb has * failed (due to out of memory event). * * Input : pointer to ethernet interface network device structure * Output : N/A */static inline void mv643xx_eth_rx_refill_descs_timer_wrapper(unsigned long data){ mv643xx_eth_rx_refill_descs((struct net_device *)data);}/* * mv643xx_eth_update_mac_address * * Update the MAC address of the port in the address table * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv643xx_eth_update_mac_address(struct net_device *dev){ struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; eth_port_init_mac_tables(port_num); eth_port_uc_addr_set(port_num, dev->dev_addr);}/* * mv643xx_eth_set_rx_mode * * Change from promiscuos to regular rx mode * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv643xx_eth_set_rx_mode(struct net_device *dev){ struct mv643xx_private *mp = netdev_priv(dev); u32 config_reg; config_reg = mv_read(PORT_CONFIG_REG(mp->port_num)); if (dev->flags & IFF_PROMISC) config_reg |= (u32) UNICAST_PROMISCUOUS_MODE; else config_reg &= ~(u32) UNICAST_PROMISCUOUS_MODE; mv_write(PORT_CONFIG_REG(mp->port_num), config_reg); eth_port_set_multicast_list(dev);}/* * mv643xx_eth_set_mac_address * * Change the interface's mac address. * No special hardware thing should be done because interface is always * put in promiscuous mode. * * Input : pointer to ethernet interface network device structure and * a pointer to the designated entry to be added to the cache. * Output : zero upon success, negative upon failure */static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr){ int i; for (i = 0; i < 6; i++) /* +2 is for the offset of the HW addr type */ dev->dev_addr[i] = ((unsigned char *)addr)[i + 2]; mv643xx_eth_update_mac_address(dev); return 0;}/* * mv643xx_eth_tx_timeout * * Called upon a timeout on transmitting a packet * * Input : pointer to ethernet interface network device structure. * Output : N/A */static void mv643xx_eth_tx_timeout(struct net_device *dev){ struct mv643xx_private *mp = netdev_priv(dev); printk(KERN_INFO "%s: TX timeout ", dev->name); /* Do the reset outside of interrupt context */ schedule_work(&mp->tx_timeout_task);}/* * mv643xx_eth_tx_timeout_task * * Actual routine to reset the adapter when a timeout on Tx has occurred */static void mv643xx_eth_tx_timeout_task(struct work_struct *ugly){ struct mv643xx_private *mp = container_of(ugly, struct mv643xx_private, tx_timeout_task); struct net_device *dev = mp->mii.dev; /* yuck */ if (!netif_running(dev)) return; netif_stop_queue(dev); eth_port_reset(mp->port_num); eth_port_start(dev); if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) netif_wake_queue(dev);}/** * mv643xx_eth_free_tx_descs - Free the tx desc data for completed descriptors * * If force is non-zero, frees uncompleted descriptors as well */int mv643xx_eth_free_tx_descs(struct net_device *dev, int force){ struct mv643xx_private *mp = netdev_priv(dev); struct eth_tx_desc *desc; u32 cmd_sts; struct sk_buff *skb; unsigned long flags; int tx_index; dma_addr_t addr; int count; int released = 0; while (mp->tx_desc_count > 0) { spin_lock_irqsave(&mp->lock, flags); /* tx_desc_count might have changed before acquiring the lock */ if (mp->tx_desc_count <= 0) { spin_unlock_irqrestore(&mp->lock, flags); return released; } tx_index = mp->tx_used_desc_q; desc = &mp->p_tx_desc_area[tx_index]; cmd_sts = desc->cmd_sts; if (!force && (cmd_sts & ETH_BUFFER_OWNED_BY_DMA)) { spin_unlock_irqrestore(&mp->lock, flags); return released; } mp->tx_used_desc_q = (tx_index + 1) % mp->tx_ring_size; mp->tx_desc_count--; addr = desc->buf_ptr; count = desc->byte_cnt; skb = mp->tx_skb[tx_index]; if (skb) mp->tx_skb[tx_index] = NULL; if (cmd_sts & ETH_ERROR_SUMMARY) { printk("%s: Error in TX\n", dev->name);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?