Commit 228c8f0d authored by Naga Sureshkumar Relli's avatar Naga Sureshkumar Relli Committed by ZhangPeng
Browse files

spi: microchip-core: fix the issues in the isr

stable inclusion
from stable-v6.6.44
commit 11e0f3c888b2e6141a7322ca4d3fba43a597197e
bugzilla: https://gitee.com/openeuler/kernel/issues/IAHMJO

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=11e0f3c888b2e6141a7322ca4d3fba43a597197e



--------------------------------

[ Upstream commit 502a582b8dd897d9282db47c0911d5320ef2e6b9 ]

It is possible for the TXDONE interrupt be raised if the tx FIFO becomes
temporarily empty while transmitting, resulting in recursive calls to
mchp_corespi_write_fifo() and therefore a garbage message might be
transmitted depending on when the interrupt is triggered. Moving all of
the tx FIFO writes out of the TXDONE portion of the interrupt handler
avoids this problem.

Most of rest of the TXDONE portion of the handler is problematic too.
Only reading the rx FIFO (and finalising the transfer) when the TXDONE
interrupt is raised can cause the transfer to stall, if the final bytes
of rx data are not available in the rx FIFO when the final TXDONE
interrupt is raised. The transfer should be finalised regardless of
which interrupt is raised, provided that all tx data has been set and
all rx data received.

The first issue was encountered "in the wild", the second is
theoretical.

Fixes: 9ac8d176 ("spi: add support for microchip fpga spi controllers")
Signed-off-by: default avatarNaga Sureshkumar Relli <nagasuresh.relli@microchip.com>
Signed-off-by: default avatarConor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20240715-candied-deforest-585685ef3c8a@wendy


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
parent 34a921a0
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -380,21 +380,18 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
	if (intfield == 0)
		return IRQ_NONE;

	if (intfield & INT_TXDONE) {
	if (intfield & INT_TXDONE)
		mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE);

	if (intfield & INT_RXRDY) {
		mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);

		if (spi->rx_len)
			mchp_corespi_read_fifo(spi);

		if (spi->tx_len)
			mchp_corespi_write_fifo(spi);

		if (!spi->rx_len)
			finalise = true;
	}

	if (intfield & INT_RXRDY)
		mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);
	if (!spi->rx_len && !spi->tx_len)
		finalise = true;

	if (intfield & INT_RX_CHANNEL_OVERFLOW) {
		mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
@@ -479,8 +476,9 @@ static int mchp_corespi_transfer_one(struct spi_master *master,
	mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH)
				   ? FIFO_DEPTH : spi->tx_len);

	if (spi->tx_len)
	while (spi->tx_len)
		mchp_corespi_write_fifo(spi);

	return 1;
}