diff options
Diffstat (limited to 'target/linux/apm821xx/patches-4.4/011-dmaengine-core-Introduce-new-universal-API-to-reques.patch')
-rw-r--r-- | target/linux/apm821xx/patches-4.4/011-dmaengine-core-Introduce-new-universal-API-to-reques.patch | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/target/linux/apm821xx/patches-4.4/011-dmaengine-core-Introduce-new-universal-API-to-reques.patch b/target/linux/apm821xx/patches-4.4/011-dmaengine-core-Introduce-new-universal-API-to-reques.patch new file mode 100644 index 0000000000..0296714639 --- /dev/null +++ b/target/linux/apm821xx/patches-4.4/011-dmaengine-core-Introduce-new-universal-API-to-reques.patch @@ -0,0 +1,345 @@ +From a8135d0d79e9d0ad3a4ff494fceeaae838becf38 Mon Sep 17 00:00:00 2001 +From: Peter Ujfalusi <peter.ujfalusi@ti.com> +Date: Mon, 14 Dec 2015 22:47:40 +0200 +Subject: [PATCH 2/3] dmaengine: core: Introduce new, universal API to request + a channel + +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); +To request a slave channel. 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 needed information from +the dma_slave_map provided by the DMA drivers. +This legacy mode needs changes in platform code, in dmaengine drivers and +finally the dmaengine user drivers can be converted: + +For each dmaengine driver an array of DMA device, slave and the parameter +for the filter function needs to be added: + +static const struct dma_slave_map da830_edma_map[] = { + { "davinci-mcasp.0", "rx", EDMA_FILTER_PARAM(0, 0) }, + { "davinci-mcasp.0", "tx", EDMA_FILTER_PARAM(0, 1) }, + { "davinci-mcasp.1", "rx", EDMA_FILTER_PARAM(0, 2) }, + { "davinci-mcasp.1", "tx", EDMA_FILTER_PARAM(0, 3) }, + { "davinci-mcasp.2", "rx", EDMA_FILTER_PARAM(0, 4) }, + { "davinci-mcasp.2", "tx", EDMA_FILTER_PARAM(0, 5) }, + { "spi_davinci.0", "rx", EDMA_FILTER_PARAM(0, 14) }, + { "spi_davinci.0", "tx", EDMA_FILTER_PARAM(0, 15) }, + { "da830-mmc.0", "rx", EDMA_FILTER_PARAM(0, 16) }, + { "da830-mmc.0", "tx", EDMA_FILTER_PARAM(0, 17) }, + { "spi_davinci.1", "rx", EDMA_FILTER_PARAM(0, 18) }, + { "spi_davinci.1", "tx", EDMA_FILTER_PARAM(0, 19) }, +}; + +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.slave_map = da830_edma_map; +da8xx_edma0_pdata.slavecnt = ARRAY_SIZE(da830_edma_map); + +The DMA driver then needs to configure the needed device -> filter_fn +mapping before it registers with dma_async_device_register() : + +ecc->dma_slave.filter_map.map = info->slave_map; +ecc->dma_slave.filter_map.mapcnt = info->slavecnt; +ecc->dma_slave.filter_map.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 use the information from the +dma_slave_map to get the channel with the dma_get_channel() internal +function. + +Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> +Reviewed-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Vinod Koul <vinod.koul@intel.com> +--- + Documentation/dmaengine/client.txt | 23 +++------- + drivers/dma/dmaengine.c | 89 +++++++++++++++++++++++++++++++++----- + include/linux/dmaengine.h | 51 +++++++++++++++++++--- + 3 files changed, 127 insertions(+), 36 deletions(-) + +diff --git a/Documentation/dmaengine/client.txt b/Documentation/dmaengine/client.txt +index 11fb87f..4b04d89 100644 +--- a/Documentation/dmaengine/client.txt ++++ b/Documentation/dmaengine/client.txt +@@ -22,25 +22,14 @@ The slave DMA usage consists of following steps: + Channel allocation is slightly different in the slave DMA context, + client drivers typically need a channel from a particular DMA + controller only and even in some cases a specific channel is desired. +- To request a channel dma_request_channel() API is used. ++ To request a channel dma_request_chan() API is used. + + Interface: +- struct dma_chan *dma_request_channel(dma_cap_mask_t mask, +- dma_filter_fn filter_fn, +- void *filter_param); +- where dma_filter_fn is defined as: +- typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); +- +- The 'filter_fn' parameter is optional, but highly recommended for +- slave and cyclic channels as they typically need to obtain a specific +- DMA channel. +- +- When the optional 'filter_fn' parameter is NULL, dma_request_channel() +- simply returns the first channel that satisfies the capability mask. +- +- Otherwise, the 'filter_fn' routine will be called once for each free +- channel which has a capability in 'mask'. 'filter_fn' is expected to +- return 'true' when the desired DMA channel is found. ++ struct dma_chan *dma_request_chan(struct device *dev, const char *name); ++ ++ Which will find and return the 'name' DMA channel associated with the 'dev' ++ device. The association is done via DT, ACPI or board file based ++ dma_slave_map matching table. + + A channel allocated via this interface is exclusive to the caller, + until dma_release_channel() is called. +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index 81a36fc..a094dbb 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> +@@ -665,27 +666,73 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, + } + EXPORT_SYMBOL_GPL(__dma_request_channel); + ++static const struct dma_slave_map *dma_filter_match(struct dma_device *device, ++ const char *name, ++ struct device *dev) ++{ ++ int i; ++ ++ if (!device->filter.mapcnt) ++ return NULL; ++ ++ for (i = 0; i < device->filter.mapcnt; i++) { ++ const struct dma_slave_map *map = &device->filter.map[i]; ++ ++ if (!strcmp(map->devname, dev_name(dev)) && ++ !strcmp(map->slave, name)) ++ return map; ++ } ++ ++ return NULL; ++} ++ + /** +- * dma_request_slave_channel_reason - try to allocate an exclusive slave channel ++ * dma_request_chan - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or an error pointer. + */ +-struct dma_chan *dma_request_slave_channel_reason(struct device *dev, +- const char *name) ++struct dma_chan *dma_request_chan(struct device *dev, const char *name) + { ++ struct dma_device *d, *_d; ++ struct dma_chan *chan = NULL; ++ + /* If device-tree is present get slave info from here */ + if (dev->of_node) +- return of_dma_request_slave_channel(dev->of_node, name); ++ 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)) +- return acpi_dma_request_slave_chan_by_name(dev, name); ++ if (has_acpi_companion(dev) && !chan) ++ chan = acpi_dma_request_slave_chan_by_name(dev, name); ++ ++ if (chan) { ++ /* Valid channel found or requester need to be deferred */ ++ if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) ++ return chan; ++ } ++ ++ /* Try to find the channel via the DMA filter map(s) */ ++ mutex_lock(&dma_list_mutex); ++ list_for_each_entry_safe(d, _d, &dma_device_list, global_node) { ++ dma_cap_mask_t mask; ++ const struct dma_slave_map *map = dma_filter_match(d, name, dev); ++ ++ if (!map) ++ continue; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); + +- return ERR_PTR(-ENODEV); ++ chan = find_candidate(d, &mask, d->filter.fn, map->param); ++ if (!IS_ERR(chan)) ++ break; ++ } ++ mutex_unlock(&dma_list_mutex); ++ ++ return chan ? chan : ERR_PTR(-EPROBE_DEFER); + } +-EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason); ++EXPORT_SYMBOL_GPL(dma_request_chan); + + /** + * dma_request_slave_channel - try to allocate an exclusive slave channel +@@ -697,17 +744,35 @@ EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason); + struct dma_chan *dma_request_slave_channel(struct device *dev, + const char *name) + { +- struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); ++ struct dma_chan *ch = dma_request_chan(dev, name); + if (IS_ERR(ch)) + return NULL; + +- dma_cap_set(DMA_PRIVATE, ch->device->cap_mask); +- ch->device->privatecnt++; +- + return ch; + } + EXPORT_SYMBOL_GPL(dma_request_slave_channel); + ++/** ++ * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities ++ * @mask: capabilities that the channel must satisfy ++ * ++ * Returns pointer to appropriate DMA channel on success or an error pointer. ++ */ ++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 c47c68e..d50a6b51 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -607,11 +607,38 @@ enum dmaengine_alignment { + }; + + /** ++ * struct dma_slave_map - associates slave device and it's slave channel with ++ * parameter to be used by a filter function ++ * @devname: name of the device ++ * @slave: slave channel name ++ * @param: opaque parameter to pass to struct dma_filter.fn ++ */ ++struct dma_slave_map { ++ const char *devname; ++ const char *slave; ++ void *param; ++}; ++ ++/** ++ * struct dma_filter - information for slave device/channel to filter_fn/param ++ * mapping ++ * @fn: filter function callback ++ * @mapcnt: number of slave device/channel in the map ++ * @map: array of channel to filter mapping data ++ */ ++struct dma_filter { ++ dma_filter_fn fn; ++ int mapcnt; ++ const struct dma_slave_map *map; ++}; ++ ++/** + * struct dma_device - info on the entity supplying DMA services + * @chancnt: how many DMA channels are supported + * @privatecnt: how many DMA channels are requested by dma_request_channel + * @channels: the list of struct dma_chan + * @global_node: list_head for global dma_device_list ++ * @filter: information for device/slave to filter function/param mapping + * @cap_mask: one or more dma_capability flags + * @max_xor: maximum number of xor sources, 0 if no capability + * @max_pq: maximum number of PQ sources and PQ-continue capability +@@ -666,6 +693,7 @@ struct dma_device { + unsigned int privatecnt; + struct list_head channels; + struct list_head global_node; ++ struct dma_filter filter; + dma_cap_mask_t cap_mask; + unsigned short max_xor; + unsigned short max_pq; +@@ -1140,9 +1168,11 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); + void dma_issue_pending_all(void); + struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, + dma_filter_fn fn, void *fn_param); +-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); ++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 +@@ -1166,16 +1196,21 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, + { + return NULL; + } +-static inline struct dma_chan *dma_request_slave_channel_reason( +- struct device *dev, const char *name) +-{ +- return ERR_PTR(-ENODEV); +-} + static inline struct dma_chan *dma_request_slave_channel(struct device *dev, + const char *name) + { + return NULL; + } ++static inline struct dma_chan *dma_request_chan(struct device *dev, ++ const char *name) ++{ ++ 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) + { + } +@@ -1186,6 +1221,8 @@ static inline int dma_get_slave_caps(struct dma_chan *chan, + } + #endif + ++#define dma_request_slave_channel_reason(dev, name) dma_request_chan(dev, name) ++ + static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx) + { + struct dma_slave_caps caps; +-- +2.8.1 + |