Commit dceb393a authored by Romain Gantois's avatar Romain Gantois Committed by Jakub Kicinski

net: phylink: add rxc_always_on flag to phylink_pcs

Some MAC drivers (e.g. stmmac) require a continuous receive clock signal to
be generated by a PCS that is handled by a standalone PCS driver.

Such a PCS driver does not have access to a PHY device, thus cannot check
the PHY_F_RXC_ALWAYS_ON flag. They cannot check max_requires_rxc in the
phylink config either, since it is a private member. Therefore, a new flag
is needed to signal to the PCS that it should keep the RX clock signal up
at all times.
Co-developed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarRomain Gantois <romain.gantois@bootlin.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20240326-rxc_bugfix-v6-2-24a74e5c761f@bootlin.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 21d9ba5b
...@@ -1042,6 +1042,21 @@ static void phylink_pcs_poll_start(struct phylink *pl) ...@@ -1042,6 +1042,21 @@ static void phylink_pcs_poll_start(struct phylink *pl)
mod_timer(&pl->link_poll, jiffies + HZ); mod_timer(&pl->link_poll, jiffies + HZ);
} }
int phylink_pcs_pre_init(struct phylink *pl, struct phylink_pcs *pcs)
{
int ret = 0;
/* Signal to PCS driver that MAC requires RX clock for init */
if (pl->config->mac_requires_rxc)
pcs->rxc_always_on = true;
if (pcs->ops->pcs_pre_init)
ret = pcs->ops->pcs_pre_init(pcs);
return ret;
}
EXPORT_SYMBOL_GPL(phylink_pcs_pre_init);
static void phylink_mac_config(struct phylink *pl, static void phylink_mac_config(struct phylink *pl,
const struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
......
...@@ -396,6 +396,10 @@ struct phylink_pcs_ops; ...@@ -396,6 +396,10 @@ struct phylink_pcs_ops;
* @phylink: pointer to &struct phylink_config * @phylink: pointer to &struct phylink_config
* @neg_mode: provide PCS neg mode via "mode" argument * @neg_mode: provide PCS neg mode via "mode" argument
* @poll: poll the PCS for link changes * @poll: poll the PCS for link changes
* @rxc_always_on: The MAC driver requires the reference clock
* to always be on. Standalone PCS drivers which
* do not have access to a PHY device can check
* this instead of PHY_F_RXC_ALWAYS_ON.
* *
* This structure is designed to be embedded within the PCS private data, * This structure is designed to be embedded within the PCS private data,
* and will be passed between phylink and the PCS. * and will be passed between phylink and the PCS.
...@@ -408,6 +412,7 @@ struct phylink_pcs { ...@@ -408,6 +412,7 @@ struct phylink_pcs {
struct phylink *phylink; struct phylink *phylink;
bool neg_mode; bool neg_mode;
bool poll; bool poll;
bool rxc_always_on;
}; };
/** /**
...@@ -422,6 +427,8 @@ struct phylink_pcs { ...@@ -422,6 +427,8 @@ struct phylink_pcs {
* @pcs_an_restart: restart 802.3z BaseX autonegotiation. * @pcs_an_restart: restart 802.3z BaseX autonegotiation.
* @pcs_link_up: program the PCS for the resolved link configuration * @pcs_link_up: program the PCS for the resolved link configuration
* (where necessary). * (where necessary).
* @pcs_pre_init: configure PCS components necessary for MAC hardware
* initialization e.g. RX clock for stmmac.
*/ */
struct phylink_pcs_ops { struct phylink_pcs_ops {
int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
...@@ -441,6 +448,7 @@ struct phylink_pcs_ops { ...@@ -441,6 +448,7 @@ struct phylink_pcs_ops {
void (*pcs_an_restart)(struct phylink_pcs *pcs); void (*pcs_an_restart)(struct phylink_pcs *pcs);
void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int neg_mode, void (*pcs_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);
int (*pcs_pre_init)(struct phylink_pcs *pcs);
}; };
#if 0 /* For kernel-doc purposes only. */ #if 0 /* For kernel-doc purposes only. */
...@@ -546,6 +554,34 @@ void pcs_an_restart(struct phylink_pcs *pcs); ...@@ -546,6 +554,34 @@ void pcs_an_restart(struct phylink_pcs *pcs);
*/ */
void pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, void pcs_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);
/**
* pcs_pre_init() - Configure PCS components necessary for MAC initialization
* @pcs: a pointer to a &struct phylink_pcs.
*
* This function can be called by MAC drivers through the
* phylink_pcs_pre_init() wrapper, before their hardware is initialized. It
* should not be called after the link is brought up, as reconfiguring the PCS
* at this point could break the link.
*
* Some MAC devices require specific hardware initialization to be performed by
* their associated PCS device before they can properly initialize their own
* hardware. An example of this is the initialization of stmmac controllers,
* which requires an active REF_CLK signal to be provided by the PHY/PCS.
*
* By calling phylink_pcs_pre_init(), MAC drivers can ensure that the PCS is
* setup in a way that allows for successful hardware initialization.
*
* The specific configuration performed by pcs_pre_init() is dependent on the
* model of PCS and the requirements of the MAC device attached to it. PCS
* driver authors should consider whether their target device is to be used in
* conjunction with a MAC device whose driver calls phylink_pcs_pre_init(). MAC
* driver authors should document their requirements for the PCS
* pre-initialization.
*
*/
int pcs_pre_init(struct phylink_pcs *pcs);
#endif #endif
struct phylink *phylink_create(struct phylink_config *, struct phylink *phylink_create(struct phylink_config *,
...@@ -565,6 +601,8 @@ void phylink_disconnect_phy(struct phylink *); ...@@ -565,6 +601,8 @@ void phylink_disconnect_phy(struct phylink *);
void phylink_mac_change(struct phylink *, bool up); void phylink_mac_change(struct phylink *, bool up);
void phylink_pcs_change(struct phylink_pcs *, bool up); void phylink_pcs_change(struct phylink_pcs *, bool up);
int phylink_pcs_pre_init(struct phylink *pl, struct phylink_pcs *pcs);
void phylink_start(struct phylink *); void phylink_start(struct phylink *);
void phylink_stop(struct phylink *); void phylink_stop(struct phylink *);
......
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