From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-21 16:30:47
The functions qcaspi_netdev_open/close are responsible of request &
free of the SPI interrupt, which wasn't the best choice. Currently
it's possible to trigger a double free of the interrupt by calling
qcaspi_netdev_close() after qcaspi_netdev_open() has failed.
So let us split IRQ allocation & enabling, so we can take advantage
of a device managed IRQ and also fix the issue.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_spi.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-21 16:30:53
After calling ethtool -g it was not possible to adjust the TX ring size
again. The reason for this is that the readonly setting rx_pending get
initialized and after that the range check in qcaspi_set_ringparam()
fails regardless of the provided parameter. Since there is no adjustable
RX ring at all, drop it from qcaspi_get_ringparam().
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 2 --
1 file changed, 2 deletions(-)
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-21 16:30:56
The qca_spi driver create/stop the SPI kernel thread in case
of netdev_open/close. This is a big issue because it allows
userspace to prevent from restarting the SPI thread after
ring parameter changes (e.g. signals which stop the thread).
This could be done by terminating a script which changes
the ring parameter in a loop.
So fix this by moving create/stop of the SPI kernel into
the init/uninit ops. The open/close ops could be realized just
by 'park/unpark' the SPI kernel thread.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_spi.c | 35 ++++++++++++++++---------
1 file changed, 23 insertions(+), 12 deletions(-)
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-21 16:30:59
In case of a reset triggered by the QCA7000 itself, the behavior of the
qca_spi driver was not quite correct:
- in case of a pending RX frame decoding the drop counter must be
incremented and decoding state machine reseted
- also the reset counter must always be incremented regardless of sync
state
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_spi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
From: Paolo Abeni <pabeni@redhat.com> Date: 2023-11-23 11:27:08
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted hunk
The qca_spi driver create/stop the SPI kernel thread in case
of netdev_open/close. This is a big issue because it allows
userspace to prevent from restarting the SPI thread after
ring parameter changes (e.g. signals which stop the thread).
This could be done by terminating a script which changes
the ring parameter in a loop.
So fix this by moving create/stop of the SPI kernel into
the init/uninit ops. The open/close ops could be realized just
by 'park/unpark' the SPI kernel thread.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_spi.c | 35 ++++++++++++++++---------
1 file changed, 23 insertions(+), 12 deletions(-)
@@ -679,25 +684,17 @@ qcaspi_netdev_open(struct net_device *dev)qca->sync=QCASPI_SYNC_UNKNOWN;qcafrm_fsm_init_spi(&qca->frm_handle);-qca->spi_thread=kthread_run((void*)qcaspi_spi_thread,-qca,"%s",dev->name);--if(IS_ERR(qca->spi_thread)){-netdev_err(dev,"%s: unable to start kernel thread.\n",-QCASPI_DRV_NAME);-returnPTR_ERR(qca->spi_thread);-}-ret=request_irq(qca->spi_dev->irq,qcaspi_intr_handler,0,dev->name,qca);if(ret){netdev_err(dev,"%s: unable to get IRQ %d (irqval=%d).\n",QCASPI_DRV_NAME,qca->spi_dev->irq,ret);-kthread_stop(qca->spi_thread);returnret;}/* SPI thread takes care of TX queue */+kthread_unpark(qca->spi_thread);+wake_up_process(qca->spi_thread);
The above looks racy: after 'request_irq()' the interrupt handler can
raise an irq before the thread being unparked.
Additionally I think you can drop the 'if (qca->spi_thread)' in
qcaspi_intr_handler()
Cheers,
Paolo
From: Paolo Abeni <pabeni@redhat.com> Date: 2023-11-23 11:37:34
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
The functions qcaspi_netdev_open/close are responsible of request &
free of the SPI interrupt, which wasn't the best choice. Currently
it's possible to trigger a double free of the interrupt by calling
qcaspi_netdev_close() after qcaspi_netdev_open() has failed.
So let us split IRQ allocation & enabling, so we can take advantage
of a device managed IRQ and also fix the issue.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
The change makes sense, but the changelog is confusing.
qcaspi_netdev_close() and qcaspi_netdev_open() are invoked only via
ndo_open and ndo_close(), right? So qcaspi_netdev_close() will never be
invoked qcaspi_netdev_open(), failure - that is when IFF_UP is not set.
Cheers,
Paolo
From: Paolo Abeni <pabeni@redhat.com> Date: 2023-11-23 11:52:46
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
After calling ethtool -g it was not possible to adjust the TX ring size
again.
Could you please report the exact command sequence that will fail?
The reason for this is that the readonly setting rx_pending get
initialized and after that the range check in qcaspi_set_ringparam()
fails regardless of the provided parameter. Since there is no adjustable
RX ring at all, drop it from qcaspi_get_ringparam().
quoted hunk
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 2 --
1 file changed, 2 deletions(-)
I think it's preferable update qcaspi_set_ringparam() to complete
successfully when the provided arguments don't change the rx_pending
default (4)
Cheers,
Paolo
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-24 13:40:57
Hi Paolo,
Am 23.11.23 um 12:26 schrieb Paolo Abeni:
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
The qca_spi driver create/stop the SPI kernel thread in case
of netdev_open/close. This is a big issue because it allows
userspace to prevent from restarting the SPI thread after
ring parameter changes (e.g. signals which stop the thread).
This could be done by terminating a script which changes
the ring parameter in a loop.
So fix this by moving create/stop of the SPI kernel into
the init/uninit ops. The open/close ops could be realized just
by 'park/unpark' the SPI kernel thread.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_spi.c | 35 ++++++++++++++++---------
1 file changed, 23 insertions(+), 12 deletions(-)
@@ -679,25 +684,17 @@ qcaspi_netdev_open(struct net_device *dev)qca->sync=QCASPI_SYNC_UNKNOWN;qcafrm_fsm_init_spi(&qca->frm_handle);-qca->spi_thread=kthread_run((void*)qcaspi_spi_thread,-qca,"%s",dev->name);--if(IS_ERR(qca->spi_thread)){-netdev_err(dev,"%s: unable to start kernel thread.\n",-QCASPI_DRV_NAME);-returnPTR_ERR(qca->spi_thread);-}-ret=request_irq(qca->spi_dev->irq,qcaspi_intr_handler,0,dev->name,qca);if(ret){netdev_err(dev,"%s: unable to get IRQ %d (irqval=%d).\n",QCASPI_DRV_NAME,qca->spi_dev->irq,ret);-kthread_stop(qca->spi_thread);returnret;}/* SPI thread takes care of TX queue */+kthread_unpark(qca->spi_thread);+wake_up_process(qca->spi_thread);
The above looks racy: after 'request_irq()' the interrupt handler can
raise an irq before the thread being unparked.
yes fixing the whole resource allocation issue requires patch 1 and 2
applied, which should avoid the race. But i didn't want to combine both
patches to keep it applicable for stable. My thought was that 2 smaller
patches are more acceptable than a big one.
Should i squash them?
My concern is about the amount of affected devices. The QCA7000 is used
mostly in EV charging stations and EVs. I don't how many of them use
this driver.
Additionally I think you can drop the 'if (qca->spi_thread)' in
qcaspi_intr_handler()
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-24 14:01:43
Hi Paolo,
Am 23.11.23 um 12:37 schrieb Paolo Abeni:
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
The functions qcaspi_netdev_open/close are responsible of request &
free of the SPI interrupt, which wasn't the best choice. Currently
it's possible to trigger a double free of the interrupt by calling
qcaspi_netdev_close() after qcaspi_netdev_open() has failed.
So let us split IRQ allocation & enabling, so we can take advantage
of a device managed IRQ and also fix the issue.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
The change makes sense, but the changelog is confusing.
qcaspi_netdev_close() and qcaspi_netdev_open() are invoked only via
ndo_open and ndo_close(), right? So qcaspi_netdev_close() will never be
invoked qcaspi_netdev_open(), failure - that is when IFF_UP is not set.
sorry, i missed to mention an important part. This issue is partly
connected to patch 3.
Please look at qcaspi_set_ringparam() which also call ndo_close() and
ndo_open(). If you only apply patch 3 you could trigger this issue by
running the following script, interrupt via Strg+C and start again:
#!/bin/bash
while [ true ]; do
ethtool -G eth1 tx 8
ethtool -g eth1
ethtool -G eth1 tx 10
done
[ 75.713471] qcaspi spi1.0 eth1: SPI thread exit
[ 75.721814] qcaspi spi1.0 eth1: SPI thread created
[ 76.795239] qcaspi spi1.0 eth1: SPI thread exit
[ 76.815801] qcaspi spi1.0 eth1: SPI thread created
[ 77.915872] qcaspi spi1.0 eth1: SPI thread exit
[ 77.933982] qcaspi spi1.0 eth1: SPI thread created
[ 79.036024] qcaspi spi1.0 eth1: SPI thread exit
[ 79.055595] qcaspi spi1.0 eth1: SPI thread created
[ 80.076223] qcaspi spi1.0 eth1: SPI thread exit
[ 80.097305] qcaspi spi1.0 eth1: SPI thread created
[ 81.196471] qcaspi spi1.0 eth1: SPI thread exit
[ 81.217351] qcaspi spi1.0 eth1: SPI thread created
[ 82.316592] qcaspi spi1.0 eth1: SPI thread exit
[ 82.336963] qcaspi spi1.0 eth1: SPI thread created
[ 83.436864] qcaspi spi1.0 eth1: SPI thread exit
[ 83.461252] qcaspi spi1.0 eth1: SPI thread created
[ 84.556950] qcaspi spi1.0 eth1: SPI thread exit
[ 84.575897] qcaspi spi1.0 eth1: SPI thread created
[ 85.677105] qcaspi spi1.0 eth1: SPI thread exit
[ 85.695061] qcaspi spi1.0 eth1: SPI thread created
[ 86.717215] qcaspi spi1.0 eth1: SPI thread exit
[ 86.739535] qcaspi spi1.0 eth1: SPI thread created
[ 87.837355] qcaspi spi1.0 eth1: SPI thread exit
<-- Strg + C
[ 87.841072] qcaspi spi1.0 eth1: qcaspi: unable to start kernel thread.
root@tarragon:/srv# ./test_ring_fast.sh
------------[ cut here ]------------
WARNING: CPU: 0 PID: 724 at kernel/irq/manage.c:1887 free_irq+0x23c/0x288
Trying to free already-free IRQ 73
CPU: 0 PID: 724 Comm: ethtool Not tainted
6.1.49-chargebyte-00029-g8c38d497af8a-dirty #108
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
unwind_backtrace from show_stack+0x10/0x14
show_stack from dump_stack_lvl+0x24/0x2c
dump_stack_lvl from __warn+0x74/0xbc
__warn from warn_slowpath_fmt+0xc8/0x120
warn_slowpath_fmt from free_irq+0x23c/0x288
free_irq from qcaspi_netdev_close+0x38/0x5c
qcaspi_netdev_close from qcaspi_set_ringparam+0x48/0x90
qcaspi_set_ringparam from ethnl_set_rings+0x2dc/0x320
ethnl_set_rings from genl_rcv_msg+0x2c4/0x344
genl_rcv_msg from netlink_rcv_skb+0x98/0xfc
netlink_rcv_skb from genl_rcv+0x20/0x34
genl_rcv from netlink_unicast+0x114/0x1a4
netlink_unicast from netlink_sendmsg+0x314/0x340
netlink_sendmsg from sock_sendmsg_nosec+0x14/0x24
sock_sendmsg_nosec from __sys_sendto+0xc4/0xf8
__sys_sendto from ret_fast_syscall+0x0/0x54
Exception stack(0xe115dfa8 to 0xe115dff0)
dfa0: b6ed24dc 0000000c 00000003 005c4238 0000002c
00000000
dfc0: b6ed24dc 0000000c b6f6a5a0 00000122 00472e04 005c41f0 00436b60
005c4190
dfe0: 00000122 bec50b68 b6e5f841 b6dd1ae6
---[ end trace 0000000000000000 ]---
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-24 14:22:25
Hi Paolo,
Am 23.11.23 um 12:51 schrieb Paolo Abeni:
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
After calling ethtool -g it was not possible to adjust the TX ring size
again.
Could you please report the exact command sequence that will fail?
ethtool -g eth1
ethtool -G eth1 tx 8
quoted
The reason for this is that the readonly setting rx_pending get
initialized and after that the range check in qcaspi_set_ringparam()
fails regardless of the provided parameter. Since there is no adjustable
RX ring at all, drop it from qcaspi_get_ringparam().
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 2 --
1 file changed, 2 deletions(-)
I think it's preferable update qcaspi_set_ringparam() to complete
successfully when the provided arguments don't change the rx_pending
default (4)
Sorry, i didn't get. The whole point is that there is no RX ring at all,
just a TX ring. During the time of writing this driver, i was under the
assumption that the driver needs to provide a rx_pending in
qcaspi_get_ringparam even this is no RX ring. The number 4 represent the
maximum of 4 packets which can be received at once. But it's not a ring.
Best regards
From: Paolo Abeni <pabeni@redhat.com> Date: 2023-11-24 15:33:14
On Fri, 2023-11-24 at 15:01 +0100, Stefan Wahren wrote:
Hi Paolo,
Am 23.11.23 um 12:37 schrieb Paolo Abeni:
quoted
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
The functions qcaspi_netdev_open/close are responsible of request &
free of the SPI interrupt, which wasn't the best choice. Currently
it's possible to trigger a double free of the interrupt by calling
qcaspi_netdev_close() after qcaspi_netdev_open() has failed.
So let us split IRQ allocation & enabling, so we can take advantage
of a device managed IRQ and also fix the issue.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
The change makes sense, but the changelog is confusing.
qcaspi_netdev_close() and qcaspi_netdev_open() are invoked only via
ndo_open and ndo_close(), right? So qcaspi_netdev_close() will never be
invoked qcaspi_netdev_open(), failure - that is when IFF_UP is not set.
sorry, i missed to mention an important part. This issue is partly
connected to patch 3.
Please look at qcaspi_set_ringparam() which also call ndo_close() and
ndo_open().
Ah, I see it now. IMHO root cause of the problem is there. The ethtool
op should not flip the device state.
A more narrow fix would be to park/unpark the thread inside
set_ringparam() - instead of the whole patch 1 && 2 I suspect.
IMHO the changes in this still make sense - a refactor for net-next.
Cheers,
Paolo
From: Paolo Abeni <pabeni@redhat.com> Date: 2023-11-24 15:49:21
On Fri, 2023-11-24 at 15:17 +0100, Stefan Wahren wrote:
Am 23.11.23 um 12:51 schrieb Paolo Abeni:
quoted
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
After calling ethtool -g it was not possible to adjust the TX ring size
again.
Could you please report the exact command sequence that will fail?
ethtool -g eth1
ethtool -G eth1 tx 8
quoted
quoted
The reason for this is that the readonly setting rx_pending get
initialized and after that the range check in qcaspi_set_ringparam()
fails regardless of the provided parameter. Since there is no adjustable
RX ring at all, drop it from qcaspi_get_ringparam().
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 2 --
1 file changed, 2 deletions(-)
I think it's preferable update qcaspi_set_ringparam() to complete
successfully when the provided arguments don't change the rx_pending
default (4)
Sorry, i didn't get. The whole point is that there is no RX ring at all,
just a TX ring.
During the time of writing this driver, i was under the
assumption that the driver needs to provide a rx_pending in
qcaspi_get_ringparam even this is no RX ring. The number 4 represent the
maximum of 4 packets which can be received at once. But it's not a ring.
Even if the H/W in charge of receiving and storing the incoming packet
is not exactly a ring but some fixed-size structure, I think it would
be better to avoid changing the exposed defaults given they are not
actually changed by this patch and they represent the current status
IMHO quite accurately.
The change I suggested is something alike the following (note that you
could possibly define a macro with a helpful name instead of the raw
number '4')
Cheers,
Paolo
---
From: Stefan Wahren <wahrenst@gmx.net> Date: 2023-11-24 22:02:22
Hi Paolo,
Am 24.11.23 um 16:33 schrieb Paolo Abeni:
On Fri, 2023-11-24 at 15:01 +0100, Stefan Wahren wrote:
quoted
Hi Paolo,
Am 23.11.23 um 12:37 schrieb Paolo Abeni:
quoted
On Tue, 2023-11-21 at 17:30 +0100, Stefan Wahren wrote:
quoted
The functions qcaspi_netdev_open/close are responsible of request &
free of the SPI interrupt, which wasn't the best choice. Currently
it's possible to trigger a double free of the interrupt by calling
qcaspi_netdev_close() after qcaspi_netdev_open() has failed.
So let us split IRQ allocation & enabling, so we can take advantage
of a device managed IRQ and also fix the issue.
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
The change makes sense, but the changelog is confusing.
qcaspi_netdev_close() and qcaspi_netdev_open() are invoked only via
ndo_open and ndo_close(), right? So qcaspi_netdev_close() will never be
invoked qcaspi_netdev_open(), failure - that is when IFF_UP is not set.
sorry, i missed to mention an important part. This issue is partly
connected to patch 3.
Please look at qcaspi_set_ringparam() which also call ndo_close() and
ndo_open().
Ah, I see it now. IMHO root cause of the problem is there. The ethtool
op should not flip the device state.
A more narrow fix would be to park/unpark the thread inside
set_ringparam() - instead of the whole patch 1 && 2 I suspect.
before i send a complete new version of this series, could you please
have a look at this replacement for patch 1 & 2:
qca_debug: Prevent crash on TX ring changes
The qca_spi driver stop and restart the SPI kernel thread
(via ndo_stop & ndo_open) in case of TX ring changes. This is
a big issue because it allows userspace to prevent restart of
the SPI kernel thread (via signals). A subsequent change of
TX ring wrongly assume a valid spi_thread pointer which result
in a crash.
So prevent this by stopping the network queue and temporary park
the SPI thread. Because this could happen during transmission
we also need to call qcaspi_flush_tx_ring().
Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for
QCA7000")
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 17 ++++++++++++-----
drivers/net/ethernet/qualcomm/qca_spi.c | 7 ++++++-
drivers/net/ethernet/qualcomm/qca_spi.h | 2 ++
3 files changed, 20 insertions(+), 6 deletions(-)