au1000_eth.c

来自「linux 内核源代码」· C语言 代码 · 共 1,315 行 · 第 1/3 页

C
1,315
字号
			       "%s: Speed (%d) is not 10/100 ???\n",			       dev->name, phydev->speed);			break;		}		aup->old_speed = phydev->speed;		status_change = 1;	}	if (phydev->link && (aup->old_duplex != phydev->duplex)) {		// duplex mode changed		/* switching duplex mode requires to disable rx and tx! */		hard_stop(dev);		if (DUPLEX_FULL == phydev->duplex)			aup->mac->control = ((aup->mac->control					     | MAC_FULL_DUPLEX)					     & ~MAC_DISABLE_RX_OWN);		else			aup->mac->control = ((aup->mac->control					      & ~MAC_FULL_DUPLEX)					     | MAC_DISABLE_RX_OWN);		au_sync_delay(1);		enable_rx_tx(dev);		aup->old_duplex = phydev->duplex;		status_change = 1;	}	if(phydev->link != aup->old_link) {		// link state changed		if (phydev->link) // link went up			netif_schedule(dev);		else { // link went down			aup->old_speed = 0;			aup->old_duplex = -1;		}		aup->old_link = phydev->link;		status_change = 1;	}	spin_unlock_irqrestore(&aup->lock, flags);	if (status_change) {		if (phydev->link)			printk(KERN_INFO "%s: link up (%d/%s)\n",			       dev->name, phydev->speed,			       DUPLEX_FULL == phydev->duplex ? "Full" : "Half");		else			printk(KERN_INFO "%s: link down\n", dev->name);	}}static int au1000_open(struct net_device *dev){	int retval;	struct au1000_private *aup = (struct au1000_private *) dev->priv;	if (au1000_debug > 4)		printk("%s: open: dev=%p\n", dev->name, dev);	if ((retval = request_irq(dev->irq, &au1000_interrupt, 0,					dev->name, dev))) {		printk(KERN_ERR "%s: unable to get IRQ %d\n",				dev->name, dev->irq);		return retval;	}	if ((retval = au1000_init(dev))) {		printk(KERN_ERR "%s: error in au1000_init\n", dev->name);		free_irq(dev->irq, dev);		return retval;	}	if (aup->phy_dev) {		/* cause the PHY state machine to schedule a link state check */		aup->phy_dev->state = PHY_CHANGELINK;		phy_start(aup->phy_dev);	}	netif_start_queue(dev);	if (au1000_debug > 4)		printk("%s: open: Initialization done.\n", dev->name);	return 0;}static int au1000_close(struct net_device *dev){	unsigned long flags;	struct au1000_private *const aup = (struct au1000_private *) dev->priv;	if (au1000_debug > 4)		printk("%s: close: dev=%p\n", dev->name, dev);	if (aup->phy_dev)		phy_stop(aup->phy_dev);	spin_lock_irqsave(&aup->lock, flags);	reset_mac_unlocked (dev);	/* stop the device */	netif_stop_queue(dev);	/* disable the interrupt */	free_irq(dev->irq, dev);	spin_unlock_irqrestore(&aup->lock, flags);	return 0;}static void __exit au1000_cleanup_module(void){	int i, j;	struct net_device *dev;	struct au1000_private *aup;	for (i = 0; i < num_ifs; i++) {		dev = iflist[i].dev;		if (dev) {			aup = (struct au1000_private *) dev->priv;			unregister_netdev(dev);			for (j = 0; j < NUM_RX_DMA; j++)				if (aup->rx_db_inuse[j])					ReleaseDB(aup, aup->rx_db_inuse[j]);			for (j = 0; j < NUM_TX_DMA; j++)				if (aup->tx_db_inuse[j])					ReleaseDB(aup, aup->tx_db_inuse[j]); 			dma_free_noncoherent(NULL, MAX_BUF_SIZE * 					     (NUM_TX_BUFFS + NUM_RX_BUFFS), 					     (void *)aup->vaddr, aup->dma_addr); 			release_mem_region(dev->base_addr, MAC_IOSIZE); 			release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);			free_netdev(dev);		}	}}static void update_tx_stats(struct net_device *dev, u32 status){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	struct net_device_stats *ps = &dev->stats;	if (status & TX_FRAME_ABORTED) {		if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {			if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {				/* any other tx errors are only valid				 * in half duplex mode */				ps->tx_errors++;				ps->tx_aborted_errors++;			}		}		else {			ps->tx_errors++;			ps->tx_aborted_errors++;			if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))				ps->tx_carrier_errors++;		}	}}/* * Called from the interrupt service routine to acknowledge * the TX DONE bits.  This is a must if the irq is setup as * edge triggered. */static void au1000_tx_ack(struct net_device *dev){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	volatile tx_dma_t *ptxd;	ptxd = aup->tx_dma_ring[aup->tx_tail];	while (ptxd->buff_stat & TX_T_DONE) {		update_tx_stats(dev, ptxd->status);		ptxd->buff_stat &= ~TX_T_DONE;		ptxd->len = 0;		au_sync();		aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);		ptxd = aup->tx_dma_ring[aup->tx_tail];		if (aup->tx_full) {			aup->tx_full = 0;			netif_wake_queue(dev);		}	}}/* * Au1000 transmit routine. */static int au1000_tx(struct sk_buff *skb, struct net_device *dev){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	struct net_device_stats *ps = &dev->stats;	volatile tx_dma_t *ptxd;	u32 buff_stat;	db_dest_t *pDB;	int i;	if (au1000_debug > 5)		printk("%s: tx: aup %x len=%d, data=%p, head %d\n",				dev->name, (unsigned)aup, skb->len,				skb->data, aup->tx_head);	ptxd = aup->tx_dma_ring[aup->tx_head];	buff_stat = ptxd->buff_stat;	if (buff_stat & TX_DMA_ENABLE) {		/* We've wrapped around and the transmitter is still busy */		netif_stop_queue(dev);		aup->tx_full = 1;		return 1;	}	else if (buff_stat & TX_T_DONE) {		update_tx_stats(dev, ptxd->status);		ptxd->len = 0;	}	if (aup->tx_full) {		aup->tx_full = 0;		netif_wake_queue(dev);	}	pDB = aup->tx_db_inuse[aup->tx_head];	skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);	if (skb->len < ETH_ZLEN) {		for (i=skb->len; i<ETH_ZLEN; i++) {			((char *)pDB->vaddr)[i] = 0;		}		ptxd->len = ETH_ZLEN;	}	else		ptxd->len = skb->len;	ps->tx_packets++;	ps->tx_bytes += ptxd->len;	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;	au_sync();	dev_kfree_skb(skb);	aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);	dev->trans_start = jiffies;	return 0;}static inline void update_rx_stats(struct net_device *dev, u32 status){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	struct net_device_stats *ps = &dev->stats;	ps->rx_packets++;	if (status & RX_MCAST_FRAME)		ps->multicast++;	if (status & RX_ERROR) {		ps->rx_errors++;		if (status & RX_MISSED_FRAME)			ps->rx_missed_errors++;		if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR))			ps->rx_length_errors++;		if (status & RX_CRC_ERROR)			ps->rx_crc_errors++;		if (status & RX_COLL)			ps->collisions++;	}	else		ps->rx_bytes += status & RX_FRAME_LEN_MASK;}/* * Au1000 receive routine. */static int au1000_rx(struct net_device *dev){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	struct sk_buff *skb;	volatile rx_dma_t *prxd;	u32 buff_stat, status;	db_dest_t *pDB;	u32	frmlen;	if (au1000_debug > 5)		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);	prxd = aup->rx_dma_ring[aup->rx_head];	buff_stat = prxd->buff_stat;	while (buff_stat & RX_T_DONE)  {		status = prxd->status;		pDB = aup->rx_db_inuse[aup->rx_head];		update_rx_stats(dev, status);		if (!(status & RX_ERROR))  {			/* good frame */			frmlen = (status & RX_FRAME_LEN_MASK);			frmlen -= 4; /* Remove FCS */			skb = dev_alloc_skb(frmlen + 2);			if (skb == NULL) {				printk(KERN_ERR				       "%s: Memory squeeze, dropping packet.\n",				       dev->name);				dev->stats.rx_dropped++;				continue;			}			skb_reserve(skb, 2);	/* 16 byte IP header align */			skb_copy_to_linear_data(skb,				(unsigned char *)pDB->vaddr, frmlen);			skb_put(skb, frmlen);			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);	/* pass the packet to upper layers */		}		else {			if (au1000_debug > 4) {				if (status & RX_MISSED_FRAME)					printk("rx miss\n");				if (status & RX_WDOG_TIMER)					printk("rx wdog\n");				if (status & RX_RUNT)					printk("rx runt\n");				if (status & RX_OVERLEN)					printk("rx overlen\n");				if (status & RX_COLL)					printk("rx coll\n");				if (status & RX_MII_ERROR)					printk("rx mii error\n");				if (status & RX_CRC_ERROR)					printk("rx crc error\n");				if (status & RX_LEN_ERROR)					printk("rx len error\n");				if (status & RX_U_CNTRL_FRAME)					printk("rx u control frame\n");				if (status & RX_MISSED_FRAME)					printk("rx miss\n");			}		}		prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);		aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);		au_sync();		/* next descriptor */		prxd = aup->rx_dma_ring[aup->rx_head];		buff_stat = prxd->buff_stat;		dev->last_rx = jiffies;	}	return 0;}/* * Au1000 interrupt service routine. */static irqreturn_t au1000_interrupt(int irq, void *dev_id){	struct net_device *dev = (struct net_device *) dev_id;	if (dev == NULL) {		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);		return IRQ_RETVAL(1);	}	/* Handle RX interrupts first to minimize chance of overrun */	au1000_rx(dev);	au1000_tx_ack(dev);	return IRQ_RETVAL(1);}/* * The Tx ring has been full longer than the watchdog timeout * value. The transmitter must be hung? */static void au1000_tx_timeout(struct net_device *dev){	printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);	reset_mac(dev);	au1000_init(dev);	dev->trans_start = jiffies;	netif_wake_queue(dev);}static void set_rx_mode(struct net_device *dev){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	if (au1000_debug > 4)		printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		aup->mac->control |= MAC_PROMISCUOUS;	} else if ((dev->flags & IFF_ALLMULTI)  ||			   dev->mc_count > MULTICAST_FILTER_LIMIT) {		aup->mac->control |= MAC_PASS_ALL_MULTI;		aup->mac->control &= ~MAC_PROMISCUOUS;		printk(KERN_INFO "%s: Pass all multicast\n", dev->name);	} else {		int i;		struct dev_mc_list *mclist;		u32 mc_filter[2];	/* Multicast hash filter */		mc_filter[1] = mc_filter[0] = 0;		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next) {			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,					(long *)mc_filter);		}		aup->mac->multi_hash_high = mc_filter[1];		aup->mac->multi_hash_low = mc_filter[0];		aup->mac->control &= ~MAC_PROMISCUOUS;		aup->mac->control |= MAC_HASH_MODE;	}}static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct au1000_private *aup = (struct au1000_private *)dev->priv;	if (!netif_running(dev)) return -EINVAL;	if (!aup->phy_dev) return -EINVAL; // PHY not controllable	return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);}module_init(au1000_init_module);module_exit(au1000_cleanup_module);

⌨️ 快捷键说明

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