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 + -
显示快捷键?