Skip to content

Commit a7c6a4c

Browse files
committed
drivers: eth_nxp_enet_qos: Fix deadlock in system workqueue
There was a deadlock occurring, exposed by http server sample because of situations like this caused by tx done work being blocked in deadlock: 1) The TX would be started by some thread and the driver TX sem would be taken. 2) The http server socket would get scheduled on the system workqueue to send something, claim the network TX interface mutex, and be blocked taking the semaphore. 3) The RX traffic class handler would get blocked trying to claim the network interface TX mutex, while trying to send an ACK in the TCP callback. This means the RX packets would not be processed. 4) Lots of RX unable to allocate packets errors would happen, and all RX would be dropped. This was the main symptom of the deadlock, which made it look like a memory leak but actually had nothing to do with the RX code nor any memory leak. 5) The TX DMA would finish and schedule the TX DMA done work onto the system work queue, behind the http server socket which is blocked on the waiting for the driver TX semaphore. 6) If the TX DMA done work would have ran, that's what gives the TX driver semaphore. So this is the reason for the deadlock of all these different threads and work items, the misqueue in the system workqueue. Fix by just calling the TX DMA done code directly from the ISR, it should be ISR safe, and really not a lot of code to execute, just freeing some net buffers and the packet and updating the stats. An optimization can be made later if needed, but for now, solving the deadlock is a more urgent priority. Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
1 parent 8cdf393 commit a7c6a4c

File tree

2 files changed

+6
-10
lines changed

2 files changed

+6
-10
lines changed

drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static int eth_nxp_enet_qos_tx(const struct device *dev, struct net_pkt *pkt)
9292

9393
/* One TX at a time in the current implementation */
9494
k_sem_take(&data->tx.tx_sem, K_FOREVER);
95+
LOG_DBG("Took driver TX sem %p by thread %p", &data->tx.tx_sem, k_current_get());
9596

9697
net_pkt_ref(pkt);
9798

@@ -141,12 +142,10 @@ static int eth_nxp_enet_qos_tx(const struct device *dev, struct net_pkt *pkt)
141142
return 0;
142143
}
143144

144-
static void tx_dma_done(struct k_work *work)
145+
static void tx_dma_done(const struct device *dev)
145146
{
146-
struct nxp_enet_qos_tx_data *tx_data =
147-
CONTAINER_OF(work, struct nxp_enet_qos_tx_data, tx_done_work);
148-
struct nxp_enet_qos_mac_data *data =
149-
CONTAINER_OF(tx_data, struct nxp_enet_qos_mac_data, tx);
147+
struct nxp_enet_qos_mac_data *data = dev->data;
148+
struct nxp_enet_qos_tx_data *tx_data = &data->tx;
150149
struct net_pkt *pkt = tx_data->pkt;
151150
struct net_buf *fragment = pkt->frags;
152151

@@ -165,6 +164,7 @@ static void tx_dma_done(struct k_work *work)
165164

166165
/* Allows another send */
167166
k_sem_give(&data->tx.tx_sem);
167+
LOG_DBG("Gave driver TX sem %p by thread %p", &data->tx.tx_sem, k_current_get());
168168
}
169169

170170
static enum ethernet_hw_caps eth_nxp_enet_qos_get_capabilities(const struct device *dev)
@@ -474,7 +474,7 @@ static void eth_nxp_enet_qos_mac_isr(const struct device *dev)
474474
if (ENET_QOS_REG_GET(DMA_INTERRUPT_STATUS, DC0IS, dma_interrupts)) {
475475
if (ENET_QOS_REG_GET(DMA_CH_DMA_CHX_STAT, TI, dma_ch0_interrupts)) {
476476
/* add pending tx to queue */
477-
k_work_submit(&data->tx.tx_done_work);
477+
tx_dma_done(dev);
478478
}
479479

480480
if (ENET_QOS_REG_GET(DMA_CH_DMA_CHX_STAT, RI, dma_ch0_interrupts)) {
@@ -842,9 +842,6 @@ static int eth_nxp_enet_qos_mac_init(const struct device *dev)
842842
/* Work upon a reception of a packet to a buffer */
843843
k_work_init(&data->rx.rx_work, eth_nxp_enet_qos_rx);
844844

845-
/* Work upon a complete transmission by a channel's TX DMA */
846-
k_work_init(&data->tx.tx_done_work, tx_dma_done);
847-
848845
return ret;
849846
}
850847

drivers/ethernet/eth_nxp_enet_qos/nxp_enet_qos_priv.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ struct nxp_enet_qos_mac_config {
106106
struct nxp_enet_qos_tx_data {
107107
struct k_sem tx_sem;
108108
struct net_pkt *pkt;
109-
struct k_work tx_done_work;
110109
struct net_buf *tx_header;
111110
volatile union nxp_enet_qos_tx_desc descriptors[NUM_TX_BUFDESC];
112111
};

0 commit comments

Comments
 (0)