static int temac_set_mac_address(struct net_device *ndev, void *address) { struct temac_local *lp = netdev_priv(ndev); if (address) memcpy(ndev->dev_addr, address, ETH_ALEN); if (!is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev); else ndev->addr_assign_type &= ~NET_ADDR_RANDOM; /* set up unicast MAC address filter set its mac address */ mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_UAW0_OFFSET, (ndev->dev_addr[0]) | (ndev->dev_addr[1] << 8) | (ndev->dev_addr[2] << 16) | (ndev->dev_addr[3] << 24)); /* There are reserved bits in EUAW1 * so don't affect them Set MAC bits [47:32] in EUAW1 */ temac_indirect_out32(lp, XTE_UAW1_OFFSET, (ndev->dev_addr[4] & 0x000000ff) | (ndev->dev_addr[5] << 8)); mutex_unlock(&lp->indirect_mutex); return 0; }
static int temac_set_mac_address(struct net_device *ndev, void *address) { struct temac_local *lp = netdev_priv(ndev); if (address) memcpy(ndev->dev_addr, address, ETH_ALEN); if (!is_valid_ether_addr(ndev->dev_addr)) random_ether_addr(ndev->dev_addr); mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_UAW0_OFFSET, (ndev->dev_addr[0]) | (ndev->dev_addr[1] << 8) | (ndev->dev_addr[2] << 16) | (ndev->dev_addr[3] << 24)); temac_indirect_out32(lp, XTE_UAW1_OFFSET, (ndev->dev_addr[4] & 0x000000ff) | (ndev->dev_addr[5] << 8)); mutex_unlock(&lp->indirect_mutex); return 0; }
static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) { struct temac_local *lp = bus->priv; dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n", phy_id, reg, val); mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val); temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg); mutex_unlock(&lp->indirect_mutex); return 0; }
static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) { struct temac_local *lp = bus->priv; dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n", phy_id, reg, val); /* First write the desired value into the write data register * and then write the address into the access initiator register */ mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val); temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg); mutex_unlock(&lp->indirect_mutex); return 0; }
static void temac_do_set_mac_address(struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); /* set up unicast MAC address filter set its mac address */ mutex_lock(&lp->indirect_mutex); temac_indirect_out32(lp, XTE_UAW0_OFFSET, (ndev->dev_addr[0]) | (ndev->dev_addr[1] << 8) | (ndev->dev_addr[2] << 16) | (ndev->dev_addr[3] << 24)); /* There are reserved bits in EUAW1 * so don't affect them Set MAC bits [47:32] in EUAW1 */ temac_indirect_out32(lp, XTE_UAW1_OFFSET, (ndev->dev_addr[4] & 0x000000ff) | (ndev->dev_addr[5] << 8)); mutex_unlock(&lp->indirect_mutex); }
static void temac_set_multicast_list(struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); u32 multi_addr_msw, multi_addr_lsw; int i = 0; unsigned long flags; bool promisc_mode_disabled = false; if (ndev->flags & (IFF_PROMISC | IFF_ALLMULTI) || (netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM)) { temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); return; } spin_lock_irqsave(lp->indirect_lock, flags); if (!netdev_mc_empty(ndev)) { struct netdev_hw_addr *ha; netdev_for_each_mc_addr(ha, ndev) { if (WARN_ON(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_locked(lp, XTE_MAW0_OFFSET, multi_addr_msw); multi_addr_lsw = ((ha->addr[5] << 8) | (ha->addr[4]) | (i << 16)); temac_indirect_out32_locked(lp, XTE_MAW1_OFFSET, multi_addr_lsw); i++; } } /* Clear all or remaining/unused address table entries */ while (i < MULTICAST_CAM_TABLE_NUM) { temac_indirect_out32_locked(lp, XTE_MAW0_OFFSET, 0); temac_indirect_out32_locked(lp, XTE_MAW1_OFFSET, i << 16); i++; } /* Enable address filter block if currently disabled */ if (temac_indirect_in32_locked(lp, XTE_AFM_OFFSET) & XTE_AFM_EPPRM_MASK) { temac_indirect_out32_locked(lp, XTE_AFM_OFFSET, 0); promisc_mode_disabled = true; } spin_unlock_irqrestore(lp->indirect_lock, flags); if (promisc_mode_disabled) dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); }
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 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) || netdev_mc_count(ndev) > 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 (!netdev_mc_empty(ndev)) { struct netdev_hw_addr *ha; i = 0; netdev_for_each_mc_addr(ha, ndev) { 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 {
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); }
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); }