kernel: remove kmod packages for bridge, stp, llc and 8021q
[oweals/openwrt.git] / target / linux / mvebu / patches-4.4 / 042-net-mvneta-Fix-race-condition-during-stopping.patch
1 From: Gregory CLEMENT <gregory.clement@free-electrons.com>
2 Date: Thu, 4 Feb 2016 22:09:29 +0100
3 Subject: [PATCH] net: mvneta: Fix race condition during stopping
4
5 When stopping the port, the CPU notifier are still there whereas the
6 mvneta_stop_dev function calls mvneta_percpu_disable() on each CPUs.
7 It was possible to have a new CPU coming at this point which could be
8 racy.
9
10 This patch adds a flag preventing executing the code notifier for a new
11 CPU when the port is stopping. It also uses the spinlock introduces
12 previously. To avoid the deadlock, the lock has been moved outside the
13 mvneta_percpu_elect function.
14
15 Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
16 Signed-off-by: David S. Miller <davem@davemloft.net>
17 ---
18
19 --- a/drivers/net/ethernet/marvell/mvneta.c
20 +++ b/drivers/net/ethernet/marvell/mvneta.c
21 @@ -374,6 +374,7 @@ struct mvneta_port {
22          * ensuring that the configuration remains coherent.
23          */
24         spinlock_t lock;
25 +       bool is_stopped;
26  
27         /* Core clock */
28         struct clk *clk;
29 @@ -2853,16 +2854,14 @@ static void mvneta_percpu_disable(void *
30         disable_percpu_irq(pp->dev->irq);
31  }
32  
33 +/* Electing a CPU must be done in an atomic way: it should be done
34 + * after or before the removal/insertion of a CPU and this function is
35 + * not reentrant.
36 + */
37  static void mvneta_percpu_elect(struct mvneta_port *pp)
38  {
39         int elected_cpu = 0, max_cpu, cpu, i = 0;
40  
41 -       /* Electing a CPU must be done in an atomic way: it should be
42 -        * done after or before the removal/insertion of a CPU and
43 -        * this function is not reentrant.
44 -        */
45 -       spin_lock(&pp->lock);
46 -
47         /* Use the cpu associated to the rxq when it is online, in all
48          * the other cases, use the cpu 0 which can't be offline.
49          */
50 @@ -2906,7 +2905,6 @@ static void mvneta_percpu_elect(struct m
51                 i++;
52  
53         }
54 -       spin_unlock(&pp->lock);
55  };
56  
57  static int mvneta_percpu_notifier(struct notifier_block *nfb,
58 @@ -2920,6 +2918,14 @@ static int mvneta_percpu_notifier(struct
59         switch (action) {
60         case CPU_ONLINE:
61         case CPU_ONLINE_FROZEN:
62 +               spin_lock(&pp->lock);
63 +               /* Configuring the driver for a new CPU while the
64 +                * driver is stopping is racy, so just avoid it.
65 +                */
66 +               if (pp->is_stopped) {
67 +                       spin_unlock(&pp->lock);
68 +                       break;
69 +               }
70                 netif_tx_stop_all_queues(pp->dev);
71  
72                 /* We have to synchronise on tha napi of each CPU
73 @@ -2957,6 +2963,7 @@ static int mvneta_percpu_notifier(struct
74                         MVNETA_CAUSE_LINK_CHANGE |
75                         MVNETA_CAUSE_PSC_SYNC_CHANGE);
76                 netif_tx_start_all_queues(pp->dev);
77 +               spin_unlock(&pp->lock);
78                 break;
79         case CPU_DOWN_PREPARE:
80         case CPU_DOWN_PREPARE_FROZEN:
81 @@ -2981,7 +2988,9 @@ static int mvneta_percpu_notifier(struct
82         case CPU_DEAD:
83         case CPU_DEAD_FROZEN:
84                 /* Check if a new CPU must be elected now this on is down */
85 +               spin_lock(&pp->lock);
86                 mvneta_percpu_elect(pp);
87 +               spin_unlock(&pp->lock);
88                 /* Unmask all ethernet port interrupts */
89                 on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
90                 mvreg_write(pp, MVNETA_INTR_MISC_MASK,
91 @@ -3033,7 +3042,7 @@ static int mvneta_open(struct net_device
92          */
93         on_each_cpu(mvneta_percpu_enable, pp, true);
94  
95 -
96 +       pp->is_stopped = false;
97         /* Register a CPU notifier to handle the case where our CPU
98          * might be taken offline.
99          */
100 @@ -3066,9 +3075,18 @@ static int mvneta_stop(struct net_device
101  {
102         struct mvneta_port *pp = netdev_priv(dev);
103  
104 +       /* Inform that we are stopping so we don't want to setup the
105 +        * driver for new CPUs in the notifiers
106 +        */
107 +       spin_lock(&pp->lock);
108 +       pp->is_stopped = true;
109         mvneta_stop_dev(pp);
110         mvneta_mdio_remove(pp);
111         unregister_cpu_notifier(&pp->cpu_notifier);
112 +       /* Now that the notifier are unregistered, we can release le
113 +        * lock
114 +        */
115 +       spin_unlock(&pp->lock);
116         on_each_cpu(mvneta_percpu_disable, pp, true);
117         free_percpu_irq(dev->irq, pp->ports);
118         mvneta_cleanup_rxqs(pp);
119 @@ -3339,7 +3357,9 @@ static int  mvneta_config_rss(struct mvn
120         mvreg_write(pp, MVNETA_PORT_CONFIG, val);
121  
122         /* Update the elected CPU matching the new rxq_def */
123 +       spin_lock(&pp->lock);
124         mvneta_percpu_elect(pp);
125 +       spin_unlock(&pp->lock);
126  
127         /* We have to synchronise on the napi of each CPU */
128         for_each_online_cpu(cpu) {