const struct stmmac_tc_ops *tc;
        const struct stmmac_mmc_ops *mmc;
        const struct mdio_xpcs_ops *xpcs;
-       struct mdio_xpcs_args xpcs_args;
+       struct mdio_xpcs_args *xpcs_args;
        struct mii_regs mii;    /* MII register Addresses */
        struct mac_link link;
        void __iomem *pcsr;     /* vpointer to device CSRs */
 
                            "Setting EEE tx-lpi is not supported\n");
 
        if (priv->hw->xpcs) {
-               ret = xpcs_config_eee(&priv->hw->xpcs_args,
+               ret = xpcs_config_eee(priv->hw->xpcs_args,
                                      priv->plat->mult_fact_100ns,
                                      edata->eee_enabled);
                if (ret)
 
 
        /* If PCS is supported, check which modes it supports. */
        if (priv->hw->xpcs)
-               xpcs_validate(&priv->hw->xpcs_args, supported, state);
+               xpcs_validate(priv->hw->xpcs_args, supported, state);
 }
 
 static void stmmac_mac_pcs_get_state(struct phylink_config *config,
        struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
 
        state->link = 0;
-       stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state);
+       stmmac_xpcs_get_state(priv, priv->hw->xpcs_args, state);
 }
 
 static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
 {
        struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
 
-       stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state);
+       stmmac_xpcs_config(priv, priv->hw->xpcs_args, state);
 }
 
 static void stmmac_mac_an_restart(struct phylink_config *config)
        struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
        u32 ctrl;
 
-       stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface);
+       stmmac_xpcs_link_up(priv, priv->hw->xpcs_args, speed, interface);
 
        ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
        ctrl &= ~priv->hw->link.speed_mask;
        if (priv->hw->pcs != STMMAC_PCS_TBI &&
            priv->hw->pcs != STMMAC_PCS_RTBI &&
            (!priv->hw->xpcs ||
-            xpcs_get_an_mode(&priv->hw->xpcs_args, mode) != DW_AN_C73)) {
+            xpcs_get_an_mode(priv->hw->xpcs_args, mode) != DW_AN_C73)) {
                ret = stmmac_init_phy(dev);
                if (ret) {
                        netdev_err(priv->dev,
 
        }
 
        /* Try to probe the XPCS by scanning all addresses. */
-       if (priv->hw->xpcs) {
-               struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args;
-               int ret, mode = priv->plat->phy_interface;
-               max_addr = PHY_MAX_ADDR;
-
-               xpcs->bus = new_bus;
-
-               found = 0;
-               for (addr = 0; addr < max_addr; addr++) {
-                       xpcs->addr = addr;
-
-                       ret = xpcs_probe(xpcs, mode);
-                       if (!ret) {
-                               found = 1;
-                               break;
+       if (mdio_bus_data->has_xpcs) {
+               int mode = priv->plat->phy_interface;
+               struct mdio_device *mdiodev;
+               struct mdio_xpcs_args *xpcs;
+
+               for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+                       mdiodev = mdio_device_create(new_bus, addr);
+                       if (IS_ERR(mdiodev))
+                               continue;
+
+                       xpcs = xpcs_create(mdiodev, mode);
+                       if (IS_ERR_OR_NULL(xpcs)) {
+                               mdio_device_free(mdiodev);
+                               continue;
                        }
+
+                       priv->hw->xpcs_args = xpcs;
+                       break;
                }
 
-               if (!found && !mdio_node) {
+               if (!priv->hw->xpcs_args) {
                        dev_warn(dev, "No XPCS found\n");
                        err = -ENODEV;
                        goto no_xpcs_found;
        if (!priv->mii)
                return 0;
 
+       if (priv->hw->xpcs) {
+               mdio_device_free(priv->hw->xpcs_args->mdiodev);
+               xpcs_destroy(priv->hw->xpcs_args);
+       }
+
        mdiobus_unregister(priv->mii);
        priv->mii->priv = NULL;
        mdiobus_free(priv->mii);
 
 static int xpcs_read(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
 {
        u32 reg_addr = mdiobus_c45_addr(dev, reg);
+       struct mii_bus *bus = xpcs->mdiodev->bus;
+       int addr = xpcs->mdiodev->addr;
 
-       return mdiobus_read(xpcs->bus, xpcs->addr, reg_addr);
+       return mdiobus_read(bus, addr, reg_addr);
 }
 
 static int xpcs_write(struct mdio_xpcs_args *xpcs, int dev, u32 reg, u16 val)
 {
        u32 reg_addr = mdiobus_c45_addr(dev, reg);
+       struct mii_bus *bus = xpcs->mdiodev->bus;
+       int addr = xpcs->mdiodev->addr;
 
-       return mdiobus_write(xpcs->bus, xpcs->addr, reg_addr, val);
+       return mdiobus_write(bus, addr, reg_addr, val);
 }
 
 static int xpcs_read_vendor(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
 #define xpcs_warn(__xpcs, __state, __args...) \
 ({ \
        if ((__state)->link) \
-               dev_warn(&(__xpcs)->bus->dev, ##__args); \
+               dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
 })
 
 static int xpcs_read_fault_c73(struct mdio_xpcs_args *xpcs,
        },
 };
 
-int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface)
+struct mdio_xpcs_args *xpcs_create(struct mdio_device *mdiodev,
+                                  phy_interface_t interface)
 {
-       u32 xpcs_id = xpcs_get_id(xpcs);
-       int i;
+       struct mdio_xpcs_args *xpcs;
+       u32 xpcs_id;
+       int i, ret;
+
+       xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
+       if (!xpcs)
+               return NULL;
+
+       xpcs->mdiodev = mdiodev;
+
+       xpcs_id = xpcs_get_id(xpcs);
 
        for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
                const struct xpcs_id *entry = &xpcs_id_list[i];
                xpcs->id = entry;
 
                compat = xpcs_find_compat(entry, interface);
-               if (!compat)
-                       return -ENODEV;
+               if (!compat) {
+                       ret = -ENODEV;
+                       goto out;
+               }
 
-               return xpcs_soft_reset(xpcs, compat);
+               ret = xpcs_soft_reset(xpcs, compat);
+               if (ret)
+                       goto out;
+
+               return xpcs;
        }
 
-       return -ENODEV;
+       ret = -ENODEV;
+
+out:
+       kfree(xpcs);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(xpcs_create);
+
+void xpcs_destroy(struct mdio_xpcs_args *xpcs)
+{
+       kfree(xpcs);
 }
-EXPORT_SYMBOL_GPL(xpcs_probe);
+EXPORT_SYMBOL_GPL(xpcs_destroy);
 
 static struct mdio_xpcs_ops xpcs_ops = {
        .config = xpcs_config,
 
 struct xpcs_id;
 
 struct mdio_xpcs_args {
-       struct mii_bus *bus;
+       struct mdio_device *mdiodev;
        const struct xpcs_id *id;
-       int addr;
 };
 
 struct mdio_xpcs_ops {
                   struct phylink_link_state *state);
 int xpcs_config_eee(struct mdio_xpcs_args *xpcs, int mult_fact_100ns,
                    int enable);
-int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface);
+struct mdio_xpcs_args *xpcs_create(struct mdio_device *mdiodev,
+                                  phy_interface_t interface);
+void xpcs_destroy(struct mdio_xpcs_args *xpcs);
 
 #endif /* __LINUX_PCS_XPCS_H */