When addressing a PHY on a bus/address the driver must translate that into a port number. This is currently done with an effort of O(n). The driver loops over all known ports and checks each if bus and address match. This is very inefficient especially for the following reasons: - The lookup must run for each single read/write operation - The SoCs have very low specs (e.g. RTL838x one core, 16K cache, 500 MHz) - High-port-count devices RTL839x and RTL931x provide up to 52 PHY ports Create a reverse lookup table per channel during setup. This stores the (overall) port number per PHY (on that channel). Take special care about absent ports that are missing from device tree because of hardware design. Save memory by using s8 type for the table (-1 = absent, 0..56 = port). Convert the lookup in otto_emdio_phy_to_port() from loop-based to table-based. Signed-off-by: Markus Stockhausen --- drivers/net/mdio/mdio-realtek-rtl9300.c | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 50fc8582571d..a36cb711b8ad 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -78,6 +78,7 @@ #define MAX_PORTS 28 #define MAX_SMI_BUSSES 4 +#define PORT_ABSENT -1 #define RAW_PAGE(priv) ((priv)->info->num_pages - 1) @@ -118,23 +119,17 @@ struct otto_emdio_info { struct otto_emdio_chan { struct otto_emdio_priv *priv; - u8 mdio_bus; + s8 port[PHY_MAX_ADDR]; }; -static int otto_emdio_phy_to_port(struct mii_bus *bus, int phy_id) +static int otto_emdio_phy_to_port(struct mii_bus *bus, unsigned int phy_id) { struct otto_emdio_chan *chan = bus->priv; - struct otto_emdio_priv *priv; - int i; - - priv = chan->priv; - for_each_set_bit(i, priv->valid_ports, priv->info->num_ports) - if (priv->smi_bus[i] == chan->mdio_bus && - priv->smi_addr[i] == phy_id) - return i; + if (phy_id >= PHY_MAX_ADDR || chan->port[phy_id] == PORT_ABSENT) + return -ENOENT; - return -ENOENT; + return chan->port[phy_id]; } static struct otto_emdio_priv *otto_emdio_bus_to_priv(struct mii_bus *bus) @@ -390,8 +385,8 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv { struct otto_emdio_chan *chan; struct mii_bus *bus; - u32 mdio_bus; - int err; + u32 mdio_bus, port; + int i, err; err = fwnode_property_read_u32(node, "reg", &mdio_bus); if (err) @@ -427,11 +422,17 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv } bus->parent = dev; chan = bus->priv; - chan->mdio_bus = mdio_bus; chan->priv = priv; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(dev), mdio_bus); + /* setup reverse lookup bus/address -> port */ + for (i = 0; i < PHY_MAX_ADDR; i++) + chan->port[i] = PORT_ABSENT; + for_each_set_bit(port, priv->valid_ports, priv->info->num_ports) + if (priv->smi_bus[port] == mdio_bus) + chan->port[priv->smi_addr[port]] = port; + err = devm_of_mdiobus_register(dev, bus, to_of_node(node)); if (err) return dev_err_probe(dev, err, "cannot register MDIO bus\n"); -- 2.54.0