static int bgmac_fixed_phy_register(struct bgmac *bgmac) { struct fixed_phy_status fphy_status = { .link = 1, .speed = SPEED_1000, .duplex = DUPLEX_FULL, }; struct phy_device *phy_dev; int err; phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL); if (!phy_dev || IS_ERR(phy_dev)) { bgmac_err(bgmac, "Failed to register fixed PHY device\n"); return -ENODEV; } err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link, PHY_INTERFACE_MODE_MII); if (err) { bgmac_err(bgmac, "Connecting PHY failed\n"); return err; } bgmac->phy_dev = phy_dev; return err; } static int bgmac_mii_register(struct bgmac *bgmac) { struct mii_bus *mii_bus; struct phy_device *phy_dev; char bus_id[MII_BUS_ID_SIZE + 3]; int err = 0; if (bgmac_is_bcm4707_family(bgmac)) return bgmac_fixed_phy_register(bgmac); mii_bus = mdiobus_alloc(); if (!mii_bus) return -ENOMEM; mii_bus->name = "bgmac mii bus"; sprintf(mii_bus->id, "%s-%d-%d", "bgmac", bgmac->core->bus->num, bgmac->core->core_unit); mii_bus->priv = bgmac; mii_bus->read = bgmac_mii_read; mii_bus->write = bgmac_mii_write; mii_bus->parent = &bgmac->core->dev; mii_bus->phy_mask = ~(1 << bgmac->phyaddr); err = mdiobus_register(mii_bus); if (err) { bgmac_err(bgmac, "Registration of mii bus failed\n"); goto err_free_bus; } bgmac->mii_bus = mii_bus; /* Connect to the PHY */ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bgmac->phyaddr); phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link, PHY_INTERFACE_MODE_MII); if (IS_ERR(phy_dev)) { bgmac_err(bgmac, "PHY connection failed\n"); err = PTR_ERR(phy_dev); goto err_unregister_bus; } bgmac->phy_dev = phy_dev; return err; err_unregister_bus: mdiobus_unregister(mii_bus); err_free_bus: mdiobus_free(mii_bus); return err; } static void bgmac_mii_unregister(struct bgmac *bgmac) { struct mii_bus *mii_bus = bgmac->mii_bus; mdiobus_unregister(mii_bus); mdiobus_free(mii_bus); } /************************************************** * BCMA bus ops **************************************************/ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ static int bgmac_probe(struct bcma_device *core) { struct net_device *net_dev; struct bgmac *bgmac; struct ssb_sprom *sprom = &core->bus->sprom; u8 *mac; int err; switch (core->core_unit) { case 0: mac = sprom->et0mac; break; case 1: mac = sprom->et1mac; break; case 2: mac = sprom->et2mac; break; default: pr_err("Unsupported core_unit %d\n", core->core_unit); return -ENOTSUPP; } if (!is_valid_ether_addr(mac)) { dev_err(&core->dev, "Invalid MAC addr: %pM\n", mac); eth_random_addr(mac); dev_warn(&core->dev, "Using random MAC: %pM\n", mac); } /* This (reset &) enable is not preset in specs or reference driver but * Broadcom does it in arch PCI code when enabling fake PCI device. */ bcma_core_enable(core, 0); /* Allocation and references */ net_dev = alloc_etherdev(sizeof(*bgmac)); if (!net_dev) return -ENOMEM; net_dev->netdev_ops = &bgmac_netdev_ops; net_dev->irq = core->irq; net_dev->ethtool_ops = &bgmac_ethtool_ops; bgmac = netdev_priv(net_dev); bgmac->net_dev = net_dev; bgmac->core = core; bcma_set_drvdata(core, bgmac); /* Defaults */ memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); /* On BCM4706 we need common core to access PHY */ if (core->id.id == BCMA_CORE_4706_MAC_GBIT && !core->bus->drv_gmac_cmn.core) { bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n"); err = -ENODEV; goto err_netdev_free; } bgmac->cmn = core->bus->drv_gmac_cmn.core; switch (core->core_unit) { case 0: bgmac->phyaddr = sprom->et0phyaddr; break; case 1: bgmac->phyaddr = sprom->et1phyaddr; break; case 2: bgmac->phyaddr = sprom->et2phyaddr; break; } bgmac->phyaddr &= BGMAC_PHY_MASK; if (bgmac->phyaddr == BGMAC_PHY_MASK) { bgmac_err(bgmac, "No PHY found\n"); err = -ENODEV; goto err_netdev_free; } bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr, bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : ""); if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) { bgmac_err(bgmac, "PCI setup not implemented\n"); err = -ENOTSUPP; goto err_netdev_free; } bgmac_chip_reset(bgmac); /* For Northstar, we have to take all GMAC core out of reset */ if (bgmac_is_bcm4707_family(bgmac)) { struct bcma_device *ns_core; int ns_gmac; /* Northstar has 4 GMAC cores */ for (ns_gmac = 0; ns_gmac < 4; ns_gmac++) { /* As Northstar requirement, we have to reset all GMACs * before accessing one. bgmac_chip_reset() call * bcma_core_enable() for this core. Then the other * three GMACs didn't reset. We do it here. */ ns_core = bcma_find_core_unit(core->bus, BCMA_CORE_MAC_GBIT, ns_gmac); if (ns_core && !bcma_core_is_enabled(ns_core)) bcma_core_enable(ns_core, 0); } } err = bgmac_dma_alloc(bgmac); if (err) { bgmac_err(bgmac, "Unable to alloc memory for DMA\n"); goto err_netdev_free; } bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK; if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0) bgmac->int_mask &= ~BGMAC_IS_TX_MASK; /* TODO: reset the external phy. Specs are needed */ bgmac_phy_reset(bgmac); bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETROBO); if (bgmac->has_robosw) bgmac_warn(bgmac, "Support for Roboswitch not implemented\n"); if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM) bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n"); netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); err = bgmac_mii_register(bgmac); if (err) { bgmac_err(bgmac, "Cannot register MDIO\n"); goto err_dma_free; } net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; net_dev->hw_features = net_dev->features; net_dev->vlan_features = net_dev->features; err = register_netdev(bgmac->net_dev); if (err) { bgmac_err(bgmac, "Cannot register net device\n"); goto err_mii_unregister; } netif_carrier_off(net_dev); return 0; err_mii_unregister: bgmac_mii_unregister(bgmac); err_dma_free: bgmac_dma_free(bgmac); err_netdev_free: bcma_set_drvdata(core, NULL); free_netdev(net_dev); return err; } static void bgmac_remove(struct bcma_device *core) { struct bgmac *bgmac = bcma_get_drvdata(core); unregister_netdev(bgmac->net_dev); bgmac_mii_unregister(bgmac); netif_napi_del(&bgmac->napi); bgmac_dma_free(bgmac); bcma_set_drvdata(core, NULL); free_netdev(bgmac->net_dev); } static struct bcma_driver bgmac_bcma_driver = { .name = KBUILD_MODNAME, .id_table = bgmac_bcma_tbl, .probe = bgmac_probe, .remove = bgmac_remove, }; static int __init bgmac_init(void) { int err; err = bcma_driver_register(&bgmac_bcma_driver); if (err) return err; pr_info("Broadcom 47xx GBit MAC driver loaded\n"); return 0; }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ static int bgmac_probe(struct bcma_device *core) { struct net_device *net_dev; struct bgmac *bgmac; struct ssb_sprom *sprom = &core->bus->sprom; u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac; int err; /* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */ if (core->core_unit > 1) { pr_err("Unsupported core_unit %d\n", core->core_unit); return -ENOTSUPP; } if (!is_valid_ether_addr(mac)) { dev_err(&core->dev, "Invalid MAC addr: %pM\n", mac); eth_random_addr(mac); dev_warn(&core->dev, "Using random MAC: %pM\n", mac); } /* Allocation and references */ net_dev = alloc_etherdev(sizeof(*bgmac)); if (!net_dev) return -ENOMEM; net_dev->netdev_ops = &bgmac_netdev_ops; net_dev->irq = core->irq; SET_ETHTOOL_OPS(net_dev, &bgmac_ethtool_ops); bgmac = netdev_priv(net_dev); bgmac->net_dev = net_dev; bgmac->core = core; bcma_set_drvdata(core, bgmac); /* Defaults */ memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN); /* On BCM4706 we need common core to access PHY */ if (core->id.id == BCMA_CORE_4706_MAC_GBIT && !core->bus->drv_gmac_cmn.core) { bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n"); err = -ENODEV; goto err_netdev_free; } bgmac->cmn = core->bus->drv_gmac_cmn.core; bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr : sprom->et0phyaddr; bgmac->phyaddr &= BGMAC_PHY_MASK; if (bgmac->phyaddr == BGMAC_PHY_MASK) { bgmac_err(bgmac, "No PHY found\n"); err = -ENODEV; goto err_netdev_free; } bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr, bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : ""); if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) { bgmac_err(bgmac, "PCI setup not implemented\n"); err = -ENOTSUPP; goto err_netdev_free; } bgmac_chip_reset(bgmac); /* For Northstar, we have to take all GMAC core out of reset */ if (core->id.id == BCMA_CHIP_ID_BCM4707 || core->id.id == BCMA_CHIP_ID_BCM53018) { struct bcma_device *ns_core; int ns_gmac; /* Northstar has 4 GMAC cores */ for (ns_gmac = 0; ns_gmac < 4; ns_gmac++) { /* As Northstar requirement, we have to reset all GMACs * before accessing one. bgmac_chip_reset() call * bcma_core_enable() for this core. Then the other * three GMACs didn't reset. We do it here. */ ns_core = bcma_find_core_unit(core->bus, BCMA_CORE_MAC_GBIT, ns_gmac); if (ns_core && !bcma_core_is_enabled(ns_core)) bcma_core_enable(ns_core, 0); } } err = bgmac_dma_alloc(bgmac); if (err) { bgmac_err(bgmac, "Unable to alloc memory for DMA\n"); goto err_netdev_free; } bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK; if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0) bgmac->int_mask &= ~BGMAC_IS_TX_MASK; /* TODO: reset the external phy. Specs are needed */ bgmac_phy_reset(bgmac); bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETROBO); if (bgmac->has_robosw) bgmac_warn(bgmac, "Support for Roboswitch not implemented\n"); if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM) bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n"); err = bgmac_mii_register(bgmac); if (err) { bgmac_err(bgmac, "Cannot register MDIO\n"); goto err_dma_free; } err = register_netdev(bgmac->net_dev); if (err) { bgmac_err(bgmac, "Cannot register net device\n"); goto err_mii_unregister; } netif_carrier_off(net_dev); netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); return 0; err_mii_unregister: bgmac_mii_unregister(bgmac); err_dma_free: bgmac_dma_free(bgmac); err_netdev_free: bcma_set_drvdata(core, NULL); free_netdev(net_dev); return err; }