Skip to content

Commit 3b0d190

Browse files
committed
Merge branch 'nps_enet-fixes'
Elad Kanfi says: ==================== nps_enet: Net driver bugs fix v3: tx_packet_sent flag is not necessary, use socket buffer pointer instead. Use wmb() instead of smp_wmb(). v2: Remove code style commit for now. Code style commit will be added after the bugs fix will be approved. Summary: 1. Bug description: TX done interrupts that arrives while interrupts are masked, during NAPI poll, will not trigger an interrupt handling. Since TX interrupt is of level edge we will lose the TX done interrupt. As a result all pending tx frames will get no service. Solution: Check if there is a pending tx request after unmasking the interrupt and if answer is yes then re-add ourselves to the NAPI poll list. 2. Bug description: CPU-A before sending a frame will set a variable to true. CPU-B that executes the tx done interrupt service routine might read a non valid value of that variable. Solution: Use the socket buffer pointer instead of the variable, and add a write memory barrier at the tx sending function after the pointer is set. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents d99079e + 05c00d8 commit 3b0d190

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

drivers/net/ethernet/ezchip/nps_enet.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static void nps_enet_tx_handler(struct net_device *ndev)
145145
u32 tx_ctrl_nt = (tx_ctrl_value & TX_CTL_NT_MASK) >> TX_CTL_NT_SHIFT;
146146

147147
/* Check if we got TX */
148-
if (!priv->tx_packet_sent || tx_ctrl_ct)
148+
if (!priv->tx_skb || tx_ctrl_ct)
149149
return;
150150

151151
/* Ack Tx ctrl register */
@@ -160,7 +160,7 @@ static void nps_enet_tx_handler(struct net_device *ndev)
160160
}
161161

162162
dev_kfree_skb(priv->tx_skb);
163-
priv->tx_packet_sent = false;
163+
priv->tx_skb = NULL;
164164

165165
if (netif_queue_stopped(ndev))
166166
netif_wake_queue(ndev);
@@ -183,6 +183,9 @@ static int nps_enet_poll(struct napi_struct *napi, int budget)
183183
work_done = nps_enet_rx_handler(ndev);
184184
if (work_done < budget) {
185185
u32 buf_int_enable_value = 0;
186+
u32 tx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
187+
u32 tx_ctrl_ct =
188+
(tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT;
186189

187190
napi_complete(napi);
188191

@@ -192,6 +195,18 @@ static int nps_enet_poll(struct napi_struct *napi, int budget)
192195

193196
nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
194197
buf_int_enable_value);
198+
199+
/* in case we will get a tx interrupt while interrupts
200+
* are masked, we will lose it since the tx is edge interrupt.
201+
* specifically, while executing the code section above,
202+
* between nps_enet_tx_handler and the interrupts enable, all
203+
* tx requests will be stuck until we will get an rx interrupt.
204+
* the two code lines below will solve this situation by
205+
* re-adding ourselves to the poll list.
206+
*/
207+
208+
if (priv->tx_skb && !tx_ctrl_ct)
209+
napi_reschedule(napi);
195210
}
196211

197212
return work_done;
@@ -217,7 +232,7 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
217232
u32 tx_ctrl_ct = (tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT;
218233
u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT;
219234

220-
if ((!tx_ctrl_ct && priv->tx_packet_sent) || rx_ctrl_cr)
235+
if ((!tx_ctrl_ct && priv->tx_skb) || rx_ctrl_cr)
221236
if (likely(napi_schedule_prep(&priv->napi))) {
222237
nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
223238
__napi_schedule(&priv->napi);
@@ -387,8 +402,6 @@ static void nps_enet_send_frame(struct net_device *ndev,
387402
/* Write the length of the Frame */
388403
tx_ctrl_value |= length << TX_CTL_NT_SHIFT;
389404

390-
/* Indicate SW is done */
391-
priv->tx_packet_sent = true;
392405
tx_ctrl_value |= NPS_ENET_ENABLE << TX_CTL_CT_SHIFT;
393406
/* Send Frame */
394407
nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl_value);
@@ -465,7 +478,7 @@ static s32 nps_enet_open(struct net_device *ndev)
465478
s32 err;
466479

467480
/* Reset private variables */
468-
priv->tx_packet_sent = false;
481+
priv->tx_skb = NULL;
469482
priv->ge_mac_cfg_2_value = 0;
470483
priv->ge_mac_cfg_3_value = 0;
471484

@@ -534,6 +547,11 @@ static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb,
534547

535548
priv->tx_skb = skb;
536549

550+
/* make sure tx_skb is actually written to the memory
551+
* before the HW is informed and the IRQ is fired.
552+
*/
553+
wmb();
554+
537555
nps_enet_send_frame(ndev, skb);
538556

539557
return NETDEV_TX_OK;

drivers/net/ethernet/ezchip/nps_enet.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,12 @@
165165
* struct nps_enet_priv - Storage of ENET's private information.
166166
* @regs_base: Base address of ENET memory-mapped control registers.
167167
* @irq: For RX/TX IRQ number.
168-
* @tx_packet_sent: SW indication if frame is being sent.
169168
* @tx_skb: socket buffer of sent frame.
170169
* @napi: Structure for NAPI.
171170
*/
172171
struct nps_enet_priv {
173172
void __iomem *regs_base;
174173
s32 irq;
175-
bool tx_packet_sent;
176174
struct sk_buff *tx_skb;
177175
struct napi_struct napi;
178176
u32 ge_mac_cfg_2_value;

0 commit comments

Comments
 (0)