| From bf291220d375f938efe5142d7c2c6f2090098c39 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 14 Jun 2024 16:50:30 +0200 |
| Subject: qca_spi: Make interrupt remembering atomic |
| |
| From: Stefan Wahren <wahrenst@gmx.net> |
| |
| [ Upstream commit 2d7198278ece01818cd95a3beffbdf8b2a353fa0 ] |
| |
| The whole mechanism to remember occurred SPI interrupts is not atomic, |
| which could lead to unexpected behavior. So fix this by using atomic bit |
| operations instead. |
| |
| Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000") |
| Signed-off-by: Stefan Wahren <wahrenst@gmx.net> |
| Link: https://lore.kernel.org/r/20240614145030.7781-1-wahrenst@gmx.net |
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/qualcomm/qca_debug.c | 6 ++---- |
| drivers/net/ethernet/qualcomm/qca_spi.c | 16 ++++++++-------- |
| drivers/net/ethernet/qualcomm/qca_spi.h | 3 +-- |
| 3 files changed, 11 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c |
| index 1822f2ad8f0dd..2ac1b1b96e6a4 100644 |
| --- a/drivers/net/ethernet/qualcomm/qca_debug.c |
| +++ b/drivers/net/ethernet/qualcomm/qca_debug.c |
| @@ -111,10 +111,8 @@ qcaspi_info_show(struct seq_file *s, void *what) |
| |
| seq_printf(s, "IRQ : %d\n", |
| qca->spi_dev->irq); |
| - seq_printf(s, "INTR REQ : %u\n", |
| - qca->intr_req); |
| - seq_printf(s, "INTR SVC : %u\n", |
| - qca->intr_svc); |
| + seq_printf(s, "INTR : %lx\n", |
| + qca->intr); |
| |
| seq_printf(s, "SPI max speed : %lu\n", |
| (unsigned long)qca->spi_dev->max_speed_hz); |
| diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c |
| index 5f3c11fb3fa27..b697a9e6face6 100644 |
| --- a/drivers/net/ethernet/qualcomm/qca_spi.c |
| +++ b/drivers/net/ethernet/qualcomm/qca_spi.c |
| @@ -48,6 +48,8 @@ |
| |
| #define MAX_DMA_BURST_LEN 5000 |
| |
| +#define SPI_INTR 0 |
| + |
| /* Modules parameters */ |
| #define QCASPI_CLK_SPEED_MIN 1000000 |
| #define QCASPI_CLK_SPEED_MAX 16000000 |
| @@ -592,14 +594,14 @@ qcaspi_spi_thread(void *data) |
| continue; |
| } |
| |
| - if ((qca->intr_req == qca->intr_svc) && |
| + if (!test_bit(SPI_INTR, &qca->intr) && |
| !qca->txr.skb[qca->txr.head]) |
| schedule(); |
| |
| set_current_state(TASK_RUNNING); |
| |
| - netdev_dbg(qca->net_dev, "have work to do. int: %d, tx_skb: %p\n", |
| - qca->intr_req - qca->intr_svc, |
| + netdev_dbg(qca->net_dev, "have work to do. int: %lu, tx_skb: %p\n", |
| + qca->intr, |
| qca->txr.skb[qca->txr.head]); |
| |
| qcaspi_qca7k_sync(qca, QCASPI_EVENT_UPDATE); |
| @@ -613,8 +615,7 @@ qcaspi_spi_thread(void *data) |
| msleep(QCASPI_QCA7K_REBOOT_TIME_MS); |
| } |
| |
| - if (qca->intr_svc != qca->intr_req) { |
| - qca->intr_svc = qca->intr_req; |
| + if (test_and_clear_bit(SPI_INTR, &qca->intr)) { |
| start_spi_intr_handling(qca, &intr_cause); |
| |
| if (intr_cause & SPI_INT_CPU_ON) { |
| @@ -676,7 +677,7 @@ qcaspi_intr_handler(int irq, void *data) |
| { |
| struct qcaspi *qca = data; |
| |
| - qca->intr_req++; |
| + set_bit(SPI_INTR, &qca->intr); |
| if (qca->spi_thread) |
| wake_up_process(qca->spi_thread); |
| |
| @@ -692,8 +693,7 @@ qcaspi_netdev_open(struct net_device *dev) |
| if (!qca) |
| return -EINVAL; |
| |
| - qca->intr_req = 1; |
| - qca->intr_svc = 0; |
| + set_bit(SPI_INTR, &qca->intr); |
| qca->sync = QCASPI_SYNC_UNKNOWN; |
| qcafrm_fsm_init_spi(&qca->frm_handle); |
| |
| diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h |
| index 3067356106f0b..58ad910068d4b 100644 |
| --- a/drivers/net/ethernet/qualcomm/qca_spi.h |
| +++ b/drivers/net/ethernet/qualcomm/qca_spi.h |
| @@ -93,8 +93,7 @@ struct qcaspi { |
| struct qcafrm_handle frm_handle; |
| struct sk_buff *rx_skb; |
| |
| - unsigned int intr_req; |
| - unsigned int intr_svc; |
| + unsigned long intr; |
| u16 reset_count; |
| |
| #ifdef CONFIG_DEBUG_FS |
| -- |
| 2.43.0 |
| |