int temac_mdio_setup(struct temac_local *lp, struct device_node *np) { struct mii_bus *bus; u32 bus_hz; int clk_div; int rc; struct resource res; struct device_node *np1 = of_get_parent(lp->phy_node); /* Calculate a reasonable divisor for the clock rate */ clk_div = 0x3f; /* worst-case default setting */ if (of_property_read_u32(np, "clock-frequency", &bus_hz) == 0) { clk_div = bus_hz / (2500 * 1000 * 2) - 1; if (clk_div < 1) clk_div = 1; if (clk_div > 0x3f) clk_div = 0x3f; } /* Enable the MDIO bus by asserting the enable bit and writing * in the clock config */ mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); mutex_unlock(&lp->indirect_mutex); bus = mdiobus_alloc(); if (!bus) return -ENOMEM; of_address_to_resource(np1, 0, &res); snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", (unsigned long long)res.start); bus->priv = lp; bus->name = "Xilinx TEMAC MDIO"; bus->read = temac_mdio_read; bus->write = temac_mdio_write; bus->parent = lp->dev; lp->mii_bus = bus; rc = of_mdiobus_register(bus, np1); if (rc) goto err_register; mutex_lock(&lp->indirect_mutex); dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n", temac_indirect_in32(lp, XTE_MC_OFFSET)); mutex_unlock(&lp->indirect_mutex); return 0; err_register: mdiobus_free(bus); return rc; }
int temac_mdio_setup(struct temac_local *lp, struct device_node *np) { struct mii_bus *bus; const u32 *bus_hz; int clk_div; int rc, size; struct resource res; clk_div = 0x3f; bus_hz = of_get_property(np, "clock-frequency", &size); if (bus_hz && size >= sizeof(*bus_hz)) { clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1; if (clk_div < 1) clk_div = 1; if (clk_div > 0x3f) clk_div = 0x3f; } mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); mutex_unlock(&lp->indirect_mutex); bus = mdiobus_alloc(); if (!bus) return -ENOMEM; of_address_to_resource(np, 0, &res); snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", (unsigned long long)res.start); bus->priv = lp; bus->name = "Xilinx TEMAC MDIO"; bus->read = temac_mdio_read; bus->write = temac_mdio_write; bus->parent = lp->dev; bus->irq = lp->mdio_irqs; lp->mii_bus = bus; rc = of_mdiobus_register(bus, np); if (rc) goto err_register; mutex_lock(&lp->indirect_mutex); dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n", temac_indirect_in32(lp, XTE_MC_OFFSET)); mutex_unlock(&lp->indirect_mutex); return 0; err_register: mdiobus_free(bus); return rc; }
static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) { struct temac_local *lp = bus->priv; u32 rc; mutex_lock(&lp->indirect_mutex); temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET); mutex_unlock(&lp->indirect_mutex); dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n", phy_id, reg, rc); return rc; }
static void temac_set_multicast_list(struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); u32 multi_addr_msw, multi_addr_lsw, val; int i; mutex_lock(&lp->indirect_mutex); if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on * the cable. If it was a promisc request the * flag is already set. If not we assert it. */ ndev->flags |= IFF_PROMISC; temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); } else if (ndev->mc_count) { struct dev_mc_list *mclist = ndev->mc_list; for (i = 0; mclist && i < ndev->mc_count; i++) { if (i >= MULTICAST_CAM_TABLE_NUM) break; multi_addr_msw = ((mclist->dmi_addr[3] << 24) | (mclist->dmi_addr[2] << 16) | (mclist->dmi_addr[1] << 8) | (mclist->dmi_addr[0])); temac_indirect_out32(lp, XTE_MAW0_OFFSET, multi_addr_msw); multi_addr_lsw = ((mclist->dmi_addr[5] << 8) | (mclist->dmi_addr[4]) | (i << 16)); temac_indirect_out32(lp, XTE_MAW1_OFFSET, multi_addr_lsw); mclist = mclist->next; } } else { val = temac_indirect_in32(lp, XTE_AFM_OFFSET); temac_indirect_out32(lp, XTE_AFM_OFFSET, val & ~XTE_AFM_EPPRM_MASK); temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); } mutex_unlock(&lp->indirect_mutex); }
/* --------------------------------------------------------------------- * MDIO Bus functions */ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) { struct temac_local *lp = bus->priv; u32 rc; /* Write the PHY address to the MIIM Access Initiator register. * When the transfer completes, the PHY register value will appear * in the LSW0 register */ mutex_lock(&lp->indirect_mutex); temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET); mutex_unlock(&lp->indirect_mutex); dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n", phy_id, reg, rc); return rc; }
static void temac_set_multicast_list(struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); u32 multi_addr_msw, multi_addr_lsw, val; int i; mutex_lock(&lp->indirect_mutex); if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { ndev->flags |= IFF_PROMISC; temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); } else if (ndev->mc_count) { struct dev_mc_list *mclist = ndev->mc_list; for (i = 0; mclist && i < ndev->mc_count; i++) { if (i >= MULTICAST_CAM_TABLE_NUM) break; multi_addr_msw = ((mclist->dmi_addr[3] << 24) | (mclist->dmi_addr[2] << 16) | (mclist->dmi_addr[1] << 8) | (mclist->dmi_addr[0])); temac_indirect_out32(lp, XTE_MAW0_OFFSET, multi_addr_msw); multi_addr_lsw = ((mclist->dmi_addr[5] << 8) | (mclist->dmi_addr[4]) | (i << 16)); temac_indirect_out32(lp, XTE_MAW1_OFFSET, multi_addr_lsw); mclist = mclist->next; } } else { val = temac_indirect_in32(lp, XTE_AFM_OFFSET); temac_indirect_out32(lp, XTE_AFM_OFFSET, val & ~XTE_AFM_EPPRM_MASK); temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); } mutex_unlock(&lp->indirect_mutex); }
if (i >= MULTICAST_CAM_TABLE_NUM) break; multi_addr_msw = ((ha->addr[3] << 24) | (ha->addr[2] << 16) | (ha->addr[1] << 8) | (ha->addr[0])); temac_indirect_out32(lp, XTE_MAW0_OFFSET, multi_addr_msw); multi_addr_lsw = ((ha->addr[5] << 8) | (ha->addr[4]) | (i << 16)); temac_indirect_out32(lp, XTE_MAW1_OFFSET, multi_addr_lsw); i++; } } else { val = temac_indirect_in32(lp, XTE_AFM_OFFSET); temac_indirect_out32(lp, XTE_AFM_OFFSET, val & ~XTE_AFM_EPPRM_MASK); temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); } mutex_unlock(&lp->indirect_mutex); } struct temac_option { int flg; u32 opt; u32 reg; u32 m_or; u32 m_and;