* [RFC 1/6] dmaengine: core: Allow NULL mask pointer in __dma_device_satisfies_mask()
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
2015-11-27 8:29 ` [RFC 2/6] dmaengine: core: Move and merge the code paths using private_candidate Peter Ujfalusi
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
Treat as true condition the case when the mask is NULL.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/dma/dmaengine.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index daf54a39bcc7..52c3eee48e2e 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -184,6 +184,9 @@ __dma_device_satisfies_mask(struct dma_device *device,
{
dma_cap_mask_t has;
+ if (!want)
+ return true;
+
bitmap_and(has.bits, want->bits, device->cap_mask.bits,
DMA_TX_TYPE_END);
return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END);
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC 2/6] dmaengine: core: Move and merge the code paths using private_candidate
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
2015-11-27 8:29 ` [RFC 1/6] dmaengine: core: Allow NULL mask pointer in __dma_device_satisfies_mask() Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
2015-11-27 8:29 ` [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel Peter Ujfalusi
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
Channel matching with private_candidate() is used in two paths, the error
checking is slightly different in them and they are duplicating code also.
Move the code under dma_get_channel() to provide consistent execution and
going to allow us to reuse this mode of channel lookup later.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/dma/dmaengine.c | 81 +++++++++++++++++++++++++------------------------
1 file changed, 42 insertions(+), 39 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 52c3eee48e2e..1249165fb4b2 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -549,6 +549,42 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
return NULL;
}
+static struct dma_chan *dma_get_channel(struct dma_device *device,
+ const dma_cap_mask_t *mask,
+ dma_filter_fn fn, void *fn_param)
+{
+ struct dma_chan *chan = private_candidate(mask, device, fn, fn_param);
+ int err;
+
+ if (chan) {
+ /* Found a suitable channel, try to grab, prep, and return it.
+ * We first set DMA_PRIVATE to disable balance_ref_count as this
+ * channel will not be published in the general-purpose
+ * allocator
+ */
+ dma_cap_set(DMA_PRIVATE, device->cap_mask);
+ device->privatecnt++;
+ err = dma_chan_get(chan);
+
+ if (err) {
+ if (err == -ENODEV) {
+ pr_debug("%s: %s module removed\n", __func__,
+ dma_chan_name(chan));
+ list_del_rcu(&device->global_node);
+ } else
+ pr_debug("%s: failed to get %s: (%d)\n",
+ __func__, dma_chan_name(chan), err);
+
+ if (--device->privatecnt == 0)
+ dma_cap_clear(DMA_PRIVATE, device->cap_mask);
+
+ chan = ERR_PTR(err);
+ }
+ }
+
+ return chan ? chan : ERR_PTR(-EPROBE_DEFER);
+}
+
/**
* dma_get_slave_channel - try to get specific channel exclusively
* @chan: target channel
@@ -587,7 +623,6 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device)
{
dma_cap_mask_t mask;
struct dma_chan *chan;
- int err;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -595,23 +630,11 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device)
/* lock against __dma_request_channel */
mutex_lock(&dma_list_mutex);
- chan = private_candidate(&mask, device, NULL, NULL);
- if (chan) {
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
- device->privatecnt++;
- err = dma_chan_get(chan);
- if (err) {
- pr_debug("%s: failed to get %s: (%d)\n",
- __func__, dma_chan_name(chan), err);
- chan = NULL;
- if (--device->privatecnt == 0)
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
- }
- }
+ chan = dma_get_channel(device, &mask, NULL, NULL);
mutex_unlock(&dma_list_mutex);
- return chan;
+ return IS_ERR(chan) ? NULL : chan;
}
EXPORT_SYMBOL_GPL(dma_get_any_slave_channel);
@@ -628,35 +651,15 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
{
struct dma_device *device, *_d;
struct dma_chan *chan = NULL;
- int err;
/* Find a channel */
mutex_lock(&dma_list_mutex);
list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
- chan = private_candidate(mask, device, fn, fn_param);
- if (chan) {
- /* Found a suitable channel, try to grab, prep, and
- * return it. We first set DMA_PRIVATE to disable
- * balance_ref_count as this channel will not be
- * published in the general-purpose allocator
- */
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
- device->privatecnt++;
- err = dma_chan_get(chan);
+ chan = dma_get_channel(device, mask, fn, fn_param);
+ if (!IS_ERR(chan))
+ break;
- if (err == -ENODEV) {
- pr_debug("%s: %s module removed\n",
- __func__, dma_chan_name(chan));
- list_del_rcu(&device->global_node);
- } else if (err)
- pr_debug("%s: failed to get %s: (%d)\n",
- __func__, dma_chan_name(chan), err);
- else
- break;
- if (--device->privatecnt == 0)
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
- chan = NULL;
- }
+ chan = NULL;
}
mutex_unlock(&dma_list_mutex);
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
2015-11-27 8:29 ` [RFC 1/6] dmaengine: core: Allow NULL mask pointer in __dma_device_satisfies_mask() Peter Ujfalusi
2015-11-27 8:29 ` [RFC 2/6] dmaengine: core: Move and merge the code paths using private_candidate Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
2015-11-27 11:00 ` Arnd Bergmann
2015-11-27 8:29 ` [RFC 4/6] dmaengine: edma: Add support for DMA filter mapping to slave devices Peter Ujfalusi
` (2 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
The two API function can cover most, if not all current APIs used to
request a channel. With minimal effort dmaengine drivers, platforms and
dmaengine user drivers can be converted to use the two function.
struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
To request any channel matching with the requested capabilities, can be
used to request channel for memcpy, memset, xor, etc where no hardware
synchronization is needed.
struct dma_chan *dma_request_chan(struct device *dev, const char *name,
const dma_cap_mask_t *mask);
To request a slave channel. The mask parameter is optional and it is used
to check if the received channel's capabilities can satisfy the requested
mask. The dma_request_chan() will try to find the channel via DT, ACPI or
in case if the kernel booted in non DT/ACPI mode it will use a filter
lookup table and retrieves the RESOURCE_DMA from the requester's device.
This legacy mode needs changes in platform code, in dmaengine drivers and
finally the dmaengine user drivers can be converted:
RESOURCE_DMA needs to be added to the platform devices with names
For each dmaengine driver a string array listing the devices handled by the
given DMA driver:
static char *da8xx_edma0_devices[] = {
"davinci-mcasp.0",
"da830-mmc.0",
};
This information is going to be needed by the dmaengine driver, so
modification to the platform_data is needed, and the driver map should be
added to the pdata of the DMA driver:
da8xx_edma0_pdata.devnames = da8xx_edma0_devices;
da8xx_edma0_pdata.devcnt = ARRAY_SIZE(da8xx_edma0_devices);
The DMA driver then needs to convigure the needed device -> filter_fn
mapping before it registers with dma_async_device_register() :
if (info->devnames) {
ecc->dma_slave.filter_map.devnames = info->devnames;
ecc->dma_slave.filter_map.devcnt = info->devcnt;
ecc->dma_slave.filter_map.filter_fn = edma_filter_fn;
}
When neither DT or ACPI lookup is available the dma_request_chan() will
try to match the requester's device name with the filter_map's list of
device names, when a match found it will requests the named DMA resource
using the requester's pdev and with the needed information available it
will try to get the channele with the dma_get_channel() internal function.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/dma/dmaengine.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/dmaengine.h | 21 +++++++++++
2 files changed, 112 insertions(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 1249165fb4b2..14c8e8a76641 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -43,6 +43,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -715,6 +716,96 @@ struct dma_chan *dma_request_slave_channel(struct device *dev,
}
EXPORT_SYMBOL_GPL(dma_request_slave_channel);
+static bool dma_filter_dev_is_match(struct dma_device *device,
+ struct device *dev)
+{
+ bool found = false;
+ int i;
+
+ if (!device->filter_map.devcnt)
+ return false;
+
+ for (i = 0; i < device->filter_map.devcnt; i++) {
+ if (!strcmp(device->filter_map.devnames[i], dev_name(dev))) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+struct dma_chan *dma_request_chan(struct device *dev, const char *name,
+ const dma_cap_mask_t *mask)
+{
+ struct dma_device *device, *_d;
+ struct dma_chan *chan = NULL;
+
+ /* If device-tree is present get slave info from here */
+ if (dev->of_node)
+ chan = of_dma_request_slave_channel(dev->of_node, name);
+
+ /* If device was enumerated by ACPI get slave info from here */
+ if (ACPI_HANDLE(dev) && !chan)
+ chan = acpi_dma_request_slave_chan_by_name(dev, name);
+
+ if (chan)
+ goto validate;
+
+ /* Try to find the channel via the DMA filter map(s) */
+ mutex_lock(&dma_list_mutex);
+ list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
+ bool match = dma_filter_dev_is_match(device, dev);
+ struct resource *r;
+
+ if (!match)
+ continue;
+
+ r = platform_get_resource_byname(to_platform_device(dev),
+ IORESOURCE_DMA, name);
+ if (!r)
+ continue;
+
+ chan = dma_get_channel(device, mask,
+ device->filter_map.filter_fn,
+ &r->start);
+ if (!IS_ERR(chan))
+ break;
+ }
+ mutex_unlock(&dma_list_mutex);
+
+ if (!chan)
+ return ERR_PTR(-EPROBE_DEFER);
+validate:
+ if (IS_ERR(chan) || !mask)
+ return chan;
+
+ if (!__dma_device_satisfies_mask(chan->device, mask)) {
+ dev_dbg(chan->device->dev, "%s: wrong capabilities for %s:%s\n",
+ __func__, dev_name(dev), name);
+ dma_release_channel(chan);
+ chan = ERR_PTR(-ENODEV);
+ }
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(dma_request_chan);
+
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
+{
+ struct dma_chan *chan;
+
+ if (!mask)
+ return ERR_PTR(-ENODEV);
+
+ chan = __dma_request_channel(mask, NULL, NULL);
+ if (!chan)
+ chan = ERR_PTR(-ENODEV);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(dma_request_chan_by_mask);
+
void dma_release_channel(struct dma_chan *chan)
{
mutex_lock(&dma_list_mutex);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index a2b7c2071cf4..e17be9a136f1 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -606,6 +606,12 @@ enum dmaengine_alignment {
DMAENGINE_ALIGN_64_BYTES = 6,
};
+struct dma_filter {
+ dma_filter_fn filter_fn;
+ int devcnt;
+ char **devnames;
+};
+
/**
* struct dma_device - info on the entity supplying DMA services
* @chancnt: how many DMA channels are supported
@@ -669,6 +675,7 @@ struct dma_device {
unsigned int privatecnt;
struct list_head channels;
struct list_head global_node;
+ struct dma_filter filter_map;
dma_cap_mask_t cap_mask;
unsigned short max_xor;
unsigned short max_pq;
@@ -1235,6 +1242,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
const char *name);
struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
+
+struct dma_chan *dma_request_chan(struct device *dev, const char *name,
+ const dma_cap_mask_t *mask);
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
+
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
#else
@@ -1268,6 +1280,15 @@ static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
{
return NULL;
}
+static inline struct dma_chan *dma_request_chan(struct device *dev,
+ const char *name, const dma_cap_mask_t *mask)
+{
+ return ERR_PTR(-ENODEV);
+}
+static inline struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
+{
+ return ERR_PTR(-ENODEV);
+}
static inline void dma_release_channel(struct dma_chan *chan)
{
}
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel
2015-11-27 8:29 ` [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel Peter Ujfalusi
@ 2015-11-27 11:00 ` Arnd Bergmann
2015-11-27 11:16 ` Peter Ujfalusi
0 siblings, 1 reply; 10+ messages in thread
From: Arnd Bergmann @ 2015-11-27 11:00 UTC (permalink / raw)
To: linux-arm-kernel
On Friday 27 November 2015 10:29:39 Peter Ujfalusi wrote:
> struct dma_chan *dma_request_chan(struct device *dev, const char *name,
> const dma_cap_mask_t *mask);
> To request a slave channel. The mask parameter is optional and it is used
> to check if the received channel's capabilities can satisfy the requested
> mask. The dma_request_chan() will try to find the channel via DT, ACPI or
> in case if the kernel booted in non DT/ACPI mode it will use a filter
> lookup table and retrieves the RESOURCE_DMA from the requester's device.
> This legacy mode needs changes in platform code, in dmaengine drivers and
> finally the dmaengine user drivers can be converted:
I think we should not introduce the mask parameter at all. In the rare
case that we actually need to pass a mask other than DMA_SLAVE today,
we should be able to encode that in the data we pass to the filter
function.
> RESOURCE_DMA needs to be added to the platform devices with names
>
> For each dmaengine driver a string array listing the devices handled by the
> given DMA driver:
>
> static char *da8xx_edma0_devices[] = {
> "davinci-mcasp.0",
> "da830-mmc.0",
> };
>
> This information is going to be needed by the dmaengine driver, so
> modification to the platform_data is needed, and the driver map should be
> added to the pdata of the DMA driver:
However, a lot of drivers definitely need to pass a data pointer for
each device. I see that you currently rely on the IORESOURCE_DMA
method that a couple of platforms use today, but I think it would
be backwards to do it that way for the platforms that require passing
more than an integer number today.
Having a pointer as the filter function argument is intentional and I'd
prefer to change the platforms that currently use IORESOURCE_DMA (davinci,
pxa, omap1, blackfin, alchemy) to stop doing it instead, and return
IORESOURCE_DMA to its original meaning that was limited to ISAPNP style
devices not using the dmaengine API.
Arnd
^ permalink raw reply [flat|nested] 10+ messages in thread* [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel
2015-11-27 11:00 ` Arnd Bergmann
@ 2015-11-27 11:16 ` Peter Ujfalusi
2015-11-27 11:26 ` Arnd Bergmann
0 siblings, 1 reply; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 11:16 UTC (permalink / raw)
To: linux-arm-kernel
On 11/27/2015 01:00 PM, Arnd Bergmann wrote:
> On Friday 27 November 2015 10:29:39 Peter Ujfalusi wrote:
>> struct dma_chan *dma_request_chan(struct device *dev, const char *name,
>> const dma_cap_mask_t *mask);
>> To request a slave channel. The mask parameter is optional and it is used
>> to check if the received channel's capabilities can satisfy the requested
>> mask. The dma_request_chan() will try to find the channel via DT, ACPI or
>> in case if the kernel booted in non DT/ACPI mode it will use a filter
>> lookup table and retrieves the RESOURCE_DMA from the requester's device.
>> This legacy mode needs changes in platform code, in dmaengine drivers and
>> finally the dmaengine user drivers can be converted:
>
> I think we should not introduce the mask parameter at all. In the rare
> case that we actually need to pass a mask other than DMA_SLAVE today,
> we should be able to encode that in the data we pass to the filter
> function.
I have seen that drivers check the capabilities themselves after getting the
channel, so I thought that if we move that also to the core we can save on
duplicated lines around the kernel. It is not needed to get the channel. As
you can see in the mmc patch, I pass NULL and the channel I got is the correct
one.
Sure, I can remove it.
>> RESOURCE_DMA needs to be added to the platform devices with names
>>
>> For each dmaengine driver a string array listing the devices handled by the
>> given DMA driver:
>>
>> static char *da8xx_edma0_devices[] = {
>> "davinci-mcasp.0",
>> "da830-mmc.0",
>> };
>>
>> This information is going to be needed by the dmaengine driver, so
>> modification to the platform_data is needed, and the driver map should be
>> added to the pdata of the DMA driver:
>
> However, a lot of drivers definitely need to pass a data pointer for
> each device. I see that you currently rely on the IORESOURCE_DMA
> method that a couple of platforms use today, but I think it would
> be backwards to do it that way for the platforms that require passing
> more than an integer number today.
>
> Having a pointer as the filter function argument is intentional and I'd
> prefer to change the platforms that currently use IORESOURCE_DMA (davinci,
> pxa, omap1, blackfin, alchemy) to stop doing it instead, and return
> IORESOURCE_DMA to its original meaning that was limited to ISAPNP style
> devices not using the dmaengine API.
Something like this:
/* include/linux/dmaengine.h */
struct dma_filter_map {
char *devname;
char *slave;
void *param;
};
struct dma_filter {
dma_filter_fn filter_fn;
int mapcnt;
struct dma_filter_map *map;
};
/* arch/arm/mach-davinci/devices-da8xx.c */
static struct dma_filter_map da8xx_edma0_map[] = {
{
.devname = "davinci-mcasp.0",
.slave = "tx",
.param = (void*)DAVINCI_DA8XX_DMA_MCASP0_AXEVT,
},
{
.devname = "davinci-mcasp.0",
.slave = "rx",
.param = (void*)DAVINCI_DA8XX_DMA_MCASP0_AREVT,
},
{
.devname = "da830-mmc.0",
.slave = "tx",
.param = (void*)DA8XX_DMA_MMCSD0_TX,
},
{
.devname = "da830-mmc.0",
.slave = "rx",
.param = (void*)DA8XX_DMA_MMCSD0_RX,
},
};
I had this version first, but decided to go with a simpler one present in this
RFC series.
--
P?ter
^ permalink raw reply [flat|nested] 10+ messages in thread* [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel
2015-11-27 11:16 ` Peter Ujfalusi
@ 2015-11-27 11:26 ` Arnd Bergmann
0 siblings, 0 replies; 10+ messages in thread
From: Arnd Bergmann @ 2015-11-27 11:26 UTC (permalink / raw)
To: linux-arm-kernel
On Friday 27 November 2015 13:16:37 Peter Ujfalusi wrote:
> On 11/27/2015 01:00 PM, Arnd Bergmann wrote:
> > On Friday 27 November 2015 10:29:39 Peter Ujfalusi wrote:
> >> struct dma_chan *dma_request_chan(struct device *dev, const char *name,
> >> const dma_cap_mask_t *mask);
> >> To request a slave channel. The mask parameter is optional and it is used
> >> to check if the received channel's capabilities can satisfy the requested
> >> mask. The dma_request_chan() will try to find the channel via DT, ACPI or
> >> in case if the kernel booted in non DT/ACPI mode it will use a filter
> >> lookup table and retrieves the RESOURCE_DMA from the requester's device.
> >> This legacy mode needs changes in platform code, in dmaengine drivers and
> >> finally the dmaengine user drivers can be converted:
> >
> > I think we should not introduce the mask parameter at all. In the rare
> > case that we actually need to pass a mask other than DMA_SLAVE today,
> > we should be able to encode that in the data we pass to the filter
> > function.
>
> I have seen that drivers check the capabilities themselves after getting the
> channel, so I thought that if we move that also to the core we can save on
> duplicated lines around the kernel. It is not needed to get the channel. As
> you can see in the mmc patch, I pass NULL and the channel I got is the correct
> one.
> Sure, I can remove it.
Ok.
> >> RESOURCE_DMA needs to be added to the platform devices with names
> >>
> >> For each dmaengine driver a string array listing the devices handled by the
> >> given DMA driver:
> >>
> >> static char *da8xx_edma0_devices[] = {
> >> "davinci-mcasp.0",
> >> "da830-mmc.0",
> >> };
> >>
> >> This information is going to be needed by the dmaengine driver, so
> >> modification to the platform_data is needed, and the driver map should be
> >> added to the pdata of the DMA driver:
> >
> > However, a lot of drivers definitely need to pass a data pointer for
> > each device. I see that you currently rely on the IORESOURCE_DMA
> > method that a couple of platforms use today, but I think it would
> > be backwards to do it that way for the platforms that require passing
> > more than an integer number today.
> >
> > Having a pointer as the filter function argument is intentional and I'd
> > prefer to change the platforms that currently use IORESOURCE_DMA (davinci,
> > pxa, omap1, blackfin, alchemy) to stop doing it instead, and return
> > IORESOURCE_DMA to its original meaning that was limited to ISAPNP style
> > devices not using the dmaengine API.
>
> Something like this:
>
> /* include/linux/dmaengine.h */
>
> struct dma_filter_map {
> char *devname;
> char *slave;
> void *param;
> };
>
> struct dma_filter {
> dma_filter_fn filter_fn;
> int mapcnt;
> struct dma_filter_map *map;
> };
>
> /* arch/arm/mach-davinci/devices-da8xx.c */
>
> static struct dma_filter_map da8xx_edma0_map[] = {
> {
> .devname = "davinci-mcasp.0",
> .slave = "tx",
> .param = (void*)DAVINCI_DA8XX_DMA_MCASP0_AXEVT,
> },
> {
> .devname = "davinci-mcasp.0",
> .slave = "rx",
> .param = (void*)DAVINCI_DA8XX_DMA_MCASP0_AREVT,
> },
> {
> .devname = "da830-mmc.0",
> .slave = "tx",
> .param = (void*)DA8XX_DMA_MMCSD0_TX,
> },
> {
> .devname = "da830-mmc.0",
> .slave = "rx",
> .param = (void*)DA8XX_DMA_MMCSD0_RX,
> },
> };
>
> I had this version first, but decided to go with a simpler one present in this
> RFC series.
Yes, that is what I had in mind. Let's see what others think about the two
options.
I would also avoid the 'struct dma_filter' entirely by using a zero-terminated
list and passing the filter function and map table separately, but your approach
seems reasonable as well.
In my initial suggestion, the idea was to do the registration of the filter map
separately from registering the dmaengine device to give us a little more
flexibility in converting existing code, but it requires listing both the
dmaengine device and the slave devname in the map, so your approach is probably
better in the long run even if it requires a little more work for doing the
conversion.
Arnd
^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC 4/6] dmaengine: edma: Add support for DMA filter mapping to slave devices
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
` (2 preceding siblings ...)
2015-11-27 8:29 ` [RFC 3/6] dmaengine: core: Introduce new, universal API to request a channel Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
2015-11-27 8:29 ` [RFC 5/6] ARM: davinci: devices-da8xx: device -> dma instance mapping support Peter Ujfalusi
2015-11-27 8:29 ` [RFC 6/6] mmc: davinci_mmc: Switch to use the new dmaengine API for requesting channel (NOT FOR MERGE) Peter Ujfalusi
5 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
Add support for providing device to filter_fn mapping so client drivers
can switch to use the dma_request_chan() API.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/dma/edma.c | 6 ++++++
include/linux/platform_data/edma.h | 3 +++
2 files changed, 9 insertions(+)
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 0675e268d577..587ceb9308b3 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -2297,6 +2297,12 @@ static int edma_probe(struct platform_device *pdev)
edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot);
}
+ if (info->devnames) {
+ ecc->dma_slave.filter_map.devnames = info->devnames;
+ ecc->dma_slave.filter_map.devcnt = info->devcnt;
+ ecc->dma_slave.filter_map.filter_fn = edma_filter_fn;
+ }
+
ret = dma_async_device_register(&ecc->dma_slave);
if (ret) {
dev_err(dev, "slave ddev registration failed (%d)\n", ret);
diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
index e2878baeb90e..58a4dcba0bdf 100644
--- a/include/linux/platform_data/edma.h
+++ b/include/linux/platform_data/edma.h
@@ -76,6 +76,9 @@ struct edma_soc_info {
s8 (*queue_priority_mapping)[2];
const s16 (*xbar_chans)[2];
+
+ char **devnames;
+ int devcnt;
};
#endif
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC 5/6] ARM: davinci: devices-da8xx: device -> dma instance mapping support
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
` (3 preceding siblings ...)
2015-11-27 8:29 ` [RFC 4/6] dmaengine: edma: Add support for DMA filter mapping to slave devices Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
2015-11-27 8:29 ` [RFC 6/6] mmc: davinci_mmc: Switch to use the new dmaengine API for requesting channel (NOT FOR MERGE) Peter Ujfalusi
5 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
In order to switch the driver to use the new simpler dmaengine API the
device mapping for the dma instances needs to be added and also the DMA
resources should be named.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
arch/arm/mach-davinci/devices-da8xx.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 28c90bc372bd..e7e042dd7603 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -233,12 +233,28 @@ static const struct platform_device_info da850_edma1_device __initconst = {
.size_data = sizeof(da850_edma1_pdata),
};
+static char *da8xx_edma0_devices[] = {
+ "davinci-mcasp.0",
+ "davinci-mcasp.1",
+ "davinci-mcasp.2",
+ "da830-mmc.0",
+ "spi_davinci.0",
+ "spi_davinci.1",
+};
+
+static char *da850_edma1_devices[] = {
+ "da830-mmc.1",
+};
+
int __init da830_register_edma(struct edma_rsv_info *rsv)
{
struct platform_device *edma_pdev;
da8xx_edma0_pdata.rsv = rsv;
+ da8xx_edma0_pdata.devnames = da8xx_edma0_devices;
+ da8xx_edma0_pdata.devcnt = ARRAY_SIZE(da8xx_edma0_devices);
+
edma_pdev = platform_device_register_full(&da8xx_edma0_device);
return IS_ERR(edma_pdev) ? PTR_ERR(edma_pdev) : 0;
}
@@ -252,11 +268,18 @@ int __init da850_register_edma(struct edma_rsv_info *rsv[2])
da850_edma1_pdata.rsv = rsv[1];
}
+ da8xx_edma0_pdata.devnames = da8xx_edma0_devices;
+ da8xx_edma0_pdata.devcnt = ARRAY_SIZE(da8xx_edma0_devices);
+
edma_pdev = platform_device_register_full(&da8xx_edma0_device);
if (IS_ERR(edma_pdev)) {
pr_warn("%s: Failed to register eDMA0\n", __func__);
return PTR_ERR(edma_pdev);
}
+
+ da850_edma1_pdata.devnames = da850_edma1_devices;
+ da850_edma1_pdata.devcnt = ARRAY_SIZE(da850_edma1_devices);
+
edma_pdev = platform_device_register_full(&da850_edma1_device);
return IS_ERR(edma_pdev) ? PTR_ERR(edma_pdev) : 0;
}
@@ -706,11 +729,13 @@ static struct resource da8xx_mmcsd0_resources[] = {
.flags = IORESOURCE_IRQ,
},
{ /* DMA RX */
+ .name = "rx",
.start = DA8XX_DMA_MMCSD0_RX,
.end = DA8XX_DMA_MMCSD0_RX,
.flags = IORESOURCE_DMA,
},
{ /* DMA TX */
+ .name = "tx",
.start = DA8XX_DMA_MMCSD0_TX,
.end = DA8XX_DMA_MMCSD0_TX,
.flags = IORESOURCE_DMA,
@@ -743,11 +768,13 @@ static struct resource da850_mmcsd1_resources[] = {
.flags = IORESOURCE_IRQ,
},
{ /* DMA RX */
+ .name = "rx",
.start = DA850_DMA_MMCSD1_RX,
.end = DA850_DMA_MMCSD1_RX,
.flags = IORESOURCE_DMA,
},
{ /* DMA TX */
+ .name = "tx",
.start = DA850_DMA_MMCSD1_TX,
.end = DA850_DMA_MMCSD1_TX,
.flags = IORESOURCE_DMA,
@@ -939,11 +966,13 @@ static struct resource da8xx_spi0_resources[] = {
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = "rx",
.start = DA8XX_DMA_SPI0_RX,
.end = DA8XX_DMA_SPI0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
+ .name = "tx",
.start = DA8XX_DMA_SPI0_TX,
.end = DA8XX_DMA_SPI0_TX,
.flags = IORESOURCE_DMA,
@@ -962,11 +991,13 @@ static struct resource da8xx_spi1_resources[] = {
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = "rx",
.start = DA8XX_DMA_SPI1_RX,
.end = DA8XX_DMA_SPI1_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
+ .name = "tx",
.start = DA8XX_DMA_SPI1_TX,
.end = DA8XX_DMA_SPI1_TX,
.flags = IORESOURCE_DMA,
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC 6/6] mmc: davinci_mmc: Switch to use the new dmaengine API for requesting channel (NOT FOR MERGE)
2015-11-27 8:29 [RFC 0/6] dmaengine: New 'universal' API for requesting channel Peter Ujfalusi
` (4 preceding siblings ...)
2015-11-27 8:29 ` [RFC 5/6] ARM: davinci: devices-da8xx: device -> dma instance mapping support Peter Ujfalusi
@ 2015-11-27 8:29 ` Peter Ujfalusi
5 siblings, 0 replies; 10+ messages in thread
From: Peter Ujfalusi @ 2015-11-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
With the new dma_request_chan() the clinet driver does not need to look for
the DMA resource and it does not need to pass filter_fn anymore.
By switching to the new API the davinci_mmc driver can now support deferred
probing against DMA.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/mmc/host/davinci_mmc.c | 51 ++++++++++++------------------------------
1 file changed, 14 insertions(+), 37 deletions(-)
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index ea2a2ebc6b91..e69bdeeee032 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -37,7 +37,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/platform_data/edma.h>
#include <linux/platform_data/mmc-davinci.h>
/*
@@ -517,35 +516,20 @@ davinci_release_dma_channels(struct mmc_davinci_host *host)
static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
{
- int r;
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->dma_tx =
- dma_request_slave_channel_compat(mask, edma_filter_fn,
- &host->txdma, mmc_dev(host->mmc), "tx");
- if (!host->dma_tx) {
+ host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx", NULL);
+ if (IS_ERR(host->dma_tx)) {
dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n");
- return -ENODEV;
+ return PTR_ERR(host->dma_tx);
}
- host->dma_rx =
- dma_request_slave_channel_compat(mask, edma_filter_fn,
- &host->rxdma, mmc_dev(host->mmc), "rx");
- if (!host->dma_rx) {
+ host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx", NULL);
+ if (IS_ERR(host->dma_rx)) {
dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n");
- r = -ENODEV;
- goto free_master_write;
+ dma_release_channel(host->dma_tx);
+ return PTR_ERR(host->dma_rx);
}
return 0;
-
-free_master_write:
- dma_release_channel(host->dma_tx);
-
- return r;
}
/*----------------------------------------------------------------------*/
@@ -1262,18 +1246,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host = mmc_priv(mmc);
host->mmc = mmc; /* Important */
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r)
- dev_warn(&pdev->dev, "RX DMA resource not specified\n");
- else
- host->rxdma = r->start;
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!r)
- dev_warn(&pdev->dev, "TX DMA resource not specified\n");
- else
- host->txdma = r->start;
-
host->mem_res = mem;
host->base = ioremap(mem->start, mem_size);
if (!host->base)
@@ -1300,8 +1272,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->mmc_irq = irq;
host->sdio_irq = platform_get_irq(pdev, 1);
- if (host->use_dma && davinci_acquire_dma_channels(host) != 0)
- host->use_dma = 0;
+ if (host->use_dma) {
+ ret = davinci_acquire_dma_channels(host);
+ if (ret == -EPROBE_DEFER)
+ goto out;
+ else if (ret)
+ host->use_dma = 0;
+ }
/* REVISIT: someday, support IRQ-driven card detection. */
mmc->caps |= MMC_CAP_NEEDS_POLL;
--
2.6.3
^ permalink raw reply related [flat|nested] 10+ messages in thread