Skip to content

Commit 34877a1

Browse files
joabreudavem330
authored andcommitted
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 <[email protected]> Cc: David S. Miller <[email protected]> Cc: Joao Pinto <[email protected]> Cc: Giuseppe Cavallaro <[email protected]> Cc: Alexandre Torgue <[email protected]> Cc: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 02281a3 commit 34877a1

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

drivers/net/ethernet/stmicro/stmmac/stmmac.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,17 @@ struct stmmac_priv {
145145
struct dentry *dbgfs_rings_status;
146146
struct dentry *dbgfs_dma_cap;
147147
#endif
148+
149+
unsigned long state;
150+
struct workqueue_struct *wq;
151+
struct work_struct service_task;
152+
};
153+
154+
enum stmmac_state {
155+
STMMAC_DOWN,
156+
STMMAC_RESET_REQUESTED,
157+
STMMAC_RESETING,
158+
STMMAC_SERVICE_SCHED,
148159
};
149160

150161
int stmmac_mdio_unregister(struct net_device *ndev);

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,20 @@ static void stmmac_start_all_queues(struct stmmac_priv *priv)
196196
netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue));
197197
}
198198

199+
static 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+
206+
static 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+
199213
/**
200214
* stmmac_clk_csr_set - dynamically set the MDC clock
201215
* @priv: driver private structure
@@ -3587,12 +3601,8 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
35873601
static void stmmac_tx_timeout(struct net_device *dev)
35883602
{
35893603
struct stmmac_priv *priv = netdev_priv(dev);
3590-
u32 tx_count = priv->plat->tx_queues_to_use;
3591-
u32 chan;
35923604

3593-
/* Clear Tx resources and restart transmitting again */
3594-
for (chan = 0; chan < tx_count; chan++)
3595-
stmmac_tx_err(priv, chan);
3605+
stmmac_global_err(priv);
35963606
}
35973607

35983608
/**
@@ -3716,6 +3726,10 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
37163726
return IRQ_NONE;
37173727
}
37183728

3729+
/* Check if adapter is up */
3730+
if (test_bit(STMMAC_DOWN, &priv->state))
3731+
return IRQ_HANDLED;
3732+
37193733
/* To handle GMAC own interrupts */
37203734
if ((priv->plat->has_gmac) || (priv->plat->has_gmac4)) {
37213735
int status = priv->hw->mac->host_irq_status(priv->hw,
@@ -4051,6 +4065,37 @@ static const struct net_device_ops stmmac_netdev_ops = {
40514065
.ndo_set_mac_address = stmmac_set_mac_address,
40524066
};
40534067

4068+
static 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+
4090+
static 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+
40544099
/**
40554100
* stmmac_hw_init - Init the MAC device
40564101
* @priv: driver private structure
@@ -4212,6 +4257,15 @@ int stmmac_dvr_probe(struct device *device,
42124257
/* Verify driver arguments */
42134258
stmmac_verify_args();
42144259

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+
42154269
/* Override with kernel parameters if supplied XXX CRS XXX
42164270
* this needs to have multiple instances
42174271
*/
@@ -4342,6 +4396,8 @@ int stmmac_dvr_probe(struct device *device,
43424396
netif_napi_del(&rx_q->napi);
43434397
}
43444398
error_hw_init:
4399+
destroy_workqueue(priv->wq);
4400+
error_wq:
43454401
free_netdev(ndev);
43464402

43474403
return ret;
@@ -4374,6 +4430,7 @@ int stmmac_dvr_remove(struct device *dev)
43744430
priv->hw->pcs != STMMAC_PCS_TBI &&
43754431
priv->hw->pcs != STMMAC_PCS_RTBI)
43764432
stmmac_mdio_unregister(ndev);
4433+
destroy_workqueue(priv->wq);
43774434
free_netdev(ndev);
43784435

43794436
return 0;

0 commit comments

Comments
 (0)