Skip to content

Commit e5df49d

Browse files
Elad Kanfidavem330
authored andcommitted
net: nps_enet: Tx handler synchronization
Below is a description of a possible problematic sequence. CPU-A is sending a frame and CPU-B handles the interrupt that indicates the frame was sent. CPU-B reads an invalid value of tx_packet_sent. CPU-A CPU-B ----- ----- nps_enet_send_frame . . tx_skb = skb tx_packet_sent = true order HW to start tx . . HW complete tx ------> get tx complete interrupt . . if(tx_packet_sent == true) handle tx_skb end memory transaction (tx_packet_sent actually written) Furthermore there is a dependency between tx_skb and tx_packet_sent. There is no assurance that tx_skb contains a valid pointer at CPU B when it sees tx_packet_sent == true. Solution: Initialize tx_skb to NULL and use it to indicate that packet was sent, in this way tx_packet_sent can be removed. Add a write memory barrier after setting tx_skb in order to make sure that it is valid before HW is informed and IRQ is fired. Fixed sequence will be: CPU-A CPU-B ----- ----- tx_skb = skb wmb() . . order HW to start tx . . HW complete tx ------> get tx complete interrupt . . if(tx_skb != NULL) handle tx_skb tx_skb = NULL Signed-off-by: Elad Kanfi <[email protected]> Acked-by: Noam Camus <[email protected]> Acked-by: Gilad Ben-Yossef <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d99079e commit e5df49d

File tree

2 files changed

+9
-8
lines changed

2 files changed

+9
-8
lines changed

drivers/net/ethernet/ezchip/nps_enet.c

Lines changed: 9 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);
@@ -217,7 +217,7 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
217217
u32 tx_ctrl_ct = (tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT;
218218
u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT;
219219

220-
if ((!tx_ctrl_ct && priv->tx_packet_sent) || rx_ctrl_cr)
220+
if ((!tx_ctrl_ct && priv->tx_skb) || rx_ctrl_cr)
221221
if (likely(napi_schedule_prep(&priv->napi))) {
222222
nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
223223
__napi_schedule(&priv->napi);
@@ -387,8 +387,6 @@ static void nps_enet_send_frame(struct net_device *ndev,
387387
/* Write the length of the Frame */
388388
tx_ctrl_value |= length << TX_CTL_NT_SHIFT;
389389

390-
/* Indicate SW is done */
391-
priv->tx_packet_sent = true;
392390
tx_ctrl_value |= NPS_ENET_ENABLE << TX_CTL_CT_SHIFT;
393391
/* Send Frame */
394392
nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl_value);
@@ -465,7 +463,7 @@ static s32 nps_enet_open(struct net_device *ndev)
465463
s32 err;
466464

467465
/* Reset private variables */
468-
priv->tx_packet_sent = false;
466+
priv->tx_skb = NULL;
469467
priv->ge_mac_cfg_2_value = 0;
470468
priv->ge_mac_cfg_3_value = 0;
471469

@@ -534,6 +532,11 @@ static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb,
534532

535533
priv->tx_skb = skb;
536534

535+
/* make sure tx_skb is actually written to the memory
536+
* before the HW is informed and the IRQ is fired.
537+
*/
538+
wmb();
539+
537540
nps_enet_send_frame(ndev, skb);
538541

539542
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)