RE: [PATCH] ASoC: fsl: imx-pcm-dma: Don't request dma channel in probe
From: Robin Gong
Date: Mon Apr 19 2021 - 03:17:21 EST
Hi Lucas,
On 2021/04/14 Lucas Stach <l.stach@xxxxxxxxxxxxxx> wrote:
> Hi Robin,
>
> Am Mittwoch, dem 14.04.2021 um 14:33 +0000 schrieb Robin Gong:
> > On 2020/05/20 17:43 Lucas Stach <l.stach@xxxxxxxxxxxxxx> wrote:
> > > Am Mittwoch, den 20.05.2020, 16:20 +0800 schrieb Shengjiu Wang:
> > > > Hi
> > > >
> > > > On Tue, May 19, 2020 at 6:04 PM Lucas Stach
> > > > <l.stach@xxxxxxxxxxxxxx>
> > > wrote:
> > > > > Am Dienstag, den 19.05.2020, 17:41 +0800 schrieb Shengjiu Wang:
> > > > > > There are two requirements that we need to move the request of
> > > > > > dma channel from probe to open.
> > > > >
> > > > > How do you handle -EPROBE_DEFER return code from the channel
> > > > > request if you don't do it in probe?
> > > >
> > > > I use the dma_request_slave_channel or dma_request_channel instead
> > > > of dmaengine_pcm_request_chan_of. so there should be not
> > > > -EPROBE_DEFER return code.
> > >
> > > This is a pretty weak argument. The dmaengine device might probe
> > > after you try to get the channel. Using a function to request the
> > > channel that doesn't allow you to handle probe deferral is IMHO a
> > > bug and should be fixed, instead of building even more assumptions on top
> of it.
> > >
> > > > > > - When dma device binds with power-domains, the power will be
> > > > > > enabled when we request dma channel. If the request of dma
> > > > > > channel happen on probe, then the power-domains will be always
> > > > > > enabled after kernel boot up, which is not good for power
> > > > > > saving, so we need to move the request of dma channel to
> > > > > > .open();
> > > > >
> > > > > This is certainly something which could be fixed in the
> > > > > dmaengine driver.
> > > >
> > > > Dma driver always call the pm_runtime_get_sync in
> > > > device_alloc_chan_resources, the device_alloc_chan_resources is
> > > > called when channel is requested. so power is enabled on channel
> request.
> > >
> > > So why can't you fix the dmaengine driver to do that RPM call at a
> > > later time when the channel is actually going to be used? This will
> > > allow further power savings with other slave devices than the audio PCM.
> > Hi Lucas,
> > Thanks for your suggestion. I have tried to implement runtime
> > autosuspend in fsl-edma driver on i.mx8qm/qxp with delay time (2 sec)
> > for this feature as below (or you can refer to
> > drivers/dma/qcom/hidma.c), and pm_runtime_get_sync/
> > pm_runtime_put_autosuspend in all dmaengine driver interface like
> > device_alloc_chan_resources/device_prep_slave_sg/device_prep_dma_cycli
> > c/
> > device_tx_status...
> >
> >
> > pm_runtime_use_autosuspend(fsl_chan->dev);
> > pm_runtime_set_autosuspend_delay(fsl_chan->dev,
> 2000);
> >
> > That could resolve this audio case since the autosuspend could suspend
> > runtime after
> > 2 seconds if there is no further dma transfer but only channel
> request(device_alloc_chan_resources).
> > But unfortunately, it cause another issue. As you know, on our
> > i.mx8qm/qxp, power domain done by scfw (drivers/firmware/imx/scu-pd.c)
> over mailbox:
> > imx_sc_pd_power()->imx_scu_call_rpc()->
> > imx_scu_ipc_write()->mbox_send_message()
> > which means have to 'waits for completion', meanwhile, some driver
> > like tty will call dmaengine interfaces in non-atomic case as below,
> >
> > static int uart_write(struct tty_struct *tty, const unsigned char
> > *buf, int count) {
> > .......
> > port = uart_port_lock(state, flags);
> > ......
> > __uart_start(tty); //call start_tx()->dmaengine_prep_slave_sg...
> > uart_port_unlock(port, flags);
> > return ret;
> > }
> >
> > Thus dma runtime resume may happen in that timing window and cause
> kernel alarm.
> > I'm not sure whether there are similar limitations on other driver
> > subsystem. But for me, It looks like the only way to resolve the
> > contradiction between tty and scu-pd (hardware limitation on
> > i.mx8qm/qxp) is to give up autosuspend and keep pm_runtime_get_sync
> only in device_alloc_chan_resources because request channel is a safe
> non-atomic phase.
> > Do you have any idea? Thanks in advance.
>
> If you look closely at the driver you used as an example (hidma.c) it looks like
> there is already something in there, which looks very much like what you need
> here:
>
> In hidma_issue_pending() the driver tries to get the device to runtime resume.
> If this doesn't work, maybe due to the power domain code not being able to
> be called in atomic context, the actual work of waking up the dma hardware
> and issuing the descriptor is shunted to a tasklet.
>
> If I'm reading this right, this is exactly what you need here to be able to call the
> dmaengine code from atomic context: try the rpm get and issue immediately
> when possible, otherwise shunt the work to a non- atomic context where you
> can deal with the requirements of scu-pd.
Yes, I can schedule_work to worker to runtime resume edma channel by calling scu-pd.
But that means all dmaengine interfaces should be taken care, not only issue_pending()
but also dmaengine_terminate_all()/dmaengine_pause()/dmaengine_resume()/
dmaengine_tx_status(). Not sure why hidma only take care issue_pending. Maybe
their user case is just for memcpy/memset so that no further complicate case as ALSA
or TTY.
Besides, for autosuspend in cyclic, we have to add pm_runtime_get_sync into interrupt
handler as qcom/bam_dma.c. but how could resolve the scu-pd's non-atmoic limitation
in interrupt handler?
>
> Also you don't need the runtime resume in all of the functions you mentioned.
> From a quick look into the edma driver it looks like for example the
> prep_slave_dma() function only touches data structures in memory, so you
> don't actually need the device to be awake at that point. Only later in the flow
> when you write registers in the dma hardware and actually issue the transfer
> you need to wake the device from sleep.
Yes, don't need add pm_runtime_get_sync into prep_slave_dma, only care where
HW indeed touched like issue_pending()/terminated_all()/pause()/resume..etc.