bfin_mac.c

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

C
1,080
字号
	if (tx_list_head->status.status_word != 0	    && current_tx_ptr != tx_list_head) {		goto adjust_head;	/* released something, just return; */	}	/*	 * if nothing released, check wait condition	 * current's next can not be the head,	 * otherwise the dma will not stop as we want	 */	if (current_tx_ptr->next->next == tx_list_head) {		while (tx_list_head->status.status_word == 0) {			mdelay(10);			if (tx_list_head->status.status_word != 0			    || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {				goto adjust_head;			}			if (timeout_cnt-- < 0) {				printk(KERN_ERR DRV_NAME				": wait for adjust tx list head timeout\n");				break;			}		}		if (tx_list_head->status.status_word != 0) {			goto adjust_head;		}	}	return;adjust_head:	do {		tx_list_head->desc_a.config &= ~DMAEN;		tx_list_head->status.status_word = 0;		if (tx_list_head->skb) {			dev_kfree_skb(tx_list_head->skb);			tx_list_head->skb = NULL;		} else {			printk(KERN_ERR DRV_NAME			       ": no sk_buff in a transmitted frame!\n");		}		tx_list_head = tx_list_head->next;	} while (tx_list_head->status.status_word != 0		 && current_tx_ptr != tx_list_head);	return;}static int bf537mac_hard_start_xmit(struct sk_buff *skb,				struct net_device *dev){	struct bf537mac_local *lp = netdev_priv(dev);	unsigned int data;	current_tx_ptr->skb = skb;	/*	 * Is skb->data always 16-bit aligned?	 * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?	 */	if ((((unsigned int)(skb->data)) & 0x02) == 2) {		/* move skb->data to current_tx_ptr payload */		data = (unsigned int)(skb->data) - 2;		*((unsigned short *)data) = (unsigned short)(skb->len);		current_tx_ptr->desc_a.start_addr = (unsigned long)data;		/* this is important! */		blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);	} else {		*((unsigned short *)(current_tx_ptr->packet)) =		    (unsigned short)(skb->len);		memcpy((char *)(current_tx_ptr->packet + 2), skb->data,		       (skb->len));		current_tx_ptr->desc_a.start_addr =		    (unsigned long)current_tx_ptr->packet;		if (current_tx_ptr->status.status_word != 0)			current_tx_ptr->status.status_word = 0;		blackfin_dcache_flush_range((unsigned int)current_tx_ptr->					    packet,					    (unsigned int)(current_tx_ptr->							   packet + skb->len) +					    2);	}	/* enable this packet's dma */	current_tx_ptr->desc_a.config |= DMAEN;	/* tx dma is running, just return */	if (bfin_read_DMA2_IRQ_STATUS() & 0x08)		goto out;	/* tx dma is not running */	bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));	/* dma enabled, read from memory, size is 6 */	bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);	/* Turn on the EMAC tx */	bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);out:	adjust_tx_list();	current_tx_ptr = current_tx_ptr->next;	dev->trans_start = jiffies;	dev->stats.tx_packets++;	dev->stats.tx_bytes += (skb->len);	return 0;}static void bf537mac_rx(struct net_device *dev){	struct sk_buff *skb, *new_skb;	struct bf537mac_local *lp = netdev_priv(dev);	unsigned short len;	/* allocate a new skb for next time receive */	skb = current_rx_ptr->skb;	new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);	if (!new_skb) {		printk(KERN_NOTICE DRV_NAME		       ": rx: low on mem - packet dropped\n");		dev->stats.rx_dropped++;		goto out;	}	/* reserve 2 bytes for RXDWA padding */	skb_reserve(new_skb, 2);	current_rx_ptr->skb = new_skb;	current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;	len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);	skb_put(skb, len);	blackfin_dcache_invalidate_range((unsigned long)skb->head,					 (unsigned long)skb->tail);	dev->last_rx = jiffies;	skb->dev = dev;	skb->protocol = eth_type_trans(skb, dev);#if defined(BFIN_MAC_CSUM_OFFLOAD)	skb->csum = current_rx_ptr->status.ip_payload_csum;	skb->ip_summed = CHECKSUM_COMPLETE;#endif	netif_rx(skb);	dev->stats.rx_packets++;	dev->stats.rx_bytes += len;	current_rx_ptr->status.status_word = 0x00000000;	current_rx_ptr = current_rx_ptr->next;out:	return;}/* interrupt routine to handle rx and error signal */static irqreturn_t bf537mac_interrupt(int irq, void *dev_id){	struct net_device *dev = dev_id;	int number = 0;get_one_packet:	if (current_rx_ptr->status.status_word == 0) {		/* no more new packet received */		if (number == 0) {			if (current_rx_ptr->next->status.status_word != 0) {				current_rx_ptr = current_rx_ptr->next;				goto real_rx;			}		}		bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |					   DMA_DONE | DMA_ERR);		return IRQ_HANDLED;	}real_rx:	bf537mac_rx(dev);	number++;	goto get_one_packet;}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void bf537mac_poll(struct net_device *dev){	disable_irq(IRQ_MAC_RX);	bf537mac_interrupt(IRQ_MAC_RX, dev);	enable_irq(IRQ_MAC_RX);}#endif				/* CONFIG_NET_POLL_CONTROLLER */static void bf537mac_disable(void){	unsigned int opmode;	opmode = bfin_read_EMAC_OPMODE();	opmode &= (~RE);	opmode &= (~TE);	/* Turn off the EMAC */	bfin_write_EMAC_OPMODE(opmode);}/* * Enable Interrupts, Receive, and Transmit */static void bf537mac_enable(void){	u32 opmode;	pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);	/* Set RX DMA */	bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));	bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);	/* Wait MII done */	mdio_poll();	/* We enable only RX here */	/* ASTP   : Enable Automatic Pad Stripping	   PR     : Promiscuous Mode for test	   PSF    : Receive frames with total length less than 64 bytes.	   FDMODE : Full Duplex Mode	   LB     : Internal Loopback for test	   RE     : Receiver Enable */	opmode = bfin_read_EMAC_OPMODE();	if (opmode & FDMODE)		opmode |= PSF;	else		opmode |= DRO | DC | PSF;	opmode |= RE;#if defined(CONFIG_BFIN_MAC_RMII)	opmode |= RMII; /* For Now only 100MBit are supported */#ifdef CONFIG_BF_REV_0_2	opmode |= TE;#endif#endif	/* Turn on the EMAC rx */	bfin_write_EMAC_OPMODE(opmode);}/* Our watchdog timed out. Called by the networking layer */static void bf537mac_timeout(struct net_device *dev){	pr_debug("%s: %s\n", dev->name, __FUNCTION__);	bf537mac_disable();	/* reset tx queue */	tx_list_tail = tx_list_head->next;	bf537mac_enable();	/* We can accept TX packets again */	dev->trans_start = jiffies;	netif_wake_queue(dev);}/* * This routine will, depending on the values passed to it, * either make it accept multicast packets, go into * promiscuous mode (for TCPDUMP and cousins) or accept * a select set of multicast packets */static void bf537mac_set_multicast_list(struct net_device *dev){	u32 sysctl;	if (dev->flags & IFF_PROMISC) {		printk(KERN_INFO "%s: set to promisc mode\n", dev->name);		sysctl = bfin_read_EMAC_OPMODE();		sysctl |= RAF;		bfin_write_EMAC_OPMODE(sysctl);	} else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {		/* accept all multicast */		sysctl = bfin_read_EMAC_OPMODE();		sysctl |= PAM;		bfin_write_EMAC_OPMODE(sysctl);	} else {		/* clear promisc or multicast mode */		sysctl = bfin_read_EMAC_OPMODE();		sysctl &= ~(RAF | PAM);		bfin_write_EMAC_OPMODE(sysctl);	}}/* * this puts the device in an inactive state */static void bf537mac_shutdown(struct net_device *dev){	/* Turn off the EMAC */	bfin_write_EMAC_OPMODE(0x00000000);	/* Turn off the EMAC RX DMA */	bfin_write_DMA1_CONFIG(0x0000);	bfin_write_DMA2_CONFIG(0x0000);}/* * Open and Initialize the interface * * Set up everything, reset the card, etc.. */static int bf537mac_open(struct net_device *dev){	struct bf537mac_local *lp = netdev_priv(dev);	int retval;	pr_debug("%s: %s\n", dev->name, __FUNCTION__);	/*	 * Check that the address is valid.  If its not, refuse	 * to bring the device up.  The user must specify an	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx	 */	if (!is_valid_ether_addr(dev->dev_addr)) {		printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n");		return -EINVAL;	}	/* initial rx and tx list */	retval = desc_list_init();	if (retval)		return retval;	phy_start(lp->phydev);	setup_system_regs(dev);	bf537mac_disable();	bf537mac_enable();	pr_debug("hardware init finished\n");	netif_start_queue(dev);	netif_carrier_on(dev);	return 0;}/* * * this makes the board clean up everything that it can * and not talk to the outside world.   Caused by * an 'ifconfig ethX down' */static int bf537mac_close(struct net_device *dev){	struct bf537mac_local *lp = netdev_priv(dev);	pr_debug("%s: %s\n", dev->name, __FUNCTION__);	netif_stop_queue(dev);	netif_carrier_off(dev);	phy_stop(lp->phydev);	/* clear everything */	bf537mac_shutdown(dev);	/* free the rx/tx buffers */	desc_list_free();	return 0;}static int __init bf537mac_probe(struct net_device *dev){	struct bf537mac_local *lp = netdev_priv(dev);	int retval;	int i;	/* Grab the MAC address in the MAC */	*(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());	*(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());	/* probe mac */	/*todo: how to proble? which is revision_register */	bfin_write_EMAC_ADDRLO(0x12345678);	if (bfin_read_EMAC_ADDRLO() != 0x12345678) {		pr_debug("can't detect bf537 mac!\n");		retval = -ENODEV;		goto err_out;	}	/* set the GPIO pins to Ethernet mode */	retval = setup_pin_mux(1);	if (retval)		return retval;	/*Is it valid? (Did bootloader initialize it?) */	if (!is_valid_ether_addr(dev->dev_addr)) {		/* Grab the MAC from the board somehow - this is done in the		   arch/blackfin/mach-bf537/boards/eth_mac.c */		bfin_get_ether_addr(dev->dev_addr);	}	/* If still not valid, get a random one */	if (!is_valid_ether_addr(dev->dev_addr)) {		random_ether_addr(dev->dev_addr);	}	setup_mac_addr(dev->dev_addr);	/* MDIO bus initial */	lp->mii_bus.priv = dev;	lp->mii_bus.read = mdiobus_read;	lp->mii_bus.write = mdiobus_write;	lp->mii_bus.reset = mdiobus_reset;	lp->mii_bus.name = "bfin_mac_mdio";	lp->mii_bus.id = 0;	lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);	for (i = 0; i < PHY_MAX_ADDR; ++i)		lp->mii_bus.irq[i] = PHY_POLL;	mdiobus_register(&lp->mii_bus);	retval = mii_probe(dev);	if (retval)		return retval;	/* Fill in the fields of the device structure with ethernet values. */	ether_setup(dev);	dev->open = bf537mac_open;	dev->stop = bf537mac_close;	dev->hard_start_xmit = bf537mac_hard_start_xmit;	dev->set_mac_address = bf537mac_set_mac_address;	dev->tx_timeout = bf537mac_timeout;	dev->set_multicast_list = bf537mac_set_multicast_list;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = bf537mac_poll;#endif	spin_lock_init(&lp->lock);	/* now, enable interrupts */	/* register irq handler */	if (request_irq	    (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,	     "BFIN537_MAC_RX", dev)) {		printk(KERN_WARNING DRV_NAME		       ": Unable to attach BlackFin MAC RX interrupt\n");		return -EBUSY;	}	retval = register_netdev(dev);	if (retval == 0) {		/* now, print out the card info, in a short format.. */		printk(KERN_INFO "%s: Version %s, %s\n",			 DRV_NAME, DRV_VERSION, DRV_DESC);	}err_out:	return retval;}static int bfin_mac_probe(struct platform_device *pdev){	struct net_device *ndev;	ndev = alloc_etherdev(sizeof(struct bf537mac_local));	if (!ndev) {		printk(KERN_WARNING DRV_NAME ": could not allocate device\n");		return -ENOMEM;	}	SET_NETDEV_DEV(ndev, &pdev->dev);	platform_set_drvdata(pdev, ndev);	if (bf537mac_probe(ndev) != 0) {		platform_set_drvdata(pdev, NULL);		free_netdev(ndev);		printk(KERN_WARNING DRV_NAME ": not found\n");		return -ENODEV;	}	return 0;}static int bfin_mac_remove(struct platform_device *pdev){	struct net_device *ndev = platform_get_drvdata(pdev);	platform_set_drvdata(pdev, NULL);	unregister_netdev(ndev);	free_irq(IRQ_MAC_RX, ndev);	free_netdev(ndev);	setup_pin_mux(0);	return 0;}#ifdef CONFIG_PMstatic int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg){	struct net_device *net_dev = platform_get_drvdata(pdev);	if (netif_running(net_dev))		bf537mac_close(net_dev);	return 0;}static int bfin_mac_resume(struct platform_device *pdev){	struct net_device *net_dev = platform_get_drvdata(pdev);	if (netif_running(net_dev))		bf537mac_open(net_dev);	return 0;}#else#define bfin_mac_suspend NULL#define bfin_mac_resume NULL#endif	/* CONFIG_PM */static struct platform_driver bfin_mac_driver = {	.probe = bfin_mac_probe,	.remove = bfin_mac_remove,	.resume = bfin_mac_resume,	.suspend = bfin_mac_suspend,	.driver = {		   .name = DRV_NAME,		   },};static int __init bfin_mac_init(void){	return platform_driver_register(&bfin_mac_driver);}module_init(bfin_mac_init);static void __exit bfin_mac_cleanup(void){	platform_driver_unregister(&bfin_mac_driver);}module_exit(bfin_mac_cleanup);

⌨️ 快捷键说明

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