Commit bea4b309 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'enetc-Migrate-to-PHYLINK-and-PCS_LYNX'

Claudiu Manoil says:

====================
enetc: Migrate to PHYLINK and PCS_LYNX

Transitioning the enetc driver from phylib to phylink.
Offloading the serdes configuration to the PCS_LYNX
module is a mandatory part of this transition. Aiming
for a cleaner, more maintainable design, and better
code reuse.
The first 2 patches are clean up prerequisites.

Tested on a p1028rdb board.

v2: validate() explicitly rejects now all interface modes not
supported by the driver instead of relying on the device tree
to provide only supported interfaces, and dropped redundant
activation of pcs_poll (addressing Ioana's findings)
====================
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents df41c19a 71b77a7a
......@@ -199,6 +199,7 @@ qsgmii_phy3: ethernet-phy@13 {
&enetc_port0 {
phy-handle = <&sgmii_phy0>;
phy-connection-type = "sgmii";
managed = "in-band-status";
status = "okay";
mdio {
......
......@@ -3,7 +3,8 @@ config FSL_ENETC
tristate "ENETC PF driver"
depends on PCI && PCI_MSI
select FSL_ENETC_MDIO
select PHYLIB
select PHYLINK
select PCS_LYNX
select DIMLIB
help
This driver supports NXP ENETC gigabit ethernet controller PCIe
......@@ -15,7 +16,7 @@ config FSL_ENETC
config FSL_ENETC_VF
tristate "ENETC VF driver"
depends on PCI && PCI_MSI
select PHYLIB
select PHYLINK
select DIMLIB
help
This driver supports NXP ENETC gigabit ethernet controller PCIe
......
......@@ -4,7 +4,6 @@
#include "enetc.h"
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/of_mdio.h>
#include <linux/vmalloc.h>
/* ENETC overhead: optional extension BD + 1 BD gap */
......@@ -1392,38 +1391,24 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv)
enetc_rxbdr_wr(&priv->si->hw, i, ENETC_RBIER, 0);
}
static void adjust_link(struct net_device *ndev)
static int enetc_phylink_connect(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
if (priv->active_offloads & ENETC_F_QBV)
enetc_sched_speed_set(ndev);
phy_print_status(phydev);
}
static int enetc_phy_connect(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct phy_device *phydev;
struct ethtool_eee edata;
int err;
if (!priv->phy_node)
if (!priv->phylink)
return 0; /* phy-less mode */
phydev = of_phy_connect(ndev, priv->phy_node, &adjust_link,
0, priv->if_mode);
if (!phydev) {
err = phylink_of_phy_connect(priv->phylink, priv->dev->of_node, 0);
if (err) {
dev_err(&ndev->dev, "could not attach to PHY\n");
return -ENODEV;
return err;
}
phy_attached_info(phydev);
/* disable EEE autoneg, until ENETC driver supports it */
memset(&edata, 0, sizeof(struct ethtool_eee));
phy_ethtool_set_eee(phydev, &edata);
phylink_ethtool_set_eee(priv->phylink, &edata);
return 0;
}
......@@ -1443,8 +1428,8 @@ void enetc_start(struct net_device *ndev)
enable_irq(irq);
}
if (ndev->phydev)
phy_start(ndev->phydev);
if (priv->phylink)
phylink_start(priv->phylink);
else
netif_carrier_on(ndev);
......@@ -1460,7 +1445,7 @@ int enetc_open(struct net_device *ndev)
if (err)
return err;
err = enetc_phy_connect(ndev);
err = enetc_phylink_connect(ndev);
if (err)
goto err_phy_connect;
......@@ -1490,8 +1475,8 @@ int enetc_open(struct net_device *ndev)
err_alloc_rx:
enetc_free_tx_resources(priv);
err_alloc_tx:
if (ndev->phydev)
phy_disconnect(ndev->phydev);
if (priv->phylink)
phylink_disconnect_phy(priv->phylink);
err_phy_connect:
enetc_free_irqs(priv);
......@@ -1514,8 +1499,8 @@ void enetc_stop(struct net_device *ndev)
napi_disable(&priv->int_vector[i]->napi);
}
if (ndev->phydev)
phy_stop(ndev->phydev);
if (priv->phylink)
phylink_stop(priv->phylink);
else
netif_carrier_off(ndev);
......@@ -1529,8 +1514,8 @@ int enetc_close(struct net_device *ndev)
enetc_stop(ndev);
enetc_clear_bdrs(priv);
if (ndev->phydev)
phy_disconnect(ndev->phydev);
if (priv->phylink)
phylink_disconnect_phy(priv->phylink);
enetc_free_rxtx_rings(priv);
enetc_free_rx_resources(priv);
enetc_free_tx_resources(priv);
......@@ -1780,6 +1765,7 @@ static int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr)
int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
if (cmd == SIOCSHWTSTAMP)
return enetc_hwtstamp_set(ndev, rq);
......@@ -1787,9 +1773,10 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
return enetc_hwtstamp_get(ndev, rq);
#endif
if (!ndev->phydev)
if (!priv->phylink)
return -EOPNOTSUPP;
return phy_mii_ioctl(ndev->phydev, rq, cmd);
return phylink_mii_ioctl(priv->phylink, rq, cmd);
}
int enetc_alloc_msix(struct enetc_ndev_priv *priv)
......
......@@ -9,7 +9,7 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/dim.h>
#include "enetc_hw.h"
......@@ -264,8 +264,7 @@ struct enetc_ndev_priv {
struct psfp_cap psfp_cap;
struct device_node *phy_node;
phy_interface_t if_mode;
struct phylink *phylink;
int ic_mode;
u32 tx_ictt;
};
......@@ -323,7 +322,7 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
#ifdef CONFIG_FSL_ENETC_QOS
int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
void enetc_sched_speed_set(struct net_device *ndev);
void enetc_sched_speed_set(struct enetc_ndev_priv *priv, int speed);
int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
int enetc_setup_tc_txtime(struct net_device *ndev, void *type_data);
int enetc_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
......@@ -388,7 +387,7 @@ static inline int enetc_psfp_disable(struct enetc_ndev_priv *priv)
#else
#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
#define enetc_sched_speed_set(ndev) (void)0
#define enetc_sched_speed_set(priv, speed) (void)0
#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
#define enetc_setup_tc_txtime(ndev, type_data) -EOPNOTSUPP
#define enetc_setup_tc_psfp(ndev, type_data) -EOPNOTSUPP
......
......@@ -686,6 +686,28 @@ static int enetc_set_wol(struct net_device *dev,
return ret;
}
static int enetc_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct enetc_ndev_priv *priv = netdev_priv(dev);
if (!priv->phylink)
return -EOPNOTSUPP;
return phylink_ethtool_ksettings_get(priv->phylink, cmd);
}
static int enetc_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
struct enetc_ndev_priv *priv = netdev_priv(dev);
if (!priv->phylink)
return -EOPNOTSUPP;
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
}
static const struct ethtool_ops enetc_pf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
......@@ -704,8 +726,8 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
.get_ringparam = enetc_get_ringparam,
.get_coalesce = enetc_get_coalesce,
.set_coalesce = enetc_set_coalesce,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_link_ksettings = enetc_get_link_ksettings,
.set_link_ksettings = enetc_set_link_ksettings,
.get_link = ethtool_op_get_link,
.get_ts_info = enetc_get_ts_info,
.get_wol = enetc_get_wol,
......
......@@ -482,8 +482,7 @@ static void enetc_port_si_configure(struct enetc_si *si)
enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
}
static void enetc_configure_port_mac(struct enetc_hw *hw,
phy_interface_t phy_mode)
static void enetc_configure_port_mac(struct enetc_hw *hw)
{
enetc_port_wr(hw, ENETC_PM0_MAXFRM,
ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
......@@ -492,12 +491,14 @@ static void enetc_configure_port_mac(struct enetc_hw *hw,
enetc_port_wr(hw, ENETC_PTXMBAR, 2 * ENETC_MAC_MAXFRM_SIZE);
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
}
static void enetc_mac_config(struct enetc_hw *hw, phy_interface_t phy_mode)
{
/* set auto-speed for RGMII */
if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG ||
phy_interface_mode_is_rgmii(phy_mode))
......@@ -507,6 +508,17 @@ static void enetc_configure_port_mac(struct enetc_hw *hw,
enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
}
static void enetc_mac_enable(struct enetc_hw *hw, bool en)
{
u32 val = enetc_port_rd(hw, ENETC_PM0_CMD_CFG);
val &= ~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
val |= en ? (ENETC_PM0_TX_EN | ENETC_PM0_RX_EN) : 0;
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, val);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, val);
}
static void enetc_configure_port_pmac(struct enetc_hw *hw)
{
u32 temp;
......@@ -527,7 +539,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
enetc_configure_port_pmac(hw);
enetc_configure_port_mac(hw, pf->if_mode);
enetc_configure_port_mac(hw);
enetc_port_si_configure(pf->si);
......@@ -733,11 +745,10 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
}
static int enetc_mdio_probe(struct enetc_pf *pf)
static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
{
struct device *dev = &pf->si->pdev->dev;
struct enetc_mdio_priv *mdio_priv;
struct device_node *np;
struct mii_bus *bus;
int err;
......@@ -754,20 +765,12 @@ static int enetc_mdio_probe(struct enetc_pf *pf)
mdio_priv->mdio_base = ENETC_EMDIO_BASE;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
np = of_get_child_by_name(dev->of_node, "mdio");
if (!np) {
dev_err(dev, "MDIO node missing\n");
return -EINVAL;
}
err = of_mdiobus_register(bus, np);
if (err) {
of_node_put(np);
dev_err(dev, "cannot register MDIO bus\n");
return err;
}
of_node_put(np);
pf->mdio = bus;
return 0;
......@@ -779,69 +782,12 @@ static void enetc_mdio_remove(struct enetc_pf *pf)
mdiobus_unregister(pf->mdio);
}
static int enetc_of_get_phy(struct enetc_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *mdio_np;
int err;
pf->phy_node = of_parse_phandle(np, "phy-handle", 0);
if (!pf->phy_node) {
if (!of_phy_is_fixed_link(np)) {
dev_err(dev, "PHY not specified\n");
return -ENODEV;
}
err = of_phy_register_fixed_link(np);
if (err < 0) {
dev_err(dev, "fixed link registration failed\n");
return err;
}
pf->phy_node = of_node_get(np);
}
mdio_np = of_get_child_by_name(np, "mdio");
if (mdio_np) {
of_node_put(mdio_np);
err = enetc_mdio_probe(pf);
if (err) {
of_node_put(pf->phy_node);
return err;
}
}
err = of_get_phy_mode(np, &pf->if_mode);
if (err) {
dev_err(dev, "missing phy type\n");
of_node_put(pf->phy_node);
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
else
enetc_mdio_remove(pf);
return -EINVAL;
}
return 0;
}
static void enetc_of_put_phy(struct enetc_pf *pf)
{
struct device_node *np = pf->si->pdev->dev.of_node;
if (np && of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
if (pf->phy_node)
of_node_put(pf->phy_node);
}
static int enetc_imdio_init(struct enetc_pf *pf, bool is_c45)
static int enetc_imdio_create(struct enetc_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
struct enetc_mdio_priv *mdio_priv;
struct phy_device *pcs;
struct lynx_pcs *pcs_lynx;
struct mdio_device *pcs;
struct mii_bus *bus;
int err;
......@@ -865,15 +811,23 @@ static int enetc_imdio_init(struct enetc_pf *pf, bool is_c45)
goto free_mdio_bus;
}
pcs = get_phy_device(bus, 0, is_c45);
pcs = mdio_device_create(bus, 0);
if (IS_ERR(pcs)) {
err = PTR_ERR(pcs);
dev_err(dev, "cannot get internal PCS PHY (%d)\n", err);
dev_err(dev, "cannot create pcs (%d)\n", err);
goto unregister_mdiobus;
}
pcs_lynx = lynx_pcs_create(pcs);
if (!pcs_lynx) {
mdio_device_free(pcs);
err = -ENOMEM;
dev_err(dev, "cannot create lynx pcs (%d)\n", err);
goto unregister_mdiobus;
}
pf->imdio = bus;
pf->pcs = pcs;
pf->pcs = pcs_lynx;
return 0;
......@@ -886,91 +840,168 @@ static int enetc_imdio_init(struct enetc_pf *pf, bool is_c45)
static void enetc_imdio_remove(struct enetc_pf *pf)
{
if (pf->pcs)
put_device(&pf->pcs->mdio.dev);
if (pf->pcs) {
mdio_device_free(pf->pcs->mdio);
lynx_pcs_destroy(pf->pcs);
}
if (pf->imdio) {
mdiobus_unregister(pf->imdio);
mdiobus_free(pf->imdio);
}
}
static void enetc_configure_sgmii(struct phy_device *pcs)
static bool enetc_port_has_pcs(struct enetc_pf *pf)
{
return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
}
static int enetc_mdiobus_create(struct enetc_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
struct device_node *mdio_np;
int err;
mdio_np = of_get_child_by_name(dev->of_node, "mdio");
if (mdio_np) {
err = enetc_mdio_probe(pf, mdio_np);
of_node_put(mdio_np);
if (err)
return err;
}
if (enetc_port_has_pcs(pf)) {
err = enetc_imdio_create(pf);
if (err) {
enetc_mdio_remove(pf);
return err;
}
}
return 0;
}
static void enetc_mdiobus_destroy(struct enetc_pf *pf)
{
/* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
* for the MAC PCS in order to acknowledge the AN.
*/
phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | ADVERTISE_LPACK);
enetc_mdio_remove(pf);
enetc_imdio_remove(pf);
}
phy_write(pcs, ENETC_PCS_IF_MODE,
ENETC_PCS_IF_MODE_SGMII_EN |
ENETC_PCS_IF_MODE_USE_SGMII_AN);
static void enetc_pl_mac_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_INTERNAL &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
state->interface != PHY_INTERFACE_MODE_2500BASEX &&
state->interface != PHY_INTERFACE_MODE_USXGMII &&
!phy_interface_mode_is_rgmii(state->interface)) {
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
return;
}
/* Adjust link timer for SGMII */
phy_write(pcs, ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
phy_write(pcs, ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
phylink_set_port_modes(mask);
phylink_set(mask, Autoneg);
phylink_set(mask, Pause);
phylink_set(mask, Asym_Pause);
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 100baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 1000baseT_Half);
phylink_set(mask, 1000baseT_Full);
if (state->interface == PHY_INTERFACE_MODE_INTERNAL ||
state->interface == PHY_INTERFACE_MODE_2500BASEX ||
state->interface == PHY_INTERFACE_MODE_USXGMII) {
phylink_set(mask, 2500baseT_Full);
phylink_set(mask, 2500baseX_Full);
}
phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE);
bitmap_and(supported, supported, mask,
__ETHTOOL_LINK_MODE_MASK_NBITS);
bitmap_and(state->advertising, state->advertising, mask,
__ETHTOOL_LINK_MODE_MASK_NBITS);
}
static void enetc_configure_2500basex(struct phy_device *pcs)
static void enetc_pl_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
phy_write(pcs, ENETC_PCS_IF_MODE,
ENETC_PCS_IF_MODE_SGMII_EN |
ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500));
struct enetc_pf *pf = phylink_to_enetc_pf(config);
struct enetc_ndev_priv *priv;
enetc_mac_config(&pf->si->hw, state->interface);
phy_write(pcs, MII_BMCR, BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_RESET);
priv = netdev_priv(pf->si->ndev);
if (pf->pcs)
phylink_set_pcs(priv->phylink, &pf->pcs->pcs);
}
static void enetc_configure_usxgmii(struct phy_device *pcs)
static void enetc_pl_mac_link_up(struct phylink_config *config,
struct phy_device *phy, unsigned int mode,
phy_interface_t interface, int speed,
int duplex, bool tx_pause, bool rx_pause)
{
/* Configure device ability for the USXGMII Replicator */
phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
ADVERTISE_SGMII | ADVERTISE_LPACK |
MDIO_USXGMII_FULL_DUPLEX);
/* Restart PCS AN */
phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR,
BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART);
struct enetc_pf *pf = phylink_to_enetc_pf(config);
struct enetc_ndev_priv *priv;
priv = netdev_priv(pf->si->ndev);
if (priv->active_offloads & ENETC_F_QBV)
enetc_sched_speed_set(priv, speed);
enetc_mac_enable(&pf->si->hw, true);
}
static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
static void enetc_pl_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct enetc_pf *pf = phylink_to_enetc_pf(config);
enetc_mac_enable(&pf->si->hw, false);
}
static const struct phylink_mac_ops enetc_mac_phylink_ops = {
.validate = enetc_pl_mac_validate,
.mac_config = enetc_pl_mac_config,
.mac_link_up = enetc_pl_mac_link_up,
.mac_link_down = enetc_pl_mac_link_down,
};
static int enetc_phylink_create(struct enetc_ndev_priv *priv)
{
bool is_c45 = priv->if_mode == PHY_INTERFACE_MODE_USXGMII;
struct enetc_pf *pf = enetc_si_priv(priv->si);
struct device *dev = &pf->si->pdev->dev;
struct phylink *phylink;
int err;
if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
priv->if_mode != PHY_INTERFACE_MODE_2500BASEX &&
priv->if_mode != PHY_INTERFACE_MODE_USXGMII)
return 0;
pf->phylink_config.dev = &priv->ndev->dev;
pf->phylink_config.type = PHYLINK_NETDEV;
err = enetc_imdio_init(pf, is_c45);
if (err)
phylink = phylink_create(&pf->phylink_config,
of_fwnode_handle(dev->of_node),
pf->if_mode, &enetc_mac_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
return err;
switch (priv->if_mode) {
case PHY_INTERFACE_MODE_SGMII:
enetc_configure_sgmii(pf->pcs);
break;
case PHY_INTERFACE_MODE_2500BASEX:
enetc_configure_2500basex(pf->pcs);
break;
case PHY_INTERFACE_MODE_USXGMII:
enetc_configure_usxgmii(pf->pcs);
break;
default:
dev_err(&pf->si->pdev->dev, "Unsupported link mode %s\n",
phy_modes(priv->if_mode));
}
priv->phylink = phylink;
return 0;
}
static void enetc_teardown_serdes(struct enetc_ndev_priv *priv)
static void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
{
struct enetc_pf *pf = enetc_si_priv(priv->si);
enetc_imdio_remove(pf);
if (priv->phylink)
phylink_destroy(priv->phylink);
}
static int enetc_pf_probe(struct pci_dev *pdev,
......@@ -1004,10 +1035,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
pf->si = si;
pf->total_vfs = pci_sriov_get_totalvfs(pdev);
err = enetc_of_get_phy(pf);
if (err)
dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
enetc_configure_port(pf);
enetc_get_si_caps(si);
......@@ -1022,8 +1049,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops);
priv = netdev_priv(ndev);
priv->phy_node = pf->phy_node;
priv->if_mode = pf->if_mode;
enetc_init_si_rings_params(priv);
......@@ -1039,20 +1064,27 @@ static int enetc_pf_probe(struct pci_dev *pdev,
goto err_alloc_msix;
}
err = enetc_configure_serdes(priv);
if (err)
dev_warn(&pdev->dev, "Attempted SerDes config but failed\n");
if (!of_get_phy_mode(pdev->dev.of_node, &pf->if_mode)) {
err = enetc_mdiobus_create(pf);
if (err)
goto err_mdiobus_create;
err = enetc_phylink_create(priv);
if (err)
goto err_phylink_create;
}
err = register_netdev(ndev);
if (err)
goto err_reg_netdev;
netif_carrier_off(ndev);
return 0;
err_reg_netdev:
enetc_teardown_serdes(priv);
enetc_phylink_destroy(priv);
err_phylink_create:
enetc_mdiobus_destroy(pf);
err_mdiobus_create:
enetc_free_msix(priv);
err_alloc_msix:
enetc_free_si_resources(priv);
......@@ -1060,8 +1092,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
si->ndev = NULL;
free_netdev(ndev);
err_alloc_netdev:
enetc_mdio_remove(pf);
enetc_of_put_phy(pf);
err_map_pf_space:
enetc_pci_remove(pdev);
......@@ -1074,16 +1104,15 @@ static void enetc_pf_remove(struct pci_dev *pdev)
struct enetc_pf *pf = enetc_si_priv(si);
struct enetc_ndev_priv *priv;
priv = netdev_priv(si->ndev);
enetc_phylink_destroy(priv);
enetc_mdiobus_destroy(pf);
if (pf->num_vfs)
enetc_sriov_configure(pdev, 0);
priv = netdev_priv(si->ndev);
unregister_netdev(si->ndev);
enetc_teardown_serdes(priv);
enetc_mdio_remove(pf);
enetc_of_put_phy(pf);
enetc_free_msix(priv);
enetc_free_si_resources(priv);
......
......@@ -2,6 +2,7 @@
/* Copyright 2017-2019 NXP */
#include "enetc.h"
#include <linux/pcs-lynx.h>
#define ENETC_PF_NUM_RINGS 8
......@@ -45,12 +46,15 @@ struct enetc_pf {
struct mii_bus *mdio; /* saved for cleanup */
struct mii_bus *imdio;
struct phy_device *pcs;
struct lynx_pcs *pcs;
struct device_node *phy_node;
phy_interface_t if_mode;
struct phylink_config phylink_config;
};
#define phylink_to_enetc_pf(config) \
container_of((config), struct enetc_pf, phylink_config)
int enetc_msg_psi_init(struct enetc_pf *pf);
void enetc_msg_psi_free(struct enetc_pf *pf);
void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
......@@ -15,17 +15,14 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
& ENETC_QBV_MAX_GCL_LEN_MASK;
}
void enetc_sched_speed_set(struct net_device *ndev)
void enetc_sched_speed_set(struct enetc_ndev_priv *priv, int speed)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
u32 old_speed = priv->speed;
u32 speed, pspeed;
u32 pspeed;
if (phydev->speed == old_speed)
if (speed == old_speed)
return;
speed = phydev->speed;
switch (speed) {
case SPEED_1000:
pspeed = ENETC_PMR_PSPEED_1000M;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment