spi: Fixes for v6.10

This pull request fixes two regressions that have been bubbling along
 for a large part of this release.  One is a revert of the multi mode
 support for the OMAP SPI controller, this introduced regressions on a
 number of systems and while there has been progress on fixing those
 we've not got something that works for everyone yet so let's just drop
 the change for now.  The other is a series of fixes from David Lechner
 for his recent message optimisation work, this interacted badly with
 spi-mux which is altogether too clever with recursive use of the bus and
 creates situations that hadn't been considered.
 
 There are also a couple of small driver specific fixes, including one
 more patch from David for sleep duration calculations in the AXI driver.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmaP8BoACgkQJNaLcl1U
 h9CaqAf/clXigdOnaNCJhwMKV4eGaa1cZPNMAnrS0r9/T2gs/gfm3Pt5vKGQnMph
 LizSMb9cyGyMrfRdqjSZknYNXur4JW7/g1+HuFlGfYKroWeqpUi+8Ye+mm/39qT5
 T5yiihv6izh3hfDya2R+x6xITi0n+0j/KjtIWGDRkEOPQqeSHjvg19nvkuT/xK8U
 kqML/tCibAMo+4c/PCSjZ3q49EiYPH595WC6EfKE9ijUKvgRGNF7bFbav4CiJB8/
 pESPqtPXHsgUITyQGPafttCdt3xl/pPDDRaMztA5rP/1s6gmjvFF4zq5/ztTceyE
 i2F8eK6JV3Jf/bHY4V0OW0bam2CEKA==
 =kPL9
 -----END PGP SIGNATURE-----

Merge tag 'spi-fix-v6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "This fixes two regressions that have been bubbling along for a large
  part of this release.

  One is a revert of the multi mode support for the OMAP SPI controller,
  this introduced regressions on a number of systems and while there has
  been progress on fixing those we've not got something that works for
  everyone yet so let's just drop the change for now.

  The other is a series of fixes from David Lechner for his recent
  message optimisation work, this interacted badly with spi-mux which
  is altogether too clever with recursive use of the bus and creates
  situations that hadn't been considered.

  There are also a couple of small driver specific fixes, including one
  more patch from David for sleep duration calculations in the AXI
  driver"

* tag 'spi-fix-v6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: mux: set ctlr->bits_per_word_mask
  spi: add defer_optimize_message controller flag
  spi: don't unoptimize message in spi_async()
  spi: omap2-mcspi: Revert multi mode support
  spi: davinci: Unset POWERDOWN bit when releasing resources
  spi: axi-spi-engine: fix sleep calculation
  spi: imx: Don't expect DMA for i.MX{25,35,50,51,53} cspi devices
This commit is contained in:
Linus Torvalds 2024-07-11 12:07:50 -07:00
commit 8a18fda0fe
7 changed files with 49 additions and 26 deletions

View File

@ -164,16 +164,20 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
}
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
int delay_ns, u32 sclk_hz)
int delay_ns, int inst_ns, u32 sclk_hz)
{
unsigned int t;
/* negative delay indicates error, e.g. from spi_delay_to_ns() */
if (delay_ns <= 0)
/*
* Negative delay indicates error, e.g. from spi_delay_to_ns(). And if
* delay is less that the instruction execution time, there is no need
* for an extra sleep instruction since the instruction execution time
* will already cover the required delay.
*/
if (delay_ns < 0 || delay_ns <= inst_ns)
return;
/* rounding down since executing the instruction adds a couple of ticks delay */
t = DIV_ROUND_DOWN_ULL((u64)delay_ns * sclk_hz, NSEC_PER_SEC);
t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC);
while (t) {
unsigned int n = min(t, 256U);
@ -220,10 +224,16 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
struct spi_device *spi = msg->spi;
struct spi_controller *host = spi->controller;
struct spi_transfer *xfer;
int clk_div, new_clk_div;
int clk_div, new_clk_div, inst_ns;
bool keep_cs = false;
u8 bits_per_word = 0;
/*
* Take into account instruction execution time for more accurate sleep
* times, especially when the delay is small.
*/
inst_ns = DIV_ROUND_UP(NSEC_PER_SEC, host->max_speed_hz);
clk_div = 1;
spi_engine_program_add_cmd(p, dry,
@ -252,7 +262,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
spi_engine_gen_xfer(p, dry, xfer);
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
xfer->effective_speed_hz);
inst_ns, xfer->effective_speed_hz);
if (xfer->cs_change) {
if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
@ -262,7 +272,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
spi_engine_gen_cs(p, dry, spi, false);
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(
&xfer->cs_change_delay, xfer),
&xfer->cs_change_delay, xfer), inst_ns,
xfer->effective_speed_hz);
if (!list_next_entry(xfer, transfer_list)->cs_off)

View File

@ -984,6 +984,9 @@ static int davinci_spi_probe(struct platform_device *pdev)
return ret;
free_dma:
/* This bit needs to be cleared to disable dpsi->clk */
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);
@ -1013,6 +1016,9 @@ static void davinci_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&dspi->bitbang);
/* This bit needs to be cleared to disable dpsi->clk */
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);

View File

@ -1050,7 +1050,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.rx_available = mx31_rx_available,
.reset = mx31_reset,
.fifo_size = 8,
.has_dmamode = true,
.has_dmamode = false,
.dynamic_burst = false,
.has_targetmode = false,
.devtype = IMX35_CSPI,

View File

@ -158,12 +158,14 @@ static int spi_mux_probe(struct spi_device *spi)
/* supported modes are the same as our parent's */
ctlr->mode_bits = spi->controller->mode_bits;
ctlr->flags = spi->controller->flags;
ctlr->bits_per_word_mask = spi->controller->bits_per_word_mask;
ctlr->transfer_one_message = spi_mux_transfer_one_message;
ctlr->setup = spi_mux_setup;
ctlr->num_chipselect = mux_control_states(priv->mux);
ctlr->bus_num = -1;
ctlr->dev.of_node = spi->dev.of_node;
ctlr->must_async = true;
ctlr->defer_optimize_message = true;
ret = devm_spi_register_controller(&spi->dev, ctlr);
if (ret)

View File

@ -1277,24 +1277,11 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
/*
* Check if this transfer contains only one word;
* OR contains 1 to 4 words, with bits_per_word == 8 and no delay between each word
* OR contains 1 to 2 words, with bits_per_word == 16 and no delay between each word
*
* If one of the two last case is true, this also change the bits_per_word of this
* transfer to make it a bit faster.
* It's not an issue to change the bits_per_word here even if the multi-mode is not
* applicable for this message, the signal on the wire will be the same.
*/
if (bits_per_word < 8 && tr->len == 1) {
/* multi-mode is applicable, only one word (1..7 bits) */
} else if (tr->word_delay.value == 0 && bits_per_word == 8 && tr->len <= 4) {
/* multi-mode is applicable, only one "bigger" word (8,16,24,32 bits) */
tr->bits_per_word = tr->len * bits_per_word;
} else if (tr->word_delay.value == 0 && bits_per_word == 16 && tr->len <= 2) {
/* multi-mode is applicable, only one "bigger" word (16,32 bits) */
tr->bits_per_word = tr->len * bits_per_word / 2;
} else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) {
/* multi-mode is applicable, only one word (9..15,17..32 bits) */
/* multi-mode is applicable, only one word (8..32 bits) */
} else {
/* multi-mode is not applicable: more than one word in the transfer */
mcspi->use_multi_mode = false;

View File

@ -2151,7 +2151,8 @@ static void __spi_unoptimize_message(struct spi_message *msg)
*/
static void spi_maybe_unoptimize_message(struct spi_message *msg)
{
if (!msg->pre_optimized && msg->optimized)
if (!msg->pre_optimized && msg->optimized &&
!msg->spi->controller->defer_optimize_message)
__spi_unoptimize_message(msg);
}
@ -4294,6 +4295,11 @@ static int __spi_optimize_message(struct spi_device *spi,
static int spi_maybe_optimize_message(struct spi_device *spi,
struct spi_message *msg)
{
if (spi->controller->defer_optimize_message) {
msg->spi = spi;
return 0;
}
if (msg->pre_optimized)
return 0;
@ -4324,6 +4330,13 @@ int spi_optimize_message(struct spi_device *spi, struct spi_message *msg)
{
int ret;
/*
* Pre-optimization is not supported and optimization is deferred e.g.
* when using spi-mux.
*/
if (spi->controller->defer_optimize_message)
return 0;
ret = __spi_optimize_message(spi, msg);
if (ret)
return ret;
@ -4350,6 +4363,9 @@ EXPORT_SYMBOL_GPL(spi_optimize_message);
*/
void spi_unoptimize_message(struct spi_message *msg)
{
if (msg->spi->controller->defer_optimize_message)
return;
__spi_unoptimize_message(msg);
msg->pre_optimized = false;
}
@ -4432,8 +4448,6 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
spi_maybe_unoptimize_message(message);
return ret;
}
EXPORT_SYMBOL_GPL(spi_async);

View File

@ -533,6 +533,9 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @queue_empty: signal green light for opportunistically skipping the queue
* for spi_sync transfers.
* @must_async: disable all fast paths in the core
* @defer_optimize_message: set to true if controller cannot pre-optimize messages
* and needs to defer the optimization step until the message is actually
* being transferred
*
* Each SPI controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals
@ -776,6 +779,7 @@ struct spi_controller {
/* Flag for enabling opportunistic skipping of the queue in spi_sync */
bool queue_empty;
bool must_async;
bool defer_optimize_message;
};
static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)