blob: ae6f8390111073994c7d40ac2100409daed83b24 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 0af5d7d021bb899d9c3880415267e178a20fb7a9 Mon Sep 17 00:00:00 2001
2From: Mans Rullgard <mans@mansr.com>
3Date: Thu, 24 Nov 2016 18:46:41 +0000
4Subject: [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 }