Commit dd557266 authored by Russell King (Oracle)'s avatar Russell King (Oracle) Committed by Jakub Kicinski
Browse files

net: stmmac: block PHY RXC clock-stop



The DesignWare core requires the receive clock to be running during
certain operations. Ensure that we block PHY RXC clock-stop during
these operations.

This is a best-efforts change - not everywhere can be covered by this
because of net's core locking, which means we can't access the MDIO
bus to configure the PHY to disable RXC clock-stop in certain areas.
These are marked with FIXME comments.

Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1tvO6p-008Vjz-Qy@rmk-PC.armlinux.org.uk


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent ddf4bd3f
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -3484,9 +3484,18 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
	if (priv->hw->phylink_pcs)
		phylink_pcs_pre_init(priv->phylink, priv->hw->phylink_pcs);

	/* Note that clk_rx_i must be running for reset to complete. This
	 * clock may also be required when setting the MAC address.
	 *
	 * Block the receive clock stop for LPI mode at the PHY in case
	 * the link is established with EEE mode active.
	 */
	phylink_rx_clk_stop_block(priv->phylink);

	/* DMA initialization and SW reset */
	ret = stmmac_init_dma_engine(priv);
	if (ret < 0) {
		phylink_rx_clk_stop_unblock(priv->phylink);
		netdev_err(priv->dev, "%s: DMA engine initialization failed\n",
			   __func__);
		return ret;
@@ -3494,6 +3503,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)

	/* Copy the MAC addr into the HW  */
	stmmac_set_umac_addr(priv, priv->hw, dev->dev_addr, 0);
	phylink_rx_clk_stop_unblock(priv->phylink);

	/* PS and related bits will be programmed according to the speed */
	if (priv->hw->pcs) {
@@ -3604,7 +3614,9 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
	/* Start the ball rolling... */
	stmmac_start_all_dma(priv);

	phylink_rx_clk_stop_block(priv->phylink);
	stmmac_set_hw_vlan_mode(priv, priv->hw);
	phylink_rx_clk_stop_unblock(priv->phylink);

	return 0;
}
@@ -5888,6 +5900,9 @@ static void stmmac_tx_timeout(struct net_device *dev, unsigned int txqueue)
 *  whenever multicast addresses must be enabled/disabled.
 *  Return value:
 *  void.
 *
 *  FIXME: This may need RXC to be running, but it may be called with BH
 *  disabled, which means we can't call phylink_rx_clk_stop*().
 */
static void stmmac_set_rx_mode(struct net_device *dev)
{
@@ -6020,7 +6035,9 @@ static int stmmac_set_features(struct net_device *netdev,
	else
		priv->hw->hw_vlan_en = false;

	phylink_rx_clk_stop_block(priv->phylink);
	stmmac_set_hw_vlan_mode(priv, priv->hw);
	phylink_rx_clk_stop_unblock(priv->phylink);

	return 0;
}
@@ -6304,7 +6321,9 @@ static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
	if (ret)
		goto set_mac_error;

	phylink_rx_clk_stop_block(priv->phylink);
	stmmac_set_umac_addr(priv, priv->hw, ndev->dev_addr, 0);
	phylink_rx_clk_stop_unblock(priv->phylink);

set_mac_error:
	pm_runtime_put(priv->device);
@@ -6660,6 +6679,9 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
	return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
}

/* FIXME: This may need RXC to be running, but it may be called with BH
 * disabled, which means we can't call phylink_rx_clk_stop*().
 */
static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
	struct stmmac_priv *priv = netdev_priv(ndev);
@@ -6691,6 +6713,9 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
	return ret;
}

/* FIXME: This may need RXC to be running, but it may be called with BH
 * disabled, which means we can't call phylink_rx_clk_stop*().
 */
static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
	struct stmmac_priv *priv = netdev_priv(ndev);
@@ -7951,9 +7976,11 @@ int stmmac_resume(struct device *dev)

	stmmac_hw_setup(ndev, false);
	stmmac_init_coalesce(priv);
	phylink_rx_clk_stop_block(priv->phylink);
	stmmac_set_rx_mode(ndev);

	stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw);
	phylink_rx_clk_stop_unblock(priv->phylink);

	stmmac_enable_all_queues(priv);
	stmmac_enable_all_dma_irq(priv);