ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 809-jailhouse-0003-ivshmem-net-fix-race-in-state-machine.patch
1 From 0af5d7d021bb899d9c3880415267e178a20fb7a9 Mon Sep 17 00:00:00 2001
2 From: Mans Rullgard <mans@mansr.com>
3 Date: Thu, 24 Nov 2016 18:46:41 +0000
4 Subject: [PATCH] ivshmem-net: fix race in state machine
5
6 (cherry picked from commit 5d663baed6a89d09bae4446f6509f9957c780bc7)
7 ---
8  drivers/net/ivshmem-net.c | 60 ++++++++++++++++++++++++-----------------------
9  1 file changed, 31 insertions(+), 29 deletions(-)
10
11 --- a/drivers/net/ivshmem-net.c
12 +++ b/drivers/net/ivshmem-net.c
13 @@ -36,6 +36,8 @@
14  #define IVSHM_NET_STATE_READY  2
15  #define IVSHM_NET_STATE_RUN    3
16  
17 +#define IVSHM_NET_FLAG_RUN     0
18 +
19  #define IVSHM_NET_MTU_MIN 256
20  #define IVSHM_NET_MTU_MAX 65535
21  #define IVSHM_NET_MTU_DEF 16384
22 @@ -96,6 +98,8 @@ struct ivshm_net {
23         u32 lstate;
24         u32 rstate;
25  
26 +       unsigned long flags;
27 +
28         struct workqueue_struct *state_wq;
29         struct work_struct state_work;
30  
31 @@ -529,12 +533,32 @@ static void ivshm_net_run(struct net_dev
32  {
33         struct ivshm_net *in = netdev_priv(ndev);
34  
35 +       if (in->lstate < IVSHM_NET_STATE_READY)
36 +               return;
37 +
38 +       if (!netif_running(ndev))
39 +               return;
40 +
41 +       if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
42 +               return;
43 +
44         netif_start_queue(ndev);
45         napi_enable(&in->napi);
46         napi_schedule(&in->napi);
47         ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
48  }
49  
50 +static void ivshm_net_do_stop(struct net_device *ndev)
51 +{
52 +       struct ivshm_net *in = netdev_priv(ndev);
53 +
54 +       if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
55 +               return;
56 +
57 +       netif_stop_queue(ndev);
58 +       napi_disable(&in->napi);
59 +}
60 +
61  static void ivshm_net_state_change(struct work_struct *work)
62  {
63         struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
64 @@ -560,21 +584,13 @@ static void ivshm_net_state_change(struc
65                 break;
66  
67         case IVSHM_NET_STATE_READY:
68 +       case IVSHM_NET_STATE_RUN:
69                 if (rstate >= IVSHM_NET_STATE_READY) {
70                         netif_carrier_on(ndev);
71 -                       if (ndev->flags & IFF_UP)
72 -                               ivshm_net_run(ndev);
73 +                       ivshm_net_run(ndev);
74                 } else {
75                         netif_carrier_off(ndev);
76 -                       ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
77 -               }
78 -               break;
79 -
80 -       case IVSHM_NET_STATE_RUN:
81 -               if (rstate < IVSHM_NET_STATE_READY) {
82 -                       netif_stop_queue(ndev);
83 -                       napi_disable(&in->napi);
84 -                       netif_carrier_off(ndev);
85 +                       ivshm_net_do_stop(ndev);
86                         ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
87                 }
88                 break;
89 @@ -584,18 +600,13 @@ static void ivshm_net_state_change(struc
90         WRITE_ONCE(in->rstate, rstate);
91  }
92  
93 -static bool ivshm_net_check_state(struct net_device *ndev)
94 +static void ivshm_net_check_state(struct net_device *ndev)
95  {
96         struct ivshm_net *in = netdev_priv(ndev);
97         u32 rstate = readl(&in->ivshm_regs->rstate);
98  
99 -       if (rstate != READ_ONCE(in->rstate) ||
100 -           in->lstate != IVSHM_NET_STATE_RUN) {
101 +       if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
102                 queue_work(in->state_wq, &in->state_work);
103 -               return false;
104 -       }
105 -
106 -       return true;
107  }
108  
109  static irqreturn_t ivshm_net_int(int irq, void *data)
110 @@ -617,24 +628,15 @@ static int ivshm_net_open(struct net_dev
111  
112         netdev_reset_queue(ndev);
113         ndev->operstate = IF_OPER_UP;
114 -
115 -       if (in->lstate == IVSHM_NET_STATE_READY)
116 -               ivshm_net_run(ndev);
117 +       ivshm_net_run(ndev);
118  
119         return 0;
120  }
121  
122  static int ivshm_net_stop(struct net_device *ndev)
123  {
124 -       struct ivshm_net *in = netdev_priv(ndev);
125 -
126         ndev->operstate = IF_OPER_DOWN;
127 -
128 -       if (in->lstate == IVSHM_NET_STATE_RUN) {
129 -               napi_disable(&in->napi);
130 -               netif_stop_queue(ndev);
131 -               ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
132 -       }
133 +       ivshm_net_do_stop(ndev);
134  
135         return 0;
136  }