* [PATCH net 0/6] mvneta fixes for SMP @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel Hi, Following this bug report: http://thread.gmane.org/gmane.linux.ports.arm.kernel/468173 and the suggestions from Russell King, I reviewed all the code involving multi-CPU. It ended with this series of patches which should improve the stability of the driver. The first patch fix a real bug, the other fix potential issues in the driver. Thanks, Gregory Gregory CLEMENT (6): net: mvneta: Fix for_each_present_cpu usage net: mvneta: Use on_each_cpu when possible net: mvneta: Remove unused code net: mvneta: Modify the queue related fields from each cpu net: mvneta: The mvneta_percpu_elect function should be atomic net: mvneta: Fix race condition during stopping drivers/net/ethernet/marvell/mvneta.c | 160 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 78 deletions(-) -- 2.5.0 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net 0/6] mvneta fixes for SMP @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau Hi, Following this bug report: http://thread.gmane.org/gmane.linux.ports.arm.kernel/468173 and the suggestions from Russell King, I reviewed all the code involving multi-CPU. It ended with this series of patches which should improve the stability of the driver. The first patch fix a real bug, the other fix potential issues in the driver. Thanks, Gregory Gregory CLEMENT (6): net: mvneta: Fix for_each_present_cpu usage net: mvneta: Use on_each_cpu when possible net: mvneta: Remove unused code net: mvneta: Modify the queue related fields from each cpu net: mvneta: The mvneta_percpu_elect function should be atomic net: mvneta: Fix race condition during stopping drivers/net/ethernet/marvell/mvneta.c | 160 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 78 deletions(-) -- 2.5.0 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net 1/6] net: mvneta: Fix for_each_present_cpu usage 2016-01-29 16:26 ` Gregory CLEMENT @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel This patch convert the for_each_present in on_each_cpu, instead of applying on the present cpus it will be applied only on the online cpus. This fix a bug reported on http://thread.gmane.org/gmane.linux.ports.arm.kernel/468173. Using the macro on_each_cpu (instead of a for_each_* loop) also ensures that all the calls will be done all at once. Fixes: f86428854480 ("net: mvneta: Statically assign queues to CPUs") Reported-by: Stefan Roese <stefan.roese@gmail.com> Suggested-by: Jisheng Zhang <jszhang@marvell.com> Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 662c2ee268c7..90ff5c7e19ea 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2564,7 +2564,7 @@ static void mvneta_start_dev(struct mvneta_port *pp) mvneta_port_enable(pp); /* Enable polling on the port */ - for_each_present_cpu(cpu) { + for_each_online_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_enable(&port->napi); @@ -2589,7 +2589,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp) phy_stop(pp->phy_dev); - for_each_present_cpu(cpu) { + for_each_online_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_disable(&port->napi); @@ -3057,13 +3057,11 @@ err_cleanup_rxqs: static int mvneta_stop(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); - int cpu; mvneta_stop_dev(pp); mvneta_mdio_remove(pp); unregister_cpu_notifier(&pp->cpu_notifier); - for_each_present_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_disable, pp, true); + on_each_cpu(mvneta_percpu_disable, pp, true); free_percpu_irq(dev->irq, pp->ports); mvneta_cleanup_rxqs(pp); mvneta_cleanup_txqs(pp); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 1/6] net: mvneta: Fix for_each_present_cpu usage @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau This patch convert the for_each_present in on_each_cpu, instead of applying on the present cpus it will be applied only on the online cpus. This fix a bug reported on http://thread.gmane.org/gmane.linux.ports.arm.kernel/468173. Using the macro on_each_cpu (instead of a for_each_* loop) also ensures that all the calls will be done all at once. Fixes: f86428854480 ("net: mvneta: Statically assign queues to CPUs") Reported-by: Stefan Roese <stefan.roese@gmail.com> Suggested-by: Jisheng Zhang <jszhang@marvell.com> Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 662c2ee268c7..90ff5c7e19ea 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2564,7 +2564,7 @@ static void mvneta_start_dev(struct mvneta_port *pp) mvneta_port_enable(pp); /* Enable polling on the port */ - for_each_present_cpu(cpu) { + for_each_online_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_enable(&port->napi); @@ -2589,7 +2589,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp) phy_stop(pp->phy_dev); - for_each_present_cpu(cpu) { + for_each_online_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_disable(&port->napi); @@ -3057,13 +3057,11 @@ err_cleanup_rxqs: static int mvneta_stop(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); - int cpu; mvneta_stop_dev(pp); mvneta_mdio_remove(pp); unregister_cpu_notifier(&pp->cpu_notifier); - for_each_present_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_disable, pp, true); + on_each_cpu(mvneta_percpu_disable, pp, true); free_percpu_irq(dev->irq, pp->ports); mvneta_cleanup_rxqs(pp); mvneta_cleanup_txqs(pp); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 2/6] net: mvneta: Use on_each_cpu when possible 2016-01-29 16:26 ` Gregory CLEMENT (?) @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel Instead of using a for_each_* loop in which we just call the smp_call_function_single macro, it is more simple to directly use the on_each_cpu macro. Moreover, this macro ensures that the calls will be done all at once. Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 90ff5c7e19ea..3d6e3137f305 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2555,7 +2555,7 @@ static void mvneta_percpu_mask_interrupt(void *arg) static void mvneta_start_dev(struct mvneta_port *pp) { - unsigned int cpu; + int cpu; mvneta_max_rx_size_set(pp, pp->pkt_size); mvneta_txq_max_tx_size_set(pp, pp->pkt_size); @@ -2571,9 +2571,8 @@ static void mvneta_start_dev(struct mvneta_port *pp) } /* Unmask interrupts. It has to be done from each CPU */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | @@ -2988,7 +2987,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, static int mvneta_open(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); - int ret, cpu; + int ret; pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu); pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) + @@ -3021,9 +3020,7 @@ static int mvneta_open(struct net_device *dev) /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_enable, - pp, true); + on_each_cpu(mvneta_percpu_enable, pp, true); /* Register a CPU notifier to handle the case where our CPU @@ -3310,9 +3307,7 @@ static int mvneta_config_rss(struct mvneta_port *pp) netif_tx_stop_all_queues(pp->dev); - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_mask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); /* We have to synchronise on the napi of each CPU */ for_each_online_cpu(cpu) { -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 2/6] net: mvneta: Use on_each_cpu when possible @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Lior Amsalem, Andrew Lunn, Russell King - ARM Linux, Jason Cooper, Nadav Haklai, Gregory CLEMENT, Marcin Wojtas, Willy Tarreau, linux-arm-kernel, Sebastian Hesselbarth Instead of using a for_each_* loop in which we just call the smp_call_function_single macro, it is more simple to directly use the on_each_cpu macro. Moreover, this macro ensures that the calls will be done all at once. Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 90ff5c7e19ea..3d6e3137f305 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2555,7 +2555,7 @@ static void mvneta_percpu_mask_interrupt(void *arg) static void mvneta_start_dev(struct mvneta_port *pp) { - unsigned int cpu; + int cpu; mvneta_max_rx_size_set(pp, pp->pkt_size); mvneta_txq_max_tx_size_set(pp, pp->pkt_size); @@ -2571,9 +2571,8 @@ static void mvneta_start_dev(struct mvneta_port *pp) } /* Unmask interrupts. It has to be done from each CPU */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | @@ -2988,7 +2987,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, static int mvneta_open(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); - int ret, cpu; + int ret; pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu); pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) + @@ -3021,9 +3020,7 @@ static int mvneta_open(struct net_device *dev) /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_enable, - pp, true); + on_each_cpu(mvneta_percpu_enable, pp, true); /* Register a CPU notifier to handle the case where our CPU @@ -3310,9 +3307,7 @@ static int mvneta_config_rss(struct mvneta_port *pp) netif_tx_stop_all_queues(pp->dev); - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_mask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); /* We have to synchronise on the napi of each CPU */ for_each_online_cpu(cpu) { -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 2/6] net: mvneta: Use on_each_cpu when possible @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau Instead of using a for_each_* loop in which we just call the smp_call_function_single macro, it is more simple to directly use the on_each_cpu macro. Moreover, this macro ensures that the calls will be done all at once. Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 90ff5c7e19ea..3d6e3137f305 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2555,7 +2555,7 @@ static void mvneta_percpu_mask_interrupt(void *arg) static void mvneta_start_dev(struct mvneta_port *pp) { - unsigned int cpu; + int cpu; mvneta_max_rx_size_set(pp, pp->pkt_size); mvneta_txq_max_tx_size_set(pp, pp->pkt_size); @@ -2571,9 +2571,8 @@ static void mvneta_start_dev(struct mvneta_port *pp) } /* Unmask interrupts. It has to be done from each CPU */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | @@ -2988,7 +2987,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, static int mvneta_open(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); - int ret, cpu; + int ret; pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu); pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) + @@ -3021,9 +3020,7 @@ static int mvneta_open(struct net_device *dev) /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_enable, - pp, true); + on_each_cpu(mvneta_percpu_enable, pp, true); /* Register a CPU notifier to handle the case where our CPU @@ -3310,9 +3307,7 @@ static int mvneta_config_rss(struct mvneta_port *pp) netif_tx_stop_all_queues(pp->dev); - for_each_online_cpu(cpu) - smp_call_function_single(cpu, mvneta_percpu_mask_interrupt, - pp, true); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); /* We have to synchronise on the napi of each CPU */ for_each_online_cpu(cpu) { -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 3/6] net: mvneta: Remove unused code 2016-01-29 16:26 ` Gregory CLEMENT (?) @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel Since the commit 2dcf75e2793c ("net: mvneta: Associate RX queues with each CPU") all the percpu irq are used and unmask at initialization, so there is no point to unmask them first. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3d6e3137f305..861b7e0d7d5f 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3009,14 +3009,6 @@ static int mvneta_open(struct net_device *dev) goto err_cleanup_txqs; } - /* Even though the documentation says that request_percpu_irq - * doesn't enable the interrupts automatically, it actually - * does so on the local CPU. - * - * Make sure it's disabled. - */ - mvneta_percpu_disable(pp); - /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 3/6] net: mvneta: Remove unused code @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Lior Amsalem, Andrew Lunn, Russell King - ARM Linux, Jason Cooper, Nadav Haklai, Gregory CLEMENT, Marcin Wojtas, Willy Tarreau, linux-arm-kernel, Sebastian Hesselbarth Since the commit 2dcf75e2793c ("net: mvneta: Associate RX queues with each CPU") all the percpu irq are used and unmask at initialization, so there is no point to unmask them first. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3d6e3137f305..861b7e0d7d5f 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3009,14 +3009,6 @@ static int mvneta_open(struct net_device *dev) goto err_cleanup_txqs; } - /* Even though the documentation says that request_percpu_irq - * doesn't enable the interrupts automatically, it actually - * does so on the local CPU. - * - * Make sure it's disabled. - */ - mvneta_percpu_disable(pp); - /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 3/6] net: mvneta: Remove unused code @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau Since the commit 2dcf75e2793c ("net: mvneta: Associate RX queues with each CPU") all the percpu irq are used and unmask at initialization, so there is no point to unmask them first. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3d6e3137f305..861b7e0d7d5f 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3009,14 +3009,6 @@ static int mvneta_open(struct net_device *dev) goto err_cleanup_txqs; } - /* Even though the documentation says that request_percpu_irq - * doesn't enable the interrupts automatically, it actually - * does so on the local CPU. - * - * Make sure it's disabled. - */ - mvneta_percpu_disable(pp); - /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts */ -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 4/6] net: mvneta: Modify the queue related fields from each cpu 2016-01-29 16:26 ` Gregory CLEMENT @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel In the MVNETA_INTR_* registers, the queues related fields are per cpu, according to the datasheet (comment in [] are added by me): "In a multi-CPU system, bits of RX[or TX] queues for which the access by the reading[or writing] CPU is disabled are read as 0, and cannot be cleared[or written]." That means that each time we want to manipulate these bits we had to do it on each cpu and not only on the current cpu. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 100 ++++++++++++++++------------------ 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 861b7e0d7d5f..1ed813d478e8 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1038,6 +1038,43 @@ static void mvneta_set_autoneg(struct mvneta_port *pp, int enable) } } +static void mvneta_percpu_unmask_interrupt(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are unmasked, but actually only the ones + * mapped to this CPU will be unmasked + */ + mvreg_write(pp, MVNETA_INTR_NEW_MASK, + MVNETA_RX_INTR_MASK_ALL | + MVNETA_TX_INTR_MASK_ALL | + MVNETA_MISCINTR_INTR_MASK); +} + +static void mvneta_percpu_mask_interrupt(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are masked, but actually only the ones + * mapped to this CPU will be masked + */ + mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); + mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +} + +static void mvneta_percpu_clear_intr_cause(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are cleared, but actually only the ones + * mapped to this CPU will be cleared + */ + mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); + mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); + mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); +} + /* This method sets defaults to the NETA port: * Clears interrupt Cause and Mask registers. * Clears all MAC tables. @@ -1055,14 +1092,10 @@ static void mvneta_defaults_set(struct mvneta_port *pp) int max_cpu = num_present_cpus(); /* Clear all Cause registers */ - mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); + on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true); /* Mask all interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_ENABLE, 0); /* Enable MBUS Retry bit16 */ @@ -2528,31 +2561,6 @@ static int mvneta_setup_txqs(struct mvneta_port *pp) return 0; } -static void mvneta_percpu_unmask_interrupt(void *arg) -{ - struct mvneta_port *pp = arg; - - /* All the queue are unmasked, but actually only the ones - * maped to this CPU will be unmasked - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK_ALL | - MVNETA_TX_INTR_MASK_ALL | - MVNETA_MISCINTR_INTR_MASK); -} - -static void mvneta_percpu_mask_interrupt(void *arg) -{ - struct mvneta_port *pp = arg; - - /* All the queue are masked, but actually only the ones - * maped to this CPU will be masked - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); -} - static void mvneta_start_dev(struct mvneta_port *pp) { int cpu; @@ -2603,13 +2611,10 @@ static void mvneta_stop_dev(struct mvneta_port *pp) mvneta_port_disable(pp); /* Clear all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); + on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true); /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); mvneta_tx_reset(pp); mvneta_rx_reset(pp); @@ -2916,9 +2921,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, } /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); napi_enable(&port->napi); @@ -2933,14 +2936,8 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, */ mvneta_percpu_elect(pp); - /* Unmask all ethernet port interrupts, as this - * notifier is called for each CPU then the CPU to - * Queue mapping is applied - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | - MVNETA_TX_INTR_MASK(txq_number) | - MVNETA_MISCINTR_INTR_MASK); + /* Unmask all ethernet port interrupts */ + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | @@ -2951,9 +2948,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, case CPU_DOWN_PREPARE_FROZEN: netif_tx_stop_all_queues(pp->dev); /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); napi_synchronize(&port->napi); napi_disable(&port->napi); @@ -2969,10 +2964,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, /* Check if a new CPU must be elected now this on is down */ mvneta_percpu_elect(pp); /* Unmask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | - MVNETA_TX_INTR_MASK(txq_number) | - MVNETA_MISCINTR_INTR_MASK); + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 4/6] net: mvneta: Modify the queue related fields from each cpu @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau In the MVNETA_INTR_* registers, the queues related fields are per cpu, according to the datasheet (comment in [] are added by me): "In a multi-CPU system, bits of RX[or TX] queues for which the access by the reading[or writing] CPU is disabled are read as 0, and cannot be cleared[or written]." That means that each time we want to manipulate these bits we had to do it on each cpu and not only on the current cpu. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 100 ++++++++++++++++------------------ 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 861b7e0d7d5f..1ed813d478e8 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1038,6 +1038,43 @@ static void mvneta_set_autoneg(struct mvneta_port *pp, int enable) } } +static void mvneta_percpu_unmask_interrupt(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are unmasked, but actually only the ones + * mapped to this CPU will be unmasked + */ + mvreg_write(pp, MVNETA_INTR_NEW_MASK, + MVNETA_RX_INTR_MASK_ALL | + MVNETA_TX_INTR_MASK_ALL | + MVNETA_MISCINTR_INTR_MASK); +} + +static void mvneta_percpu_mask_interrupt(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are masked, but actually only the ones + * mapped to this CPU will be masked + */ + mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); + mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); +} + +static void mvneta_percpu_clear_intr_cause(void *arg) +{ + struct mvneta_port *pp = arg; + + /* All the queue are cleared, but actually only the ones + * mapped to this CPU will be cleared + */ + mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); + mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); + mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); +} + /* This method sets defaults to the NETA port: * Clears interrupt Cause and Mask registers. * Clears all MAC tables. @@ -1055,14 +1092,10 @@ static void mvneta_defaults_set(struct mvneta_port *pp) int max_cpu = num_present_cpus(); /* Clear all Cause registers */ - mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); + on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true); /* Mask all interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_ENABLE, 0); /* Enable MBUS Retry bit16 */ @@ -2528,31 +2561,6 @@ static int mvneta_setup_txqs(struct mvneta_port *pp) return 0; } -static void mvneta_percpu_unmask_interrupt(void *arg) -{ - struct mvneta_port *pp = arg; - - /* All the queue are unmasked, but actually only the ones - * maped to this CPU will be unmasked - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK_ALL | - MVNETA_TX_INTR_MASK_ALL | - MVNETA_MISCINTR_INTR_MASK); -} - -static void mvneta_percpu_mask_interrupt(void *arg) -{ - struct mvneta_port *pp = arg; - - /* All the queue are masked, but actually only the ones - * maped to this CPU will be masked - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); -} - static void mvneta_start_dev(struct mvneta_port *pp) { int cpu; @@ -2603,13 +2611,10 @@ static void mvneta_stop_dev(struct mvneta_port *pp) mvneta_port_disable(pp); /* Clear all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); - mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0); + on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true); /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); mvneta_tx_reset(pp); mvneta_rx_reset(pp); @@ -2916,9 +2921,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, } /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); napi_enable(&port->napi); @@ -2933,14 +2936,8 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, */ mvneta_percpu_elect(pp); - /* Unmask all ethernet port interrupts, as this - * notifier is called for each CPU then the CPU to - * Queue mapping is applied - */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | - MVNETA_TX_INTR_MASK(txq_number) | - MVNETA_MISCINTR_INTR_MASK); + /* Unmask all ethernet port interrupts */ + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | @@ -2951,9 +2948,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, case CPU_DOWN_PREPARE_FROZEN: netif_tx_stop_all_queues(pp->dev); /* Mask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); - mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); - mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); + on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); napi_synchronize(&port->napi); napi_disable(&port->napi); @@ -2969,10 +2964,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, /* Check if a new CPU must be elected now this on is down */ mvneta_percpu_elect(pp); /* Unmask all ethernet port interrupts */ - mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | - MVNETA_TX_INTR_MASK(txq_number) | - MVNETA_MISCINTR_INTR_MASK); + on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true); mvreg_write(pp, MVNETA_INTR_MISC_MASK, MVNETA_CAUSE_PHY_STATUS_CHANGE | MVNETA_CAUSE_LINK_CHANGE | -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic 2016-01-29 16:26 ` Gregory CLEMENT @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel Electing a CPU must be done in an atomic way: it should be done after or before the removal/insertion of a CPU and this function is not reentrant. During the loop of mvneta_percpu_elect we associates the queues to the CPUs, if there is a topology change during this loop, then the mapping between the CPUs and the queues could be wrong. During this loop the interrupt mask is also updating for each CPUs, It should not be changed in the same time by other part of the driver. This patch adds spinlock to create the needed critical sections. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 1ed813d478e8..3358c9a70467 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -370,6 +370,8 @@ struct mvneta_port { struct net_device *dev; struct notifier_block cpu_notifier; int rxq_def; + /* protect */ + spinlock_t lock; /* Core clock */ struct clk *clk; @@ -2855,6 +2857,11 @@ static void mvneta_percpu_elect(struct mvneta_port *pp) { int online_cpu_idx, max_cpu, cpu, i = 0; + /* Electing a CPU must done in an atomic way: it should be + * done after or before the removal/insertion of a CPU and + * this function is not reentrant. + */ + spin_lock(&pp->lock); online_cpu_idx = pp->rxq_def % num_online_cpus(); max_cpu = num_present_cpus(); @@ -2893,6 +2900,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp) i++; } + spin_unlock(&pp->lock); }; static int mvneta_percpu_notifier(struct notifier_block *nfb, @@ -2947,8 +2955,13 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: netif_tx_stop_all_queues(pp->dev); + /* Thanks to this lock we are sure that any pending + * cpu election is done + */ + spin_lock(&pp->lock); /* Mask all ethernet port interrupts */ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); + spin_unlock(&pp->lock); napi_synchronize(&port->napi); napi_disable(&port->napi); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau Electing a CPU must be done in an atomic way: it should be done after or before the removal/insertion of a CPU and this function is not reentrant. During the loop of mvneta_percpu_elect we associates the queues to the CPUs, if there is a topology change during this loop, then the mapping between the CPUs and the queues could be wrong. During this loop the interrupt mask is also updating for each CPUs, It should not be changed in the same time by other part of the driver. This patch adds spinlock to create the needed critical sections. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 1ed813d478e8..3358c9a70467 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -370,6 +370,8 @@ struct mvneta_port { struct net_device *dev; struct notifier_block cpu_notifier; int rxq_def; + /* protect */ + spinlock_t lock; /* Core clock */ struct clk *clk; @@ -2855,6 +2857,11 @@ static void mvneta_percpu_elect(struct mvneta_port *pp) { int online_cpu_idx, max_cpu, cpu, i = 0; + /* Electing a CPU must done in an atomic way: it should be + * done after or before the removal/insertion of a CPU and + * this function is not reentrant. + */ + spin_lock(&pp->lock); online_cpu_idx = pp->rxq_def % num_online_cpus(); max_cpu = num_present_cpus(); @@ -2893,6 +2900,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp) i++; } + spin_unlock(&pp->lock); }; static int mvneta_percpu_notifier(struct notifier_block *nfb, @@ -2947,8 +2955,13 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: netif_tx_stop_all_queues(pp->dev); + /* Thanks to this lock we are sure that any pending + * cpu election is done + */ + spin_lock(&pp->lock); /* Mask all ethernet port interrupts */ on_each_cpu(mvneta_percpu_mask_interrupt, pp, true); + spin_unlock(&pp->lock); napi_synchronize(&port->napi); napi_disable(&port->napi); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic 2016-01-29 16:26 ` Gregory CLEMENT @ 2016-01-30 4:38 ` David Miller -1 siblings, 0 replies; 20+ messages in thread From: David Miller @ 2016-01-30 4:38 UTC (permalink / raw) To: linux-arm-kernel From: Gregory CLEMENT <gregory.clement@free-electrons.com> Date: Fri, 29 Jan 2016 17:26:06 +0100 > @@ -370,6 +370,8 @@ struct mvneta_port { > struct net_device *dev; > struct notifier_block cpu_notifier; > int rxq_def; > + /* protect */ > + spinlock_t lock; > > /* Core clock */ > struct clk *clk; Protect what? This comment needs a lot of improvement. Everyone knows a spinlock "protects" things, so if you aren't going to actually describe what this lock protects, and in what contexts the lock is used, you might as well not say anything at all. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic @ 2016-01-30 4:38 ` David Miller 0 siblings, 0 replies; 20+ messages in thread From: David Miller @ 2016-01-30 4:38 UTC (permalink / raw) To: gregory.clement Cc: linux-kernel, netdev, thomas.petazzoni, jason, andrew, sebastian.hesselbarth, linux-arm-kernel, alior, nadavh, mw, linux, w From: Gregory CLEMENT <gregory.clement@free-electrons.com> Date: Fri, 29 Jan 2016 17:26:06 +0100 > @@ -370,6 +370,8 @@ struct mvneta_port { > struct net_device *dev; > struct notifier_block cpu_notifier; > int rxq_def; > + /* protect */ > + spinlock_t lock; > > /* Core clock */ > struct clk *clk; Protect what? This comment needs a lot of improvement. Everyone knows a spinlock "protects" things, so if you aren't going to actually describe what this lock protects, and in what contexts the lock is used, you might as well not say anything at all. ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic 2016-01-30 4:38 ` David Miller @ 2016-02-01 10:22 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-02-01 10:22 UTC (permalink / raw) To: linux-arm-kernel Hi David, On sam., janv. 30 2016, David Miller <davem@davemloft.net> wrote: > From: Gregory CLEMENT <gregory.clement@free-electrons.com> > Date: Fri, 29 Jan 2016 17:26:06 +0100 > >> @@ -370,6 +370,8 @@ struct mvneta_port { >> struct net_device *dev; >> struct notifier_block cpu_notifier; >> int rxq_def; >> + /* protect */ >> + spinlock_t lock; >> >> /* Core clock */ >> struct clk *clk; > > Protect what? This comment needs a lot of improvement. Sorry about it, this was a left-over. > > Everyone knows a spinlock "protects" things, so if you aren't going > to actually describe what this lock protects, and in what contexts > the lock is used, you might as well not say anything at all. I can only agree with you, I will fix it for next version. Thanks, Gregory -- Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic @ 2016-02-01 10:22 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-02-01 10:22 UTC (permalink / raw) To: David Miller Cc: linux-kernel, netdev, thomas.petazzoni, jason, andrew, sebastian.hesselbarth, linux-arm-kernel, alior, nadavh, mw, linux, w Hi David, On sam., janv. 30 2016, David Miller <davem@davemloft.net> wrote: > From: Gregory CLEMENT <gregory.clement@free-electrons.com> > Date: Fri, 29 Jan 2016 17:26:06 +0100 > >> @@ -370,6 +370,8 @@ struct mvneta_port { >> struct net_device *dev; >> struct notifier_block cpu_notifier; >> int rxq_def; >> + /* protect */ >> + spinlock_t lock; >> >> /* Core clock */ >> struct clk *clk; > > Protect what? This comment needs a lot of improvement. Sorry about it, this was a left-over. > > Everyone knows a spinlock "protects" things, so if you aren't going > to actually describe what this lock protects, and in what contexts > the lock is used, you might as well not say anything at all. I can only agree with you, I will fix it for next version. Thanks, Gregory -- Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net 6/6] net: mvneta: Fix race condition during stopping 2016-01-29 16:26 ` Gregory CLEMENT @ 2016-01-29 16:26 ` Gregory CLEMENT -1 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: linux-arm-kernel When stopping the port, the CPU notifier are still there whereas the mvneta_stop_dev function calls mvneta_percpu_disable() on each CPUs. It was possible to have a new CPU coming at this point which could be racy. This patch adds a flag preventing executing the code notifier for a new CPU when the port is stopping. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3358c9a70467..22962fac47c2 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -372,6 +372,7 @@ struct mvneta_port { int rxq_def; /* protect */ spinlock_t lock; + bool is_stopping; /* Core clock */ struct clk *clk; @@ -2914,6 +2915,11 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: + /* Configuring the driver for a new CPU while the + * driver is stopping is racy, so just avoid it. + */ + if (pp->is_stopping) + break; netif_tx_stop_all_queues(pp->dev); /* We have to synchronise on tha napi of each CPU @@ -3052,9 +3058,17 @@ static int mvneta_stop(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); + /* Inform that we are stopping so we don't want to setup the + * driver for new CPUs in the notifiers + */ + pp->is_stopping = true; mvneta_stop_dev(pp); mvneta_mdio_remove(pp); unregister_cpu_notifier(&pp->cpu_notifier); + /* Now that the notifier are unregistered, we can clear the + * flag + */ + pp->is_stopping = false; on_each_cpu(mvneta_percpu_disable, pp, true); free_percpu_irq(dev->irq, pp->ports); mvneta_cleanup_rxqs(pp); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net 6/6] net: mvneta: Fix race condition during stopping @ 2016-01-29 16:26 ` Gregory CLEMENT 0 siblings, 0 replies; 20+ messages in thread From: Gregory CLEMENT @ 2016-01-29 16:26 UTC (permalink / raw) To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas, Russell King - ARM Linux, Willy Tarreau When stopping the port, the CPU notifier are still there whereas the mvneta_stop_dev function calls mvneta_percpu_disable() on each CPUs. It was possible to have a new CPU coming at this point which could be racy. This patch adds a flag preventing executing the code notifier for a new CPU when the port is stopping. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> --- drivers/net/ethernet/marvell/mvneta.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3358c9a70467..22962fac47c2 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -372,6 +372,7 @@ struct mvneta_port { int rxq_def; /* protect */ spinlock_t lock; + bool is_stopping; /* Core clock */ struct clk *clk; @@ -2914,6 +2915,11 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb, switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: + /* Configuring the driver for a new CPU while the + * driver is stopping is racy, so just avoid it. + */ + if (pp->is_stopping) + break; netif_tx_stop_all_queues(pp->dev); /* We have to synchronise on tha napi of each CPU @@ -3052,9 +3058,17 @@ static int mvneta_stop(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); + /* Inform that we are stopping so we don't want to setup the + * driver for new CPUs in the notifiers + */ + pp->is_stopping = true; mvneta_stop_dev(pp); mvneta_mdio_remove(pp); unregister_cpu_notifier(&pp->cpu_notifier); + /* Now that the notifier are unregistered, we can clear the + * flag + */ + pp->is_stopping = false; on_each_cpu(mvneta_percpu_disable, pp, true); free_percpu_irq(dev->irq, pp->ports); mvneta_cleanup_rxqs(pp); -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
end of thread, other threads:[~2016-02-01 10:23 UTC | newest] Thread overview: 20+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-01-29 16:26 [PATCH net 0/6] mvneta fixes for SMP Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 1/6] net: mvneta: Fix for_each_present_cpu usage Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 2/6] net: mvneta: Use on_each_cpu when possible Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 3/6] net: mvneta: Remove unused code Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 4/6] net: mvneta: Modify the queue related fields from each cpu Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 5/6] net: mvneta: The mvneta_percpu_elect function should be atomic Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT 2016-01-30 4:38 ` David Miller 2016-01-30 4:38 ` David Miller 2016-02-01 10:22 ` Gregory CLEMENT 2016-02-01 10:22 ` Gregory CLEMENT 2016-01-29 16:26 ` [PATCH net 6/6] net: mvneta: Fix race condition during stopping Gregory CLEMENT 2016-01-29 16:26 ` Gregory CLEMENT
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.