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
6 (cherry picked from commit 5d663baed6a89d09bae4446f6509f9957c780bc7)
8 drivers/net/ivshmem-net.c | 60 ++++++++++++++++++++++++-----------------------
9 1 file changed, 31 insertions(+), 29 deletions(-)
11 --- a/drivers/net/ivshmem-net.c
12 +++ b/drivers/net/ivshmem-net.c
14 #define IVSHM_NET_STATE_READY 2
15 #define IVSHM_NET_STATE_RUN 3
17 +#define IVSHM_NET_FLAG_RUN 0
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 {
26 + unsigned long flags;
28 struct workqueue_struct *state_wq;
29 struct work_struct state_work;
31 @@ -529,12 +533,32 @@ static void ivshm_net_run(struct net_dev
33 struct ivshm_net *in = netdev_priv(ndev);
35 + if (in->lstate < IVSHM_NET_STATE_READY)
38 + if (!netif_running(ndev))
41 + if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
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);
50 +static void ivshm_net_do_stop(struct net_device *ndev)
52 + struct ivshm_net *in = netdev_priv(ndev);
54 + if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
57 + netif_stop_queue(ndev);
58 + napi_disable(&in->napi);
61 static void ivshm_net_state_change(struct work_struct *work)
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
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);
75 netif_carrier_off(ndev);
76 - ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
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);
89 @@ -584,18 +600,13 @@ static void ivshm_net_state_change(struc
90 WRITE_ONCE(in->rstate, rstate);
93 -static bool ivshm_net_check_state(struct net_device *ndev)
94 +static void ivshm_net_check_state(struct net_device *ndev)
96 struct ivshm_net *in = netdev_priv(ndev);
97 u32 rstate = readl(&in->ivshm_regs->rstate);
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);
109 static irqreturn_t ivshm_net_int(int irq, void *data)
110 @@ -617,24 +628,15 @@ static int ivshm_net_open(struct net_dev
112 netdev_reset_queue(ndev);
113 ndev->operstate = IF_OPER_UP;
115 - if (in->lstate == IVSHM_NET_STATE_READY)
116 - ivshm_net_run(ndev);
117 + ivshm_net_run(ndev);
122 static int ivshm_net_stop(struct net_device *ndev)
124 - struct ivshm_net *in = netdev_priv(ndev);
126 ndev->operstate = IF_OPER_DOWN;
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);
133 + ivshm_net_do_stop(ndev);