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

📄 ibm_emac_core.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)		return -EINVAL;	if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)		return -EINVAL;	if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)		return -EINVAL;	if (cmd->autoneg == AUTONEG_DISABLE)		switch (cmd->speed) {		case SPEED_10:			if (cmd->duplex == DUPLEX_HALF &&			    (features & SUPPORTED_10baseT_Half) == 0)				return -EINVAL;			if (cmd->duplex == DUPLEX_FULL &&			    (features & SUPPORTED_10baseT_Full) == 0)				return -EINVAL;			break;		case SPEED_100:			if (cmd->duplex == DUPLEX_HALF &&			    (features & SUPPORTED_100baseT_Half) == 0)				return -EINVAL;			if (cmd->duplex == DUPLEX_FULL &&			    (features & SUPPORTED_100baseT_Full) == 0)				return -EINVAL;			break;		case SPEED_1000:			if (cmd->duplex == DUPLEX_HALF &&			    (features & SUPPORTED_1000baseT_Half) == 0)				return -EINVAL;			if (cmd->duplex == DUPLEX_FULL &&			    (features & SUPPORTED_1000baseT_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, cmd);	spin_unlock_irq(&fep->lock);	return 0;}static voidemac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info){	struct ocp_enet_private *fep = ndev->priv;	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	info->fw_version[0] = '\0';	sprintf(info->bus_info, "IBM EMAC %d", fep->ocpdev->def->index);	info->regdump_len = 0;}static int emac_nway_reset(struct net_device *ndev){	struct ocp_enet_private *fep = ndev->priv;	if (!fep->want_autoneg)		return -EINVAL;	spin_lock_irq(&fep->lock);	emac_start_link(fep, NULL);	spin_unlock_irq(&fep->lock);	return 0;}static u32 emac_get_link(struct net_device *ndev){	return netif_carrier_ok(ndev);}static struct ethtool_ops emac_ethtool_ops = {	.get_settings = emac_get_settings,	.set_settings = emac_set_settings,	.get_drvinfo = emac_get_drvinfo,	.nway_reset = emac_nway_reset,	.get_link = emac_get_link};static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct ocp_enet_private *fep = dev->priv;	uint *data = (uint *) & rq->ifr_ifru;	switch (cmd) {	case SIOCGMIIPHY:		data[0] = fep->mii_phy_addr;		/* Fall through */	case SIOCGMIIREG:		data[3] = emac_phy_read(dev, fep->mii_phy_addr, data[1]);		return 0;	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 int emac_open(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	int rc;	spin_lock_irq(&fep->lock);	fep->opened = 1;	netif_carrier_off(dev);	/* 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, "IBM EMAC MAC", dev);	if (rc != 0) {		printk("dev->irq %d failed\n", dev->irq);		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 int emac_close(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	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_carrier_off(dev);	netif_stop_queue(dev);	/*	 * Check for a link, some PHYs don't provide a clock if	 * no link is present.  Some EMACs will not come out of	 * soft reset without a PHY clock present.	 */	if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) {		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);	spin_unlock_irq(&fep->lock);	return 0;}static void emac_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->rgmii_dev)		emac_close_rgmii(ep->rgmii_dev);	if (ep->zmii_dev)		emac_close_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,};#ifdef CONFIG_NET_POLL_CONTROLLERstatic int emac_netpoll(struct net_device *ndev){	emac_rxeob_dev((void *)ndev, 0);	emac_txeob_dev((void *)ndev, 0);	return 0;}#endifstatic int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal){	int deferred_init = 0;	int rc = 0, i;	struct net_device *ndev;	struct ocp_enet_private *ep;	struct ocp_func_emac_data *emacdata;	int commac_reg = 0;	u32 phy_map;	emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions;	if (!emacdata) {		printk(KERN_ERR "emac%d: Missing additional data!\n",		       ocpdev->def->index);		return -ENODEV;	}	/* 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;	ep->ndev = ndev;	ep->ocpdev = ocpdev;	ndev->irq = ocpdev->def->irq;	ep->wol_irq = emacdata->wol_irq;	if (emacdata->mdio_idx >= 0) {		if (emacdata->mdio_idx == ocpdev->def->index) {			/* Set the common MDIO net_device */			mdio_ndev = ndev;			deferred_init = 1;		}		ep->mdio_dev = mdio_ndev;	} else {		ep->mdio_dev = 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_tx_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 = (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, ep->zmii_input,					 emacdata->phy_mode)) != 0)			goto bail;	}	/* Check if we need to attach to a RGMII */	if (emacdata->rgmii_idx >= 0) {		ep->rgmii_input = emacdata->rgmii_mux;		ep->rgmii_dev =		    ocp_find_device(OCP_ANY_ID, OCP_FUNC_RGMII,				    emacdata->rgmii_idx);		if (ep->rgmii_dev == NULL)			printk(KERN_WARNING			       "emac%d: RGMII %d requested but not found !\n",			       ocpdev->def->index, emacdata->rgmii_idx);		else if ((rc =			  emac_init_rgmii(ep->rgmii_dev, ep->rgmii_input,					  emacdata->phy_mode)) != 0)			goto bail;	}	/* Check if we need to attach to a TAH */	if (emacdata->tah_idx >= 0) {		ep->tah_dev =		    ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH,				    emacdata->tah_idx);		if (ep->tah_dev == NULL)			printk(KERN_WARNING			       "emac%d: TAH %d requested but not found !\n",			       ocpdev->def->index, emacdata->tah_idx);		else if ((rc = emac_init_tah(ep)) != 0)			goto bail;	}	if (deferred_init) {		if (!list_empty(&emac_init_list)) {			struct list_head *entry;			struct emac_def_dev *ddev;			list_for_each(entry, &emac_init_list) {				ddev =				    list_entry(entry, struct emac_def_dev,					       link);				emac_init_device(ddev->ocpdev, ddev->mal);			}		}	}	/* 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;	ep->phy_mii.mode = emacdata->phy_mode;	/* Find PHY */	phy_map = emacdata->phy_map | 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 */	for (i = 0; i < 6; i++)		ndev->dev_addr[i] = emacdata->mac_addr[i];	/* 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;	if (emacdata->jumbo)		ndev->change_mtu = &emac_change_mtu;	ndev->set_mac_address = &emac_set_mac_address;	ndev->set_multicast_list = &emac_set_multicast_list;	ndev->do_ioctl = &emac_ioctl;	SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);	if (emacdata->tah_idx >= 0)		ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG;#ifdef CONFIG_NET_POLL_CONTROLLER	ndev->poll_controller = emac_netpoll;#endif	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;}static int emac_probe(struct ocp_device *ocpdev){	struct ocp_device *maldev;	struct ibm_ocp_mal *mal;	struct ocp_func_emac_data *emacdata;	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;	}	/* Get the MAL device  */	maldev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_MAL, emacdata->mal_idx);	if (maldev == NULL) {		printk("No maldev\n");		return -ENODEV;	}	/*	 * Get MAL driver data, it must be here due to link order.	 * When the driver is modularized, symbol dependencies will	 * ensure the MAL driver is already present if built as a	 * module.	 */	mal = (struct ibm_ocp_mal *)ocp_get_drvdata(maldev);	if (mal == NULL) {		printk("No maldrv\n");		return -ENODEV;	}	/* 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) && !mdio_ndev) {		struct emac_def_dev *ddev;		/* Add this index to the deferred init table */		ddev = kmalloc(sizeof(struct emac_def_dev), GFP_KERNEL);		ddev->ocpdev = ocpdev;		ddev->mal = mal;		list_add_tail(&ddev->link, &emac_init_list);	} else {		emac_init_device(ocpdev, mal);	}	return 0;}/* 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 __init emac_init(void){	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;	}	return ocp_register_driver(&emac_driver);}static void __exit emac_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 + -