aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Abreu <Jose.Abreu@synopsys.com>2018-03-29 05:40:18 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-30 12:31:59 -0400
commit34877a15f787b594649ed375943ecc65f4342e30 (patch)
tree9704e1ee4180c86dd96e6818f6fe2a62aa0ba4c9
parent02281a3525c9f1c07d792d64b079a2d677ed0ea5 (diff)
net: stmmac: Rework and fix TX Timeout code
Currently TX Timeout handler does not behaves as expected and leads to an unrecoverable state. Rework current implementation of TX Timeout handling to actually perform a complete reset of the driver state and IP. We use deferred work to init a task which will be responsible for resetting the system. Signed-off-by: Jose Abreu <joabreu@synopsys.com> Cc: David S. Miller <davem@davemloft.net> Cc: Joao Pinto <jpinto@synopsys.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Alexandre Torgue <alexandre.torgue@st.com> Cc: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c67
2 files changed, 73 insertions, 5 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 75161e1b7e55..1485d8fcfaa9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -145,6 +145,17 @@ struct stmmac_priv {
145 struct dentry *dbgfs_rings_status; 145 struct dentry *dbgfs_rings_status;
146 struct dentry *dbgfs_dma_cap; 146 struct dentry *dbgfs_dma_cap;
147#endif 147#endif
148
149 unsigned long state;
150 struct workqueue_struct *wq;
151 struct work_struct service_task;
152};
153
154enum stmmac_state {
155 STMMAC_DOWN,
156 STMMAC_RESET_REQUESTED,
157 STMMAC_RESETING,
158 STMMAC_SERVICE_SCHED,
148}; 159};
149 160
150int stmmac_mdio_unregister(struct net_device *ndev); 161int stmmac_mdio_unregister(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 9f983dd069d5..b75ecf3d19fe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -196,6 +196,20 @@ static void stmmac_start_all_queues(struct stmmac_priv *priv)
196 netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue)); 196 netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue));
197} 197}
198 198
199static void stmmac_service_event_schedule(struct stmmac_priv *priv)
200{
201 if (!test_bit(STMMAC_DOWN, &priv->state) &&
202 !test_and_set_bit(STMMAC_SERVICE_SCHED, &priv->state))
203 queue_work(priv->wq, &priv->service_task);
204}
205
206static void stmmac_global_err(struct stmmac_priv *priv)
207{
208 netif_carrier_off(priv->dev);
209 set_bit(STMMAC_RESET_REQUESTED, &priv->state);
210 stmmac_service_event_schedule(priv);
211}
212
199/** 213/**
200 * stmmac_clk_csr_set - dynamically set the MDC clock 214 * stmmac_clk_csr_set - dynamically set the MDC clock
201 * @priv: driver private structure 215 * @priv: driver private structure
@@ -3587,12 +3601,8 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
3587static void stmmac_tx_timeout(struct net_device *dev) 3601static void stmmac_tx_timeout(struct net_device *dev)
3588{ 3602{
3589 struct stmmac_priv *priv = netdev_priv(dev); 3603 struct stmmac_priv *priv = netdev_priv(dev);
3590 u32 tx_count = priv->plat->tx_queues_to_use;
3591 u32 chan;
3592 3604
3593 /* Clear Tx resources and restart transmitting again */ 3605 stmmac_global_err(priv);
3594 for (chan = 0; chan < tx_count; chan++)
3595 stmmac_tx_err(priv, chan);
3596} 3606}
3597 3607
3598/** 3608/**
@@ -3716,6 +3726,10 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
3716 return IRQ_NONE; 3726 return IRQ_NONE;
3717 } 3727 }
3718 3728
3729 /* Check if adapter is up */
3730 if (test_bit(STMMAC_DOWN, &priv->state))
3731 return IRQ_HANDLED;
3732
3719 /* To handle GMAC own interrupts */ 3733 /* To handle GMAC own interrupts */
3720 if ((priv->plat->has_gmac) || (priv->plat->has_gmac4)) { 3734 if ((priv->plat->has_gmac) || (priv->plat->has_gmac4)) {
3721 int status = priv->hw->mac->host_irq_status(priv->hw, 3735 int status = priv->hw->mac->host_irq_status(priv->hw,
@@ -4051,6 +4065,37 @@ static const struct net_device_ops stmmac_netdev_ops = {
4051 .ndo_set_mac_address = stmmac_set_mac_address, 4065 .ndo_set_mac_address = stmmac_set_mac_address,
4052}; 4066};
4053 4067
4068static void stmmac_reset_subtask(struct stmmac_priv *priv)
4069{
4070 if (!test_and_clear_bit(STMMAC_RESET_REQUESTED, &priv->state))
4071 return;
4072 if (test_bit(STMMAC_DOWN, &priv->state))
4073 return;
4074
4075 netdev_err(priv->dev, "Reset adapter.\n");
4076
4077 rtnl_lock();
4078 netif_trans_update(priv->dev);
4079 while (test_and_set_bit(STMMAC_RESETING, &priv->state))
4080 usleep_range(1000, 2000);
4081
4082 set_bit(STMMAC_DOWN, &priv->state);
4083 dev_close(priv->dev);
4084 dev_open(priv->dev);
4085 clear_bit(STMMAC_DOWN, &priv->state);
4086 clear_bit(STMMAC_RESETING, &priv->state);
4087 rtnl_unlock();
4088}
4089
4090static void stmmac_service_task(struct work_struct *work)
4091{
4092 struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
4093 service_task);
4094
4095 stmmac_reset_subtask(priv);
4096 clear_bit(STMMAC_SERVICE_SCHED, &priv->state);
4097}
4098
4054/** 4099/**
4055 * stmmac_hw_init - Init the MAC device 4100 * stmmac_hw_init - Init the MAC device
4056 * @priv: driver private structure 4101 * @priv: driver private structure
@@ -4212,6 +4257,15 @@ int stmmac_dvr_probe(struct device *device,
4212 /* Verify driver arguments */ 4257 /* Verify driver arguments */
4213 stmmac_verify_args(); 4258 stmmac_verify_args();
4214 4259
4260 /* Allocate workqueue */
4261 priv->wq = create_singlethread_workqueue("stmmac_wq");
4262 if (!priv->wq) {
4263 dev_err(priv->device, "failed to create workqueue\n");
4264 goto error_wq;
4265 }
4266
4267 INIT_WORK(&priv->service_task, stmmac_service_task);
4268
4215 /* Override with kernel parameters if supplied XXX CRS XXX 4269 /* Override with kernel parameters if supplied XXX CRS XXX
4216 * this needs to have multiple instances 4270 * this needs to have multiple instances
4217 */ 4271 */
@@ -4342,6 +4396,8 @@ error_mdio_register:
4342 netif_napi_del(&rx_q->napi); 4396 netif_napi_del(&rx_q->napi);
4343 } 4397 }
4344error_hw_init: 4398error_hw_init:
4399 destroy_workqueue(priv->wq);
4400error_wq:
4345 free_netdev(ndev); 4401 free_netdev(ndev);
4346 4402
4347 return ret; 4403 return ret;
@@ -4374,6 +4430,7 @@ int stmmac_dvr_remove(struct device *dev)
4374 priv->hw->pcs != STMMAC_PCS_TBI && 4430 priv->hw->pcs != STMMAC_PCS_TBI &&
4375 priv->hw->pcs != STMMAC_PCS_RTBI) 4431 priv->hw->pcs != STMMAC_PCS_RTBI)
4376 stmmac_mdio_unregister(ndev); 4432 stmmac_mdio_unregister(ndev);
4433 destroy_workqueue(priv->wq);
4377 free_netdev(ndev); 4434 free_netdev(ndev);
4378 4435
4379 return 0; 4436 return 0;