Mark, Andy,

On Thu, May 21, 2020 at 04:21:51AM +0300, Serge Semin wrote:
>  

[nip]

> +static void dw_spi_dma_calc_delay(struct dw_spi *dws, u32 nents,
> +                               struct spi_delay *delay)
> +{
> +     unsigned long ns, us;
> +
> +     ns = (NSEC_PER_SEC / spi_get_clk(dws)) * nents * dws->n_bytes *
> +          BITS_PER_BYTE;
> +
> +     if (ns <= NSEC_PER_USEC) {
> +             delay->unit = SPI_DELAY_UNIT_NSECS;
> +             delay->value = ns;
> +     } else {
> +             us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
> +             delay->unit = SPI_DELAY_UNIT_USECS;
> +             delay->value = clamp_val(us, 0, USHRT_MAX);
> +     }
> +}
> +
> +static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
> +{
> +     return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT);
> +}
> +
> +static void dw_spi_dma_wait_tx_done(struct dw_spi *dws)
> +{
> +     int retry = WAIT_RETRIES;
> +     struct spi_delay delay;
> +     u32 nents;
> +
> +     nents = dw_readl(dws, DW_SPI_TXFLR);
> +     dw_spi_dma_calc_delay(dws, nents, &delay);
> +
> +     while (dw_spi_dma_tx_busy(dws) && retry--)

> +             spi_delay_exec(&delay, NULL);

I've just discovered using spi_delay_exec() wasn't a good idea here. Look at the
call stack:
dw_dma_tasklet() -> dwc_scan_descriptors() -> dwc_descriptor_complete() ->
dw_spi_dma_tx_done() -> spi_delay_exec() -> usleep_range() -> ...

So tasklet is calling a sleeping function.((( I've absolutely forgotten to check
the context the DMA completion function is called with. We'll have to manually
select either ndelay or udelay here and nothing else. Since basically both
functions represent an atomic context and most of the platforms ndelay 
fallsback to
udelay, I'll get the ndelay back to the wait functions. I'll resend a patchset
shortly.

-Sergey

Reply via email to