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 + -
显示快捷键?