Add layer to support Jailhouse hypervisor
[AGL/meta-agl-devel.git] / meta-agl-jailhouse / recipes-kernel / linux / linux / 0015-ivshmem-net-fix-race-in-state-machine.patch
1 From 1349a457e5e33580fb26afab087e6b932b1a4372 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 15/32] ivshmem-net: fix race in state machine
5
6 ---
7  drivers/net/ivshmem-net.c | 60 ++++++++++++++++++++++++-----------------------
8  1 file changed, 31 insertions(+), 29 deletions(-)
9
10 diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
11 index a535cb71adde..acd00e47acd7 100644
12 --- a/drivers/net/ivshmem-net.c
13 +++ b/drivers/net/ivshmem-net.c
14 @@ -36,6 +36,8 @@
15  #define IVSHM_NET_STATE_READY  2
16  #define IVSHM_NET_STATE_RUN    3
17  
18 +#define IVSHM_NET_FLAG_RUN     0
19 +
20  #define IVSHM_NET_MTU_MIN 256
21  #define IVSHM_NET_MTU_MAX 65535
22  #define IVSHM_NET_MTU_DEF 16384
23 @@ -96,6 +98,8 @@ struct ivshm_net {
24         u32 lstate;
25         u32 rstate;
26  
27 +       unsigned long flags;
28 +
29         struct workqueue_struct *state_wq;
30         struct work_struct state_work;
31  
32 @@ -529,12 +533,32 @@ static void ivshm_net_run(struct net_device *ndev)
33  {
34         struct ivshm_net *in = netdev_priv(ndev);
35  
36 +       if (in->lstate < IVSHM_NET_STATE_READY)
37 +               return;
38 +
39 +       if (!netif_running(ndev))
40 +               return;
41 +
42 +       if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
43 +               return;
44 +
45         netif_start_queue(ndev);
46         napi_enable(&in->napi);
47         napi_schedule(&in->napi);
48         ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
49  }
50  
51 +static void ivshm_net_do_stop(struct net_device *ndev)
52 +{
53 +       struct ivshm_net *in = netdev_priv(ndev);
54 +
55 +       if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
56 +               return;
57 +
58 +       netif_stop_queue(ndev);
59 +       napi_disable(&in->napi);
60 +}
61 +
62  static void ivshm_net_state_change(struct work_struct *work)
63  {
64         struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
65 @@ -560,21 +584,13 @@ static void ivshm_net_state_change(struct work_struct *work)
66                 break;
67  
68         case IVSHM_NET_STATE_READY:
69 +       case IVSHM_NET_STATE_RUN:
70                 if (rstate >= IVSHM_NET_STATE_READY) {
71                         netif_carrier_on(ndev);
72 -                       if (ndev->flags & IFF_UP)
73 -                               ivshm_net_run(ndev);
74 +                       ivshm_net_run(ndev);
75                 } else {
76                         netif_carrier_off(ndev);
77 -                       ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
78 -               }
79 -               break;
80 -
81 -       case IVSHM_NET_STATE_RUN:
82 -               if (rstate < IVSHM_NET_STATE_READY) {
83 -                       netif_stop_queue(ndev);
84 -                       napi_disable(&in->napi);
85 -                       netif_carrier_off(ndev);
86 +                       ivshm_net_do_stop(ndev);
87                         ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
88                 }
89                 break;
90 @@ -584,18 +600,13 @@ static void ivshm_net_state_change(struct work_struct *work)
91         WRITE_ONCE(in->rstate, rstate);
92  }
93  
94 -static bool ivshm_net_check_state(struct net_device *ndev)
95 +static void ivshm_net_check_state(struct net_device *ndev)
96  {
97         struct ivshm_net *in = netdev_priv(ndev);
98         u32 rstate = readl(&in->ivshm_regs->rstate);
99  
100 -       if (rstate != READ_ONCE(in->rstate) ||
101 -           in->lstate != IVSHM_NET_STATE_RUN) {
102 +       if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
103                 queue_work(in->state_wq, &in->state_work);
104 -               return false;
105 -       }
106 -
107 -       return true;
108  }
109  
110  static irqreturn_t ivshm_net_int(int irq, void *data)
111 @@ -617,24 +628,15 @@ static int ivshm_net_open(struct net_device *ndev)
112  
113         netdev_reset_queue(ndev);
114         ndev->operstate = IF_OPER_UP;
115 -
116 -       if (in->lstate == IVSHM_NET_STATE_READY)
117 -               ivshm_net_run(ndev);
118 +       ivshm_net_run(ndev);
119  
120         return 0;
121  }
122  
123  static int ivshm_net_stop(struct net_device *ndev)
124  {
125 -       struct ivshm_net *in = netdev_priv(ndev);
126 -
127         ndev->operstate = IF_OPER_DOWN;
128 -
129 -       if (in->lstate == IVSHM_NET_STATE_RUN) {
130 -               napi_disable(&in->napi);
131 -               netif_stop_queue(ndev);
132 -               ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
133 -       }
134 +       ivshm_net_do_stop(ndev);
135  
136         return 0;
137  }
138 -- 
139 2.11.0
140