net: nps_enet: Tx handler synchronization
authorElad Kanfi <eladkan@mellanox.com>
Mon, 9 May 2016 17:13:19 +0000 (20:13 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 10 May 2016 19:04:49 +0000 (15:04 -0400)
commite5df49d564fe993c68f5cff6d96972a6358b4958
tree899ce25dfc99e15b7454b845a894dabfd4e3d1dd
parentd99079e2fbd5ac38884f498ca99435d525152a88
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 <eladkan@mellanox.com>
Acked-by: Noam Camus <noamca@mellanox.com>
Acked-by: Gilad Ben-Yossef <giladby@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ezchip/nps_enet.c
drivers/net/ethernet/ezchip/nps_enet.h