cpmac.c

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

C
1,197
字号
	strcpy(info->version, CPMAC_VERSION);	info->fw_version[0] = '\0';	sprintf(info->bus_info, "%s", "cpmac");	info->regdump_len = 0;}static const struct ethtool_ops cpmac_ethtool_ops = {	.get_settings = cpmac_get_settings,	.set_settings = cpmac_set_settings,	.get_drvinfo = cpmac_get_drvinfo,	.get_link = ethtool_op_get_link,	.get_ringparam = cpmac_get_ringparam,	.set_ringparam = cpmac_set_ringparam,};static void cpmac_adjust_link(struct net_device *dev){	struct cpmac_priv *priv = netdev_priv(dev);	int new_state = 0;	spin_lock(&priv->lock);	if (priv->phy->link) {		netif_start_queue(dev);		if (priv->phy->duplex != priv->oldduplex) {			new_state = 1;			priv->oldduplex = priv->phy->duplex;		}		if (priv->phy->speed != priv->oldspeed) {			new_state = 1;			priv->oldspeed = priv->phy->speed;		}		if (!priv->oldlink) {			new_state = 1;			priv->oldlink = 1;			netif_schedule(dev);		}	} else if (priv->oldlink) {		netif_stop_queue(dev);		new_state = 1;		priv->oldlink = 0;		priv->oldspeed = 0;		priv->oldduplex = -1;	}	if (new_state && netif_msg_link(priv) && net_ratelimit())		phy_print_status(priv->phy);	spin_unlock(&priv->lock);}static int cpmac_link_update(struct net_device *dev,			     struct fixed_phy_status *status){	status->link = 1;	status->speed = 100;	status->duplex = 1;	return 0;}static int cpmac_open(struct net_device *dev){	int i, size, res;	struct cpmac_priv *priv = netdev_priv(dev);	struct resource *mem;	struct cpmac_desc *desc;	struct sk_buff *skb;	mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");	if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {		if (netif_msg_drv(priv))			printk(KERN_ERR "%s: failed to request registers\n",			       dev->name);		res = -ENXIO;		goto fail_reserve;	}	priv->regs = ioremap(mem->start, mem->end - mem->start);	if (!priv->regs) {		if (netif_msg_drv(priv))			printk(KERN_ERR "%s: failed to remap registers\n",			       dev->name);		res = -ENXIO;		goto fail_remap;	}	size = priv->ring_size + CPMAC_QUEUES;	priv->desc_ring = dma_alloc_coherent(&dev->dev,					     sizeof(struct cpmac_desc) * size,					     &priv->dma_ring,					     GFP_KERNEL);	if (!priv->desc_ring) {		res = -ENOMEM;		goto fail_alloc;	}	for (i = 0; i < size; i++)		priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i;	priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];	for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) {		skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);		if (unlikely(!skb)) {			res = -ENOMEM;			goto fail_desc;		}		skb_reserve(skb, 2);		desc->skb = skb;		desc->data_mapping = dma_map_single(&dev->dev, skb->data,						    CPMAC_SKB_SIZE,						    DMA_FROM_DEVICE);		desc->hw_data = (u32)desc->data_mapping;		desc->buflen = CPMAC_SKB_SIZE;		desc->dataflags = CPMAC_OWN;		desc->next = &priv->rx_head[(i + 1) % priv->ring_size];		desc->hw_next = (u32)desc->next->mapping;	}	if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,			       dev->name, dev))) {		if (netif_msg_drv(priv))			printk(KERN_ERR "%s: failed to obtain irq\n",			       dev->name);		goto fail_irq;	}	INIT_WORK(&priv->reset_work, cpmac_hw_error);	cpmac_hw_start(dev);	napi_enable(&priv->napi);	priv->phy->state = PHY_CHANGELINK;	phy_start(priv->phy);	return 0;fail_irq:fail_desc:	for (i = 0; i < priv->ring_size; i++) {		if (priv->rx_head[i].skb) {			dma_unmap_single(&dev->dev,					 priv->rx_head[i].data_mapping,					 CPMAC_SKB_SIZE,					 DMA_FROM_DEVICE);			kfree_skb(priv->rx_head[i].skb);		}	}fail_alloc:	kfree(priv->desc_ring);	iounmap(priv->regs);fail_remap:	release_mem_region(mem->start, mem->end - mem->start);fail_reserve:	return res;}static int cpmac_stop(struct net_device *dev){	int i;	struct cpmac_priv *priv = netdev_priv(dev);	struct resource *mem;	netif_stop_queue(dev);	cancel_work_sync(&priv->reset_work);	napi_disable(&priv->napi);	phy_stop(priv->phy);	cpmac_hw_stop(dev);	for (i = 0; i < 8; i++)		cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);	cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0);	cpmac_write(priv->regs, CPMAC_MBP, 0);	free_irq(dev->irq, dev);	iounmap(priv->regs);	mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");	release_mem_region(mem->start, mem->end - mem->start);	priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];	for (i = 0; i < priv->ring_size; i++) {		if (priv->rx_head[i].skb) {			dma_unmap_single(&dev->dev,					 priv->rx_head[i].data_mapping,					 CPMAC_SKB_SIZE,					 DMA_FROM_DEVICE);			kfree_skb(priv->rx_head[i].skb);		}	}	dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) *			  (CPMAC_QUEUES + priv->ring_size),			  priv->desc_ring, priv->dma_ring);	return 0;}static int external_switch;static int __devinit cpmac_probe(struct platform_device *pdev){	int rc, phy_id, i;	struct resource *mem;	struct cpmac_priv *priv;	struct net_device *dev;	struct plat_cpmac_data *pdata;	struct fixed_info *fixed_phy;	DECLARE_MAC_BUF(mac);	pdata = pdev->dev.platform_data;	for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {		if (!(pdata->phy_mask & (1 << phy_id)))			continue;		if (!cpmac_mii.phy_map[phy_id])			continue;		break;	}	if (phy_id == PHY_MAX_ADDR) {		if (external_switch || dumb_switch)			phy_id = 0;		else {			printk(KERN_ERR "cpmac: no PHY present\n");			return -ENODEV;		}	}	dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES);	if (!dev) {		printk(KERN_ERR "cpmac: Unable to allocate net_device\n");		return -ENOMEM;	}	platform_set_drvdata(pdev, dev);	priv = netdev_priv(dev);	priv->pdev = pdev;	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");	if (!mem) {		rc = -ENODEV;		goto fail;	}	dev->irq = platform_get_irq_byname(pdev, "irq");	dev->open               = cpmac_open;	dev->stop               = cpmac_stop;	dev->set_config         = cpmac_config;	dev->hard_start_xmit    = cpmac_start_xmit;	dev->do_ioctl           = cpmac_ioctl;	dev->set_multicast_list = cpmac_set_multicast_list;	dev->tx_timeout         = cpmac_tx_timeout;	dev->ethtool_ops        = &cpmac_ethtool_ops;	dev->features |= NETIF_F_MULTI_QUEUE;	netif_napi_add(dev, &priv->napi, cpmac_poll, 64);	spin_lock_init(&priv->lock);	spin_lock_init(&priv->rx_lock);	priv->dev = dev;	priv->ring_size = 64;	priv->msg_enable = netif_msg_init(debug_level, 0xff);	memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));	if (phy_id == 31) {		snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id,			 phy_id);	} else {		/* Let's try to get a free fixed phy... */		for (i = 0; i < MAX_PHY_AMNT; i++) {			fixed_phy = fixed_mdio_get_phydev(i);			if (!fixed_phy)				continue;			if (!fixed_phy->phydev->attached_dev) {				strncpy(priv->phy_name,					fixed_phy->phydev->dev.bus_id,					BUS_ID_SIZE);				fixed_mdio_set_link_update(fixed_phy->phydev,							   &cpmac_link_update);				goto phy_found;			}		}		if (netif_msg_drv(priv))			printk(KERN_ERR "%s: Could not find fixed PHY\n",			       dev->name);		rc = -ENODEV;		goto fail;	}phy_found:	priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,				PHY_INTERFACE_MODE_MII);	if (IS_ERR(priv->phy)) {		if (netif_msg_drv(priv))			printk(KERN_ERR "%s: Could not attach to PHY\n",			       dev->name);		return PTR_ERR(priv->phy);	}	if ((rc = register_netdev(dev))) {		printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,		       dev->name);		goto fail;	}	if (netif_msg_probe(priv)) {		printk(KERN_INFO		       "cpmac: device %s (regs: %p, irq: %d, phy: %s, "		       "mac: %s)\n", dev->name, (void *)mem->start, dev->irq,		       priv->phy_name, print_mac(mac, dev->dev_addr));	}	return 0;fail:	free_netdev(dev);	return rc;}static int __devexit cpmac_remove(struct platform_device *pdev){	struct net_device *dev = platform_get_drvdata(pdev);	unregister_netdev(dev);	free_netdev(dev);	return 0;}static struct platform_driver cpmac_driver = {	.driver.name = "cpmac",	.probe = cpmac_probe,	.remove = __devexit_p(cpmac_remove),};int __devinit cpmac_init(void){	u32 mask;	int i, res;	cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);	if (!cpmac_mii.priv) {		printk(KERN_ERR "Can't ioremap mdio registers\n");		return -ENXIO;	}#warning FIXME: unhardcode gpio&reset bits	ar7_gpio_disable(26);	ar7_gpio_disable(27);	ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);	ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);	ar7_device_reset(AR7_RESET_BIT_EPHY);	cpmac_mii.reset(&cpmac_mii);	for (i = 0; i < 300000; i++)		if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))			break;		else			cpu_relax();	mask &= 0x7fffffff;	if (mask & (mask - 1)) {		external_switch = 1;		mask = 0;	}	cpmac_mii.phy_mask = ~(mask | 0x80000000);	res = mdiobus_register(&cpmac_mii);	if (res)		goto fail_mii;	res = platform_driver_register(&cpmac_driver);	if (res)		goto fail_cpmac;	return 0;fail_cpmac:	mdiobus_unregister(&cpmac_mii);fail_mii:	iounmap(cpmac_mii.priv);	return res;}void __devexit cpmac_exit(void){	platform_driver_unregister(&cpmac_driver);	mdiobus_unregister(&cpmac_mii);	iounmap(cpmac_mii.priv);}module_init(cpmac_init);module_exit(cpmac_exit);

⌨️ 快捷键说明

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