amd8111e.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,175 行 · 第 1/4 页

C
2,175
字号
		/* Clear CMD2 */	writel(CMD2_CLEAR, mmio +CMD2);	/* Clear CMD7 */	writel(CMD7_CLEAR , mmio + CMD7);	/* Clear DLY_INT_A and DLY_INT_B */	writel(0x0, mmio + DLY_INT_A);	writel(0x0, mmio + DLY_INT_B);	/* Clear FLOW_CONTROL */	writel(0x0, mmio + FLOW_CONTROL);	/* Clear INT0  write 1 to clear register */	reg_val = readl(mmio + INT0);	writel(reg_val, mmio + INT0);	/* Clear STVAL */	writel(0x0, mmio + STVAL);	/* Clear INTEN0 */	writel( INTEN0_CLEAR, mmio + INTEN0);	/* Clear LADRF */	writel(0x0 , mmio + LADRF);	/* Set SRAM_SIZE & SRAM_BOUNDARY registers  */	writel( 0x80010,mmio + SRAM_SIZE);	/* Clear RCV_RING0_LEN */	writel(0x0, mmio +  RCV_RING_LEN0);	/* Clear XMT_RING0/1/2/3_LEN */	writel(0x0, mmio +  XMT_RING_LEN0);	writel(0x0, mmio +  XMT_RING_LEN1);	writel(0x0, mmio +  XMT_RING_LEN2);	writel(0x0, mmio +  XMT_RING_LEN3);	/* Clear XMT_RING_LIMIT */	writel(0x0, mmio + XMT_RING_LIMIT);	/* Clear MIB */	writew(MIB_CLEAR, mmio + MIB_ADDR);	/* Clear LARF */	amd8111e_writeq(*(u64*)logic_filter,mmio+LADRF);	/* SRAM_SIZE register */	reg_val = readl(mmio + SRAM_SIZE);		if(lp->options & OPTION_JUMBO_ENABLE)		writel( VAL2|JUMBO, mmio + CMD3);#if AMD8111E_VLAN_TAG_USED	writel(VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3 );#endif	/* Set default value to CTRL1 Register */	writel(CTRL1_DEFAULT, mmio + CTRL1);	/* To avoid PCI posting bug */	readl(mmio + CMD2);}/* This function disables the interrupt and clears all the pending interrupts in INT0 */static void amd8111e_disable_interrupt(struct amd8111e_priv* lp){		u32 intr0;	/* Disable interrupt */	writel(INTREN, lp->mmio + CMD0);		/* Clear INT0 */	intr0 = readl(lp->mmio + INT0);	writel(intr0, lp->mmio + INT0);		/* To avoid PCI posting bug */	readl(lp->mmio + INT0);}/*This function stops the chip. */static void amd8111e_stop_chip(struct amd8111e_priv* lp){	writel(RUN, lp->mmio + CMD0);		/* To avoid PCI posting bug */	readl(lp->mmio + CMD0);}/* This function frees the  transmiter and receiver descriptor rings.*/static void amd8111e_free_ring(struct amd8111e_priv* lp){		/* Free transmit and receive skbs */	amd8111e_free_skbs(lp->amd8111e_net_dev);	/* Free transmit and receive descriptor rings */	if(lp->rx_ring){		pci_free_consistent(lp->pci_dev, 			sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,			lp->rx_ring, lp->rx_ring_dma_addr);		lp->rx_ring = NULL;	}		if(lp->tx_ring){		pci_free_consistent(lp->pci_dev, 			sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,			lp->tx_ring, lp->tx_ring_dma_addr);		lp->tx_ring = NULL;	}}#if AMD8111E_VLAN_TAG_USED	/* This is the receive indication function for packets with vlan tag.*/	static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag){#ifdef CONFIG_AMD8111E_NAPI	return vlan_hwaccel_receive_skb(skb, lp->vlgrp,vlan_tag);#else	return vlan_hwaccel_rx(skb, lp->vlgrp, vlan_tag);#endif /* CONFIG_AMD8111E_NAPI */}#endif/*This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb. */static int amd8111e_tx(struct net_device *dev){	struct amd8111e_priv* lp = netdev_priv(dev);	int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK;	int status;	/* Complete all the transmit packet */	while (lp->tx_complete_idx != lp->tx_idx){		tx_index =  lp->tx_complete_idx & TX_RING_DR_MOD_MASK;		status = le16_to_cpu(lp->tx_ring[tx_index].tx_flags);		if(status & OWN_BIT)			break;	/* It still hasn't been Txed */		lp->tx_ring[tx_index].buff_phy_addr = 0;		/* We must free the original skb */		if (lp->tx_skbuff[tx_index]) {			pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[tx_index],				  	lp->tx_skbuff[tx_index]->len,					PCI_DMA_TODEVICE);			dev_kfree_skb_irq (lp->tx_skbuff[tx_index]);			lp->tx_skbuff[tx_index] = NULL;			lp->tx_dma_addr[tx_index] = 0;		}		lp->tx_complete_idx++;		/*COAL update tx coalescing parameters */		lp->coal_conf.tx_packets++;		lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;			if (netif_queue_stopped(dev) &&			lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){			/* The ring is no longer full, clear tbusy. */			/* lp->tx_full = 0; */			netif_wake_queue (dev);		}	}	return 0;}#ifdef CONFIG_AMD8111E_NAPI/* This function handles the driver receive operation in polling mode */static int amd8111e_rx_poll(struct net_device *dev, int * budget){	struct amd8111e_priv *lp = dev->priv;	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;	void * mmio = lp->mmio;	struct sk_buff *skb,*new_skb;	int min_pkt_len, status;	unsigned int intr0;	int num_rx_pkt = 0;	/*int max_rx_pkt = NUM_RX_BUFFERS;*/	short pkt_len;#if AMD8111E_VLAN_TAG_USED			short vtag;#endif	int rx_pkt_limit = dev->quota;		do{   		/* process receive packets until we use the quota*/		/* If we own the next entry, it's a new packet. Send it up. */		while(!(lp->rx_ring[rx_index].rx_flags & OWN_BIT)){	       			/* check if err summary bit is set */ 			if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) 								& ERR_BIT){			/* 			 * There is a tricky error noted by John Murphy,			 * <murf@perftech.com> to Russ Nelson: Even with			 * full-sized * buffers it's possible for a  			 * jabber packet to use two buffers, with only 			 * the last correctly noting the error.			 */			/* reseting flags */			lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;			goto err_next_pkt;			}			/* check for STP and ENP */		status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);		if(!((status & STP_BIT) && (status & ENP_BIT))){			/* reseting flags */			lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS;			goto err_next_pkt;		}		pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;#if AMD8111E_VLAN_TAG_USED				vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;		/*MAC will strip vlan tag*/ 		if(lp->vlgrp != NULL && vtag !=0)			min_pkt_len =MIN_PKT_LEN - 4;		else#endif			min_pkt_len =MIN_PKT_LEN;		if (pkt_len < min_pkt_len) {			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			lp->drv_rx_errors++;			goto err_next_pkt;		}		if(--rx_pkt_limit < 0)			goto rx_not_empty;		if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){			/* if allocation fail, 				ignore that pkt and go to next one */			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			lp->drv_rx_errors++;			goto err_next_pkt;		}				skb_reserve(new_skb, 2);		skb = lp->rx_skbuff[rx_index];		pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],			lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);		skb_put(skb, pkt_len);		skb->dev = dev;		lp->rx_skbuff[rx_index] = new_skb;		new_skb->dev = dev;		lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,			new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);			skb->protocol = eth_type_trans(skb, dev);#if AMD8111E_VLAN_TAG_USED						vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;		if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){			amd8111e_vlan_rx(lp, skb,				    lp->rx_ring[rx_index].tag_ctrl_info);		} else#endif						netif_receive_skb(skb);		/*COAL update rx coalescing parameters*/		lp->coal_conf.rx_packets++;		lp->coal_conf.rx_bytes += pkt_len;			num_rx_pkt++;		dev->last_rx = jiffies;	err_next_pkt:			lp->rx_ring[rx_index].buff_phy_addr			 = cpu_to_le32(lp->rx_dma_addr[rx_index]);		lp->rx_ring[rx_index].buff_count = 				cpu_to_le16(lp->rx_buff_len-2);		lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);		rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;	}	/* Check the interrupt status register for more packets in the 	mean time. Process them since we have not used up our quota.*/	intr0 = readl(mmio + INT0);	/*Ack receive packets */	writel(intr0 & RINT0,mmio + INT0);	}while(intr0 & RINT0);	/* Receive descriptor is empty now */	dev->quota -= num_rx_pkt;	*budget -= num_rx_pkt;	netif_rx_complete(dev);	/* enable receive interrupt */	writel(VAL0|RINTEN0, mmio + INTEN0);	writel(VAL2 | RDMD0, mmio + CMD0);	return 0;rx_not_empty:	/* Do not call a netif_rx_complete */	dev->quota -= num_rx_pkt;		*budget -= num_rx_pkt;	return 1;	}#else/* This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs.*/static int amd8111e_rx(struct net_device *dev){	struct amd8111e_priv *lp = netdev_priv(dev);	struct sk_buff *skb,*new_skb;	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;	int min_pkt_len, status;	int num_rx_pkt = 0;	int max_rx_pkt = NUM_RX_BUFFERS;	short pkt_len;#if AMD8111E_VLAN_TAG_USED			short vtag;#endif		/* If we own the next entry, it's a new packet. Send it up. */	while(++num_rx_pkt <= max_rx_pkt){		if(lp->rx_ring[rx_index].rx_flags & OWN_BIT)			return 0;	       		/* check if err summary bit is set */ 		if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){			/* 			 * There is a tricky error noted by John Murphy,			 * <murf@perftech.com> to Russ Nelson: Even with full-sized			 * buffers it's possible for a jabber packet to use two			 * buffers, with only the last correctly noting the error.			 */			/* reseting flags */			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			goto err_next_pkt;		}		/* check for STP and ENP */		status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);		if(!((status & STP_BIT) && (status & ENP_BIT))){			/* reseting flags */			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			goto err_next_pkt;		}		pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;#if AMD8111E_VLAN_TAG_USED				vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;		/*MAC will strip vlan tag*/ 		if(lp->vlgrp != NULL && vtag !=0)			min_pkt_len =MIN_PKT_LEN - 4;		else#endif			min_pkt_len =MIN_PKT_LEN;		if (pkt_len < min_pkt_len) {			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			lp->drv_rx_errors++;			goto err_next_pkt;		}		if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){			/* if allocation fail, 				ignore that pkt and go to next one */			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;			lp->drv_rx_errors++;			goto err_next_pkt;		}				skb_reserve(new_skb, 2);		skb = lp->rx_skbuff[rx_index];		pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],			lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);		skb_put(skb, pkt_len);		skb->dev = dev;		lp->rx_skbuff[rx_index] = new_skb;		new_skb->dev = dev;		lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,			new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);			skb->protocol = eth_type_trans(skb, dev);#if AMD8111E_VLAN_TAG_USED						vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;		if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){			amd8111e_vlan_rx(lp, skb,				    lp->rx_ring[rx_index].tag_ctrl_info);		} else#endif						netif_rx (skb);			/*COAL update rx coalescing parameters*/			lp->coal_conf.rx_packets++;			lp->coal_conf.rx_bytes += pkt_len;				dev->last_rx = jiffies;	err_next_pkt:		lp->rx_ring[rx_index].buff_phy_addr			 = cpu_to_le32(lp->rx_dma_addr[rx_index]);		lp->rx_ring[rx_index].buff_count = 				cpu_to_le16(lp->rx_buff_len-2);		lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);		rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;	}	return 0;}#endif /* CONFIG_AMD8111E_NAPI *//* This function will indicate the link status to the kernel.*/static int amd8111e_link_change(struct net_device* dev){		struct amd8111e_priv *lp = netdev_priv(dev);	int status0,speed;	/* read the link change */     	status0 = readl(lp->mmio + STAT0);		if(status0 & LINK_STATS){		if(status0 & AUTONEG_COMPLETE)			lp->link_config.autoneg = AUTONEG_ENABLE;		else 			lp->link_config.autoneg = AUTONEG_DISABLE;		if(status0 & FULL_DPLX)			lp->link_config.duplex = DUPLEX_FULL;		else 			lp->link_config.duplex = DUPLEX_HALF;		speed = (status0 & SPEED_MASK) >> 7;		if(speed == PHY_SPEED_10)			lp->link_config.speed = SPEED_10;		else if(speed == PHY_SPEED_100)			lp->link_config.speed = SPEED_100;		printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n",			dev->name,		       (lp->link_config.speed == SPEED_100) ? "100": "10", 		       (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half"); 		netif_carrier_on(dev);	}	else{			lp->link_config.speed = SPEED_INVALID;		lp->link_config.duplex = DUPLEX_INVALID;		lp->link_config.autoneg = AUTONEG_INVALID;		printk(KERN_INFO "%s: Link is Down.\n",dev->name);		netif_carrier_off(dev);	}			return 0;}/*This function reads the mib counters. 	 */static int amd8111e_read_mib(void* mmio, u8 MIB_COUNTER){	unsigned int  status;	unsigned  int data;	unsigned int repeat = REPEAT_CNT;	writew( MIB_RD_CMD | MIB_COUNTER, mmio + MIB_ADDR);	do {		status = readw(mmio + MIB_ADDR);		udelay(2);	/* controller takes MAX 2 us to get mib data */	}	while (--repeat && (status & MIB_CMD_ACTIVE));	data = readl(mmio + MIB_DATA);	return data;}/*This function reads the mib registers and returns the hardware statistics. It  updates previous internal driver statistics with new values.*/ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev){	struct amd8111e_priv *lp = netdev_priv(dev);	void * mmio = lp->mmio;	unsigned long flags;	/* struct net_device_stats *prev_stats = &lp->prev_stats; */	struct net_device_stats* new_stats = &lp->stats;		if(!lp->opened)		return &lp->stats;		spin_lock_irqsave (&lp->lock, flags);	/* stats.rx_packets */	new_stats->rx_packets = amd8111e_read_mib(mmio, rcv_broadcast_pkts)+				amd8111e_read_mib(mmio, rcv_multicast_pkts)+				amd8111e_read_mib(mmio, rcv_unicast_pkts);	/* stats.tx_packets */	new_stats->tx_packets = amd8111e_read_mib(mmio, xmt_packets);	/*stats.rx_bytes */	new_stats->rx_bytes = amd8111e_read_mib(mmio, rcv_octets);	/* stats.tx_bytes */	new_stats->tx_bytes = amd8111e_read_mib(mmio, xmt_octets);	/* stats.rx_errors */	/* hw errors + errors driver reported */	new_stats->rx_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+				amd8111e_read_mib(mmio, rcv_fragments)+				amd8111e_read_mib(mmio, rcv_jabbers)+				amd8111e_read_mib(mmio, rcv_alignment_errors)+				amd8111e_read_mib(mmio, rcv_fcs_errors)+				amd8111e_read_mib(mmio, rcv_miss_pkts)+				lp->drv_rx_errors;	/* stats.tx_errors */	new_stats->tx_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts);	/* stats.rx_dropped*/	new_stats->rx_dropped = amd8111e_read_mib(mmio, rcv_miss_pkts);	/* stats.tx_dropped*/	new_stats->tx_dropped = amd8111e_read_mib(mmio,  xmt_underrun_pkts);	/* stats.multicast*/	new_stats->multicast = amd8111e_read_mib(mmio, rcv_multicast_pkts);	/* stats.collisions*/	new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions);	/* stats.rx_length_errors*/	new_stats->rx_length_errors = 		amd8111e_read_mib(mmio, rcv_undersize_pkts)+		amd8111e_read_mib(mmio, rcv_oversize_pkts);	/* stats.rx_over_errors*/	new_stats->rx_over_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);	/* stats.rx_crc_errors*/	new_stats->rx_crc_errors = amd8111e_read_mib(mmio, rcv_fcs_errors);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?