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

📄 ibm_emac_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			if (cmd->duplex == DUPLEX_FULL			    && !(f & SUPPORTED_100baseT_Full))				return -EINVAL;			break;		case SPEED_1000:			if (cmd->duplex == DUPLEX_HALF			    && !(f & SUPPORTED_1000baseT_Half))				return -EINVAL;			if (cmd->duplex == DUPLEX_FULL			    && !(f & SUPPORTED_1000baseT_Full))				return -EINVAL;			break;		default:			return -EINVAL;		}		local_bh_disable();		dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed,						cmd->duplex);	} else {		if (!(f & SUPPORTED_Autoneg))			return -EINVAL;		local_bh_disable();		dev->phy.def->ops->setup_aneg(&dev->phy,					      (cmd->advertising & f) |					      (dev->phy.advertising &					       (ADVERTISED_Pause |						ADVERTISED_Asym_Pause)));	}	emac_force_link_update(dev);	local_bh_enable();	return 0;}static void emac_ethtool_get_ringparam(struct net_device *ndev,				       struct ethtool_ringparam *rp){	rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF;	rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF;}static void emac_ethtool_get_pauseparam(struct net_device *ndev,					struct ethtool_pauseparam *pp){	struct ocp_enet_private *dev = ndev->priv;	local_bh_disable();	if ((dev->phy.features & SUPPORTED_Autoneg) &&	    (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause)))		pp->autoneg = 1;	if (dev->phy.duplex == DUPLEX_FULL) {		if (dev->phy.pause)			pp->rx_pause = pp->tx_pause = 1;		else if (dev->phy.asym_pause)			pp->tx_pause = 1;	}	local_bh_enable();}static u32 emac_ethtool_get_rx_csum(struct net_device *ndev){	struct ocp_enet_private *dev = ndev->priv;	return dev->tah_dev != 0;}static int emac_get_regs_len(struct ocp_enet_private *dev){	return sizeof(struct emac_ethtool_regs_subhdr) + EMAC_ETHTOOL_REGS_SIZE;}static int emac_ethtool_get_regs_len(struct net_device *ndev){	struct ocp_enet_private *dev = ndev->priv;	return sizeof(struct emac_ethtool_regs_hdr) +	    emac_get_regs_len(dev) + mal_get_regs_len(dev->mal) +	    zmii_get_regs_len(dev->zmii_dev) +	    rgmii_get_regs_len(dev->rgmii_dev) +	    tah_get_regs_len(dev->tah_dev);}static void *emac_dump_regs(struct ocp_enet_private *dev, void *buf){	struct emac_ethtool_regs_subhdr *hdr = buf;	hdr->version = EMAC_ETHTOOL_REGS_VER;	hdr->index = dev->def->index;	memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE);	return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE);}static void emac_ethtool_get_regs(struct net_device *ndev,				  struct ethtool_regs *regs, void *buf){	struct ocp_enet_private *dev = ndev->priv;	struct emac_ethtool_regs_hdr *hdr = buf;	hdr->components = 0;	buf = hdr + 1;	local_irq_disable();	buf = mal_dump_regs(dev->mal, buf);	buf = emac_dump_regs(dev, buf);	if (dev->zmii_dev) {		hdr->components |= EMAC_ETHTOOL_REGS_ZMII;		buf = zmii_dump_regs(dev->zmii_dev, buf);	}	if (dev->rgmii_dev) {		hdr->components |= EMAC_ETHTOOL_REGS_RGMII;		buf = rgmii_dump_regs(dev->rgmii_dev, buf);	}	if (dev->tah_dev) {		hdr->components |= EMAC_ETHTOOL_REGS_TAH;		buf = tah_dump_regs(dev->tah_dev, buf);	}	local_irq_enable();}static int emac_ethtool_nway_reset(struct net_device *ndev){	struct ocp_enet_private *dev = ndev->priv;	int res = 0;	DBG("%d: nway_reset" NL, dev->def->index);	if (dev->phy.address < 0)		return -EOPNOTSUPP;	local_bh_disable();	if (!dev->phy.autoneg) {		res = -EINVAL;		goto out;	}	dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising);	emac_force_link_update(dev);      out:	local_bh_enable();	return res;}static int emac_ethtool_get_stats_count(struct net_device *ndev){	return EMAC_ETHTOOL_STATS_COUNT;}static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,				     u8 * buf){	if (stringset == ETH_SS_STATS)		memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys));}static void emac_ethtool_get_ethtool_stats(struct net_device *ndev,					   struct ethtool_stats *estats,					   u64 * tmp_stats){	struct ocp_enet_private *dev = ndev->priv;	local_irq_disable();	memcpy(tmp_stats, &dev->stats, sizeof(dev->stats));	tmp_stats += sizeof(dev->stats) / sizeof(u64);	memcpy(tmp_stats, &dev->estats, sizeof(dev->estats));	local_irq_enable();}static void emac_ethtool_get_drvinfo(struct net_device *ndev,				     struct ethtool_drvinfo *info){	struct ocp_enet_private *dev = ndev->priv;	strcpy(info->driver, "ibm_emac");	strcpy(info->version, DRV_VERSION);	info->fw_version[0] = '\0';	sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index);	info->n_stats = emac_ethtool_get_stats_count(ndev);	info->regdump_len = emac_ethtool_get_regs_len(ndev);}static struct ethtool_ops emac_ethtool_ops = {	.get_settings = emac_ethtool_get_settings,	.set_settings = emac_ethtool_set_settings,	.get_drvinfo = emac_ethtool_get_drvinfo,	.get_regs_len = emac_ethtool_get_regs_len,	.get_regs = emac_ethtool_get_regs,	.nway_reset = emac_ethtool_nway_reset,	.get_ringparam = emac_ethtool_get_ringparam,	.get_pauseparam = emac_ethtool_get_pauseparam,	.get_rx_csum = emac_ethtool_get_rx_csum,	.get_strings = emac_ethtool_get_strings,	.get_stats_count = emac_ethtool_get_stats_count,	.get_ethtool_stats = emac_ethtool_get_ethtool_stats,	.get_link = ethtool_op_get_link,	.get_tx_csum = ethtool_op_get_tx_csum,	.get_sg = ethtool_op_get_sg,};static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd){	struct ocp_enet_private *dev = ndev->priv;	uint16_t *data = (uint16_t *) & rq->ifr_ifru;	DBG("%d: ioctl %08x" NL, dev->def->index, cmd);	if (dev->phy.address < 0)		return -EOPNOTSUPP;	switch (cmd) {	case SIOCGMIIPHY:	case SIOCDEVPRIVATE:		data[0] = dev->phy.address;		/* Fall through */	case SIOCGMIIREG:	case SIOCDEVPRIVATE + 1:		data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]);		return 0;	case SIOCSMIIREG:	case SIOCDEVPRIVATE + 2:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		emac_mdio_write(ndev, dev->phy.address, data[1], data[2]);		return 0;	default:		return -EOPNOTSUPP;	}}static int __init emac_probe(struct ocp_device *ocpdev){	struct ocp_func_emac_data *emacdata = ocpdev->def->additions;	struct net_device *ndev;	struct ocp_device *maldev;	struct ocp_enet_private *dev;	int err, i;	DBG("%d: probe" NL, ocpdev->def->index);	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) {		printk(KERN_ERR "emac%d: could not allocate ethernet device!\n",		       ocpdev->def->index);		return -ENOMEM;	}	dev = ndev->priv;	dev->ndev = ndev;	dev->ldev = &ocpdev->dev;	dev->def = ocpdev->def;	SET_MODULE_OWNER(ndev);	/* Find MAL device we are connected to */	maldev =	    ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_MAL, emacdata->mal_idx);	if (!maldev) {		printk(KERN_ERR "emac%d: unknown mal%d device!\n",		       dev->def->index, emacdata->mal_idx);		err = -ENODEV;		goto out;	}	dev->mal = ocp_get_drvdata(maldev);	if (!dev->mal) {		printk(KERN_ERR "emac%d: mal%d hasn't been initialized yet!\n",		       dev->def->index, emacdata->mal_idx);		err = -ENODEV;		goto out;	}	/* Register with MAL */	dev->commac.ops = &emac_commac_ops;	dev->commac.dev = dev;	dev->commac.tx_chan_mask = MAL_CHAN_MASK(emacdata->mal_tx_chan);	dev->commac.rx_chan_mask = MAL_CHAN_MASK(emacdata->mal_rx_chan);	err = mal_register_commac(dev->mal, &dev->commac);	if (err) {		printk(KERN_ERR "emac%d: failed to register with mal%d!\n",		       dev->def->index, emacdata->mal_idx);		goto out;	}	dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);	dev->rx_sync_size = emac_rx_sync_size(ndev->mtu);	/* Get pointers to BD rings */	dev->tx_desc =	    dev->mal->bd_virt + mal_tx_bd_offset(dev->mal,						 emacdata->mal_tx_chan);	dev->rx_desc =	    dev->mal->bd_virt + mal_rx_bd_offset(dev->mal,						 emacdata->mal_rx_chan);	DBG("%d: tx_desc %p" NL, ocpdev->def->index, dev->tx_desc);	DBG("%d: rx_desc %p" NL, ocpdev->def->index, dev->rx_desc);	/* Clean rings */	memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));	memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));	/* If we depend on another EMAC for MDIO, check whether it was probed already */	if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) {		struct ocp_device *mdiodev =		    ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC,				    emacdata->mdio_idx);		if (!mdiodev) {			printk(KERN_ERR "emac%d: unknown emac%d device!\n",			       dev->def->index, emacdata->mdio_idx);			err = -ENODEV;			goto out2;		}		dev->mdio_dev = ocp_get_drvdata(mdiodev);		if (!dev->mdio_dev) {			printk(KERN_ERR			       "emac%d: emac%d hasn't been initialized yet!\n",			       dev->def->index, emacdata->mdio_idx);			err = -ENODEV;			goto out2;		}	}	/* Attach to ZMII, if needed */	if ((err = zmii_attach(dev)) != 0)		goto out2;	/* Attach to RGMII, if needed */	if ((err = rgmii_attach(dev)) != 0)		goto out3;	/* Attach to TAH, if needed */	if ((err = tah_attach(dev)) != 0)		goto out4;	/* Map EMAC regs */	dev->emacp =	    (struct emac_regs *)ioremap(dev->def->paddr,					sizeof(struct emac_regs));	if (!dev->emacp) {		printk(KERN_ERR "emac%d: could not ioremap device registers!\n",		       dev->def->index);		err = -ENOMEM;		goto out5;	}	/* Fill in MAC address */	for (i = 0; i < 6; ++i)		ndev->dev_addr[i] = emacdata->mac_addr[i];	/* Set some link defaults before we can find out real parameters */	dev->phy.speed = SPEED_100;	dev->phy.duplex = DUPLEX_FULL;	dev->phy.autoneg = AUTONEG_DISABLE;	dev->phy.pause = dev->phy.asym_pause = 0;	dev->stop_timeout = STOP_TIMEOUT_100;	init_timer(&dev->link_timer);	dev->link_timer.function = emac_link_timer;	dev->link_timer.data = (unsigned long)dev;	/* Find PHY if any */	dev->phy.dev = ndev;	dev->phy.mode = emacdata->phy_mode;	if (emacdata->phy_map != 0xffffffff) {		u32 phy_map = emacdata->phy_map | busy_phy_map;		u32 adv;		DBG("%d: PHY maps %08x %08x" NL, dev->def->index,		    emacdata->phy_map, busy_phy_map);		EMAC_RX_CLK_TX(dev->def->index);		dev->phy.mdio_read = emac_mdio_read;		dev->phy.mdio_write = emac_mdio_write;		/* Configure EMAC with defaults so we can at least use MDIO		 * This is needed mostly for 440GX		 */		if (emac_phy_gpcs(dev->phy.mode)) {			/* XXX			 * Make GPCS PHY address equal to EMAC index.			 * We probably should take into account busy_phy_map			 * and/or phy_map here.			 */			dev->phy.address = dev->def->index;		}				emac_configure(dev);		for (i = 0; i < 0x20; phy_map >>= 1, ++i)			if (!(phy_map & 1)) {				int r;				busy_phy_map |= 1 << i;				/* Quick check if there is a PHY at the address */				r = emac_mdio_read(dev->ndev, i, MII_BMCR);				if (r == 0xffff || r < 0)					continue;				if (!mii_phy_probe(&dev->phy, i))					break;			}		if (i == 0x20) {			printk(KERN_WARNING "emac%d: can't find PHY!\n",			       dev->def->index);			goto out6;		}		/* Init PHY */		if (dev->phy.def->ops->init)			dev->phy.def->ops->init(&dev->phy);				/* Disable any PHY features not supported by the platform */		dev->phy.def->features &= ~emacdata->phy_feat_exc;		/* Setup initial link parameters */		if (dev->phy.features & SUPPORTED_Autoneg) {			adv = dev->phy.features;#if !defined(CONFIG_40x)			adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;#endif			/* Restart autonegotiation */			dev->phy.def->ops->setup_aneg(&dev->phy, adv);		} else {			u32 f = dev->phy.def->features;			int speed = SPEED_10, fd = DUPLEX_HALF;			/* Select highest supported speed/duplex */			if (f & SUPPORTED_1000baseT_Full) {				speed = SPEED_1000;				fd = DUPLEX_FULL;			} else if (f & SUPPORTED_1000baseT_Half)				speed = SPEED_1000;			else if (f & SUPPORTED_100baseT_Full) {				speed = SPEED_100;				fd = DUPLEX_FULL;			} else if (f & SUPPORTED_100baseT_Half)				speed = SPEED_100;			else if (f & SUPPORTED_10baseT_Full)				fd = DUPLEX_FULL;			/* Force link parameters */			dev->phy.def->ops->setup_forced(&dev->phy, speed, fd);		}	} else {		emac_reset(dev);		/* PHY-less configuration.		 * XXX I probably should move these settings to emacdata		 */		dev->phy.address = -1;		dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;		dev->phy.pause = 1;	}	/* Fill in the driver function table */	ndev->open = &emac_open;	if (dev->tah_dev) {		ndev->hard_start_xmit = &emac_start_xmit_sg;		ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;	} else		ndev->hard_start_xmit = &emac_start_xmit;	ndev->tx_timeout = &emac_full_tx_reset;	ndev->watchdog_timeo = 5 * HZ;	ndev->stop = &emac_close;	ndev->get_stats = &emac_stats;	ndev->set_multicast_list = &emac_set_multicast_list;	ndev->do_ioctl = &emac_ioctl;	if (emac_phy_supports_gige(emacdata->phy_mode)) {		ndev->change_mtu = &emac_change_mtu;		dev->commac.ops = &emac_commac_sg_ops;	}	SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);	netif_carrier_off(ndev);	netif_stop_queue(ndev);	err = register_netdev(ndev);	if (err) {		printk(KERN_ERR "emac%d: failed to register net device (%d)!\n",		       dev->def->index, err);		goto out6;	}	ocp_set_drvdata(ocpdev, dev);	printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",	       ndev->name, dev->def->index,	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);	if (dev->phy.address >= 0)		printk("%s: found %s PHY (0x%02x)\n", ndev->name,		       dev->phy.def->name, dev->phy.address);	emac_dbg_register(dev->def->index, dev);	return 0;      out6:	iounmap((void *)dev->emacp);      out5:	tah_fini(dev->tah_dev);      out4:	rgmii_fini(dev->rgmii_dev, dev->rgmii_input);      out3:	zmii_fini(dev->zmii_dev, dev->zmii_input);      out2:	mal_unregister_commac(dev->mal, &dev->commac);      out:	kfree(ndev);	return err;}static struct ocp_device_id emac_ids[] = {	{ .vendor = OCP_VENDOR_IBM, .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_DESC ", version " DRV_VERSION "\n");	DBG(": init" NL);	if (mal_init())		return -ENODEV;	EMAC_CLK_INTERNAL;	if (ocp_register_driver(&emac_driver)) {		EMAC_CLK_EXTERNAL;		ocp_unregister_driver(&emac_driver);		mal_exit();		return -ENODEV;	}	EMAC_CLK_EXTERNAL;	emac_init_debug();	return 0;}static void __exit emac_exit(void){	DBG(": exit" NL);	ocp_unregister_driver(&emac_driver);	mal_exit();	emac_fini_debug();}module_init(emac_init);module_exit(emac_exit);

⌨️ 快捷键说明

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