core.c

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

C
2,457
字号
static u32 emac_ethtool_get_rx_csum(struct net_device *ndev){	struct emac_instance *dev = netdev_priv(ndev);	return dev->tah_dev != NULL;}static int emac_get_regs_len(struct emac_instance *dev){	if (emac_has_feature(dev, EMAC_FTR_EMAC4))		return sizeof(struct emac_ethtool_regs_subhdr) +			EMAC4_ETHTOOL_REGS_SIZE;	else		return sizeof(struct emac_ethtool_regs_subhdr) +			EMAC_ETHTOOL_REGS_SIZE;}static int emac_ethtool_get_regs_len(struct net_device *ndev){	struct emac_instance *dev = netdev_priv(ndev);	int size;	size = sizeof(struct emac_ethtool_regs_hdr) +		emac_get_regs_len(dev) + mal_get_regs_len(dev->mal);	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		size += zmii_get_regs_len(dev->zmii_dev);	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		size += rgmii_get_regs_len(dev->rgmii_dev);	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))		size += tah_get_regs_len(dev->tah_dev);	return size;}static void *emac_dump_regs(struct emac_instance *dev, void *buf){	struct emac_ethtool_regs_subhdr *hdr = buf;	hdr->index = dev->cell_index;	if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {		hdr->version = EMAC4_ETHTOOL_REGS_VER;		memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE);		return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE);	} else {		hdr->version = EMAC_ETHTOOL_REGS_VER;		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 emac_instance *dev = netdev_priv(ndev);	struct emac_ethtool_regs_hdr *hdr = buf;	hdr->components = 0;	buf = hdr + 1;	buf = mal_dump_regs(dev->mal, buf);	buf = emac_dump_regs(dev, buf);	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) {		hdr->components |= EMAC_ETHTOOL_REGS_ZMII;		buf = zmii_dump_regs(dev->zmii_dev, buf);	}	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {		hdr->components |= EMAC_ETHTOOL_REGS_RGMII;		buf = rgmii_dump_regs(dev->rgmii_dev, buf);	}	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) {		hdr->components |= EMAC_ETHTOOL_REGS_TAH;		buf = tah_dump_regs(dev->tah_dev, buf);	}}static int emac_ethtool_nway_reset(struct net_device *ndev){	struct emac_instance *dev = netdev_priv(ndev);	int res = 0;	DBG(dev, "nway_reset" NL);	if (dev->phy.address < 0)		return -EOPNOTSUPP;	mutex_lock(&dev->link_lock);	if (!dev->phy.autoneg) {		res = -EINVAL;		goto out;	}	dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); out:	mutex_unlock(&dev->link_lock);	emac_force_link_update(dev);	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 emac_instance *dev = netdev_priv(ndev);	memcpy(tmp_stats, &dev->stats, sizeof(dev->stats));	tmp_stats += sizeof(dev->stats) / sizeof(u64);	memcpy(tmp_stats, &dev->estats, sizeof(dev->estats));}static void emac_ethtool_get_drvinfo(struct net_device *ndev,				     struct ethtool_drvinfo *info){	struct emac_instance *dev = netdev_priv(ndev);	strcpy(info->driver, "ibm_emac");	strcpy(info->version, DRV_VERSION);	info->fw_version[0] = '\0';	sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",		dev->cell_index, dev->ofdev->node->full_name);	info->n_stats = emac_ethtool_get_stats_count(ndev);	info->regdump_len = emac_ethtool_get_regs_len(ndev);}static const 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 emac_instance *dev = netdev_priv(ndev);	uint16_t *data = (uint16_t *) & rq->ifr_ifru;	DBG(dev, "ioctl %08x" NL, 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;	}}struct emac_depentry {	u32			phandle;	struct device_node	*node;	struct of_device	*ofdev;	void			*drvdata;};#define	EMAC_DEP_MAL_IDX	0#define	EMAC_DEP_ZMII_IDX	1#define	EMAC_DEP_RGMII_IDX	2#define	EMAC_DEP_TAH_IDX	3#define	EMAC_DEP_MDIO_IDX	4#define	EMAC_DEP_PREV_IDX	5#define	EMAC_DEP_COUNT		6static int __devinit emac_check_deps(struct emac_instance *dev,				     struct emac_depentry *deps){	int i, there = 0;	struct device_node *np;	for (i = 0; i < EMAC_DEP_COUNT; i++) {		/* no dependency on that item, allright */		if (deps[i].phandle == 0) {			there++;			continue;		}		/* special case for blist as the dependency might go away */		if (i == EMAC_DEP_PREV_IDX) {			np = *(dev->blist - 1);			if (np == NULL) {				deps[i].phandle = 0;				there++;				continue;			}			if (deps[i].node == NULL)				deps[i].node = of_node_get(np);		}		if (deps[i].node == NULL)			deps[i].node = of_find_node_by_phandle(deps[i].phandle);		if (deps[i].node == NULL)			continue;		if (deps[i].ofdev == NULL)			deps[i].ofdev = of_find_device_by_node(deps[i].node);		if (deps[i].ofdev == NULL)			continue;		if (deps[i].drvdata == NULL)			deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev);		if (deps[i].drvdata != NULL)			there++;	}	return (there == EMAC_DEP_COUNT);}static void emac_put_deps(struct emac_instance *dev){	if (dev->mal_dev)		of_dev_put(dev->mal_dev);	if (dev->zmii_dev)		of_dev_put(dev->zmii_dev);	if (dev->rgmii_dev)		of_dev_put(dev->rgmii_dev);	if (dev->mdio_dev)		of_dev_put(dev->mdio_dev);	if (dev->tah_dev)		of_dev_put(dev->tah_dev);}static int __devinit emac_of_bus_notify(struct notifier_block *nb,					unsigned long action, void *data){	/* We are only intereted in device addition */	if (action == BUS_NOTIFY_BOUND_DRIVER)		wake_up_all(&emac_probe_wait);	return 0;}static struct notifier_block emac_of_bus_notifier = {	.notifier_call = emac_of_bus_notify};static int __devinit emac_wait_deps(struct emac_instance *dev){	struct emac_depentry deps[EMAC_DEP_COUNT];	int i, err;	memset(&deps, 0, sizeof(deps));	deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph;	deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph;	deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph;	if (dev->tah_ph)		deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph;	if (dev->mdio_ph)		deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph;	if (dev->blist && dev->blist > emac_boot_list)		deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu;	bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier);	wait_event_timeout(emac_probe_wait,			   emac_check_deps(dev, deps),			   EMAC_PROBE_DEP_TIMEOUT);	bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier);	err = emac_check_deps(dev, deps) ? 0 : -ENODEV;	for (i = 0; i < EMAC_DEP_COUNT; i++) {		if (deps[i].node)			of_node_put(deps[i].node);		if (err && deps[i].ofdev)			of_dev_put(deps[i].ofdev);	}	if (err == 0) {		dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev;		dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev;		dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev;		dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev;		dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev;	}	if (deps[EMAC_DEP_PREV_IDX].ofdev)		of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev);	return err;}static int __devinit emac_read_uint_prop(struct device_node *np, const char *name,					 u32 *val, int fatal){	int len;	const u32 *prop = of_get_property(np, name, &len);	if (prop == NULL || len < sizeof(u32)) {		if (fatal)			printk(KERN_ERR "%s: missing %s property\n",			       np->full_name, name);		return -ENODEV;	}	*val = *prop;	return 0;}static int __devinit emac_init_phy(struct emac_instance *dev){	struct device_node *np = dev->ofdev->node;	struct net_device *ndev = dev->ndev;	u32 phy_map, adv;	int i;	dev->phy.dev = ndev;	dev->phy.mode = dev->phy_mode;	/* PHY-less configuration.	 * XXX I probably should move these settings to the dev tree	 */	if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {		emac_reset(dev);		/* PHY-less configuration.		 * XXX I probably should move these settings to the dev tree		 */		dev->phy.address = -1;		dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;		dev->phy.pause = 1;		return 0;	}	mutex_lock(&emac_phy_map_lock);	phy_map = dev->phy_map | busy_phy_map;	DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map);	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.		 *		 * Note that the busy_phy_map is currently global		 * while it should probably be per-ASIC...		 */		dev->phy.address = dev->cell_index;	}	emac_configure(dev);	if (dev->phy_address != 0xffffffff)		phy_map = ~(1 << dev->phy_address);	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 (!emac_mii_phy_probe(&dev->phy, i))				break;		}	mutex_unlock(&emac_phy_map_lock);	if (i == 0x20) {		printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);		return -ENXIO;	}	/* 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 &= ~dev->phy_feat_exc;	/* Setup initial link parameters */	if (dev->phy.features & SUPPORTED_Autoneg) {		adv = dev->phy.features;		if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x))			adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;		/* 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);	}	return 0;}static int __devinit emac_init_config(struct emac_instance *dev){	struct device_node *np = dev->ofdev->node;	const void *p;	unsigned int plen;	const char *pm, *phy_modes[] = {		[PHY_MODE_NA] = "",		[PHY_MODE_MII] = "mii",		[PHY_MODE_RMII] = "rmii",		[PHY_MODE_SMII] = "smii",		[PHY_MODE_RGMII] = "rgmii",		[PHY_MODE_TBI] = "tbi",		[PHY_MODE_GMII] = "gmii",		[PHY_MODE_RTBI] = "rtbi",		[PHY_MODE_SGMII] = "sgmii",	};	/* Read config from device-tree */	if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))		return -ENXIO;	if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1))		return -ENXIO;	if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1))		return -ENXIO;	if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1))		return -ENXIO;	if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0))		dev->max_mtu = 1500;	if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0))		dev->rx_fifo_size = 2048;	if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0))		dev->tx_fifo_size = 2048;	if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0))		dev->rx_fifo_size_gige = dev->rx_fifo_size;	if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0))		dev->tx_fifo_size_gige = dev->tx_fifo_size;	if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0))		dev->phy_address = 0xffffffff;	if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))		dev->phy_map = 0xffffffff;	if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))		return -ENXIO;	if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))		dev->tah_ph = 0;	if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))		dev->tah_port = 0;	if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))		dev->mdio_ph = 0;	if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))		dev->zmii_ph = 0;;	if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0))		dev->zmii_port = 0xffffffff;;	if (emac_read_uint_prop(np, "

⌨️ 快捷键说明

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