⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif /* CONFIG_PMAC_PBOOK *//* * Handle a transmit timeout */static voidgmac_tx_timeout(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	int i, timeout;	unsigned long flags;			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);	spin_lock_irqsave(&gm->lock, flags);	/* Stop chip */	gmac_stop_dma(gm);	/* Empty Tx ring of any remaining gremlins */	gmac_tx_cleanup(dev, 1);	/* Empty Rx ring of any remaining gremlins */	for (i = 0; i < NRX; ++i) {		if (gm->rx_buff[i] != 0) {			dev_kfree_skb_irq(gm->rx_buff[i]);			gm->rx_buff[i] = 0;		}	}	/* Perform a software reset */	GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);	for (timeout = 100; timeout > 0; --timeout) {		mdelay(10);		if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) {			/* Mask out all chips interrupts */			GM_OUT(GM_IRQ_MASK, 0xffffffff);			break;		}	}	if (!timeout)		printk(KERN_ERR "%s reset chip failed !\n", dev->name);	/* Create fresh rings */	gmac_init_rings(gm, 1);	/* re-initialize the MAC */	gmac_mac_init(gm, dev->dev_addr);		/* re-initialize the multicast tables & promisc mode if any */	gmac_set_multicast(dev);	/* Restart PHY auto-poll */	mii_interrupt(gm);	/* Restart chip */	gmac_start_dma(gm);		spin_unlock_irqrestore(&gm->lock, flags);	netif_wake_queue(dev);}/* * Add a packet to the transmit ring */static intgmac_xmit_start(struct sk_buff *skb, struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	volatile struct gmac_dma_desc *dp;	unsigned long flags;	int i;	spin_lock_irqsave(&gm->lock, flags);	i = gm->next_tx;	if (gm->tx_buff[i] != 0) {		/* 		 * Buffer is full, can't send this packet at the moment		 * 		 * Can this ever happen in 2.4 ?		 */		netif_stop_queue(dev);		spin_unlock_irqrestore(&gm->lock, flags);		return 1;	}	gm->next_tx = (i + 1) & (NTX - 1);	gm->tx_buff[i] = skb;		dp = &gm->txring[i];	/* FIXME: Interrupt on all packet for now, change this to every N packet,	 * with N to be adjusted	 */	dp->flags = TX_FL_INTERRUPT;	dp->hi_addr = 0;	st_le32(&dp->lo_addr, virt_to_bus(skb->data));	mb();	st_le32(&dp->size, TX_SZ_SOP | TX_SZ_EOP | skb->len);	mb();	GM_OUT(GM_TX_KICK, gm->next_tx);	if (gm->tx_buff[gm->next_tx] != 0)		netif_stop_queue(dev);	spin_unlock_irqrestore(&gm->lock, flags);	dev->trans_start = jiffies;	return 0;}/* * Handle servicing of the transmit ring by deallocating used * Tx packets and restoring flow control when necessary */static voidgmac_tx_cleanup(struct net_device *dev, int force_cleanup){	struct gmac *gm = (struct gmac *) dev->priv;	volatile struct gmac_dma_desc *dp;	struct sk_buff *skb;	int gone, i;	i = gm->tx_gone;	/* Note: If i==gone, we empty the entire ring. This works because	 * if the ring was empty, we wouldn't have received the interrupt	 */	do {		gone = GM_IN(GM_TX_COMP);		skb = gm->tx_buff[i];		if (skb == NULL)			break;		dp = &gm->txring[i];		if (force_cleanup)			++gm->stats.tx_errors;		else {			++gm->stats.tx_packets;			gm->stats.tx_bytes += skb->len;		}		gm->tx_buff[i] = NULL;		dev_kfree_skb_irq(skb);		if (++i >= NTX)			i = 0;	} while (force_cleanup || i != gone);	gm->tx_gone = i;	if (!force_cleanup && netif_queue_stopped(dev) &&	    (gm->tx_buff[gm->next_tx] == 0))		netif_wake_queue(dev);}/* * Handle servicing of receive ring */static voidgmac_receive(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	int i = gm->next_rx;	volatile struct gmac_dma_desc *dp;	struct sk_buff *skb, *new_skb;	int len, flags, drop, last;	unsigned char *data;	u16 csum;	last = -1;	for (;;) {		dp = &gm->rxring[i];		/* Buffer not yet filled, no more Rx buffers to handle */		if (ld_le32(&dp->size) & RX_SZ_OWN)			break;		/* Get packet length, flags, etc... */		len = (ld_le32(&dp->size) >> 16) & 0x7fff;		flags = ld_le32(&dp->flags);		skb = gm->rx_buff[i];		drop = 0;		new_skb = NULL;		csum = ld_le32(&dp->size) & RX_SZ_CKSUM_MASK;				/* Handle errors */		if ((len < ETH_ZLEN)||(flags & RX_FL_CRC_ERROR)||(!skb)) {			++gm->stats.rx_errors;			if (len < ETH_ZLEN)				++gm->stats.rx_length_errors;			if (flags & RX_FL_CRC_ERROR)				++gm->stats.rx_crc_errors;			if (!skb) {				++gm->stats.rx_dropped;				skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);				if (skb) {					gm->rx_buff[i] = skb;			    		skb->dev = dev;			    		skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);			    		skb_reserve(skb, RX_OFFSET);				}			}			drop = 1;		} else {			/* Large packet, alloc a new skb for the ring */			if (len > RX_COPY_THRESHOLD) {			    new_skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);			    if(!new_skb) {			    	printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",			    		dev->name);			    	drop = 1;			    	++gm->stats.rx_dropped;			    	goto finish;			    }			    gm->rx_buff[i] = new_skb;			    new_skb->dev = dev;			    skb_put(new_skb, ETH_FRAME_LEN + RX_OFFSET);			    skb_reserve(new_skb, RX_OFFSET);			    skb_trim(skb, len);			} else {			    /* Small packet, copy it to a new small skb */			    struct sk_buff *copy_skb = dev_alloc_skb(len + RX_OFFSET);			    if(!copy_skb) {				printk(KERN_INFO "%s: Out of SKBs in Rx, packet dropped !\n",					dev->name);				drop = 1;				++gm->stats.rx_dropped;			    	goto finish;			    }			    copy_skb->dev = dev;			    skb_reserve(copy_skb, RX_OFFSET);			    skb_put(copy_skb, len);			    memcpy(copy_skb->data, skb->data, len);			    new_skb = skb;			    skb = copy_skb;			}		}	finish:		/* Need to drop packet ? */		if (drop) {			new_skb = skb;			skb = NULL;		}				/* Put back ring entry */		data = new_skb ? (new_skb->data - RX_OFFSET) : dummy_buf;		dp->hi_addr = 0;		st_le32(&dp->lo_addr, virt_to_bus(data));		mb();		st_le32(&dp->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));				/* Got Rx packet ? */		if (skb) {			/* Yes, baby, keep that hot ;) */			if(!(csum ^ 0xffff))				skb->ip_summed = CHECKSUM_UNNECESSARY;			else				skb->ip_summed = CHECKSUM_NONE;			skb->ip_summed = CHECKSUM_NONE;			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			gm->stats.rx_bytes += skb->len;			++gm->stats.rx_packets;		}				last = i;		if (++i >= NRX)			i = 0;	}	gm->next_rx = i;	if (last >= 0) {		mb();		GM_OUT(GM_RX_KICK, last & 0xfffffffc);	}}/* * Service chip interrupts */static voidgmac_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *) dev_id;	struct gmac *gm = (struct gmac *) dev->priv;	unsigned int status;	status = GM_IN(GM_IRQ_STATUS);	if (status & (GM_IRQ_BUS_ERROR | GM_IRQ_MIF))		GM_OUT(GM_IRQ_ACK, status & (GM_IRQ_BUS_ERROR | GM_IRQ_MIF));		if (status & (GM_IRQ_RX_TAG_ERR | GM_IRQ_BUS_ERROR)) {		printk(KERN_ERR "%s: IRQ Error status: 0x%08x\n",			dev->name, status);	}		if (status & GM_IRQ_MIF) {		spin_lock(&gm->lock);		mii_interrupt(gm);		spin_unlock(&gm->lock);	}		if (status & GM_IRQ_RX_DONE) {		spin_lock(&gm->lock);		gmac_receive(dev);		spin_unlock(&gm->lock);	}			if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) {		spin_lock(&gm->lock);		gmac_tx_cleanup(dev, 0);		spin_unlock(&gm->lock);	}}/* * Retreive some error stats from chip and return them * to above layer */static struct net_device_stats *gmac_stats(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	struct net_device_stats *stats = &gm->stats;	if (gm && gm->opened) {		stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR);		GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);		stats->rx_frame_errors += GM_IN(GM_MAC_RX_ALIGN_ERR_CTR);		GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);		stats->rx_length_errors += GM_IN(GM_MAC_RX_LEN_ERR_CTR);		GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);		stats->tx_aborted_errors += GM_IN(GM_MAC_EXCS_COLLISION_CTR);		stats->collisions +=			(GM_IN(GM_MAC_EXCS_COLLISION_CTR) +			 GM_IN(GM_MAC_LATE_COLLISION_CTR));		GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);		GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);	}	return stats;}static int __initgmac_probe(void){	struct device_node *gmac;	/* We bump use count during probe since get_free_page can sleep	 * which can be a race condition if module is unloaded at this	 * point.	 */	MOD_INC_USE_COUNT;		/*	 * We don't use PCI scanning on pmac since the GMAC cell is disabled	 * by default, and thus absent from kernel original PCI probing.	 */	for (gmac = find_compatible_devices("network", "gmac"); gmac != 0;	     gmac = gmac->next)		gmac_probe1(gmac);	MOD_DEC_USE_COUNT;	return 0;}static voidgmac_probe1(struct device_node *gmac){	struct gmac *gm;	unsigned long tx_descpage, rx_descpage;	unsigned char *addr;	struct net_device *dev;	int i;	if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {		printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",		       gmac->full_name, gmac->n_addrs, gmac->n_intrs);		return;	}	addr = get_property(gmac, "local-mac-address", NULL);	if (addr == NULL) {		printk(KERN_ERR "Can't get mac-address for GMAC %s\n",		       gmac->full_name);		return;	}	tx_descpage = get_free_page(GFP_KERNEL);	if (tx_descpage == 0) {		printk(KERN_ERR "GMAC: can't get a page for tx descriptors\n");		return;	}	rx_descpage = get_free_page(GFP_KERNEL);	if (rx_descpage == 0) {		printk(KERN_ERR "GMAC: can't get a page for rx descriptors\n");		free_page(tx_descpage);		return;	}	dev = init_etherdev(NULL, sizeof(struct gmac));	if (!dev) {		printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n");		free_page(tx_descpage);		free_page(rx_descpage);		return;	}	SET_MODULE_OWNER(dev);	gm = dev->priv;	dev->base_addr = gmac->addrs[0].address;	gm->regs = (volatile unsigned int *)		ioremap(gmac->addrs[0].address, 0x10000);	dev->irq = gmac->intrs[0].line;	gm->dev = dev;	gm->of_node = gmac;	spin_lock_init(&gm->lock);		if (pci_device_from_OF_node(gmac, &gm->pci_bus, &gm->pci_devfn)) {		gm->pci_bus = gm->pci_devfn = 0xff;		printk(KERN_ERR "Can't locate GMAC PCI entry\n");	}	printk(KERN_INFO "%s: GMAC at", dev->name);	for (i = 0; i < 6; ++i) {		dev->dev_addr[i] = addr[i];		printk("%c%.2x", (i? ':': ' '), addr[i]);	}	printk(", driver " GMAC_VERSION "\n");	gm->tx_desc_page = tx_descpage;	gm->rx_desc_page = rx_descpage;	gm->rxring = (volatile struct gmac_dma_desc *) rx_descpage;	gm->txring = (volatile struct gmac_dma_desc *) tx_descpage;	gm->phy_addr = 0;	gm->opened = 0;	dev->open = gmac_open;	dev->stop = gmac_close;	dev->hard_start_xmit = gmac_xmit_start;	dev->get_stats = gmac_stats;	dev->set_multicast_list = &gmac_set_multicast;	dev->tx_timeout = &gmac_tx_timeout;	dev->watchdog_timeo = 5*HZ;	ether_setup(dev);		gm->next_gmac = gmacs;	gmacs = dev;#ifdef CONFIG_PMAC_PBOOK	pmu_register_sleep_notifier(&gmac_sleep_notifier);#endif}MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");MODULE_DESCRIPTION("PowerMac GMAC driver.");static void __exit gmac_cleanup_module(void){	struct gmac *gm;	struct net_device *dev;	while ((dev = gmacs) != NULL) {		gm = (struct gmac *) dev->priv;		unregister_netdev(dev);		free_page(gm->tx_desc_page);		free_page(gm->rx_desc_page);		gmacs = gm->next_gmac;		kfree(dev);	}}module_init(gmac_probe);module_exit(gmac_cleanup_module);

⌨️ 快捷键说明

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