Commit 46d38026 authored by David S. Miller's avatar David S. Miller

Merge branch 'stmmac-net'

Giuseppe Cavallaro says:

====================
stmmac: review and fix lock and atomicity

Recently some issues have been reported for the driver for locking mechanism
and atomicity.

In fact, enabling DEBUG support to prove lock and to verify if sleeping while
atomic context some warnings occur at runtime. I have reproduced all on STi
platforms.

Concerning the tx path, I had provided a patch time ago but
I discarded the idea to completely remove locks; in this patch-set we can have
some useful fixes instead of.

This patch-set is to fix the atomicity in the PM stuff where I tried to collect
all the points and advice reported in the past weeks.
As final result, on my side no warnings and no problem when suspend/resume the
driver on STi boxes.

I also added a patch that fixes the locks for the EEE.
As pointed in some thread there was a design problem behind the eee
initialization and I have tried to fix that before.
As final result no issues when proving locks too.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b994ca6b 777da230
...@@ -276,6 +276,7 @@ static void stmmac_eee_ctrl_timer(unsigned long arg) ...@@ -276,6 +276,7 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
bool stmmac_eee_init(struct stmmac_priv *priv) bool stmmac_eee_init(struct stmmac_priv *priv)
{ {
char *phy_bus_name = priv->plat->phy_bus_name; char *phy_bus_name = priv->plat->phy_bus_name;
unsigned long flags;
bool ret = false; bool ret = false;
/* Using PCS we cannot dial with the phy registers at this stage /* Using PCS we cannot dial with the phy registers at this stage
...@@ -300,6 +301,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv) ...@@ -300,6 +301,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
* changed). * changed).
* In that case the driver disable own timers. * In that case the driver disable own timers.
*/ */
spin_lock_irqsave(&priv->lock, flags);
if (priv->eee_active) { if (priv->eee_active) {
pr_debug("stmmac: disable EEE\n"); pr_debug("stmmac: disable EEE\n");
del_timer_sync(&priv->eee_ctrl_timer); del_timer_sync(&priv->eee_ctrl_timer);
...@@ -307,9 +309,11 @@ bool stmmac_eee_init(struct stmmac_priv *priv) ...@@ -307,9 +309,11 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
tx_lpi_timer); tx_lpi_timer);
} }
priv->eee_active = 0; priv->eee_active = 0;
spin_unlock_irqrestore(&priv->lock, flags);
goto out; goto out;
} }
/* Activate the EEE and start timers */ /* Activate the EEE and start timers */
spin_lock_irqsave(&priv->lock, flags);
if (!priv->eee_active) { if (!priv->eee_active) {
priv->eee_active = 1; priv->eee_active = 1;
init_timer(&priv->eee_ctrl_timer); init_timer(&priv->eee_ctrl_timer);
...@@ -325,9 +329,10 @@ bool stmmac_eee_init(struct stmmac_priv *priv) ...@@ -325,9 +329,10 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
/* Set HW EEE according to the speed */ /* Set HW EEE according to the speed */
priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link); priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link);
pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
ret = true; ret = true;
spin_unlock_irqrestore(&priv->lock, flags);
pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
} }
out: out:
return ret; return ret;
...@@ -760,12 +765,12 @@ static void stmmac_adjust_link(struct net_device *dev) ...@@ -760,12 +765,12 @@ static void stmmac_adjust_link(struct net_device *dev)
if (new_state && netif_msg_link(priv)) if (new_state && netif_msg_link(priv))
phy_print_status(phydev); phy_print_status(phydev);
spin_unlock_irqrestore(&priv->lock, flags);
/* At this stage, it could be needed to setup the EEE or adjust some /* At this stage, it could be needed to setup the EEE or adjust some
* MAC related HW registers. * MAC related HW registers.
*/ */
priv->eee_enabled = stmmac_eee_init(priv); priv->eee_enabled = stmmac_eee_init(priv);
spin_unlock_irqrestore(&priv->lock, flags);
} }
/** /**
...@@ -959,12 +964,12 @@ static void stmmac_clear_descriptors(struct stmmac_priv *priv) ...@@ -959,12 +964,12 @@ static void stmmac_clear_descriptors(struct stmmac_priv *priv)
} }
static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
int i) int i, gfp_t flags)
{ {
struct sk_buff *skb; struct sk_buff *skb;
skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
GFP_KERNEL); flags);
if (!skb) { if (!skb) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__); pr_err("%s: Rx init fails; skb is NULL\n", __func__);
return -ENOMEM; return -ENOMEM;
...@@ -1006,7 +1011,7 @@ static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i) ...@@ -1006,7 +1011,7 @@ static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i)
* and allocates the socket buffers. It suppors the chained and ring * and allocates the socket buffers. It suppors the chained and ring
* modes. * modes.
*/ */
static int init_dma_desc_rings(struct net_device *dev) static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
{ {
int i; int i;
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
...@@ -1041,7 +1046,7 @@ static int init_dma_desc_rings(struct net_device *dev) ...@@ -1041,7 +1046,7 @@ static int init_dma_desc_rings(struct net_device *dev)
else else
p = priv->dma_rx + i; p = priv->dma_rx + i;
ret = stmmac_init_rx_buffers(priv, p, i); ret = stmmac_init_rx_buffers(priv, p, i, flags);
if (ret) if (ret)
goto err_init_rx_buffers; goto err_init_rx_buffers;
...@@ -1647,11 +1652,6 @@ static int stmmac_hw_setup(struct net_device *dev) ...@@ -1647,11 +1652,6 @@ static int stmmac_hw_setup(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
int ret; int ret;
ret = init_dma_desc_rings(dev);
if (ret < 0) {
pr_err("%s: DMA descriptors initialization failed\n", __func__);
return ret;
}
/* DMA initialization and SW reset */ /* DMA initialization and SW reset */
ret = stmmac_init_dma_engine(priv); ret = stmmac_init_dma_engine(priv);
if (ret < 0) { if (ret < 0) {
...@@ -1705,10 +1705,6 @@ static int stmmac_hw_setup(struct net_device *dev) ...@@ -1705,10 +1705,6 @@ static int stmmac_hw_setup(struct net_device *dev)
} }
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
priv->eee_enabled = stmmac_eee_init(priv);
stmmac_init_tx_coalesce(priv);
if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
priv->rx_riwt = MAX_DMA_RIWT; priv->rx_riwt = MAX_DMA_RIWT;
priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT); priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
...@@ -1761,12 +1757,20 @@ static int stmmac_open(struct net_device *dev) ...@@ -1761,12 +1757,20 @@ static int stmmac_open(struct net_device *dev)
goto dma_desc_error; goto dma_desc_error;
} }
ret = init_dma_desc_rings(dev, GFP_KERNEL);
if (ret < 0) {
pr_err("%s: DMA descriptors initialization failed\n", __func__);
goto init_error;
}
ret = stmmac_hw_setup(dev); ret = stmmac_hw_setup(dev);
if (ret < 0) { if (ret < 0) {
pr_err("%s: Hw setup failed\n", __func__); pr_err("%s: Hw setup failed\n", __func__);
goto init_error; goto init_error;
} }
stmmac_init_tx_coalesce(priv);
if (priv->phydev) if (priv->phydev)
phy_start(priv->phydev); phy_start(priv->phydev);
...@@ -1894,7 +1898,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1894,7 +1898,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int nopaged_len = skb_headlen(skb); unsigned int nopaged_len = skb_headlen(skb);
unsigned int enh_desc = priv->plat->enh_desc; unsigned int enh_desc = priv->plat->enh_desc;
spin_lock(&priv->tx_lock);
if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) { if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
spin_unlock(&priv->tx_lock);
if (!netif_queue_stopped(dev)) { if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev); netif_stop_queue(dev);
/* This is a hard error, log it. */ /* This is a hard error, log it. */
...@@ -1903,8 +1910,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1903,8 +1910,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
spin_lock(&priv->tx_lock);
if (priv->tx_path_in_lpi_mode) if (priv->tx_path_in_lpi_mode)
stmmac_disable_eee_mode(priv); stmmac_disable_eee_mode(priv);
...@@ -2025,6 +2030,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2025,6 +2030,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
dma_map_err: dma_map_err:
spin_unlock(&priv->tx_lock);
dev_err(priv->device, "Tx dma map failed\n"); dev_err(priv->device, "Tx dma map failed\n");
dev_kfree_skb(skb); dev_kfree_skb(skb);
priv->dev->stats.tx_dropped++; priv->dev->stats.tx_dropped++;
...@@ -2281,9 +2287,7 @@ static void stmmac_set_rx_mode(struct net_device *dev) ...@@ -2281,9 +2287,7 @@ static void stmmac_set_rx_mode(struct net_device *dev)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
spin_lock(&priv->lock);
priv->hw->mac->set_filter(priv->hw, dev); priv->hw->mac->set_filter(priv->hw, dev);
spin_unlock(&priv->lock);
} }
/** /**
...@@ -2950,7 +2954,7 @@ int stmmac_suspend(struct net_device *ndev) ...@@ -2950,7 +2954,7 @@ int stmmac_suspend(struct net_device *ndev)
stmmac_set_mac(priv->ioaddr, false); stmmac_set_mac(priv->ioaddr, false);
pinctrl_pm_select_sleep_state(priv->device); pinctrl_pm_select_sleep_state(priv->device);
/* Disable clock in case of PWM is off */ /* Disable clock in case of PWM is off */
clk_disable_unprepare(priv->stmmac_clk); clk_disable(priv->stmmac_clk);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -2982,7 +2986,7 @@ int stmmac_resume(struct net_device *ndev) ...@@ -2982,7 +2986,7 @@ int stmmac_resume(struct net_device *ndev)
} else { } else {
pinctrl_pm_select_default_state(priv->device); pinctrl_pm_select_default_state(priv->device);
/* enable the clk prevously disabled */ /* enable the clk prevously disabled */
clk_prepare_enable(priv->stmmac_clk); clk_enable(priv->stmmac_clk);
/* reset the phy so that it's ready */ /* reset the phy so that it's ready */
if (priv->mii) if (priv->mii)
stmmac_mdio_reset(priv->mii); stmmac_mdio_reset(priv->mii);
...@@ -2990,7 +2994,9 @@ int stmmac_resume(struct net_device *ndev) ...@@ -2990,7 +2994,9 @@ int stmmac_resume(struct net_device *ndev)
netif_device_attach(ndev); netif_device_attach(ndev);
init_dma_desc_rings(ndev, GFP_ATOMIC);
stmmac_hw_setup(ndev); stmmac_hw_setup(ndev);
stmmac_init_tx_coalesce(priv);
napi_enable(&priv->napi); napi_enable(&priv->napi);
......
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