mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-03 19:55:31 +00:00
Merge branch 'net-pcs-xpcs-cleanups-batch-1'
Russell King says: ==================== net: pcs: xpcs: cleanups batch 1 First, sorry for the bland series subject - this is the first in a number of cleanup series to the XPCS driver. This series has some functional changes beyond merely cleanups, notably the first patch. This series starts off with a patch that moves the PCS reset from the xpcs_create*() family of calls to when phylink first configures the PHY. The motivation for this change is to get rid of the interface argument to the xpcs_create*() functions, which I see as unnecessary complexity. This patch should be tested on Wangxun and STMMAC drivers. Patch 2 removes the now unnecessary interface argument from the internal xpcs_create() and xpcs_init_iface() functions. With this, xpcs_init_iface() becomes a misnamed function, but patch 3 removes this function, moving its now meager contents to xpcs_create(). Patch 4 adds xpcs_destroy_pcs() and xpcs_create_pcs_mdiodev() functions which return and take a phylink_pcs, allowing SJA1105 and Wangxun drivers to be converted to using the phylink_pcs structure internally. Patches 5 through 8 convert both these drivers to that end. Patch 9 drops the interface argument from the remaining xpcs_create*() functions, addressing the only remaining caller of these functions, that being the STMMAC driver. As patch 7 removed the direct calls to the XPCS config/link-up functions, the last patch makes these functions static. ==================== Link: https://patch.msgid.link/ZvwdKIp3oYSenGdH@shell.armlinux.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
6b67e098c9
@ -278,7 +278,7 @@ struct sja1105_private {
|
|||||||
struct mii_bus *mdio_base_t1;
|
struct mii_bus *mdio_base_t1;
|
||||||
struct mii_bus *mdio_base_tx;
|
struct mii_bus *mdio_base_tx;
|
||||||
struct mii_bus *mdio_pcs;
|
struct mii_bus *mdio_pcs;
|
||||||
struct dw_xpcs *xpcs[SJA1105_MAX_NUM_PORTS];
|
struct phylink_pcs *pcs[SJA1105_MAX_NUM_PORTS];
|
||||||
struct sja1105_ptp_data ptp_data;
|
struct sja1105_ptp_data ptp_data;
|
||||||
struct sja1105_tas_data tas_data;
|
struct sja1105_tas_data tas_data;
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_net.h>
|
#include <linux/of_net.h>
|
||||||
#include <linux/of_mdio.h>
|
#include <linux/of_mdio.h>
|
||||||
#include <linux/pcs/pcs-xpcs.h>
|
|
||||||
#include <linux/netdev_features.h>
|
#include <linux/netdev_features.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/if_bridge.h>
|
#include <linux/if_bridge.h>
|
||||||
@ -1257,29 +1256,11 @@ static int sja1105_parse_dt(struct sja1105_private *priv)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert link speed from SJA1105 to ethtool encoding */
|
static int sja1105_set_port_speed(struct sja1105_private *priv, int port,
|
||||||
static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv,
|
int speed_mbps)
|
||||||
u64 speed)
|
|
||||||
{
|
|
||||||
if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS])
|
|
||||||
return SPEED_10;
|
|
||||||
if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS])
|
|
||||||
return SPEED_100;
|
|
||||||
if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS])
|
|
||||||
return SPEED_1000;
|
|
||||||
if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS])
|
|
||||||
return SPEED_2500;
|
|
||||||
return SPEED_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set link speed in the MAC configuration for a specific port. */
|
|
||||||
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
|
|
||||||
int speed_mbps)
|
|
||||||
{
|
{
|
||||||
struct sja1105_mac_config_entry *mac;
|
struct sja1105_mac_config_entry *mac;
|
||||||
struct device *dev = priv->ds->dev;
|
|
||||||
u64 speed;
|
u64 speed;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
|
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
|
||||||
* tables. On E/T, MAC reconfig tables are not readable, only writable.
|
* tables. On E/T, MAC reconfig tables are not readable, only writable.
|
||||||
@ -1313,7 +1294,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
|
|||||||
speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
|
speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(dev, "Invalid speed %iMbps\n", speed_mbps);
|
dev_err(priv->ds->dev, "Invalid speed %iMbps\n", speed_mbps);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,11 +1306,31 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
|
|||||||
* we need to configure the PCS only (if even that).
|
* we need to configure the PCS only (if even that).
|
||||||
*/
|
*/
|
||||||
if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII)
|
if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII)
|
||||||
mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
|
speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
|
||||||
else if (priv->phy_mode[port] == PHY_INTERFACE_MODE_2500BASEX)
|
else if (priv->phy_mode[port] == PHY_INTERFACE_MODE_2500BASEX)
|
||||||
mac[port].speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
|
speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
|
||||||
else
|
|
||||||
mac[port].speed = speed;
|
mac[port].speed = speed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the MAC Configuration Table entry and, if necessary, the CGU settings,
|
||||||
|
* after a link speedchange for this port.
|
||||||
|
*/
|
||||||
|
static int sja1105_set_port_config(struct sja1105_private *priv, int port)
|
||||||
|
{
|
||||||
|
struct sja1105_mac_config_entry *mac;
|
||||||
|
struct device *dev = priv->ds->dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
|
||||||
|
* tables. On E/T, MAC reconfig tables are not readable, only writable.
|
||||||
|
* We have to *know* what the MAC looks like. For the sake of keeping
|
||||||
|
* the code common, we'll use the static configuration tables as a
|
||||||
|
* reasonable approximation for both E/T and P/Q/R/S.
|
||||||
|
*/
|
||||||
|
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
|
||||||
|
|
||||||
/* Write to the dynamic reconfiguration tables */
|
/* Write to the dynamic reconfiguration tables */
|
||||||
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
|
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
|
||||||
@ -1356,12 +1357,8 @@ sja1105_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
|
|||||||
{
|
{
|
||||||
struct dsa_port *dp = dsa_phylink_to_port(config);
|
struct dsa_port *dp = dsa_phylink_to_port(config);
|
||||||
struct sja1105_private *priv = dp->ds->priv;
|
struct sja1105_private *priv = dp->ds->priv;
|
||||||
struct dw_xpcs *xpcs = priv->xpcs[dp->index];
|
|
||||||
|
|
||||||
if (xpcs)
|
return priv->pcs[dp->index];
|
||||||
return &xpcs->pcs;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sja1105_mac_config(struct phylink_config *config,
|
static void sja1105_mac_config(struct phylink_config *config,
|
||||||
@ -1390,7 +1387,8 @@ static void sja1105_mac_link_up(struct phylink_config *config,
|
|||||||
struct sja1105_private *priv = dp->ds->priv;
|
struct sja1105_private *priv = dp->ds->priv;
|
||||||
int port = dp->index;
|
int port = dp->index;
|
||||||
|
|
||||||
sja1105_adjust_port_config(priv, port, speed);
|
if (!sja1105_set_port_speed(priv, port, speed))
|
||||||
|
sja1105_set_port_config(priv, port);
|
||||||
|
|
||||||
sja1105_inhibit_tx(priv, BIT(port), false);
|
sja1105_inhibit_tx(priv, BIT(port), false);
|
||||||
}
|
}
|
||||||
@ -2293,8 +2291,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|||||||
{
|
{
|
||||||
struct ptp_system_timestamp ptp_sts_before;
|
struct ptp_system_timestamp ptp_sts_before;
|
||||||
struct ptp_system_timestamp ptp_sts_after;
|
struct ptp_system_timestamp ptp_sts_after;
|
||||||
int speed_mbps[SJA1105_MAX_NUM_PORTS];
|
|
||||||
u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
|
u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
|
||||||
|
u64 mac_speed[SJA1105_MAX_NUM_PORTS];
|
||||||
struct sja1105_mac_config_entry *mac;
|
struct sja1105_mac_config_entry *mac;
|
||||||
struct dsa_switch *ds = priv->ds;
|
struct dsa_switch *ds = priv->ds;
|
||||||
s64 t1, t2, t3, t4;
|
s64 t1, t2, t3, t4;
|
||||||
@ -2307,17 +2305,16 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|||||||
|
|
||||||
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
|
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
|
||||||
|
|
||||||
/* Back up the dynamic link speed changed by sja1105_adjust_port_config
|
/* Back up the dynamic link speed changed by sja1105_set_port_speed()
|
||||||
* in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
|
* in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
|
||||||
* switch wants to see in the static config in order to allow us to
|
* switch wants to see in the static config in order to allow us to
|
||||||
* change it through the dynamic interface later.
|
* change it through the dynamic interface later.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < ds->num_ports; i++) {
|
for (i = 0; i < ds->num_ports; i++) {
|
||||||
speed_mbps[i] = sja1105_port_speed_to_ethtool(priv,
|
mac_speed[i] = mac[i].speed;
|
||||||
mac[i].speed);
|
|
||||||
mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
|
mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
|
||||||
|
|
||||||
if (priv->xpcs[i])
|
if (priv->pcs[i])
|
||||||
bmcr[i] = mdiobus_c45_read(priv->mdio_pcs, i,
|
bmcr[i] = mdiobus_c45_read(priv->mdio_pcs, i,
|
||||||
MDIO_MMD_VEND2, MDIO_CTRL1);
|
MDIO_MMD_VEND2, MDIO_CTRL1);
|
||||||
}
|
}
|
||||||
@ -2374,14 +2371,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ds->num_ports; i++) {
|
for (i = 0; i < ds->num_ports; i++) {
|
||||||
struct dw_xpcs *xpcs = priv->xpcs[i];
|
struct phylink_pcs *pcs = priv->pcs[i];
|
||||||
unsigned int neg_mode;
|
unsigned int neg_mode;
|
||||||
|
|
||||||
rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
|
mac[i].speed = mac_speed[i];
|
||||||
|
rc = sja1105_set_port_config(priv, i);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!xpcs)
|
if (!pcs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bmcr[i] & BMCR_ANENABLE)
|
if (bmcr[i] & BMCR_ANENABLE)
|
||||||
@ -2389,7 +2387,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|||||||
else
|
else
|
||||||
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
|
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
|
||||||
|
|
||||||
rc = xpcs_do_config(xpcs, priv->phy_mode[i], NULL, neg_mode);
|
rc = pcs->ops->pcs_config(pcs, neg_mode, priv->phy_mode[i],
|
||||||
|
NULL, true);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -2405,8 +2404,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|||||||
else
|
else
|
||||||
speed = SPEED_10;
|
speed = SPEED_10;
|
||||||
|
|
||||||
xpcs_link_up(&xpcs->pcs, neg_mode, priv->phy_mode[i],
|
pcs->ops->pcs_link_up(pcs, neg_mode, priv->phy_mode[i],
|
||||||
speed, DUPLEX_FULL);
|
speed, DUPLEX_FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (port = 0; port < ds->num_ports; port++) {
|
for (port = 0; port < ds->num_ports; port++) {
|
||||||
struct dw_xpcs *xpcs;
|
struct phylink_pcs *pcs;
|
||||||
|
|
||||||
if (dsa_is_unused_port(ds, port))
|
if (dsa_is_unused_port(ds, port))
|
||||||
continue;
|
continue;
|
||||||
@ -409,13 +409,13 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
|
|||||||
priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)
|
priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]);
|
pcs = xpcs_create_pcs_mdiodev(bus, port);
|
||||||
if (IS_ERR(xpcs)) {
|
if (IS_ERR(pcs)) {
|
||||||
rc = PTR_ERR(xpcs);
|
rc = PTR_ERR(pcs);
|
||||||
goto out_pcs_free;
|
goto out_pcs_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->xpcs[port] = xpcs;
|
priv->pcs[port] = pcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->mdio_pcs = bus;
|
priv->mdio_pcs = bus;
|
||||||
@ -424,11 +424,10 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
|
|||||||
|
|
||||||
out_pcs_free:
|
out_pcs_free:
|
||||||
for (port = 0; port < ds->num_ports; port++) {
|
for (port = 0; port < ds->num_ports; port++) {
|
||||||
if (!priv->xpcs[port])
|
if (priv->pcs[port]) {
|
||||||
continue;
|
xpcs_destroy_pcs(priv->pcs[port]);
|
||||||
|
priv->pcs[port] = NULL;
|
||||||
xpcs_destroy(priv->xpcs[port]);
|
}
|
||||||
priv->xpcs[port] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mdiobus_unregister(bus);
|
mdiobus_unregister(bus);
|
||||||
@ -446,11 +445,10 @@ static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (port = 0; port < ds->num_ports; port++) {
|
for (port = 0; port < ds->num_ports; port++) {
|
||||||
if (!priv->xpcs[port])
|
if (priv->pcs[port]) {
|
||||||
continue;
|
xpcs_destroy_pcs(priv->pcs[port]);
|
||||||
|
priv->pcs[port] = NULL;
|
||||||
xpcs_destroy(priv->xpcs[port]);
|
}
|
||||||
priv->xpcs[port] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mdiobus_unregister(priv->mdio_pcs);
|
mdiobus_unregister(priv->mdio_pcs);
|
||||||
|
@ -500,23 +500,22 @@ int stmmac_pcs_setup(struct net_device *ndev)
|
|||||||
struct fwnode_handle *devnode, *pcsnode;
|
struct fwnode_handle *devnode, *pcsnode;
|
||||||
struct dw_xpcs *xpcs = NULL;
|
struct dw_xpcs *xpcs = NULL;
|
||||||
struct stmmac_priv *priv;
|
struct stmmac_priv *priv;
|
||||||
int addr, mode, ret;
|
int addr, ret;
|
||||||
|
|
||||||
priv = netdev_priv(ndev);
|
priv = netdev_priv(ndev);
|
||||||
mode = priv->plat->phy_interface;
|
|
||||||
devnode = priv->plat->port_node;
|
devnode = priv->plat->port_node;
|
||||||
|
|
||||||
if (priv->plat->pcs_init) {
|
if (priv->plat->pcs_init) {
|
||||||
ret = priv->plat->pcs_init(priv);
|
ret = priv->plat->pcs_init(priv);
|
||||||
} else if (fwnode_property_present(devnode, "pcs-handle")) {
|
} else if (fwnode_property_present(devnode, "pcs-handle")) {
|
||||||
pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
|
pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
|
||||||
xpcs = xpcs_create_fwnode(pcsnode, mode);
|
xpcs = xpcs_create_fwnode(pcsnode);
|
||||||
fwnode_handle_put(pcsnode);
|
fwnode_handle_put(pcsnode);
|
||||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||||
} else if (priv->plat->mdio_bus_data &&
|
} else if (priv->plat->mdio_bus_data &&
|
||||||
priv->plat->mdio_bus_data->pcs_mask) {
|
priv->plat->mdio_bus_data->pcs_mask) {
|
||||||
addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
|
addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
|
||||||
xpcs = xpcs_create_mdiodev(priv->mii, addr, mode);
|
xpcs = xpcs_create_mdiodev(priv->mii, addr);
|
||||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -122,7 +122,7 @@ static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum
|
|||||||
static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
|
static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
|
||||||
{
|
{
|
||||||
struct mii_bus *mii_bus;
|
struct mii_bus *mii_bus;
|
||||||
struct dw_xpcs *xpcs;
|
struct phylink_pcs *pcs;
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
struct wx *wx;
|
struct wx *wx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -147,11 +147,11 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
xpcs = xpcs_create_mdiodev(mii_bus, 0, PHY_INTERFACE_MODE_10GBASER);
|
pcs = xpcs_create_pcs_mdiodev(mii_bus, 0);
|
||||||
if (IS_ERR(xpcs))
|
if (IS_ERR(pcs))
|
||||||
return PTR_ERR(xpcs);
|
return PTR_ERR(pcs);
|
||||||
|
|
||||||
txgbe->xpcs = xpcs;
|
txgbe->pcs = pcs;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
|
|||||||
struct txgbe *txgbe = wx->priv;
|
struct txgbe *txgbe = wx->priv;
|
||||||
|
|
||||||
if (interface == PHY_INTERFACE_MODE_10GBASER)
|
if (interface == PHY_INTERFACE_MODE_10GBASER)
|
||||||
return &txgbe->xpcs->pcs;
|
return txgbe->pcs;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -302,7 +302,7 @@ irqreturn_t txgbe_link_irq_handler(int irq, void *data)
|
|||||||
status = rd32(wx, TXGBE_CFG_PORT_ST);
|
status = rd32(wx, TXGBE_CFG_PORT_ST);
|
||||||
up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP);
|
up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP);
|
||||||
|
|
||||||
phylink_pcs_change(&txgbe->xpcs->pcs, up);
|
phylink_pcs_change(txgbe->pcs, up);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -778,7 +778,7 @@ int txgbe_init_phy(struct txgbe *txgbe)
|
|||||||
err_destroy_phylink:
|
err_destroy_phylink:
|
||||||
phylink_destroy(wx->phylink);
|
phylink_destroy(wx->phylink);
|
||||||
err_destroy_xpcs:
|
err_destroy_xpcs:
|
||||||
xpcs_destroy(txgbe->xpcs);
|
xpcs_destroy_pcs(txgbe->pcs);
|
||||||
err_unregister_swnode:
|
err_unregister_swnode:
|
||||||
software_node_unregister_node_group(txgbe->nodes.group);
|
software_node_unregister_node_group(txgbe->nodes.group);
|
||||||
|
|
||||||
@ -798,6 +798,6 @@ void txgbe_remove_phy(struct txgbe *txgbe)
|
|||||||
clkdev_drop(txgbe->clock);
|
clkdev_drop(txgbe->clock);
|
||||||
clk_unregister(txgbe->clk);
|
clk_unregister(txgbe->clk);
|
||||||
phylink_destroy(txgbe->wx->phylink);
|
phylink_destroy(txgbe->wx->phylink);
|
||||||
xpcs_destroy(txgbe->xpcs);
|
xpcs_destroy_pcs(txgbe->pcs);
|
||||||
software_node_unregister_node_group(txgbe->nodes.group);
|
software_node_unregister_node_group(txgbe->nodes.group);
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ struct txgbe {
|
|||||||
struct wx *wx;
|
struct wx *wx;
|
||||||
struct txgbe_nodes nodes;
|
struct txgbe_nodes nodes;
|
||||||
struct txgbe_irq misc;
|
struct txgbe_irq misc;
|
||||||
struct dw_xpcs *xpcs;
|
struct phylink_pcs *pcs;
|
||||||
struct platform_device *sfp_dev;
|
struct platform_device *sfp_dev;
|
||||||
struct platform_device *i2c_dev;
|
struct platform_device *i2c_dev;
|
||||||
struct clk_lookup *clock;
|
struct clk_lookup *clock;
|
||||||
|
@ -659,6 +659,30 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xpcs_config_eee);
|
EXPORT_SYMBOL_GPL(xpcs_config_eee);
|
||||||
|
|
||||||
|
static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface)
|
||||||
|
{
|
||||||
|
struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
|
||||||
|
const struct dw_xpcs_compat *compat;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!xpcs->need_reset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
compat = xpcs_find_compat(xpcs->desc, interface);
|
||||||
|
if (!compat) {
|
||||||
|
dev_err(&xpcs->mdiodev->dev, "unsupported interface %s\n",
|
||||||
|
phy_modes(interface));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = xpcs_soft_reset(xpcs, compat);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&xpcs->mdiodev->dev, "soft reset failed: %pe\n",
|
||||||
|
ERR_PTR(ret));
|
||||||
|
|
||||||
|
xpcs->need_reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
|
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
|
||||||
unsigned int neg_mode)
|
unsigned int neg_mode)
|
||||||
{
|
{
|
||||||
@ -827,8 +851,9 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
|
|||||||
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
|
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
|
static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
|
||||||
const unsigned long *advertising, unsigned int neg_mode)
|
const unsigned long *advertising,
|
||||||
|
unsigned int neg_mode)
|
||||||
{
|
{
|
||||||
const struct dw_xpcs_compat *compat;
|
const struct dw_xpcs_compat *compat;
|
||||||
int ret;
|
int ret;
|
||||||
@ -881,7 +906,6 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xpcs_do_config);
|
|
||||||
|
|
||||||
static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
||||||
phy_interface_t interface,
|
phy_interface_t interface,
|
||||||
@ -1183,8 +1207,8 @@ static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int neg_mode,
|
|||||||
pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
|
pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
|
static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
|
||||||
phy_interface_t interface, int speed, int duplex)
|
phy_interface_t interface, int speed, int duplex)
|
||||||
{
|
{
|
||||||
struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
|
struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
|
||||||
|
|
||||||
@ -1195,7 +1219,6 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
|
|||||||
if (interface == PHY_INTERFACE_MODE_1000BASEX)
|
if (interface == PHY_INTERFACE_MODE_1000BASEX)
|
||||||
return xpcs_link_up_1000basex(xpcs, neg_mode, speed, duplex);
|
return xpcs_link_up_1000basex(xpcs, neg_mode, speed, duplex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xpcs_link_up);
|
|
||||||
|
|
||||||
static void xpcs_an_restart(struct phylink_pcs *pcs)
|
static void xpcs_an_restart(struct phylink_pcs *pcs)
|
||||||
{
|
{
|
||||||
@ -1365,6 +1388,7 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = {
|
|||||||
|
|
||||||
static const struct phylink_pcs_ops xpcs_phylink_ops = {
|
static const struct phylink_pcs_ops xpcs_phylink_ops = {
|
||||||
.pcs_validate = xpcs_validate,
|
.pcs_validate = xpcs_validate,
|
||||||
|
.pcs_pre_config = xpcs_pre_config,
|
||||||
.pcs_config = xpcs_config,
|
.pcs_config = xpcs_config,
|
||||||
.pcs_get_state = xpcs_get_state,
|
.pcs_get_state = xpcs_get_state,
|
||||||
.pcs_an_restart = xpcs_an_restart,
|
.pcs_an_restart = xpcs_an_restart,
|
||||||
@ -1458,24 +1482,7 @@ static int xpcs_init_id(struct dw_xpcs *xpcs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xpcs_init_iface(struct dw_xpcs *xpcs, phy_interface_t interface)
|
static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev)
|
||||||
{
|
|
||||||
const struct dw_xpcs_compat *compat;
|
|
||||||
|
|
||||||
compat = xpcs_find_compat(xpcs->desc, interface);
|
|
||||||
if (!compat)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
|
|
||||||
xpcs->pcs.poll = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xpcs_soft_reset(xpcs, compat);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
|
|
||||||
phy_interface_t interface)
|
|
||||||
{
|
{
|
||||||
struct dw_xpcs *xpcs;
|
struct dw_xpcs *xpcs;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1492,9 +1499,10 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_clear_clks;
|
goto out_clear_clks;
|
||||||
|
|
||||||
ret = xpcs_init_iface(xpcs, interface);
|
if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID)
|
||||||
if (ret)
|
xpcs->pcs.poll = false;
|
||||||
goto out_clear_clks;
|
else
|
||||||
|
xpcs->need_reset = true;
|
||||||
|
|
||||||
return xpcs;
|
return xpcs;
|
||||||
|
|
||||||
@ -1511,14 +1519,12 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
|
|||||||
* xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr
|
* xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr
|
||||||
* @bus: pointer to the MDIO-bus descriptor for the device to be looked at
|
* @bus: pointer to the MDIO-bus descriptor for the device to be looked at
|
||||||
* @addr: device MDIO-bus ID
|
* @addr: device MDIO-bus ID
|
||||||
* @interface: requested PHY interface
|
|
||||||
*
|
*
|
||||||
* Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
|
* Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
|
||||||
* the PCS device couldn't be found on the bus and other negative errno related
|
* the PCS device couldn't be found on the bus and other negative errno related
|
||||||
* to the data allocation and MDIO-bus communications.
|
* to the data allocation and MDIO-bus communications.
|
||||||
*/
|
*/
|
||||||
struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
|
struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)
|
||||||
phy_interface_t interface)
|
|
||||||
{
|
{
|
||||||
struct mdio_device *mdiodev;
|
struct mdio_device *mdiodev;
|
||||||
struct dw_xpcs *xpcs;
|
struct dw_xpcs *xpcs;
|
||||||
@ -1527,7 +1533,7 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
|
|||||||
if (IS_ERR(mdiodev))
|
if (IS_ERR(mdiodev))
|
||||||
return ERR_CAST(mdiodev);
|
return ERR_CAST(mdiodev);
|
||||||
|
|
||||||
xpcs = xpcs_create(mdiodev, interface);
|
xpcs = xpcs_create(mdiodev);
|
||||||
|
|
||||||
/* xpcs_create() has taken a refcount on the mdiodev if it was
|
/* xpcs_create() has taken a refcount on the mdiodev if it was
|
||||||
* successful. If xpcs_create() fails, this will free the mdio
|
* successful. If xpcs_create() fails, this will free the mdio
|
||||||
@ -1541,10 +1547,21 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);
|
EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);
|
||||||
|
|
||||||
|
struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr)
|
||||||
|
{
|
||||||
|
struct dw_xpcs *xpcs;
|
||||||
|
|
||||||
|
xpcs = xpcs_create_mdiodev(bus, addr);
|
||||||
|
if (IS_ERR(xpcs))
|
||||||
|
return ERR_CAST(xpcs);
|
||||||
|
|
||||||
|
return &xpcs->pcs;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xpcs_create_pcs_mdiodev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode
|
* xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode
|
||||||
* @fwnode: fwnode handle poining to the DW XPCS device
|
* @fwnode: fwnode handle poining to the DW XPCS device
|
||||||
* @interface: requested PHY interface
|
|
||||||
*
|
*
|
||||||
* Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
|
* Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
|
||||||
* the fwnode device is unavailable or the PCS device couldn't be found on the
|
* the fwnode device is unavailable or the PCS device couldn't be found on the
|
||||||
@ -1552,8 +1569,7 @@ EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);
|
|||||||
* other negative errno related to the data allocations and MDIO-bus
|
* other negative errno related to the data allocations and MDIO-bus
|
||||||
* communications.
|
* communications.
|
||||||
*/
|
*/
|
||||||
struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode,
|
struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode)
|
||||||
phy_interface_t interface)
|
|
||||||
{
|
{
|
||||||
struct mdio_device *mdiodev;
|
struct mdio_device *mdiodev;
|
||||||
struct dw_xpcs *xpcs;
|
struct dw_xpcs *xpcs;
|
||||||
@ -1565,7 +1581,7 @@ struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode,
|
|||||||
if (!mdiodev)
|
if (!mdiodev)
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
|
||||||
xpcs = xpcs_create(mdiodev, interface);
|
xpcs = xpcs_create(mdiodev);
|
||||||
|
|
||||||
/* xpcs_create() has taken a refcount on the mdiodev if it was
|
/* xpcs_create() has taken a refcount on the mdiodev if it was
|
||||||
* successful. If xpcs_create() fails, this will free the mdio
|
* successful. If xpcs_create() fails, this will free the mdio
|
||||||
@ -1590,5 +1606,11 @@ void xpcs_destroy(struct dw_xpcs *xpcs)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xpcs_destroy);
|
EXPORT_SYMBOL_GPL(xpcs_destroy);
|
||||||
|
|
||||||
|
void xpcs_destroy_pcs(struct phylink_pcs *pcs)
|
||||||
|
{
|
||||||
|
xpcs_destroy(phylink_pcs_to_xpcs(pcs));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xpcs_destroy_pcs);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Synopsys DesignWare XPCS library");
|
MODULE_DESCRIPTION("Synopsys DesignWare XPCS library");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@ -61,20 +61,18 @@ struct dw_xpcs {
|
|||||||
struct clk_bulk_data clks[DW_XPCS_NUM_CLKS];
|
struct clk_bulk_data clks[DW_XPCS_NUM_CLKS];
|
||||||
struct phylink_pcs pcs;
|
struct phylink_pcs pcs;
|
||||||
phy_interface_t interface;
|
phy_interface_t interface;
|
||||||
|
bool need_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
|
int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
|
||||||
void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
|
|
||||||
phy_interface_t interface, int speed, int duplex);
|
|
||||||
int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
|
|
||||||
const unsigned long *advertising, unsigned int neg_mode);
|
|
||||||
void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces);
|
void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces);
|
||||||
int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns,
|
int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns,
|
||||||
int enable);
|
int enable);
|
||||||
struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
|
struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr);
|
||||||
phy_interface_t interface);
|
struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode);
|
||||||
struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode,
|
|
||||||
phy_interface_t interface);
|
|
||||||
void xpcs_destroy(struct dw_xpcs *xpcs);
|
void xpcs_destroy(struct dw_xpcs *xpcs);
|
||||||
|
|
||||||
|
struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr);
|
||||||
|
void xpcs_destroy_pcs(struct phylink_pcs *pcs);
|
||||||
|
|
||||||
#endif /* __LINUX_PCS_XPCS_H */
|
#endif /* __LINUX_PCS_XPCS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user