* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Tony Lindgren @ 2018-11-25 1:11 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Aaro Koskinen, Peter Ujfalusi, vkoul, dan.j.williams, dmaengine,
linux-kernel, linux-omap
* Tony Lindgren <tony@atomide.com> [181125 01:07]:
> * Russell King - ARM Linux <linux@armlinux.org.uk> [181124 20:10]:
> > On Fri, Nov 23, 2018 at 08:52:15PM +0200, Aaro Koskinen wrote:
> > > Hi,
> > >
> > > On Fri, Nov 23, 2018 at 02:35:04PM +0200, Peter Ujfalusi wrote:
> > > > On 22/11/2018 17.12, Russell King - ARM Linux wrote:
> > > > > I'm also not sure about this:
> > > > >
> > > > > if (cpu_is_omap15xx())
> > > > > end++;
> > > > >
> > > > > in dma_dest_len() - is that missing from the omap-dma driver? It looks
> > > > > like a work-around for some problem on OMAP15xx, but I can't make sense
> > > > > about why it's in the UDC driver rather than the legacy DMA driver.
> > > >
> > > > afaik no other legacy drivers were doing similar thing, this must be
> > > > something which is needed for the omap_udc driver to fix up something?
> > >
> > > Here's the patch that added it: https://marc.info/?l=linux-omap&m=119634396324221&w=2
> > >
> > > "Make DMA-OUT behave on the 1510 ... the 1510 CPC register was just
> > > off-by-one with respect to the 1611 CDAC"
> >
> > ... which suggests that's a problem with the CPC register itself, and
> > we should fix that in the DMAengine driver rather than the USB gadget
> > driver.
> >
> > Tony, any input on this?
>
> Yeah that sounds like some hardware work-around for 15xx as described
> in the DMA_DEST_LAST macro reading CSAC on 15xx instead of CDAC. Seems
> like it should be done in the dmaengine driver.. My guess is that other
> dma users never needed to read CSAC register?
And it looks like for 15xx we have CPC and CSAC both at offset 0x18 in
arch/arm/mach-omap1/dma.c, seems like the dma driver is missing handling
for the CPC register that's there only for 15xx.
Regards,
Tony
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Tony Lindgren @ 2018-11-25 1:07 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Aaro Koskinen, Peter Ujfalusi, vkoul, dan.j.williams, dmaengine,
linux-kernel, linux-omap
* Russell King - ARM Linux <linux@armlinux.org.uk> [181124 20:10]:
> On Fri, Nov 23, 2018 at 08:52:15PM +0200, Aaro Koskinen wrote:
> > Hi,
> >
> > On Fri, Nov 23, 2018 at 02:35:04PM +0200, Peter Ujfalusi wrote:
> > > On 22/11/2018 17.12, Russell King - ARM Linux wrote:
> > > > I'm also not sure about this:
> > > >
> > > > if (cpu_is_omap15xx())
> > > > end++;
> > > >
> > > > in dma_dest_len() - is that missing from the omap-dma driver? It looks
> > > > like a work-around for some problem on OMAP15xx, but I can't make sense
> > > > about why it's in the UDC driver rather than the legacy DMA driver.
> > >
> > > afaik no other legacy drivers were doing similar thing, this must be
> > > something which is needed for the omap_udc driver to fix up something?
> >
> > Here's the patch that added it: https://marc.info/?l=linux-omap&m=119634396324221&w=2
> >
> > "Make DMA-OUT behave on the 1510 ... the 1510 CPC register was just
> > off-by-one with respect to the 1611 CDAC"
>
> ... which suggests that's a problem with the CPC register itself, and
> we should fix that in the DMAengine driver rather than the USB gadget
> driver.
>
> Tony, any input on this?
Yeah that sounds like some hardware work-around for 15xx as described
in the DMA_DEST_LAST macro reading CSAC on 15xx instead of CDAC. Seems
like it should be done in the dmaengine driver.. My guess is that other
dma users never needed to read CSAC register?
Regards,
Tony
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Russell King - ARM Linux @ 2018-11-24 20:09 UTC (permalink / raw)
To: Aaro Koskinen, tony
Cc: Peter Ujfalusi, vkoul, dan.j.williams, dmaengine, linux-kernel,
linux-omap
On Fri, Nov 23, 2018 at 08:52:15PM +0200, Aaro Koskinen wrote:
> Hi,
>
> On Fri, Nov 23, 2018 at 02:35:04PM +0200, Peter Ujfalusi wrote:
> > On 22/11/2018 17.12, Russell King - ARM Linux wrote:
> > > I'm also not sure about this:
> > >
> > > if (cpu_is_omap15xx())
> > > end++;
> > >
> > > in dma_dest_len() - is that missing from the omap-dma driver? It looks
> > > like a work-around for some problem on OMAP15xx, but I can't make sense
> > > about why it's in the UDC driver rather than the legacy DMA driver.
> >
> > afaik no other legacy drivers were doing similar thing, this must be
> > something which is needed for the omap_udc driver to fix up something?
>
> Here's the patch that added it: https://marc.info/?l=linux-omap&m=119634396324221&w=2
>
> "Make DMA-OUT behave on the 1510 ... the 1510 CPC register was just
> off-by-one with respect to the 1611 CDAC"
... which suggests that's a problem with the CPC register itself, and
we should fix that in the DMAengine driver rather than the USB gadget
driver.
Tony, any input on this?
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Russell King - ARM Linux @ 2018-11-24 19:29 UTC (permalink / raw)
To: Aaro Koskinen
Cc: Greg KH, Peter Ujfalusi, vkoul, dan.j.williams, dmaengine,
linux-kernel, tony, linux-omap, Felipe Balbi
On Sat, Nov 24, 2018 at 09:06:48PM +0200, Aaro Koskinen wrote:
> Hello,
>
> On Sat, Nov 24, 2018 at 05:48:23PM +0000, Russell King - ARM Linux wrote:
> > Hmm, there's more questionable stuff in this driver, and the gadget
> > layer.
>
> [...]
>
> > So, whatever way I look at this, the code in the removal path both
> > in omap_udc and the gadget removal code higher up looks very wrong
> > and broken to me.
>
> Yes, week ago I saw omap_udc crashing on both probe failure and
> module removal and sent some fixes for the most obvious failures (see
> https://marc.info/?l=linux-usb&m=154258778316932&w=2).
The effect of your patch is basically to replace the release function
with a no-op function.
> Is there any good driver that uses usb_add_gadget_udc_release() correctly?
> Looking at fsl_qe_udc.c and fsl_udc_core.c they should also crash if
> usb_add_gadget_udc_release() fails.
usb_add_gadget_udc_release() itself will call the release function
automatically on error.
The release function should _also_ be called when usb_del_gadget_udc()
is called (and would be guaranteed if the memset() is removed.)
So, moving the cleanup in the remove path into the release function
would solve the problem with omap_udc, and removing the memset()
would solve the problem with the core code.
It does leave a problem if the omap_udc module is removed - the
release function _could_ be called after the module has been removed
which would lead to an oops. That's presumably why there's a
completion. One solution to that would be to move the assignment
of udc->done before the call to usb_del_gadget_udc().
However, using a completion for something like this tends to be
frowned upon, but I don't see any other way to ensure correctness
here.
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Aaro Koskinen @ 2018-11-24 19:06 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Greg KH, Peter Ujfalusi, vkoul, dan.j.williams, dmaengine,
linux-kernel, tony, linux-omap, Felipe Balbi
Hello,
On Sat, Nov 24, 2018 at 05:48:23PM +0000, Russell King - ARM Linux wrote:
> Hmm, there's more questionable stuff in this driver, and the gadget
> layer.
[...]
> So, whatever way I look at this, the code in the removal path both
> in omap_udc and the gadget removal code higher up looks very wrong
> and broken to me.
Yes, week ago I saw omap_udc crashing on both probe failure and
module removal and sent some fixes for the most obvious failures (see
https://marc.info/?l=linux-usb&m=154258778316932&w=2).
Is there any good driver that uses usb_add_gadget_udc_release() correctly?
Looking at fsl_qe_udc.c and fsl_udc_core.c they should also crash if
usb_add_gadget_udc_release() fails.
A.
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Russell King - ARM Linux @ 2018-11-24 17:48 UTC (permalink / raw)
To: Aaro Koskinen, Greg KH
Cc: Peter Ujfalusi, vkoul, dan.j.williams, dmaengine, linux-kernel,
tony, linux-omap, Felipe Balbi
On Sat, Nov 24, 2018 at 02:17:40AM +0200, Aaro Koskinen wrote:
> Hi,
>
> On Fri, Nov 23, 2018 at 01:45:46PM +0200, Peter Ujfalusi wrote:
> > On 23/11/2018 0.01, Aaro Koskinen wrote:
> > > With that reverted, the DMA works OK (and I can also now confirm that
> > > OMAP_DMA_LCH_2D works). I haven't yet checked if we actually need that
> > > quirk in OMAP UDC,
> >
> > The omap_udc driver is a bit of a mess, need to check it myself, but for
> > now we can just set the quirk_ep_out_aligned_size and investigate later.
>
> OK, with quirk_ep_out_aligned_size we get 770/16xx DMA working again,
> but on 15xx the omap_udc DMA still doesn't work (tested today for the
> first time ever, I have no idea if it has ever worked and if so, when?).
Hmm, there's more questionable stuff in this driver, and the gadget
layer.
Fundamental fact of struct device - it's a ref-counted structure and
will only be freed when the last reference is dropped. dev_unregister()
merely drops the refcount, it doesn't guarantee that it's dropped to
zero (iow, there can be other users). Only when the refcount drops
to zero is the dev.release function called. However:
usb_add_gadget_udc_release(..., release)
{
if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release;
device_initialize(&gadget->dev);
ret = device_add(&gadget->dev);
}
At this point, that struct device is registered, so its refcount can
be increased by other users.
void usb_del_gadget_udc(struct usb_gadget *gadget)
{
...
device_unregister(&gadget->dev);
memset(&gadget->dev, 0x00, sizeof(gadget->dev));
}
That memset() is down-right wrong - the refcount on this struct device
may _not_ be zero at this point, the struct device could well be in
use by another thread. That memset will trample over the contents of
the structure potentially while someone else is using it, and
_potentially_ before the gadget->dev.release function has been called.
However, that _may_ be a good thing when you read the omap_udc code:
status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
omap_udc_release);
During the omap_udc_remove() function:
{
...
usb_del_gadget_udc(&udc->gadget);
if (udc->driver)
return -EBUSY;
udc->done = &done;
... more dereferences of udc, which is a _global_ variable ...
wait_for_completion(&done);
}
Now, omap_udc_release() does this:
complete(udc->done);
kfree(udc);
udc = NULL;
So, when usb_del_gadget_udc() is called, if device_unregister() within
there drops the last reference count, omap_udc_release() will be called
immediately. Since udc->done hasn't been setup at that point, that
complete() will fail with a NULL pointer dereference. If that doesn't
happen, then the kfree() and following set of the global 'udc' variable
to NULL means that all future references to 'udc' after the call to
usb_del_gadget_udc() in omap_udc_remove() will be dereferencing a NULL
pointer. So one way or the other, this leads to a kernel OOPS.
If, on the other hand, omap_udc_release() was not called in
device_unregister(), the function pointer will be zeroed by the
memset(), which will lead to 'udc' never being freed - in other words,
we leak memory.
What's more is that 'done' is never "completed" so we end up hanging
at the wait_for_completion().
Then there's the pointless:
if (udc->driver)
return -EBUSY;
in omap_udc_remove(). The effect of returning an error is... what
exactly? It doesn't prevent the device being removed at all, it
doesn't delay it, in fact the whole "remove returns an int" is
nothing but confusion - the return value from all driver remove
methods is completely ignored.
If udc->driver is still set at this point, it basically means that
we skip the rest of the tear down, but the platform device will
still be unbound from the driver, leaving (eg) the transceiver phy
still claimed, the procfs file still registered, the interrupts
still claimed, the memory region still registered, etc. If omap_udc
is built as a module, the module could even be removed while all
that is still registered.
So, whatever way I look at this, the code in the removal path both
in omap_udc and the gadget removal code higher up looks very wrong
and broken to me.
^ permalink raw reply
* [3/5] dmaengine: imx-sdma: remove dma_slave_config direction usage
From: Vinod Koul @ 2018-11-24 14:50 UTC (permalink / raw)
To: Robin Gong; +Cc: dmaengine@vger.kernel.org
On 20-11-18, 09:01, Robin Gong wrote:
> Hi Vinod,
> Thanks for your kind reminding.
> I have test your patch these days and unfortunately, found it breaks uart/spi
> on i.mx6 boards. I identified the issue finally, could you please merge attached
> patch into your patch set to ensure no any regression?
Thanks for testing and I have squashed this to single commit
^ permalink raw reply
* dmaengine: ep93xx_dma: fix misspell
From: Vinod Koul @ 2018-11-24 14:39 UTC (permalink / raw)
To: Yangtao Li; +Cc: dan.j.williams, dmaengine, linux-kernel
On 19-11-18, 10:15, Yangtao Li wrote:
> couln't -> couldn't
Applied, thanks
^ permalink raw reply
* [v4,1/2] dt-bindings: dmaengine: dw-dmac: add protection control property
From: Vinod Koul @ 2018-11-24 14:38 UTC (permalink / raw)
To: Christian Lamparter
Cc: dmaengine, devicetree, Dan Williams, Andy Shevchenko,
Viresh Kumar, Rob Herring, Mark Rutland
On 17-11-18, 17:17, Christian Lamparter wrote:
> This patch for the DesignWare AHB Central
> Direct Memory Access Controller adds the dma
> protection control property:
> "snps,dma-protection-control"
>
> as well as the properties specific values defines into
> a new include file: include/dt-bindings/dma/dw-dmac.h
>
> Note: The protection control signals are one-to-one
> mapped to the AHB HPROT[1:3] signals for this controller.
> The HPROT0 (Data Access) is always hardwired to 1.
Applied this series, thanks.
^ permalink raw reply
* [resend] dt-bindings: dmaengine: usb-dmac: Add binding for r8a774a1
From: Vinod Koul @ 2018-11-24 14:33 UTC (permalink / raw)
To: Fabrizio Castro
Cc: Rob Herring, Mark Rutland, Biju Das, dmaengine, devicetree,
Simon Horman, Geert Uytterhoeven, Chris Paterson,
linux-renesas-soc
On 15-11-18, 11:59, Fabrizio Castro wrote:
> From: Biju Das <biju.das@bp.renesas.com>
>
> This patch adds binding for r8a774a1 (RZ/G2M).
>
> Signed-off-by: Biju Das <biju.das@bp.renesas.com>
Applied, thanks
^ permalink raw reply
* [resend] dmaengine: rcar-dmac: Document R8A774A1 bindings
From: Vinod Koul @ 2018-11-24 14:32 UTC (permalink / raw)
To: Fabrizio Castro
Cc: Rob Herring, Mark Rutland, dmaengine, devicetree, Simon Horman,
Geert Uytterhoeven, Chris Paterson, Biju Das, linux-renesas-soc
On 15-11-18, 11:58, Fabrizio Castro wrote:
> Renesas' RZ/G2M (R8A774A1) SoC has DMA controllers compatible
> with this driver, therefore document RZ/G2M specific bindings.
Applied, thanks
^ permalink raw reply
* dma: coh901318: Fix a double-lock bug
From: Vinod Koul @ 2018-11-24 14:30 UTC (permalink / raw)
To: Jia-Ju Bai
Cc: linus.walleij, dan.j.williams, linux-arm-kernel, dmaengine,
linux-kernel
On 06-11-18, 11:33, Jia-Ju Bai wrote:
> The function coh901318_alloc_chan_resources() calls spin_lock_irqsave()
> before calling coh901318_config().
> But coh901318_config() calls spin_lock_irqsave() again in its
> definition, which may cause a double-lock bug.
>
> Because coh901318_config() is only called by
> coh901318_alloc_chan_resources(), the bug fix is to remove the
> calls to spin-lock and -unlock functions in coh901318_config().
Applied after fixing subsystem tag, thanks
^ permalink raw reply
* dma: cppi41: delete channel from pending list when stop channel
From: Vinod Koul @ 2018-11-24 14:28 UTC (permalink / raw)
To: Bin Liu, Peter Ujfalusi; +Cc: dmaengine, linux-usb, stable
On 12-11-18, 09:43, Bin Liu wrote:
> The driver defines three states for a cppi channel.
> - idle: .chan_busy == 0 && not in .pending list
> - pending: .chan_busy == 0 && in .pending list
> - busy: .chan_busy == 1 && not in .pending list
>
> There are cases in which the cppi channel could be in the pending state
> when cppi41_dma_issue_pending() is called after cppi41_runtime_suspend()
> is called.
>
> cppi41_stop_chan() has a bug for these cases to set channels to idle state.
> It only checks the .chan_busy flag, but not the .pending list, then later
> when cppi41_runtime_resume() is called the channels in .pending list will
> be transitioned to busy state.
>
> Removing channels from the .pending list solves the problem.
I would like some testing, given that intent is to go to stable.
Peter..?
>
> Fixes: 975faaeb9985 ("dma: cppi41: start tear down only if channel is busy")
> Cc: stable@vger.kernel.org # v3.15+
> Signed-off-by: Bin Liu <b-liu@ti.com>
> ---
> drivers/dma/ti/cppi41.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma/ti/cppi41.c b/drivers/dma/ti/cppi41.c
> index 1497da367710..e507ec36c0d3 100644
> --- a/drivers/dma/ti/cppi41.c
> +++ b/drivers/dma/ti/cppi41.c
> @@ -723,8 +723,22 @@ static int cppi41_stop_chan(struct dma_chan *chan)
>
> desc_phys = lower_32_bits(c->desc_phys);
> desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
> - if (!cdd->chan_busy[desc_num])
> + if (!cdd->chan_busy[desc_num]) {
> + struct cppi41_channel *cc, *_ct;
> +
> + /*
> + * channels might still be in the pendling list if
> + * cppi41_dma_issue_pending() is called after
> + * cppi41_runtime_suspend() is called
> + */
> + list_for_each_entry_safe(cc, _ct, &cdd->pending, node) {
> + if (cc != c)
> + continue;
> + list_del(&cc->node);
> + break;
> + }
> return 0;
> + }
>
> ret = cppi41_tear_down_chan(c);
> if (ret)
> --
> 2.17.1
^ permalink raw reply
* mm: Replace all open encodings for NUMA_NO_NODE
From: Vinod Koul @ 2018-11-24 14:05 UTC (permalink / raw)
To: Anshuman Khandual
Cc: linux-mm, linux-kernel, ocfs2-devel, linux-fbdev, dri-devel,
netdev, intel-wired-lan, linux-media, iommu, linux-rdma,
dmaengine, linux-block, sparclinux, linuxppc-dev, linux-ia64,
linux-alpha, akpm, jiangqi903, hverkuil
On 23-11-18, 15:24, Anshuman Khandual wrote:
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -386,7 +386,8 @@ EXPORT_SYMBOL(dma_issue_pending_all);
> static bool dma_chan_is_local(struct dma_chan *chan, int cpu)
> {
> int node = dev_to_node(chan->device->dev);
> - return node == -1 || cpumask_test_cpu(cpu, cpumask_of_node(node));
> + return node == NUMA_NO_NODE ||
> + cpumask_test_cpu(cpu, cpumask_of_node(node));
> }
I do not see dev_to_node being updated first, that returns -1 so I would
prefer to check for -1 unless it return NUMA_NO_NODE
^ permalink raw reply
* dmaengine: dmatest: move size checks earlier in function
From: Vinod Koul @ 2018-11-24 13:51 UTC (permalink / raw)
To: Alexandru Ardelean; +Cc: dmaengine
On 01-11-18, 18:07, Alexandru Ardelean wrote:
> There's no need to allocate all that memory if these sizes are invalid
> anyway.
Applied, thanks
^ permalink raw reply
* [V2] dmaengine: dmatest: unmap data on a single code-path when xfer done
From: Vinod Koul @ 2018-11-24 13:47 UTC (permalink / raw)
To: Alexandru Ardelean; +Cc: dmaengine, dan.j.williams
On 29-10-18, 12:08, Alexandru Ardelean wrote:
> After the DMA transfer is done, we don't need to call the un-mapping code
> in 3 places. One is enough.
Applied, thanks
^ permalink raw reply
* dmaengine: dmatest: use dmaengine_terminate_sync() instead
From: Vinod Koul @ 2018-11-24 13:46 UTC (permalink / raw)
To: Alexandru Ardelean; +Cc: dmaengine, dan.j.williams, vinod.koul
On 29-10-18, 11:23, Alexandru Ardelean wrote:
> The `dmaengine_terminate_all()` is marked as deprecated, so update the test
> with `dmaengine_terminate_sync()` which is the recommended alternative.
Applied, thanks
^ permalink raw reply
* dmaengine: xilinx_dma: Remove __aligned attribute on zynqmp_dma_desc_ll
From: Vinod Koul @ 2018-11-24 13:41 UTC (permalink / raw)
To: Nathan Chancellor
Cc: Dan Williams, Michal Simek, dmaengine, linux-arm-kernel,
linux-kernel, Nick Desaulniers
On 25-10-18, 11:05, Nathan Chancellor wrote:
> Clang warns:
>
> drivers/dma/xilinx/zynqmp_dma.c:166:4: warning: attribute 'aligned' is
> ignored, place it after "struct" to apply attribute to type declaration
> [-Wignored-attributes]
> }; __aligned(64)
> ^
> ./include/linux/compiler_types.h:200:38: note: expanded from macro
> '__aligned'
> #define __aligned(x) __attribute__((aligned(x)))
> ^
> 1 warning generated.
>
> As Nick pointed out in the previous version of this patch, the author
> likely intended for this struct to be 8-byte (64-bit) aligned, not
> 64-byte, which is the default. Remove the hanging __aligned attribute.
Applied, thanks
^ permalink raw reply
* dmaengine: imx-sdma: Use a single line for dma_alloc_coherent()
From: Vinod Koul @ 2018-11-24 13:38 UTC (permalink / raw)
To: Fabio Estevam; +Cc: dmaengine
On 25-10-18, 14:52, Fabio Estevam wrote:
> Make the call to dma_alloc_coherent() to fit into a single line, which
> helps readability.
Applied, thanks
^ permalink raw reply
* mm: Replace all open encodings for NUMA_NO_NODE
From: Anshuman Khandual @ 2018-11-24 11:13 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-mm, linux-kernel, ocfs2-devel, linux-fbdev, dri-devel,
netdev, intel-wired-lan, linux-media, iommu, linux-rdma,
dmaengine, linux-block, sparclinux, linuxppc-dev, linux-ia64,
linux-alpha, jiangqi903, hverkuil
On 11/24/2018 05:14 AM, Andrew Morton wrote:
> On Fri, 23 Nov 2018 15:24:16 +0530 Anshuman Khandual <anshuman.khandual@arm.com> wrote:
>
>> At present there are multiple places where invalid node number is encoded
>> as -1. Even though implicitly understood it is always better to have macros
>> in there. Replace these open encodings for an invalid node number with the
>> global macro NUMA_NO_NODE. This helps remove NUMA related assumptions like
>> 'invalid node' from various places redirecting them to a common definition.
>>
>> ...
>>
>> Build tested this with multiple cross compiler options like alpha, sparc,
>> arm64, x86, powerpc, powerpc64le etc with their default config which might
>> not have compiled tested all driver related changes. I will appreciate
>> folks giving this a test in their respective build environment.
>>
>> All these places for replacement were found by running the following grep
>> patterns on the entire kernel code. Please let me know if this might have
>> missed some instances. This might also have replaced some false positives.
>> I will appreciate suggestions, inputs and review.
>>
>> 1. git grep "nid == -1"
>> 2. git grep "node == -1"
>> 3. git grep "nid = -1"
>> 4. git grep "node = -1"
>
> The build testing is good, but I worry that some of the affected files
> don't clearly have numa.h in their include paths, for the NUMA_NO_NODE
> definition.
>
> The first thing I looked it is arch/powerpc/include/asm/pci-bridge.h.
> Maybe it somehow manages to include numa.h via some nested include, but
> if so, is that reliable across all config combinations and as code
> evolves?
>
> So I think that the patch should have added an explicit include of
> numa.h, especially in cases where the affected file previously had no
> references to any of the things which numa.h defines.
Fair enough. Will include numa.h in those particular files.
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Aaro Koskinen @ 2018-11-24 0:17 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: vkoul, dan.j.williams, dmaengine, linux-kernel, tony, linux-omap,
rmk+kernel, Felipe Balbi
Hi,
On Fri, Nov 23, 2018 at 01:45:46PM +0200, Peter Ujfalusi wrote:
> On 23/11/2018 0.01, Aaro Koskinen wrote:
> > With that reverted, the DMA works OK (and I can also now confirm that
> > OMAP_DMA_LCH_2D works). I haven't yet checked if we actually need that
> > quirk in OMAP UDC,
>
> The omap_udc driver is a bit of a mess, need to check it myself, but for
> now we can just set the quirk_ep_out_aligned_size and investigate later.
OK, with quirk_ep_out_aligned_size we get 770/16xx DMA working again,
but on 15xx the omap_udc DMA still doesn't work (tested today for the
first time ever, I have no idea if it has ever worked and if so, when?).
A.
^ permalink raw reply
* mm: Replace all open encodings for NUMA_NO_NODE
From: Andrew Morton @ 2018-11-23 23:44 UTC (permalink / raw)
To: Anshuman Khandual
Cc: linux-mm, linux-kernel, ocfs2-devel, linux-fbdev, dri-devel,
netdev, intel-wired-lan, linux-media, iommu, linux-rdma,
dmaengine, linux-block, sparclinux, linuxppc-dev, linux-ia64,
linux-alpha, jiangqi903, hverkuil
On Fri, 23 Nov 2018 15:24:16 +0530 Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> At present there are multiple places where invalid node number is encoded
> as -1. Even though implicitly understood it is always better to have macros
> in there. Replace these open encodings for an invalid node number with the
> global macro NUMA_NO_NODE. This helps remove NUMA related assumptions like
> 'invalid node' from various places redirecting them to a common definition.
>
> ...
>
> Build tested this with multiple cross compiler options like alpha, sparc,
> arm64, x86, powerpc, powerpc64le etc with their default config which might
> not have compiled tested all driver related changes. I will appreciate
> folks giving this a test in their respective build environment.
>
> All these places for replacement were found by running the following grep
> patterns on the entire kernel code. Please let me know if this might have
> missed some instances. This might also have replaced some false positives.
> I will appreciate suggestions, inputs and review.
>
> 1. git grep "nid == -1"
> 2. git grep "node == -1"
> 3. git grep "nid = -1"
> 4. git grep "node = -1"
The build testing is good, but I worry that some of the affected files
don't clearly have numa.h in their include paths, for the NUMA_NO_NODE
definition.
The first thing I looked it is arch/powerpc/include/asm/pci-bridge.h.
Maybe it somehow manages to include numa.h via some nested include, but
if so, is that reliable across all config combinations and as code
evolves?
So I think that the patch should have added an explicit include of
numa.h, especially in cases where the affected file previously had no
references to any of the things which numa.h defines.
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Russell King - ARM Linux @ 2018-11-23 23:27 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: Aaro Koskinen, vkoul, dan.j.williams, dmaengine, linux-kernel,
tony, linux-omap
On Fri, Nov 23, 2018 at 04:16:59PM +0000, Russell King - ARM Linux wrote:
> Hi Peter,
>
> Here's the patch, which should now support IN as well as OUT.
> Completely untested, as mentioned before.
Now compile tested...
drivers/usb/gadget/udc/omap_udc.c | 291 ++++++++++++++++++--------------------
drivers/usb/gadget/udc/omap_udc.h | 3 +-
2 files changed, 137 insertions(+), 157 deletions(-)
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 3a16431da321..dd85476ec234 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -28,6 +28,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
+#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -203,7 +204,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
/* set endpoint to initial state */
ep->dma_channel = 0;
ep->has_dma = 0;
- ep->lch = -1;
+ ep->dma = NULL;
use_ep(ep, UDC_EP_SEL);
omap_writew(udc->clr_halt, UDC_CTRL);
ep->ackwait = 0;
@@ -468,43 +469,6 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
/*-------------------------------------------------------------------------*/
-static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- /* IN-DMA needs this on fault/cancel paths, so 15xx misreports
- * the last transfer's bytecount by more than a FIFO's worth.
- */
- if (cpu_is_omap15xx())
- return 0;
-
- end = omap_get_dma_src_pos(ep->lch);
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- end = omap_get_dma_dst_pos(ep->lch);
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (cpu_is_omap15xx())
- end++;
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-
/* Each USB transfer request using DMA maps to one or more DMA transfers.
* When DMA completion isn't request completion, the UDC continues with
* the next DMA transfer for that USB transfer.
@@ -512,34 +476,53 @@ static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
{
- u16 txdma_ctrl, w;
- unsigned length = req->req.length - req->req.actual;
- const int sync_mode = cpu_is_omap15xx()
- ? OMAP_DMA_SYNC_FRAME
- : OMAP_DMA_SYNC_ELEMENT;
- int dma_trigger = 0;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma = ep->dma;
+ dma_cookie_t cookie;
+ unsigned burst, length;
+ u16 txdma_ctrl, w;
+ struct dma_slave_config omap_udc_in_cfg = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = UDC_DATA_DMA,
+ };
+
+ length = req->req.length - req->req.actual;
/* measure length in either bytes or packets */
- if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
- || (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) ||
+ (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ omap_udc_in_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
txdma_ctrl = UDC_TXN_EOT | length;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode, dma_trigger, 0);
+ burst = length;
} else {
- length = min(length / ep->maxpacket,
- (unsigned) UDC_TXN_TSC + 1);
+ omap_udc_in_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ length = min_t(unsigned, length / ep->maxpacket,
+ UDC_TXN_TSC + 1);
txdma_ctrl = length;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, length, sync_mode,
- dma_trigger, 0);
length *= ep->maxpacket;
+ burst = ep->ep.maxpacket >> 1;
}
- omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
- 0, 0);
- omap_start_dma(ep->lch);
- ep->dma_counter = omap_get_dma_src_pos(ep->lch);
+ if (!cpu_is_omap15xx())
+ burst = 1;
+
+ omap_udc_in_cfg.dst_maxburst = burst;
+
+ if (WARN_ON(dmaengine_slave_config(dma, &omap_udc_in_cfg)))
+ return;
+
+ tx = dmaengine_prep_slave_single(dma, req->req.dma + req->req.actual,
+ length, DMA_MEM_TO_DEV, 0);
+ if (WARN_ON(!tx))
+ return;
+
+ cookie = dmaengine_submit(tx);
+ if (WARN_ON(dma_submit_error(cookie)))
+ return;
+
+ ep->dma_cookie = cookie;
+ dma_async_issue_pending(dma);
+
w = omap_readw(UDC_DMA_IRQ_EN);
w |= UDC_TX_DONE_IE(ep->dma_channel);
omap_writew(w, UDC_DMA_IRQ_EN);
@@ -549,11 +532,14 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
{
+ struct dma_tx_state state;
u16 w;
- if (status == 0) {
- req->req.actual += req->dma_bytes;
+ dmaengine_tx_status(ep->dma, ep->dma_cookie, &state);
+
+ req->req.actual += req->dma_bytes - state.residue;
+ if (status == 0) {
/* return if this request needs to send data or zlp */
if (req->req.actual < req->req.length)
return;
@@ -561,36 +547,47 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
&& req->dma_bytes != 0
&& (req->req.actual % ep->maxpacket) == 0)
return;
- } else
- req->req.actual += dma_src_len(ep, req->req.dma
- + req->req.actual);
+ }
/* tx completion */
- omap_stop_dma(ep->lch);
+ dmaengine_terminate_async(ep->dma);
+
w = omap_readw(UDC_DMA_IRQ_EN);
w &= ~UDC_TX_DONE_IE(ep->dma_channel);
omap_writew(w, UDC_DMA_IRQ_EN);
done(ep, req, status);
}
+static struct dma_slave_config omap_udc_out_cfg = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
+ /*
+ * DMAengine uses frame sync mode, setting maxburst=1
+ * is equivalent to element sync mode.
+ */
+ .src_maxburst = 1,
+ .src_addr = UDC_DATA_DMA,
+};
+
static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
{
- unsigned packets = req->req.length - req->req.actual;
- int dma_trigger = 0;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma = ep->dma;
+ dma_cookie_t cookie;
+ unsigned packets, length;
u16 w;
- /* set up this DMA transfer, enable the fifo, start */
- packets /= ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
- req->dma_bytes = packets * ep->ep.maxpacket;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, packets,
- OMAP_DMA_SYNC_ELEMENT,
- dma_trigger, 0);
- omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
- 0, 0);
- ep->dma_counter = omap_get_dma_dst_pos(ep->lch);
+ length = req->req.length - req->req.actual;
+ packets = min_t(unsigned, length / ep->ep.maxpacket, UDC_RXN_TC + 1);
+ length = packets * ep->ep.maxpacket;
+
+ if (WARN_ON(dmaengine_slave_config(dma, &omap_udc_out_cfg)))
+ return;
+
+ tx = dmaengine_prep_slave_single(dma, req->req.dma + req->req.actual,
+ length, DMA_DEV_TO_MEM, 0);
+ if (WARN_ON(!tx))
+ return;
omap_writew(UDC_RXN_STOP | (packets - 1), UDC_RXDMA(ep->dma_channel));
w = omap_readw(UDC_DMA_IRQ_EN);
@@ -599,29 +596,42 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
omap_writew(ep->bEndpointAddress & 0xf, UDC_EP_NUM);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
- omap_start_dma(ep->lch);
+ cookie = dmaengine_submit(tx);
+ if (WARN_ON(dma_submit_error(cookie)))
+ return;
+
+ ep->dma_cookie = cookie;
+ dma_async_issue_pending(dma);
+ req->dma_bytes = length;
}
static void
finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
{
+ struct dma_tx_state state;
u16 count, w;
- if (status == 0)
- ep->dma_counter = (u16) (req->req.dma + req->req.actual);
- count = dma_dest_len(ep, req->req.dma + req->req.actual);
+ dmaengine_tx_status(ep->dma, ep->dma_cookie, &state);
+
+ count = req->dma_bytes - state.residue;
count += req->req.actual;
if (one)
count--;
+
+ /*
+ * FIXME: Surely if count > req->req.length, something has gone
+ * seriously wrong and we've scribbled over memory we should not...
+ * so surely we should be a WARN_ON() at the very least?
+ */
if (count <= req->req.length)
req->req.actual = count;
- if (count != req->dma_bytes || status)
- omap_stop_dma(ep->lch);
-
+ if (count != req->dma_bytes || status) {
+ dmaengine_terminate_async(ep->dma);
/* if this wasn't short, request may need another transfer */
- else if (req->req.actual < req->req.length)
+ } else if (req->req.actual < req->req.length) {
return;
+ }
/* rx completion */
w = omap_readw(UDC_DMA_IRQ_EN);
@@ -683,32 +693,25 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
}
}
-static void dma_error(int lch, u16 ch_status, void *data)
-{
- struct omap_ep *ep = data;
-
- /* if ch_status & OMAP_DMA_DROP_IRQ ... */
- /* if ch_status & OMAP1_DMA_TOUT_IRQ ... */
- ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status);
-
- /* complete current transfer ... */
-}
-
static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
{
+ dma_cap_mask_t mask;
+ struct dma_chan *dma;
+ u32 dma_cfg;
u16 reg;
int status, restart, is_in;
int dma_channel;
is_in = ep->bEndpointAddress & USB_DIR_IN;
if (is_in)
- reg = omap_readw(UDC_TXDMA_CFG);
+ dma_cfg = UDC_TXDMA_CFG;
else
- reg = omap_readw(UDC_RXDMA_CFG);
+ dma_cfg = UDC_RXDMA_CFG;
+ reg = omap_readw(dma_cfg);
reg |= UDC_DMA_REQ; /* "pulse" activated */
ep->dma_channel = 0;
- ep->lch = -1;
+ ep->dma = NULL;
if (channel == 0 || channel > 3) {
if ((reg & 0x0f00) == 0)
channel = 3;
@@ -722,65 +725,38 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
}
}
reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1));
- ep->dma_channel = channel;
- if (is_in) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ if (is_in)
dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
- status = omap_request_dma(dma_channel,
- ep->ep.name, dma_error, ep, &ep->lch);
- if (status == 0) {
- omap_writew(reg, UDC_TXDMA_CFG);
- /* EMIFF or SDRC */
- omap_set_dma_src_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
- omap_set_dma_src_data_pack(ep->lch, 1);
- /* TIPB */
- omap_set_dma_dest_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
- UDC_DATA_DMA,
- 0, 0);
- }
- } else {
+ else
dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
- status = omap_request_dma(dma_channel,
- ep->ep.name, dma_error, ep, &ep->lch);
- if (status == 0) {
- omap_writew(reg, UDC_RXDMA_CFG);
- /* TIPB */
- omap_set_dma_src_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
- UDC_DATA_DMA,
- 0, 0);
- /* EMIFF or SDRC */
- omap_set_dma_dest_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
- omap_set_dma_dest_data_pack(ep->lch, 1);
- }
- }
- if (status)
- ep->dma_channel = 0;
- else {
- ep->has_dma = 1;
- omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
- /* channel type P: hw synch (fifo) */
- if (!cpu_is_omap15xx())
- omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
+ dma = __dma_request_channel(&mask, omap_dma_filter_fn,
+ (void *)dma_channel);
+ if (dma) {
+ omap_writew(reg, dma_cfg);
+ ep->dma_channel = channel;
+ ep->dma = dma;
+ ep->has_dma = 1;
+ status = 0;
+ } else {
+ ep->dma_channel = 0;
+ status = -EINVAL;
}
just_restart:
/* restart any queue, even if the claim failed */
restart = !ep->stopped && !list_empty(&ep->queue);
- if (status)
- DBG("%s no dma channel: %d%s\n", ep->ep.name, status,
- restart ? " (restart)" : "");
+ if (ep->dma)
+ DBG("%s claimed %cxdma%d dmaengine %s%s\n", ep->ep.name,
+ is_in ? 't' : 'r', ep->dma_channel - 1,
+ dma_chan_name(ep->dma), restart ? " (restart)" : "");
else
- DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name,
- is_in ? 't' : 'r',
- ep->dma_channel - 1, ep->lch,
+ DBG("%s no dma channel: %d%s\n", ep->ep.name, status,
restart ? " (restart)" : "");
if (restart) {
@@ -814,7 +790,8 @@ static void dma_channel_release(struct omap_ep *ep)
else
req = NULL;
- active = omap_get_dma_active_status(ep->lch);
+ active = dma_async_is_tx_complete(ep->dma, ep->dma_cookie, NULL, NULL)
+ == DMA_IN_PROGRESS;
DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
active ? "active" : "idle",
@@ -850,9 +827,9 @@ static void dma_channel_release(struct omap_ep *ep)
if (req)
finish_out_dma(ep, req, -ECONNRESET, 0);
}
- omap_free_dma(ep->lch);
+ dma_release_channel(ep->dma);
ep->dma_channel = 0;
- ep->lch = -1;
+ ep->dma = NULL;
/* has_dma still set, till endpoint is fully quiesced */
}
@@ -2146,9 +2123,9 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
use_ep(ep, 0);
if (use_dma && ep->has_dma)
- snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ",
+ snprintf(buf, sizeof buf, "(%cxdma%d dma %s) ",
(ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
- ep->dma_channel - 1, ep->lch);
+ ep->dma_channel - 1, dma_chan_name(ep->dma));
else
buf[0] = 0;
@@ -2194,9 +2171,11 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
unsigned length = req->req.actual;
if (use_dma && buf[0]) {
- length += ((ep->bEndpointAddress & USB_DIR_IN)
- ? dma_src_len : dma_dest_len)
- (ep, req->req.dma + length);
+ struct dma_tx_state state;
+
+ dmaengine_tx_status(ep->dma, ep->dma_cookie,
+ &state);
+ length += req->dma_bytes - state.residue;
buf[0] = 0;
}
seq_printf(s, "\treq %p len %d/%d buf %p\n",
diff --git a/drivers/usb/gadget/udc/omap_udc.h b/drivers/usb/gadget/udc/omap_udc.h
index 00f9e608e755..e04c48f669ed 100644
--- a/drivers/usb/gadget/udc/omap_udc.h
+++ b/drivers/usb/gadget/udc/omap_udc.h
@@ -152,7 +152,8 @@ struct omap_ep {
u8 ackwait;
u8 dma_channel;
u16 dma_counter;
- int lch;
+ struct dma_chan *dma;
+ dma_cookie_t dma_cookie;
struct omap_udc *udc;
struct timer_list timer;
};
^ permalink raw reply related
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Aaro Koskinen @ 2018-11-23 18:52 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: Russell King - ARM Linux, vkoul, dan.j.williams, dmaengine,
linux-kernel, tony, linux-omap
Hi,
On Fri, Nov 23, 2018 at 02:35:04PM +0200, Peter Ujfalusi wrote:
> On 22/11/2018 17.12, Russell King - ARM Linux wrote:
> > I'm also not sure about this:
> >
> > if (cpu_is_omap15xx())
> > end++;
> >
> > in dma_dest_len() - is that missing from the omap-dma driver? It looks
> > like a work-around for some problem on OMAP15xx, but I can't make sense
> > about why it's in the UDC driver rather than the legacy DMA driver.
>
> afaik no other legacy drivers were doing similar thing, this must be
> something which is needed for the omap_udc driver to fix up something?
Here's the patch that added it: https://marc.info/?l=linux-omap&m=119634396324221&w=2
"Make DMA-OUT behave on the 1510 ... the 1510 CPC register was just
off-by-one with respect to the 1611 CDAC"
A.
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Russell King - ARM Linux @ 2018-11-23 16:16 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: Aaro Koskinen, vkoul, dan.j.williams, dmaengine, linux-kernel,
tony, linux-omap
Hi Peter,
Here's the patch, which should now support IN as well as OUT.
Completely untested, as mentioned before.
drivers/usb/gadget/udc/omap_udc.c | 286 ++++++++++++++++++--------------------
drivers/usb/gadget/udc/omap_udc.h | 3 +-
2 files changed, 135 insertions(+), 154 deletions(-)
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 3a16431da321..ad6f315e4327 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -28,6 +28,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
+#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -203,7 +204,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
/* set endpoint to initial state */
ep->dma_channel = 0;
ep->has_dma = 0;
- ep->lch = -1;
+ ep->dma = NULL;
use_ep(ep, UDC_EP_SEL);
omap_writew(udc->clr_halt, UDC_CTRL);
ep->ackwait = 0;
@@ -468,43 +469,6 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
/*-------------------------------------------------------------------------*/
-static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- /* IN-DMA needs this on fault/cancel paths, so 15xx misreports
- * the last transfer's bytecount by more than a FIFO's worth.
- */
- if (cpu_is_omap15xx())
- return 0;
-
- end = omap_get_dma_src_pos(ep->lch);
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- end = omap_get_dma_dst_pos(ep->lch);
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (cpu_is_omap15xx())
- end++;
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-
/* Each USB transfer request using DMA maps to one or more DMA transfers.
* When DMA completion isn't request completion, the UDC continues with
* the next DMA transfer for that USB transfer.
@@ -512,34 +476,53 @@ static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
{
- u16 txdma_ctrl, w;
- unsigned length = req->req.length - req->req.actual;
- const int sync_mode = cpu_is_omap15xx()
- ? OMAP_DMA_SYNC_FRAME
- : OMAP_DMA_SYNC_ELEMENT;
- int dma_trigger = 0;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma = ep->dma;
+ dma_cookie_t cookie;
+ unsigned burst, length;
+ u16 txdma_ctrl, w;
+ struct dma_slave_config omap_udc_in_cfg = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = UDC_DATA_DMA,
+ };
+
+ length = req->req.length - req->req.actual;
/* measure length in either bytes or packets */
- if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
- || (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) ||
+ (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ omap_udc_in_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
txdma_ctrl = UDC_TXN_EOT | length;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode, dma_trigger, 0);
+ burst = length;
} else {
- length = min(length / ep->maxpacket,
- (unsigned) UDC_TXN_TSC + 1);
+ omap_udc_in_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTE;
+ length = min_t(unsigned, length / ep->maxpacket,
+ UDC_TXN_TSC + 1);
txdma_ctrl = length;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, length, sync_mode,
- dma_trigger, 0);
length *= ep->maxpacket;
+ burst = ep->ep.maxpacket >> 1;
}
- omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
- 0, 0);
- omap_start_dma(ep->lch);
- ep->dma_counter = omap_get_dma_src_pos(ep->lch);
+ if (!cpu_is_omap15xx())
+ burst = 1;
+
+ omap_udc_in_cfg.dst_maxburst = burst;
+
+ if (WARN_ON(dmaengine_slave_config(dma, &omap_udc_in_cfg)))
+ return;
+
+ tx = dmaengine_prep_slave_single(dma, req->req.dma + req->req.actual,
+ length, DMA_MEM_TO_DEV, 0);
+ if (WARN_ON(!tx))
+ return;
+
+ cookie = dmaengine_submit(tx);
+ if (WARN_ON(dma_submit_error(cookie)))
+ return;
+
+ ep->dma_cookie = cookie;
+ dma_async_issue_pending(dma);
+
w = omap_readw(UDC_DMA_IRQ_EN);
w |= UDC_TX_DONE_IE(ep->dma_channel);
omap_writew(w, UDC_DMA_IRQ_EN);
@@ -549,11 +532,14 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
{
+ struct dma_tx_state state;
u16 w;
- if (status == 0) {
- req->req.actual += req->dma_bytes;
+ dmaengine_tx_status(ep->dma, ep->dma_cookie, &state);
+ req->req.actual += req->dma_bytes - state.residual;
+
+ if (status == 0) {
/* return if this request needs to send data or zlp */
if (req->req.actual < req->req.length)
return;
@@ -561,36 +547,47 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
&& req->dma_bytes != 0
&& (req->req.actual % ep->maxpacket) == 0)
return;
- } else
- req->req.actual += dma_src_len(ep, req->req.dma
- + req->req.actual);
+ }
/* tx completion */
- omap_stop_dma(ep->lch);
+ dmaengine_terminate_async(ep->dma);
+
w = omap_readw(UDC_DMA_IRQ_EN);
w &= ~UDC_TX_DONE_IE(ep->dma_channel);
omap_writew(w, UDC_DMA_IRQ_EN);
done(ep, req, status);
}
+static const struct dma_slave_config omap_udc_out_cfg = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTE,
+ /*
+ * DMAengine uses frame sync mode, setting maxburst=1
+ * is equivalent to element sync mode.
+ */
+ .src_maxburst = 1,
+ .src_addr = UDC_DATA_DMA,
+};
+
static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
{
- unsigned packets = req->req.length - req->req.actual;
- int dma_trigger = 0;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma = ep->dma;
+ dma_cookie_t cookie;
+ unsigned packets, length;
u16 w;
- /* set up this DMA transfer, enable the fifo, start */
- packets /= ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
- req->dma_bytes = packets * ep->ep.maxpacket;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, packets,
- OMAP_DMA_SYNC_ELEMENT,
- dma_trigger, 0);
- omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
- 0, 0);
- ep->dma_counter = omap_get_dma_dst_pos(ep->lch);
+ length = req->req.length - req->req.actual;
+ packets = min_t(unsigned, length / ep->ep.maxpacket, UDC_RXN_TC + 1);
+ length = packets * ep->ep.maxpacket;
+
+ if (WARN_ON(dmaengine_slave_config(dma, &omap_udc_out_cfg)))
+ return;
+
+ tx = dmaengine_prep_slave_single(dma, req->req.dma + req->req.actual,
+ length, DMA_DEV_TO_MEM, 0);
+ if (WARN_ON(!tx))
+ return;
omap_writew(UDC_RXN_STOP | (packets - 1), UDC_RXDMA(ep->dma_channel));
w = omap_readw(UDC_DMA_IRQ_EN);
@@ -599,29 +596,42 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
omap_writew(ep->bEndpointAddress & 0xf, UDC_EP_NUM);
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
- omap_start_dma(ep->lch);
+ cookie = dmaengine_submit(tx);
+ if (WARN_ON(dma_submit_error(cookie)))
+ return;
+
+ ep->dma_cookie = cookie;
+ dma_async_issue_pending(dma);
+ req->dma_bytes = length;
}
static void
finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
{
+ struct dma_tx_state state;
u16 count, w;
- if (status == 0)
- ep->dma_counter = (u16) (req->req.dma + req->req.actual);
- count = dma_dest_len(ep, req->req.dma + req->req.actual);
+ dmaengine_tx_status(ep->dma, ep->dma_cookie, &state);
+
+ count = req->dma_bytes - state.residual;
count += req->req.actual;
if (one)
count--;
+
+ /*
+ * FIXME: Surely if count > req->req.length, something has gone
+ * seriously wrong and we've scribbled over memory we should not...
+ * so surely we should be a WARN_ON() at the very least?
+ */
if (count <= req->req.length)
req->req.actual = count;
- if (count != req->dma_bytes || status)
- omap_stop_dma(ep->lch);
-
+ if (count != req->dma_bytes || status) {
+ dmaengine_terminate_async(ep->dma);
/* if this wasn't short, request may need another transfer */
- else if (req->req.actual < req->req.length)
+ } else if (req->req.actual < req->req.length) {
return;
+ }
/* rx completion */
w = omap_readw(UDC_DMA_IRQ_EN);
@@ -683,19 +693,10 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
}
}
-static void dma_error(int lch, u16 ch_status, void *data)
-{
- struct omap_ep *ep = data;
-
- /* if ch_status & OMAP_DMA_DROP_IRQ ... */
- /* if ch_status & OMAP1_DMA_TOUT_IRQ ... */
- ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status);
-
- /* complete current transfer ... */
-}
-
static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
{
+ dma_cap_mask_t mask;
+ struct dma_chan *dma;
u16 reg;
int status, restart, is_in;
int dma_channel;
@@ -708,7 +709,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
reg |= UDC_DMA_REQ; /* "pulse" activated */
ep->dma_channel = 0;
- ep->lch = -1;
+ ep->dma = NULL;
if (channel == 0 || channel > 3) {
if ((reg & 0x0f00) == 0)
channel = 3;
@@ -722,65 +723,41 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
}
}
reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1));
- ep->dma_channel = channel;
- if (is_in) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ if (is_in)
dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
- status = omap_request_dma(dma_channel,
- ep->ep.name, dma_error, ep, &ep->lch);
- if (status == 0) {
- omap_writew(reg, UDC_TXDMA_CFG);
- /* EMIFF or SDRC */
- omap_set_dma_src_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
- omap_set_dma_src_data_pack(ep->lch, 1);
- /* TIPB */
- omap_set_dma_dest_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
- UDC_DATA_DMA,
- 0, 0);
- }
- } else {
+ else
dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
- status = omap_request_dma(dma_channel,
- ep->ep.name, dma_error, ep, &ep->lch);
- if (status == 0) {
+
+ dma = __dma_request_channel(&mask, omap_dma_filter_fn,
+ (void *)dma_channel);
+ if (dma) {
+ ep->dma_channel = channel;
+ ep->dma = dma;
+ if (is_in)
+ omap_writew(reg, UDC_TXDMA_CFG);
+ else
omap_writew(reg, UDC_RXDMA_CFG);
- /* TIPB */
- omap_set_dma_src_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
- UDC_DATA_DMA,
- 0, 0);
- /* EMIFF or SDRC */
- omap_set_dma_dest_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
- omap_set_dma_dest_data_pack(ep->lch, 1);
- }
- }
- if (status)
- ep->dma_channel = 0;
- else {
ep->has_dma = 1;
- omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
-
- /* channel type P: hw synch (fifo) */
- if (!cpu_is_omap15xx())
- omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
+ status = 0;
+ } else {
+ ep->dma_channel = 0;
+ status = -EINVAL;
}
just_restart:
/* restart any queue, even if the claim failed */
restart = !ep->stopped && !list_empty(&ep->queue);
- if (status)
- DBG("%s no dma channel: %d%s\n", ep->ep.name, status,
- restart ? " (restart)" : "");
+ if (d->dma)
+ DBG("%s claimed %cxdma%d dmaengine %s%s\n", ep->ep.name,
+ is_in ? 't' : 'r', ep->dma_channel - 1,
+ dma_chan_name(d->dma), restart ? " (restart)" : "");
else
- DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name,
- is_in ? 't' : 'r',
- ep->dma_channel - 1, ep->lch,
+ DBG("%s no dma channel: %d%s\n", ep->ep.name, status,
restart ? " (restart)" : "");
if (restart) {
@@ -814,7 +791,8 @@ static void dma_channel_release(struct omap_ep *ep)
else
req = NULL;
- active = omap_get_dma_active_status(ep->lch);
+ active = dma_async_is_tx_complete(ep->dma, ep->dma_cookie, NULL, NULL)
+ == DMA_IN_PROGRESS;
DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
active ? "active" : "idle",
@@ -850,9 +828,9 @@ static void dma_channel_release(struct omap_ep *ep)
if (req)
finish_out_dma(ep, req, -ECONNRESET, 0);
}
- omap_free_dma(ep->lch);
+ dma_release_channel(ep->dma);
ep->dma_channel = 0;
- ep->lch = -1;
+ ep->dma = NULL;
/* has_dma still set, till endpoint is fully quiesced */
}
@@ -2146,9 +2124,9 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
use_ep(ep, 0);
if (use_dma && ep->has_dma)
- snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ",
+ snprintf(buf, sizeof buf, "(%cxdma%d dma %s) ",
(ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
- ep->dma_channel - 1, ep->lch);
+ ep->dma_channel - 1, dma_chan_name(ep->dma));
else
buf[0] = 0;
@@ -2194,9 +2172,11 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
unsigned length = req->req.actual;
if (use_dma && buf[0]) {
- length += ((ep->bEndpointAddress & USB_DIR_IN)
- ? dma_src_len : dma_dest_len)
- (ep, req->req.dma + length);
+ struct dma_tx_state state;
+
+ dmaengine_tx_status(ep->dma, ep->dma_cookie,
+ &state);
+ length += req->dma_bytes - state.residual;
buf[0] = 0;
}
seq_printf(s, "\treq %p len %d/%d buf %p\n",
diff --git a/drivers/usb/gadget/udc/omap_udc.h b/drivers/usb/gadget/udc/omap_udc.h
index 00f9e608e755..e04c48f669ed 100644
--- a/drivers/usb/gadget/udc/omap_udc.h
+++ b/drivers/usb/gadget/udc/omap_udc.h
@@ -152,7 +152,8 @@ struct omap_ep {
u8 ackwait;
u8 dma_channel;
u16 dma_counter;
- int lch;
+ struct dma_chan *dma;
+ dma_cookie_t dma_cookie;
struct omap_udc *udc;
struct timer_list timer;
};
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox