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

📄 ibm_ocp_enet.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (link == netif_carrier_ok(fep->ndev)) {	        if (!link && fep->want_autoneg && (++fep->timer_ticks) > 10)		        emac_start_link(fep, NULL);	        goto out;        }	printk(KERN_INFO "%s: Link is %s\n", fep->ndev->name, link ? "Up" : "Down");	if (link) {	        netif_carrier_on(fep->ndev);                /* Chip needs a full reset on config change. That sucks, so I                 * should ultimately move that to some tasklet to limit                 * latency peaks caused by this code                 */                emac_reset_configure(fep);		if (fep->opened)                	emac_kick(fep);	} else {	        fep->timer_ticks = 0;	        netif_carrier_off(fep->ndev);	}out:	mod_timer(&fep->link_timer, jiffies + HZ);	spin_unlock_irq(&fep->lock);}static voidemac_set_multicast_list(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	spin_lock_irq(&fep->lock);        __emac_set_multicast_list(dev);	spin_unlock_irq(&fep->lock);}static intemac_ethtool(struct net_device *dev, void* ep_user){        struct ocp_enet_private *fep = dev->priv;        struct ethtool_cmd ecmd;        unsigned long features = fep->phy_mii.def->features;        if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))                return -EFAULT;        switch(ecmd.cmd) {        case ETHTOOL_GDRVINFO: {                struct ethtool_drvinfo info;                memset(&info, 0, sizeof(info));                info.cmd = ETHTOOL_GDRVINFO;                strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);                strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);                info.fw_version[0] = '\0';                sprintf(info.bus_info, "OCP EMAC %d", fep->ocpdev->def->index);                info.regdump_len = 0;                if (copy_to_user(ep_user, &info, sizeof(info)))                        return -EFAULT;                return 0;                }        case ETHTOOL_GSET:                ecmd.supported = features;                ecmd.port = PORT_MII;                ecmd.transceiver = XCVR_EXTERNAL;                ecmd.phy_address = fep->mii_phy_addr;                spin_lock_irq(&fep->lock);                ecmd.autoneg = fep->want_autoneg;                ecmd.speed = fep->phy_mii.speed;                ecmd.duplex = fep->phy_mii.duplex;                spin_unlock_irq(&fep->lock);                if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))                        return -EFAULT;                return 0;        case ETHTOOL_SSET:                if (!capable(CAP_NET_ADMIN))                        return -EPERM;                                if (ecmd.autoneg != AUTONEG_ENABLE &&                    ecmd.autoneg != AUTONEG_DISABLE)                        return -EINVAL;                if (ecmd.autoneg == AUTONEG_ENABLE &&                    ecmd.advertising == 0)                        return -EINVAL;                if (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL)                        return -EINVAL;                if (ecmd.autoneg == AUTONEG_DISABLE)                        switch(ecmd.speed) {                        case SPEED_10:                                if (ecmd.duplex == DUPLEX_HALF &&                                    (features & SUPPORTED_10baseT_Half) == 0)                                        return -EINVAL;                                if (ecmd.duplex == DUPLEX_FULL &&                                    (features & SUPPORTED_10baseT_Full) == 0)                                        return -EINVAL;                                break;                        case SPEED_100:                                if (ecmd.duplex == DUPLEX_HALF &&                                    (features & SUPPORTED_100baseT_Half) == 0)                                        return -EINVAL;                                if (ecmd.duplex == DUPLEX_FULL &&                                    (features & SUPPORTED_100baseT_Full) == 0)                                        return -EINVAL;                                break;                        default:                                return -EINVAL;                        }                else if ((features & SUPPORTED_Autoneg) == 0)                        return -EINVAL;                spin_lock_irq(&fep->lock);                emac_start_link(fep, &ecmd);                spin_unlock_irq(&fep->lock);                                return 0;        case ETHTOOL_NWAY_RST:                if (!fep->want_autoneg)                        return -EINVAL;                spin_lock_irq(&fep->lock);                emac_start_link(fep, NULL);                spin_unlock_irq(&fep->lock);                return 0;        case ETHTOOL_GLINK: {                struct ethtool_value edata;                memset(&edata, 0, sizeof(edata));                edata.cmd = ETHTOOL_GLINK;                edata.data = netif_carrier_ok(dev);                if (copy_to_user(ep_user, &edata, sizeof(edata)))                        return -EFAULT;                return 0;                }        }        return -EOPNOTSUPP;}static intemac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct ocp_enet_private *fep = dev->priv;	uint *data = (uint *) & rq->ifr_data;	switch (cmd) {        case SIOCETHTOOL:                return emac_ethtool(dev, rq->ifr_data);	case SIOCDEVPRIVATE:	case SIOCGMIIPHY:		data[0] = fep->mii_phy_addr;		/*FALLTHRU*/	case SIOCDEVPRIVATE + 1:	case SIOCGMIIREG:		data[3] = emac_phy_read(dev, fep->mii_phy_addr, data[1]);		return 0;	case SIOCDEVPRIVATE + 2:	case SIOCSMIIREG:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		emac_phy_write(dev, fep->mii_phy_addr, data[1], data[2]);		return 0;	default:		return -EOPNOTSUPP;	}} static intemac_open(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	int rc;	spin_lock_irq(&fep->lock);	fep->opened = 1;                /* Reset & configure the chip */        emac_reset_configure(fep);	spin_unlock_irq(&fep->lock);        /* Request our interrupt lines */	rc = request_irq(dev->irq, emac_mac_irq, 0, "OCP EMAC MAC", dev);	if (rc != 0)		goto bail;	rc = request_irq(fep->wol_irq, emac_wakeup_irq, 0, "OCP EMAC Wakeup", dev);	if (rc != 0) {		free_irq(dev->irq, dev);		goto bail;	}        /* Kick the chip rx & tx channels into life */ 	spin_lock_irq(&fep->lock);        emac_kick(fep);        spin_unlock_irq(&fep->lock);	netif_start_queue(dev);bail:	return rc;}static intemac_close(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	volatile emac_t *emacp = fep->emacp;	/* XXX Stop IRQ emitting here */	spin_lock_irq(&fep->lock);	fep->opened = 0;	mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask);	mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask);	netif_stop_queue(dev);	out_be32(&emacp->em0mr0, EMAC_M0_SRST);	udelay(10);	if (emacp->em0mr0 & EMAC_M0_SRST) {		/*not sure what to do here hopefully it clears before another open */		printk(KERN_ERR "%s: Phy SoftReset didn't clear, no link?\n",		       dev->name);	}	/* Free the irq's */	free_irq(dev->irq, dev);	free_irq(fep->wol_irq, dev);	spin_unlock_irq(&fep->lock);	return 0;}static voidemac_remove(struct ocp_device *ocpdev){	struct net_device *dev = ocp_get_drvdata(ocpdev);	struct ocp_enet_private *ep = dev->priv;	/* FIXME: locking, races, ... */	ep->going_away = 1;	ocp_set_drvdata(ocpdev, NULL);	if (ep->zmii_dev)		emac_fini_zmii(ep->zmii_dev);	unregister_netdev(dev);	del_timer_sync(&ep->link_timer);	mal_unregister_commac(ep->mal, &ep->commac);	iounmap((void *)ep->emacp);	kfree(dev);}struct mal_commac_ops emac_commac_ops = {	.txeob = &emac_txeob_dev,	.txde = &emac_txde_dev,	.rxeob = &emac_rxeob_dev,	.rxde = &emac_rxde_dev,};static intemac_probe(struct ocp_device *ocpdev){	int rc = 0, i;	bd_t *bd;	struct net_device *ndev;	struct ocp_enet_private *ep;	struct ocp_device *maldev;	struct ibm_ocp_mal *mal;	struct ocp_func_emac_data *emacdata;	struct ocp_device *mdiodev;	struct net_device *mdio_ndev = NULL;	int commac_reg = 0;	u32 phy_map;		emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions;	if (emacdata == NULL) {		printk(KERN_ERR "emac%d: Missing additional datas !\n", ocpdev->def->index);		return -ENODEV;	}	/* Wait for MAL to show up */	maldev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_MAL, emacdata->mal_idx);	if (maldev == NULL)		return -EAGAIN;	/* Check if MAL driver attached yet */	mal = (struct ibm_ocp_mal *)ocp_get_drvdata(maldev);	if (mal == NULL)		return -EAGAIN;	/* If we depend on another EMAC for MDIO, wait for it to show up */	if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) {		mdiodev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_EMAC, emacdata->mdio_idx);		if (mdiodev == NULL)			return -EAGAIN;		mdio_ndev = (struct net_device *)ocp_get_drvdata(mdiodev);		if (mdio_ndev == NULL)			return -EAGAIN;	}	/* Allocate our net_device structure */	ndev = alloc_etherdev(sizeof (struct ocp_enet_private));	if (ndev == NULL) {		printk(KERN_ERR		       "emac%d: Could not allocate ethernet device.\n", ocpdev->def->index);		return -ENOMEM;	}	ep = ndev->priv;	memset(ep, 0, sizeof(*ep));	ep->ndev = ndev;	ep->ocpdev = ocpdev;	ndev->irq = ocpdev->def->irq;	ep->wol_irq = emacdata->wol_irq;	ep->mdio_dev = mdio_ndev;	ocp_set_drvdata(ocpdev, ndev);	spin_lock_init(&ep->lock);	/* Fill out MAL informations and register commac */	ep->mal = mal;	ep->mal_tx_chan = emacdata->mal_tx1_chan;	ep->mal_rx_chan = emacdata->mal_rx_chan;	ep->commac.ops = &emac_commac_ops;	ep->commac.dev = ndev;	ep->commac.tx_chan_mask = MAL_CHAN_MASK(ep->mal_tx_chan);	ep->commac.rx_chan_mask = MAL_CHAN_MASK(ep->mal_rx_chan);	rc = mal_register_commac(ep->mal, &ep->commac);	if (rc != 0)		goto bail;	commac_reg = 1;	/* Map our MMIOs */	ep->emacp = (volatile emac_t *)ioremap(ocpdev->def->paddr, sizeof (emac_t));	/* Check if we need to attach to a ZMII */	if (emacdata->zmii_idx >= 0) {		ep->zmii_input = emacdata->zmii_mux;		ep->zmii_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_ZMII, emacdata->zmii_idx);		if (ep->zmii_dev == NULL)	                printk(KERN_WARNING "emac%d: ZMII %d requested but not found !\n",	                	ocpdev->def->index, emacdata->zmii_idx);		else if ((rc = emac_init_zmii(ep->zmii_dev, ZMII_AUTO)) != 0)			goto bail;	}	/* Reset the EMAC */	out_be32(&ep->emacp->em0mr0, EMAC_M0_SRST);	udelay(20);        for (i=0; i<100; i++) {                if ((in_be32(&ep->emacp->em0mr0) & EMAC_M0_SRST) == 0)                        break;                udelay(10);        }	        if (i >= 100) {                printk(KERN_ERR "emac%d: Cannot reset EMAC\n", ocpdev->def->index);		rc = -ENXIO;		goto bail;        }	/* Init link monitoring timer */	init_timer(&ep->link_timer);	ep->link_timer.function = emac_link_timer;	ep->link_timer.data = (unsigned long) ep;	ep->timer_ticks = 0;	/* Fill up the mii_phy structure */	ep->phy_mii.dev = ndev;	ep->phy_mii.mdio_read = emac_phy_read;	ep->phy_mii.mdio_write = emac_phy_write;	/* Find PHY */	phy_map = emac_phy_map[ocpdev->def->index] | busy_phy_map;	for (i = 0; i <= 0x1f; i++, phy_map >>= 1) {		if ((phy_map & 0x1) == 0) {			int  val = emac_phy_read(ndev, i, MII_BMCR);			if (val != 0xffff && val != -1)			        break;		}	}	if (i == 0x20) {	        printk(KERN_WARNING "emac%d: Can't find PHY.\n", ocpdev->def->index);		rc = -ENODEV;		goto bail;	}	busy_phy_map |= 1 << i;	ep->mii_phy_addr = i;	rc = mii_phy_probe(&ep->phy_mii, i);	if (rc) {	        printk(KERN_WARNING "emac%d: Failed to probe PHY type.\n", ocpdev->def->index);		rc = -ENODEV;		goto bail;	}	/* Setup initial PHY config & startup aneg */	if (ep->phy_mii.def->ops->init)	        ep->phy_mii.def->ops->init(&ep->phy_mii);	netif_carrier_off(ndev);        if (ep->phy_mii.def->features & SUPPORTED_Autoneg)                ep->want_autoneg = 1;	emac_start_link(ep, NULL);	/* read the MAC Address */	bd = (bd_t *) __res;	for (i = 0; i < 6; i++)		ndev->dev_addr[i] = bd->BD_EMAC_ADDR(ocpdev->def->index, i);	/* Marco to disques array */	/* Fill in the driver function table */	ndev->open = &emac_open;	ndev->hard_start_xmit = &emac_start_xmit;	ndev->stop = &emac_close;	ndev->get_stats = &emac_stats;	ndev->set_multicast_list = &emac_set_multicast_list;	ndev->do_ioctl = &emac_ioctl;	SET_MODULE_OWNER(ndev);		rc = register_netdev(ndev);	if (rc != 0)		goto bail;	printk("%s: IBM emac, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",		ndev->name,		ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],		ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);	printk(KERN_INFO "%s: Found %s PHY (0x%02x)\n",		ndev->name, ep->phy_mii.def->name, ep->mii_phy_addr);bail:	if (rc && commac_reg)		mal_unregister_commac(ep->mal, &ep->commac);	if (rc && ndev)		kfree(ndev);	return rc;}/* Structure for a device driver */static struct ocp_device_id emac_ids[] ={	{ .vendor = OCP_ANY_ID, .function = OCP_FUNC_EMAC },	{ .vendor = OCP_VENDOR_INVALID }};static struct ocp_driver emac_driver ={	.name 		= "emac",	.id_table	= emac_ids,		.probe		= emac_probe,	.remove		= emac_remove,};static int __initemac_init(void){	int rc;	        printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n");        printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n");	if (skb_res > 2) {	    printk(KERN_WARNING "Invalid skb_res: %d, cropping to 2\n", skb_res);	    skb_res = 2;	}	rc = ocp_register_driver(&emac_driver);	if (rc == 0) {		ocp_unregister_driver(&emac_driver);		return -ENODEV;	}	return 0;}static void __exitemac_exit(void){	ocp_unregister_driver(&emac_driver);}module_init(emac_init);module_exit(emac_exit);

⌨️ 快捷键说明

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