162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * This code implements the DMA subsystem. It provides a HW-neutral interface 862306a36Sopenharmony_ci * for other kernel code to use asynchronous memory copy capabilities, 962306a36Sopenharmony_ci * if present, and allows different HW DMA drivers to register as providing 1062306a36Sopenharmony_ci * this capability. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Due to the fact we are accelerating what is already a relatively fast 1362306a36Sopenharmony_ci * operation, the code goes to great lengths to avoid additional overhead, 1462306a36Sopenharmony_ci * such as locking. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * LOCKING: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * The subsystem keeps a global list of dma_device structs it is protected by a 1962306a36Sopenharmony_ci * mutex, dma_list_mutex. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * A subsystem can get access to a channel by calling dmaengine_get() followed 2262306a36Sopenharmony_ci * by dma_find_channel(), or if it has need for an exclusive channel it can call 2362306a36Sopenharmony_ci * dma_request_channel(). Once a channel is allocated a reference is taken 2462306a36Sopenharmony_ci * against its corresponding driver to disable removal. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Each device has a channels list, which runs unlocked but is never modified 2762306a36Sopenharmony_ci * once the device is registered, it's just setup by the driver. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * See Documentation/driver-api/dmaengine for more details 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/platform_device.h> 3562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3662306a36Sopenharmony_ci#include <linux/init.h> 3762306a36Sopenharmony_ci#include <linux/module.h> 3862306a36Sopenharmony_ci#include <linux/mm.h> 3962306a36Sopenharmony_ci#include <linux/device.h> 4062306a36Sopenharmony_ci#include <linux/dmaengine.h> 4162306a36Sopenharmony_ci#include <linux/hardirq.h> 4262306a36Sopenharmony_ci#include <linux/spinlock.h> 4362306a36Sopenharmony_ci#include <linux/percpu.h> 4462306a36Sopenharmony_ci#include <linux/rcupdate.h> 4562306a36Sopenharmony_ci#include <linux/mutex.h> 4662306a36Sopenharmony_ci#include <linux/jiffies.h> 4762306a36Sopenharmony_ci#include <linux/rculist.h> 4862306a36Sopenharmony_ci#include <linux/idr.h> 4962306a36Sopenharmony_ci#include <linux/slab.h> 5062306a36Sopenharmony_ci#include <linux/acpi.h> 5162306a36Sopenharmony_ci#include <linux/acpi_dma.h> 5262306a36Sopenharmony_ci#include <linux/of_dma.h> 5362306a36Sopenharmony_ci#include <linux/mempool.h> 5462306a36Sopenharmony_ci#include <linux/numa.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include "dmaengine.h" 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic DEFINE_MUTEX(dma_list_mutex); 5962306a36Sopenharmony_cistatic DEFINE_IDA(dma_ida); 6062306a36Sopenharmony_cistatic LIST_HEAD(dma_device_list); 6162306a36Sopenharmony_cistatic long dmaengine_ref_count; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* --- debugfs implementation --- */ 6462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 6562306a36Sopenharmony_ci#include <linux/debugfs.h> 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct dentry *rootdir; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void dmaengine_debug_register(struct dma_device *dma_dev) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci dma_dev->dbg_dev_root = debugfs_create_dir(dev_name(dma_dev->dev), 7262306a36Sopenharmony_ci rootdir); 7362306a36Sopenharmony_ci if (IS_ERR(dma_dev->dbg_dev_root)) 7462306a36Sopenharmony_ci dma_dev->dbg_dev_root = NULL; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void dmaengine_debug_unregister(struct dma_device *dma_dev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci debugfs_remove_recursive(dma_dev->dbg_dev_root); 8062306a36Sopenharmony_ci dma_dev->dbg_dev_root = NULL; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void dmaengine_dbg_summary_show(struct seq_file *s, 8462306a36Sopenharmony_ci struct dma_device *dma_dev) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct dma_chan *chan; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci list_for_each_entry(chan, &dma_dev->channels, device_node) { 8962306a36Sopenharmony_ci if (chan->client_count) { 9062306a36Sopenharmony_ci seq_printf(s, " %-13s| %s", dma_chan_name(chan), 9162306a36Sopenharmony_ci chan->dbg_client_name ?: "in-use"); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (chan->router) 9462306a36Sopenharmony_ci seq_printf(s, " (via router: %s)\n", 9562306a36Sopenharmony_ci dev_name(chan->router->dev)); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci seq_puts(s, "\n"); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int dmaengine_summary_show(struct seq_file *s, void *data) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct dma_device *dma_dev = NULL; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 10762306a36Sopenharmony_ci list_for_each_entry(dma_dev, &dma_device_list, global_node) { 10862306a36Sopenharmony_ci seq_printf(s, "dma%d (%s): number of channels: %u\n", 10962306a36Sopenharmony_ci dma_dev->dev_id, dev_name(dma_dev->dev), 11062306a36Sopenharmony_ci dma_dev->chancnt); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (dma_dev->dbg_summary_show) 11362306a36Sopenharmony_ci dma_dev->dbg_summary_show(s, dma_dev); 11462306a36Sopenharmony_ci else 11562306a36Sopenharmony_ci dmaengine_dbg_summary_show(s, dma_dev); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (!list_is_last(&dma_dev->global_node, &dma_device_list)) 11862306a36Sopenharmony_ci seq_puts(s, "\n"); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dmaengine_summary); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void __init dmaengine_debugfs_init(void) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci rootdir = debugfs_create_dir("dmaengine", NULL); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* /sys/kernel/debug/dmaengine/summary */ 13162306a36Sopenharmony_ci debugfs_create_file("summary", 0444, rootdir, NULL, 13262306a36Sopenharmony_ci &dmaengine_summary_fops); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci#else 13562306a36Sopenharmony_cistatic inline void dmaengine_debugfs_init(void) { } 13662306a36Sopenharmony_cistatic inline int dmaengine_debug_register(struct dma_device *dma_dev) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic inline void dmaengine_debug_unregister(struct dma_device *dma_dev) { } 14262306a36Sopenharmony_ci#endif /* DEBUG_FS */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* --- sysfs implementation --- */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define DMA_SLAVE_NAME "slave" 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/** 14962306a36Sopenharmony_ci * dev_to_dma_chan - convert a device pointer to its sysfs container object 15062306a36Sopenharmony_ci * @dev: device node 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Must be called under dma_list_mutex. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cistatic struct dma_chan *dev_to_dma_chan(struct device *dev) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct dma_chan_dev *chan_dev; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci chan_dev = container_of(dev, typeof(*chan_dev), device); 15962306a36Sopenharmony_ci return chan_dev->chan; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic ssize_t memcpy_count_show(struct device *dev, 16362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct dma_chan *chan; 16662306a36Sopenharmony_ci unsigned long count = 0; 16762306a36Sopenharmony_ci int i; 16862306a36Sopenharmony_ci int err; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 17162306a36Sopenharmony_ci chan = dev_to_dma_chan(dev); 17262306a36Sopenharmony_ci if (chan) { 17362306a36Sopenharmony_ci for_each_possible_cpu(i) 17462306a36Sopenharmony_ci count += per_cpu_ptr(chan->local, i)->memcpy_count; 17562306a36Sopenharmony_ci err = sysfs_emit(buf, "%lu\n", count); 17662306a36Sopenharmony_ci } else 17762306a36Sopenharmony_ci err = -ENODEV; 17862306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return err; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(memcpy_count); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic ssize_t bytes_transferred_show(struct device *dev, 18562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct dma_chan *chan; 18862306a36Sopenharmony_ci unsigned long count = 0; 18962306a36Sopenharmony_ci int i; 19062306a36Sopenharmony_ci int err; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 19362306a36Sopenharmony_ci chan = dev_to_dma_chan(dev); 19462306a36Sopenharmony_ci if (chan) { 19562306a36Sopenharmony_ci for_each_possible_cpu(i) 19662306a36Sopenharmony_ci count += per_cpu_ptr(chan->local, i)->bytes_transferred; 19762306a36Sopenharmony_ci err = sysfs_emit(buf, "%lu\n", count); 19862306a36Sopenharmony_ci } else 19962306a36Sopenharmony_ci err = -ENODEV; 20062306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return err; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bytes_transferred); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic ssize_t in_use_show(struct device *dev, struct device_attribute *attr, 20762306a36Sopenharmony_ci char *buf) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct dma_chan *chan; 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 21362306a36Sopenharmony_ci chan = dev_to_dma_chan(dev); 21462306a36Sopenharmony_ci if (chan) 21562306a36Sopenharmony_ci err = sysfs_emit(buf, "%d\n", chan->client_count); 21662306a36Sopenharmony_ci else 21762306a36Sopenharmony_ci err = -ENODEV; 21862306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return err; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(in_use); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic struct attribute *dma_dev_attrs[] = { 22562306a36Sopenharmony_ci &dev_attr_memcpy_count.attr, 22662306a36Sopenharmony_ci &dev_attr_bytes_transferred.attr, 22762306a36Sopenharmony_ci &dev_attr_in_use.attr, 22862306a36Sopenharmony_ci NULL, 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ciATTRIBUTE_GROUPS(dma_dev); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void chan_dev_release(struct device *dev) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct dma_chan_dev *chan_dev; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci chan_dev = container_of(dev, typeof(*chan_dev), device); 23762306a36Sopenharmony_ci kfree(chan_dev); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic struct class dma_devclass = { 24162306a36Sopenharmony_ci .name = "dma", 24262306a36Sopenharmony_ci .dev_groups = dma_dev_groups, 24362306a36Sopenharmony_ci .dev_release = chan_dev_release, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* --- client and device registration --- */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* enable iteration over all operation types */ 24962306a36Sopenharmony_cistatic dma_cap_mask_t dma_cap_mask_all; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * struct dma_chan_tbl_ent - tracks channel allocations per core/operation 25362306a36Sopenharmony_ci * @chan: associated channel for this entry 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_cistruct dma_chan_tbl_ent { 25662306a36Sopenharmony_ci struct dma_chan *chan; 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/* percpu lookup table for memory-to-memory offload providers */ 26062306a36Sopenharmony_cistatic struct dma_chan_tbl_ent __percpu *channel_table[DMA_TX_TYPE_END]; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int __init dma_channel_table_init(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci enum dma_transaction_type cap; 26562306a36Sopenharmony_ci int err = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 'interrupt', 'private', and 'slave' are channel capabilities, 27062306a36Sopenharmony_ci * but are not associated with an operation so they do not need 27162306a36Sopenharmony_ci * an entry in the channel_table 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits); 27462306a36Sopenharmony_ci clear_bit(DMA_PRIVATE, dma_cap_mask_all.bits); 27562306a36Sopenharmony_ci clear_bit(DMA_SLAVE, dma_cap_mask_all.bits); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci for_each_dma_cap_mask(cap, dma_cap_mask_all) { 27862306a36Sopenharmony_ci channel_table[cap] = alloc_percpu(struct dma_chan_tbl_ent); 27962306a36Sopenharmony_ci if (!channel_table[cap]) { 28062306a36Sopenharmony_ci err = -ENOMEM; 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (err) { 28662306a36Sopenharmony_ci pr_err("dmaengine dma_channel_table_init failure: %d\n", err); 28762306a36Sopenharmony_ci for_each_dma_cap_mask(cap, dma_cap_mask_all) 28862306a36Sopenharmony_ci free_percpu(channel_table[cap]); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return err; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ciarch_initcall(dma_channel_table_init); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/** 29662306a36Sopenharmony_ci * dma_chan_is_local - checks if the channel is in the same NUMA-node as the CPU 29762306a36Sopenharmony_ci * @chan: DMA channel to test 29862306a36Sopenharmony_ci * @cpu: CPU index which the channel should be close to 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * Returns true if the channel is in the same NUMA-node as the CPU. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_cistatic bool dma_chan_is_local(struct dma_chan *chan, int cpu) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci int node = dev_to_node(chan->device->dev); 30562306a36Sopenharmony_ci return node == NUMA_NO_NODE || 30662306a36Sopenharmony_ci cpumask_test_cpu(cpu, cpumask_of_node(node)); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/** 31062306a36Sopenharmony_ci * min_chan - finds the channel with min count and in the same NUMA-node as the CPU 31162306a36Sopenharmony_ci * @cap: capability to match 31262306a36Sopenharmony_ci * @cpu: CPU index which the channel should be close to 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * If some channels are close to the given CPU, the one with the lowest 31562306a36Sopenharmony_ci * reference count is returned. Otherwise, CPU is ignored and only the 31662306a36Sopenharmony_ci * reference count is taken into account. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * Must be called under dma_list_mutex. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_cistatic struct dma_chan *min_chan(enum dma_transaction_type cap, int cpu) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct dma_device *device; 32362306a36Sopenharmony_ci struct dma_chan *chan; 32462306a36Sopenharmony_ci struct dma_chan *min = NULL; 32562306a36Sopenharmony_ci struct dma_chan *localmin = NULL; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci list_for_each_entry(device, &dma_device_list, global_node) { 32862306a36Sopenharmony_ci if (!dma_has_cap(cap, device->cap_mask) || 32962306a36Sopenharmony_ci dma_has_cap(DMA_PRIVATE, device->cap_mask)) 33062306a36Sopenharmony_ci continue; 33162306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) { 33262306a36Sopenharmony_ci if (!chan->client_count) 33362306a36Sopenharmony_ci continue; 33462306a36Sopenharmony_ci if (!min || chan->table_count < min->table_count) 33562306a36Sopenharmony_ci min = chan; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (dma_chan_is_local(chan, cpu)) 33862306a36Sopenharmony_ci if (!localmin || 33962306a36Sopenharmony_ci chan->table_count < localmin->table_count) 34062306a36Sopenharmony_ci localmin = chan; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci chan = localmin ? localmin : min; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (chan) 34762306a36Sopenharmony_ci chan->table_count++; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return chan; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/** 35362306a36Sopenharmony_ci * dma_channel_rebalance - redistribute the available channels 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Optimize for CPU isolation (each CPU gets a dedicated channel for an 35662306a36Sopenharmony_ci * operation type) in the SMP case, and operation isolation (avoid 35762306a36Sopenharmony_ci * multi-tasking channels) in the non-SMP case. 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * Must be called under dma_list_mutex. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cistatic void dma_channel_rebalance(void) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct dma_chan *chan; 36462306a36Sopenharmony_ci struct dma_device *device; 36562306a36Sopenharmony_ci int cpu; 36662306a36Sopenharmony_ci int cap; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* undo the last distribution */ 36962306a36Sopenharmony_ci for_each_dma_cap_mask(cap, dma_cap_mask_all) 37062306a36Sopenharmony_ci for_each_possible_cpu(cpu) 37162306a36Sopenharmony_ci per_cpu_ptr(channel_table[cap], cpu)->chan = NULL; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci list_for_each_entry(device, &dma_device_list, global_node) { 37462306a36Sopenharmony_ci if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) 37562306a36Sopenharmony_ci continue; 37662306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) 37762306a36Sopenharmony_ci chan->table_count = 0; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* don't populate the channel_table if no clients are available */ 38162306a36Sopenharmony_ci if (!dmaengine_ref_count) 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* redistribute available channels */ 38562306a36Sopenharmony_ci for_each_dma_cap_mask(cap, dma_cap_mask_all) 38662306a36Sopenharmony_ci for_each_online_cpu(cpu) { 38762306a36Sopenharmony_ci chan = min_chan(cap, cpu); 38862306a36Sopenharmony_ci per_cpu_ptr(channel_table[cap], cpu)->chan = chan; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int dma_device_satisfies_mask(struct dma_device *device, 39362306a36Sopenharmony_ci const dma_cap_mask_t *want) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci dma_cap_mask_t has; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci bitmap_and(has.bits, want->bits, device->cap_mask.bits, 39862306a36Sopenharmony_ci DMA_TX_TYPE_END); 39962306a36Sopenharmony_ci return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic struct module *dma_chan_to_owner(struct dma_chan *chan) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci return chan->device->owner; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/** 40862306a36Sopenharmony_ci * balance_ref_count - catch up the channel reference count 40962306a36Sopenharmony_ci * @chan: channel to balance ->client_count versus dmaengine_ref_count 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Must be called under dma_list_mutex. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_cistatic void balance_ref_count(struct dma_chan *chan) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct module *owner = dma_chan_to_owner(chan); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci while (chan->client_count < dmaengine_ref_count) { 41862306a36Sopenharmony_ci __module_get(owner); 41962306a36Sopenharmony_ci chan->client_count++; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void dma_device_release(struct kref *ref) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct dma_device *device = container_of(ref, struct dma_device, ref); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci list_del_rcu(&device->global_node); 42862306a36Sopenharmony_ci dma_channel_rebalance(); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (device->device_release) 43162306a36Sopenharmony_ci device->device_release(device); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void dma_device_put(struct dma_device *device) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci lockdep_assert_held(&dma_list_mutex); 43762306a36Sopenharmony_ci kref_put(&device->ref, dma_device_release); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * dma_chan_get - try to grab a DMA channel's parent driver module 44262306a36Sopenharmony_ci * @chan: channel to grab 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * Must be called under dma_list_mutex. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_cistatic int dma_chan_get(struct dma_chan *chan) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct module *owner = dma_chan_to_owner(chan); 44962306a36Sopenharmony_ci int ret; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* The channel is already in use, update client count */ 45262306a36Sopenharmony_ci if (chan->client_count) { 45362306a36Sopenharmony_ci __module_get(owner); 45462306a36Sopenharmony_ci chan->client_count++; 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!try_module_get(owner)) 45962306a36Sopenharmony_ci return -ENODEV; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ret = kref_get_unless_zero(&chan->device->ref); 46262306a36Sopenharmony_ci if (!ret) { 46362306a36Sopenharmony_ci ret = -ENODEV; 46462306a36Sopenharmony_ci goto module_put_out; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* allocate upon first client reference */ 46862306a36Sopenharmony_ci if (chan->device->device_alloc_chan_resources) { 46962306a36Sopenharmony_ci ret = chan->device->device_alloc_chan_resources(chan); 47062306a36Sopenharmony_ci if (ret < 0) 47162306a36Sopenharmony_ci goto err_out; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci chan->client_count++; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) 47762306a36Sopenharmony_ci balance_ref_count(chan); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cierr_out: 48262306a36Sopenharmony_ci dma_device_put(chan->device); 48362306a36Sopenharmony_cimodule_put_out: 48462306a36Sopenharmony_ci module_put(owner); 48562306a36Sopenharmony_ci return ret; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/** 48962306a36Sopenharmony_ci * dma_chan_put - drop a reference to a DMA channel's parent driver module 49062306a36Sopenharmony_ci * @chan: channel to release 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * Must be called under dma_list_mutex. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_cistatic void dma_chan_put(struct dma_chan *chan) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci /* This channel is not in use, bail out */ 49762306a36Sopenharmony_ci if (!chan->client_count) 49862306a36Sopenharmony_ci return; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci chan->client_count--; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* This channel is not in use anymore, free it */ 50362306a36Sopenharmony_ci if (!chan->client_count && chan->device->device_free_chan_resources) { 50462306a36Sopenharmony_ci /* Make sure all operations have completed */ 50562306a36Sopenharmony_ci dmaengine_synchronize(chan); 50662306a36Sopenharmony_ci chan->device->device_free_chan_resources(chan); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* If the channel is used via a DMA request router, free the mapping */ 51062306a36Sopenharmony_ci if (chan->router && chan->router->route_free) { 51162306a36Sopenharmony_ci chan->router->route_free(chan->router->dev, chan->route_data); 51262306a36Sopenharmony_ci chan->router = NULL; 51362306a36Sopenharmony_ci chan->route_data = NULL; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci dma_device_put(chan->device); 51762306a36Sopenharmony_ci module_put(dma_chan_to_owner(chan)); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cienum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci enum dma_status status; 52362306a36Sopenharmony_ci unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci dma_async_issue_pending(chan); 52662306a36Sopenharmony_ci do { 52762306a36Sopenharmony_ci status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); 52862306a36Sopenharmony_ci if (time_after_eq(jiffies, dma_sync_wait_timeout)) { 52962306a36Sopenharmony_ci dev_err(chan->device->dev, "%s: timeout!\n", __func__); 53062306a36Sopenharmony_ci return DMA_ERROR; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci if (status != DMA_IN_PROGRESS) 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci cpu_relax(); 53562306a36Sopenharmony_ci } while (1); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return status; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ciEXPORT_SYMBOL(dma_sync_wait); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/** 54262306a36Sopenharmony_ci * dma_find_channel - find a channel to carry out the operation 54362306a36Sopenharmony_ci * @tx_type: transaction type 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistruct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci return this_cpu_read(channel_table[tx_type]->chan); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ciEXPORT_SYMBOL(dma_find_channel); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/** 55262306a36Sopenharmony_ci * dma_issue_pending_all - flush all pending operations across all channels 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_civoid dma_issue_pending_all(void) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct dma_device *device; 55762306a36Sopenharmony_ci struct dma_chan *chan; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci rcu_read_lock(); 56062306a36Sopenharmony_ci list_for_each_entry_rcu(device, &dma_device_list, global_node) { 56162306a36Sopenharmony_ci if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) 56262306a36Sopenharmony_ci continue; 56362306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) 56462306a36Sopenharmony_ci if (chan->client_count) 56562306a36Sopenharmony_ci device->device_issue_pending(chan); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci rcu_read_unlock(); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ciEXPORT_SYMBOL(dma_issue_pending_all); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ciint dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct dma_device *device; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (!chan || !caps) 57662306a36Sopenharmony_ci return -EINVAL; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci device = chan->device; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* check if the channel supports slave transactions */ 58162306a36Sopenharmony_ci if (!(test_bit(DMA_SLAVE, device->cap_mask.bits) || 58262306a36Sopenharmony_ci test_bit(DMA_CYCLIC, device->cap_mask.bits))) 58362306a36Sopenharmony_ci return -ENXIO; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * Check whether it reports it uses the generic slave 58762306a36Sopenharmony_ci * capabilities, if not, that means it doesn't support any 58862306a36Sopenharmony_ci * kind of slave capabilities reporting. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci if (!device->directions) 59162306a36Sopenharmony_ci return -ENXIO; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci caps->src_addr_widths = device->src_addr_widths; 59462306a36Sopenharmony_ci caps->dst_addr_widths = device->dst_addr_widths; 59562306a36Sopenharmony_ci caps->directions = device->directions; 59662306a36Sopenharmony_ci caps->min_burst = device->min_burst; 59762306a36Sopenharmony_ci caps->max_burst = device->max_burst; 59862306a36Sopenharmony_ci caps->max_sg_burst = device->max_sg_burst; 59962306a36Sopenharmony_ci caps->residue_granularity = device->residue_granularity; 60062306a36Sopenharmony_ci caps->descriptor_reuse = device->descriptor_reuse; 60162306a36Sopenharmony_ci caps->cmd_pause = !!device->device_pause; 60262306a36Sopenharmony_ci caps->cmd_resume = !!device->device_resume; 60362306a36Sopenharmony_ci caps->cmd_terminate = !!device->device_terminate_all; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* 60662306a36Sopenharmony_ci * DMA engine device might be configured with non-uniformly 60762306a36Sopenharmony_ci * distributed slave capabilities per device channels. In this 60862306a36Sopenharmony_ci * case the corresponding driver may provide the device_caps 60962306a36Sopenharmony_ci * callback to override the generic capabilities with 61062306a36Sopenharmony_ci * channel-specific ones. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci if (device->device_caps) 61362306a36Sopenharmony_ci device->device_caps(chan, caps); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_get_slave_caps); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic struct dma_chan *private_candidate(const dma_cap_mask_t *mask, 62062306a36Sopenharmony_ci struct dma_device *dev, 62162306a36Sopenharmony_ci dma_filter_fn fn, void *fn_param) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct dma_chan *chan; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (mask && !dma_device_satisfies_mask(dev, mask)) { 62662306a36Sopenharmony_ci dev_dbg(dev->dev, "%s: wrong capabilities\n", __func__); 62762306a36Sopenharmony_ci return NULL; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci /* devices with multiple channels need special handling as we need to 63062306a36Sopenharmony_ci * ensure that all channels are either private or public. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask)) 63362306a36Sopenharmony_ci list_for_each_entry(chan, &dev->channels, device_node) { 63462306a36Sopenharmony_ci /* some channels are already publicly allocated */ 63562306a36Sopenharmony_ci if (chan->client_count) 63662306a36Sopenharmony_ci return NULL; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci list_for_each_entry(chan, &dev->channels, device_node) { 64062306a36Sopenharmony_ci if (chan->client_count) { 64162306a36Sopenharmony_ci dev_dbg(dev->dev, "%s: %s busy\n", 64262306a36Sopenharmony_ci __func__, dma_chan_name(chan)); 64362306a36Sopenharmony_ci continue; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci if (fn && !fn(chan, fn_param)) { 64662306a36Sopenharmony_ci dev_dbg(dev->dev, "%s: %s filter said false\n", 64762306a36Sopenharmony_ci __func__, dma_chan_name(chan)); 64862306a36Sopenharmony_ci continue; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci return chan; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return NULL; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic struct dma_chan *find_candidate(struct dma_device *device, 65762306a36Sopenharmony_ci const dma_cap_mask_t *mask, 65862306a36Sopenharmony_ci dma_filter_fn fn, void *fn_param) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct dma_chan *chan = private_candidate(mask, device, fn, fn_param); 66162306a36Sopenharmony_ci int err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (chan) { 66462306a36Sopenharmony_ci /* Found a suitable channel, try to grab, prep, and return it. 66562306a36Sopenharmony_ci * We first set DMA_PRIVATE to disable balance_ref_count as this 66662306a36Sopenharmony_ci * channel will not be published in the general-purpose 66762306a36Sopenharmony_ci * allocator 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, device->cap_mask); 67062306a36Sopenharmony_ci device->privatecnt++; 67162306a36Sopenharmony_ci err = dma_chan_get(chan); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (err) { 67462306a36Sopenharmony_ci if (err == -ENODEV) { 67562306a36Sopenharmony_ci dev_dbg(device->dev, "%s: %s module removed\n", 67662306a36Sopenharmony_ci __func__, dma_chan_name(chan)); 67762306a36Sopenharmony_ci list_del_rcu(&device->global_node); 67862306a36Sopenharmony_ci } else 67962306a36Sopenharmony_ci dev_dbg(device->dev, 68062306a36Sopenharmony_ci "%s: failed to get %s: (%d)\n", 68162306a36Sopenharmony_ci __func__, dma_chan_name(chan), err); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (--device->privatecnt == 0) 68462306a36Sopenharmony_ci dma_cap_clear(DMA_PRIVATE, device->cap_mask); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci chan = ERR_PTR(err); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return chan ? chan : ERR_PTR(-EPROBE_DEFER); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * dma_get_slave_channel - try to get specific channel exclusively 69562306a36Sopenharmony_ci * @chan: target channel 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_cistruct dma_chan *dma_get_slave_channel(struct dma_chan *chan) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci /* lock against __dma_request_channel */ 70062306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (chan->client_count == 0) { 70362306a36Sopenharmony_ci struct dma_device *device = chan->device; 70462306a36Sopenharmony_ci int err; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, device->cap_mask); 70762306a36Sopenharmony_ci device->privatecnt++; 70862306a36Sopenharmony_ci err = dma_chan_get(chan); 70962306a36Sopenharmony_ci if (err) { 71062306a36Sopenharmony_ci dev_dbg(chan->device->dev, 71162306a36Sopenharmony_ci "%s: failed to get %s: (%d)\n", 71262306a36Sopenharmony_ci __func__, dma_chan_name(chan), err); 71362306a36Sopenharmony_ci chan = NULL; 71462306a36Sopenharmony_ci if (--device->privatecnt == 0) 71562306a36Sopenharmony_ci dma_cap_clear(DMA_PRIVATE, device->cap_mask); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci } else 71862306a36Sopenharmony_ci chan = NULL; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return chan; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_get_slave_channel); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistruct dma_chan *dma_get_any_slave_channel(struct dma_device *device) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci dma_cap_mask_t mask; 73062306a36Sopenharmony_ci struct dma_chan *chan; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci dma_cap_zero(mask); 73362306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* lock against __dma_request_channel */ 73662306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci chan = find_candidate(device, &mask, NULL, NULL); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci return IS_ERR(chan) ? NULL : chan; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_get_any_slave_channel); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/** 74762306a36Sopenharmony_ci * __dma_request_channel - try to allocate an exclusive channel 74862306a36Sopenharmony_ci * @mask: capabilities that the channel must satisfy 74962306a36Sopenharmony_ci * @fn: optional callback to disposition available channels 75062306a36Sopenharmony_ci * @fn_param: opaque parameter to pass to dma_filter_fn() 75162306a36Sopenharmony_ci * @np: device node to look for DMA channels 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * Returns pointer to appropriate DMA channel on success or NULL. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_cistruct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, 75662306a36Sopenharmony_ci dma_filter_fn fn, void *fn_param, 75762306a36Sopenharmony_ci struct device_node *np) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct dma_device *device, *_d; 76062306a36Sopenharmony_ci struct dma_chan *chan = NULL; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* Find a channel */ 76362306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 76462306a36Sopenharmony_ci list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { 76562306a36Sopenharmony_ci /* Finds a DMA controller with matching device node */ 76662306a36Sopenharmony_ci if (np && device->dev->of_node && np != device->dev->of_node) 76762306a36Sopenharmony_ci continue; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci chan = find_candidate(device, mask, fn, fn_param); 77062306a36Sopenharmony_ci if (!IS_ERR(chan)) 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci chan = NULL; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci pr_debug("%s: %s (%s)\n", 77862306a36Sopenharmony_ci __func__, 77962306a36Sopenharmony_ci chan ? "success" : "fail", 78062306a36Sopenharmony_ci chan ? dma_chan_name(chan) : NULL); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return chan; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__dma_request_channel); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic const struct dma_slave_map *dma_filter_match(struct dma_device *device, 78762306a36Sopenharmony_ci const char *name, 78862306a36Sopenharmony_ci struct device *dev) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci int i; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!device->filter.mapcnt) 79362306a36Sopenharmony_ci return NULL; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci for (i = 0; i < device->filter.mapcnt; i++) { 79662306a36Sopenharmony_ci const struct dma_slave_map *map = &device->filter.map[i]; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (!strcmp(map->devname, dev_name(dev)) && 79962306a36Sopenharmony_ci !strcmp(map->slave, name)) 80062306a36Sopenharmony_ci return map; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return NULL; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/** 80762306a36Sopenharmony_ci * dma_request_chan - try to allocate an exclusive slave channel 80862306a36Sopenharmony_ci * @dev: pointer to client device structure 80962306a36Sopenharmony_ci * @name: slave channel name 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * Returns pointer to appropriate DMA channel on success or an error pointer. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_cistruct dma_chan *dma_request_chan(struct device *dev, const char *name) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct dma_device *d, *_d; 81662306a36Sopenharmony_ci struct dma_chan *chan = NULL; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* If device-tree is present get slave info from here */ 81962306a36Sopenharmony_ci if (dev->of_node) 82062306a36Sopenharmony_ci chan = of_dma_request_slave_channel(dev->of_node, name); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* If device was enumerated by ACPI get slave info from here */ 82362306a36Sopenharmony_ci if (has_acpi_companion(dev) && !chan) 82462306a36Sopenharmony_ci chan = acpi_dma_request_slave_chan_by_name(dev, name); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (PTR_ERR(chan) == -EPROBE_DEFER) 82762306a36Sopenharmony_ci return chan; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(chan)) 83062306a36Sopenharmony_ci goto found; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* Try to find the channel via the DMA filter map(s) */ 83362306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 83462306a36Sopenharmony_ci list_for_each_entry_safe(d, _d, &dma_device_list, global_node) { 83562306a36Sopenharmony_ci dma_cap_mask_t mask; 83662306a36Sopenharmony_ci const struct dma_slave_map *map = dma_filter_match(d, name, dev); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (!map) 83962306a36Sopenharmony_ci continue; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci dma_cap_zero(mask); 84262306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci chan = find_candidate(d, &mask, d->filter.fn, map->param); 84562306a36Sopenharmony_ci if (!IS_ERR(chan)) 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (IS_ERR(chan)) 85162306a36Sopenharmony_ci return chan; 85262306a36Sopenharmony_ci if (!chan) 85362306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cifound: 85662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 85762306a36Sopenharmony_ci chan->dbg_client_name = kasprintf(GFP_KERNEL, "%s:%s", dev_name(dev), 85862306a36Sopenharmony_ci name); 85962306a36Sopenharmony_ci#endif 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci chan->name = kasprintf(GFP_KERNEL, "dma:%s", name); 86262306a36Sopenharmony_ci if (!chan->name) 86362306a36Sopenharmony_ci return chan; 86462306a36Sopenharmony_ci chan->slave = dev; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (sysfs_create_link(&chan->dev->device.kobj, &dev->kobj, 86762306a36Sopenharmony_ci DMA_SLAVE_NAME)) 86862306a36Sopenharmony_ci dev_warn(dev, "Cannot create DMA %s symlink\n", DMA_SLAVE_NAME); 86962306a36Sopenharmony_ci if (sysfs_create_link(&dev->kobj, &chan->dev->device.kobj, chan->name)) 87062306a36Sopenharmony_ci dev_warn(dev, "Cannot create DMA %s symlink\n", chan->name); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return chan; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_request_chan); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/** 87762306a36Sopenharmony_ci * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities 87862306a36Sopenharmony_ci * @mask: capabilities that the channel must satisfy 87962306a36Sopenharmony_ci * 88062306a36Sopenharmony_ci * Returns pointer to appropriate DMA channel on success or an error pointer. 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_cistruct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct dma_chan *chan; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!mask) 88762306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci chan = __dma_request_channel(mask, NULL, NULL, NULL); 89062306a36Sopenharmony_ci if (!chan) { 89162306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 89262306a36Sopenharmony_ci if (list_empty(&dma_device_list)) 89362306a36Sopenharmony_ci chan = ERR_PTR(-EPROBE_DEFER); 89462306a36Sopenharmony_ci else 89562306a36Sopenharmony_ci chan = ERR_PTR(-ENODEV); 89662306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci return chan; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_request_chan_by_mask); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_civoid dma_release_channel(struct dma_chan *chan) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 90662306a36Sopenharmony_ci WARN_ONCE(chan->client_count != 1, 90762306a36Sopenharmony_ci "chan reference count %d != 1\n", chan->client_count); 90862306a36Sopenharmony_ci dma_chan_put(chan); 90962306a36Sopenharmony_ci /* drop PRIVATE cap enabled by __dma_request_channel() */ 91062306a36Sopenharmony_ci if (--chan->device->privatecnt == 0) 91162306a36Sopenharmony_ci dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (chan->slave) { 91462306a36Sopenharmony_ci sysfs_remove_link(&chan->dev->device.kobj, DMA_SLAVE_NAME); 91562306a36Sopenharmony_ci sysfs_remove_link(&chan->slave->kobj, chan->name); 91662306a36Sopenharmony_ci kfree(chan->name); 91762306a36Sopenharmony_ci chan->name = NULL; 91862306a36Sopenharmony_ci chan->slave = NULL; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 92262306a36Sopenharmony_ci kfree(chan->dbg_client_name); 92362306a36Sopenharmony_ci chan->dbg_client_name = NULL; 92462306a36Sopenharmony_ci#endif 92562306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_release_channel); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci/** 93062306a36Sopenharmony_ci * dmaengine_get - register interest in dma_channels 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_civoid dmaengine_get(void) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci struct dma_device *device, *_d; 93562306a36Sopenharmony_ci struct dma_chan *chan; 93662306a36Sopenharmony_ci int err; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 93962306a36Sopenharmony_ci dmaengine_ref_count++; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* try to grab channels */ 94262306a36Sopenharmony_ci list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { 94362306a36Sopenharmony_ci if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) 94462306a36Sopenharmony_ci continue; 94562306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) { 94662306a36Sopenharmony_ci err = dma_chan_get(chan); 94762306a36Sopenharmony_ci if (err == -ENODEV) { 94862306a36Sopenharmony_ci /* module removed before we could use it */ 94962306a36Sopenharmony_ci list_del_rcu(&device->global_node); 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci } else if (err) 95262306a36Sopenharmony_ci dev_dbg(chan->device->dev, 95362306a36Sopenharmony_ci "%s: failed to get %s: (%d)\n", 95462306a36Sopenharmony_ci __func__, dma_chan_name(chan), err); 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* if this is the first reference and there were channels 95962306a36Sopenharmony_ci * waiting we need to rebalance to get those channels 96062306a36Sopenharmony_ci * incorporated into the channel table 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci if (dmaengine_ref_count == 1) 96362306a36Sopenharmony_ci dma_channel_rebalance(); 96462306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ciEXPORT_SYMBOL(dmaengine_get); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci/** 96962306a36Sopenharmony_ci * dmaengine_put - let DMA drivers be removed when ref_count == 0 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_civoid dmaengine_put(void) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct dma_device *device, *_d; 97462306a36Sopenharmony_ci struct dma_chan *chan; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 97762306a36Sopenharmony_ci dmaengine_ref_count--; 97862306a36Sopenharmony_ci BUG_ON(dmaengine_ref_count < 0); 97962306a36Sopenharmony_ci /* drop channel references */ 98062306a36Sopenharmony_ci list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { 98162306a36Sopenharmony_ci if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) 98262306a36Sopenharmony_ci continue; 98362306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) 98462306a36Sopenharmony_ci dma_chan_put(chan); 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ciEXPORT_SYMBOL(dmaengine_put); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic bool device_has_all_tx_types(struct dma_device *device) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci /* A device that satisfies this test has channels that will never cause 99362306a36Sopenharmony_ci * an async_tx channel switch event as all possible operation types can 99462306a36Sopenharmony_ci * be handled. 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ci #ifdef CONFIG_ASYNC_TX_DMA 99762306a36Sopenharmony_ci if (!dma_has_cap(DMA_INTERRUPT, device->cap_mask)) 99862306a36Sopenharmony_ci return false; 99962306a36Sopenharmony_ci #endif 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci #if IS_ENABLED(CONFIG_ASYNC_MEMCPY) 100262306a36Sopenharmony_ci if (!dma_has_cap(DMA_MEMCPY, device->cap_mask)) 100362306a36Sopenharmony_ci return false; 100462306a36Sopenharmony_ci #endif 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci #if IS_ENABLED(CONFIG_ASYNC_XOR) 100762306a36Sopenharmony_ci if (!dma_has_cap(DMA_XOR, device->cap_mask)) 100862306a36Sopenharmony_ci return false; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci #ifndef CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA 101162306a36Sopenharmony_ci if (!dma_has_cap(DMA_XOR_VAL, device->cap_mask)) 101262306a36Sopenharmony_ci return false; 101362306a36Sopenharmony_ci #endif 101462306a36Sopenharmony_ci #endif 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci #if IS_ENABLED(CONFIG_ASYNC_PQ) 101762306a36Sopenharmony_ci if (!dma_has_cap(DMA_PQ, device->cap_mask)) 101862306a36Sopenharmony_ci return false; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci #ifndef CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA 102162306a36Sopenharmony_ci if (!dma_has_cap(DMA_PQ_VAL, device->cap_mask)) 102262306a36Sopenharmony_ci return false; 102362306a36Sopenharmony_ci #endif 102462306a36Sopenharmony_ci #endif 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci return true; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int get_dma_id(struct dma_device *device) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci int rc = ida_alloc(&dma_ida, GFP_KERNEL); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (rc < 0) 103462306a36Sopenharmony_ci return rc; 103562306a36Sopenharmony_ci device->dev_id = rc; 103662306a36Sopenharmony_ci return 0; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic int __dma_async_device_channel_register(struct dma_device *device, 104062306a36Sopenharmony_ci struct dma_chan *chan) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci int rc; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci chan->local = alloc_percpu(typeof(*chan->local)); 104562306a36Sopenharmony_ci if (!chan->local) 104662306a36Sopenharmony_ci return -ENOMEM; 104762306a36Sopenharmony_ci chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL); 104862306a36Sopenharmony_ci if (!chan->dev) { 104962306a36Sopenharmony_ci rc = -ENOMEM; 105062306a36Sopenharmony_ci goto err_free_local; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 105462306a36Sopenharmony_ci * When the chan_id is a negative value, we are dynamically adding 105562306a36Sopenharmony_ci * the channel. Otherwise we are static enumerating. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL); 105862306a36Sopenharmony_ci if (chan->chan_id < 0) { 105962306a36Sopenharmony_ci pr_err("%s: unable to alloc ida for chan: %d\n", 106062306a36Sopenharmony_ci __func__, chan->chan_id); 106162306a36Sopenharmony_ci rc = chan->chan_id; 106262306a36Sopenharmony_ci goto err_free_dev; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci chan->dev->device.class = &dma_devclass; 106662306a36Sopenharmony_ci chan->dev->device.parent = device->dev; 106762306a36Sopenharmony_ci chan->dev->chan = chan; 106862306a36Sopenharmony_ci chan->dev->dev_id = device->dev_id; 106962306a36Sopenharmony_ci dev_set_name(&chan->dev->device, "dma%dchan%d", 107062306a36Sopenharmony_ci device->dev_id, chan->chan_id); 107162306a36Sopenharmony_ci rc = device_register(&chan->dev->device); 107262306a36Sopenharmony_ci if (rc) 107362306a36Sopenharmony_ci goto err_out_ida; 107462306a36Sopenharmony_ci chan->client_count = 0; 107562306a36Sopenharmony_ci device->chancnt++; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci err_out_ida: 108062306a36Sopenharmony_ci ida_free(&device->chan_ida, chan->chan_id); 108162306a36Sopenharmony_ci err_free_dev: 108262306a36Sopenharmony_ci kfree(chan->dev); 108362306a36Sopenharmony_ci err_free_local: 108462306a36Sopenharmony_ci free_percpu(chan->local); 108562306a36Sopenharmony_ci chan->local = NULL; 108662306a36Sopenharmony_ci return rc; 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ciint dma_async_device_channel_register(struct dma_device *device, 109062306a36Sopenharmony_ci struct dma_chan *chan) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci int rc; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci rc = __dma_async_device_channel_register(device, chan); 109562306a36Sopenharmony_ci if (rc < 0) 109662306a36Sopenharmony_ci return rc; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci dma_channel_rebalance(); 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_async_device_channel_register); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic void __dma_async_device_channel_unregister(struct dma_device *device, 110462306a36Sopenharmony_ci struct dma_chan *chan) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci if (chan->local == NULL) 110762306a36Sopenharmony_ci return; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci WARN_ONCE(!device->device_release && chan->client_count, 111062306a36Sopenharmony_ci "%s called while %d clients hold a reference\n", 111162306a36Sopenharmony_ci __func__, chan->client_count); 111262306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 111362306a36Sopenharmony_ci device->chancnt--; 111462306a36Sopenharmony_ci chan->dev->chan = NULL; 111562306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 111662306a36Sopenharmony_ci ida_free(&device->chan_ida, chan->chan_id); 111762306a36Sopenharmony_ci device_unregister(&chan->dev->device); 111862306a36Sopenharmony_ci free_percpu(chan->local); 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_civoid dma_async_device_channel_unregister(struct dma_device *device, 112262306a36Sopenharmony_ci struct dma_chan *chan) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci __dma_async_device_channel_unregister(device, chan); 112562306a36Sopenharmony_ci dma_channel_rebalance(); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_async_device_channel_unregister); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/** 113062306a36Sopenharmony_ci * dma_async_device_register - registers DMA devices found 113162306a36Sopenharmony_ci * @device: pointer to &struct dma_device 113262306a36Sopenharmony_ci * 113362306a36Sopenharmony_ci * After calling this routine the structure should not be freed except in the 113462306a36Sopenharmony_ci * device_release() callback which will be called after 113562306a36Sopenharmony_ci * dma_async_device_unregister() is called and no further references are taken. 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ciint dma_async_device_register(struct dma_device *device) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci int rc; 114062306a36Sopenharmony_ci struct dma_chan* chan; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (!device) 114362306a36Sopenharmony_ci return -ENODEV; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* validate device routines */ 114662306a36Sopenharmony_ci if (!device->dev) { 114762306a36Sopenharmony_ci pr_err("DMAdevice must have dev\n"); 114862306a36Sopenharmony_ci return -EIO; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci device->owner = device->dev->driver->owner; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci#define CHECK_CAP(_name, _type) \ 115462306a36Sopenharmony_ci{ \ 115562306a36Sopenharmony_ci if (dma_has_cap(_type, device->cap_mask) && !device->device_prep_##_name) { \ 115662306a36Sopenharmony_ci dev_err(device->dev, \ 115762306a36Sopenharmony_ci "Device claims capability %s, but op is not defined\n", \ 115862306a36Sopenharmony_ci __stringify(_type)); \ 115962306a36Sopenharmony_ci return -EIO; \ 116062306a36Sopenharmony_ci } \ 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci CHECK_CAP(dma_memcpy, DMA_MEMCPY); 116462306a36Sopenharmony_ci CHECK_CAP(dma_xor, DMA_XOR); 116562306a36Sopenharmony_ci CHECK_CAP(dma_xor_val, DMA_XOR_VAL); 116662306a36Sopenharmony_ci CHECK_CAP(dma_pq, DMA_PQ); 116762306a36Sopenharmony_ci CHECK_CAP(dma_pq_val, DMA_PQ_VAL); 116862306a36Sopenharmony_ci CHECK_CAP(dma_memset, DMA_MEMSET); 116962306a36Sopenharmony_ci CHECK_CAP(dma_interrupt, DMA_INTERRUPT); 117062306a36Sopenharmony_ci CHECK_CAP(dma_cyclic, DMA_CYCLIC); 117162306a36Sopenharmony_ci CHECK_CAP(interleaved_dma, DMA_INTERLEAVE); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci#undef CHECK_CAP 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!device->device_tx_status) { 117662306a36Sopenharmony_ci dev_err(device->dev, "Device tx_status is not defined\n"); 117762306a36Sopenharmony_ci return -EIO; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (!device->device_issue_pending) { 118262306a36Sopenharmony_ci dev_err(device->dev, "Device issue_pending is not defined\n"); 118362306a36Sopenharmony_ci return -EIO; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (!device->device_release) 118762306a36Sopenharmony_ci dev_dbg(device->dev, 118862306a36Sopenharmony_ci "WARN: Device release is not defined so it is not safe to unbind this driver while in use\n"); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci kref_init(&device->ref); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* note: this only matters in the 119362306a36Sopenharmony_ci * CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_ci if (device_has_all_tx_types(device)) 119662306a36Sopenharmony_ci dma_cap_set(DMA_ASYNC_TX, device->cap_mask); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci rc = get_dma_id(device); 119962306a36Sopenharmony_ci if (rc != 0) 120062306a36Sopenharmony_ci return rc; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci ida_init(&device->chan_ida); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* represent channels in sysfs. Probably want devs too */ 120562306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) { 120662306a36Sopenharmony_ci rc = __dma_async_device_channel_register(device, chan); 120762306a36Sopenharmony_ci if (rc < 0) 120862306a36Sopenharmony_ci goto err_out; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 121262306a36Sopenharmony_ci /* take references on public channels */ 121362306a36Sopenharmony_ci if (dmaengine_ref_count && !dma_has_cap(DMA_PRIVATE, device->cap_mask)) 121462306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) { 121562306a36Sopenharmony_ci /* if clients are already waiting for channels we need 121662306a36Sopenharmony_ci * to take references on their behalf 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_ci if (dma_chan_get(chan) == -ENODEV) { 121962306a36Sopenharmony_ci /* note we can only get here for the first 122062306a36Sopenharmony_ci * channel as the remaining channels are 122162306a36Sopenharmony_ci * guaranteed to get a reference 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci rc = -ENODEV; 122462306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 122562306a36Sopenharmony_ci goto err_out; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci list_add_tail_rcu(&device->global_node, &dma_device_list); 122962306a36Sopenharmony_ci if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) 123062306a36Sopenharmony_ci device->privatecnt++; /* Always private */ 123162306a36Sopenharmony_ci dma_channel_rebalance(); 123262306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci dmaengine_debug_register(device); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return 0; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cierr_out: 123962306a36Sopenharmony_ci /* if we never registered a channel just release the idr */ 124062306a36Sopenharmony_ci if (!device->chancnt) { 124162306a36Sopenharmony_ci ida_free(&dma_ida, device->dev_id); 124262306a36Sopenharmony_ci return rc; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci list_for_each_entry(chan, &device->channels, device_node) { 124662306a36Sopenharmony_ci if (chan->local == NULL) 124762306a36Sopenharmony_ci continue; 124862306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 124962306a36Sopenharmony_ci chan->dev->chan = NULL; 125062306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 125162306a36Sopenharmony_ci device_unregister(&chan->dev->device); 125262306a36Sopenharmony_ci free_percpu(chan->local); 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci return rc; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ciEXPORT_SYMBOL(dma_async_device_register); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci/** 125962306a36Sopenharmony_ci * dma_async_device_unregister - unregister a DMA device 126062306a36Sopenharmony_ci * @device: pointer to &struct dma_device 126162306a36Sopenharmony_ci * 126262306a36Sopenharmony_ci * This routine is called by dma driver exit routines, dmaengine holds module 126362306a36Sopenharmony_ci * references to prevent it being called while channels are in use. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_civoid dma_async_device_unregister(struct dma_device *device) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci struct dma_chan *chan, *n; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci dmaengine_debug_unregister(device); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci list_for_each_entry_safe(chan, n, &device->channels, device_node) 127262306a36Sopenharmony_ci __dma_async_device_channel_unregister(device, chan); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci mutex_lock(&dma_list_mutex); 127562306a36Sopenharmony_ci /* 127662306a36Sopenharmony_ci * setting DMA_PRIVATE ensures the device being torn down will not 127762306a36Sopenharmony_ci * be used in the channel_table 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, device->cap_mask); 128062306a36Sopenharmony_ci dma_channel_rebalance(); 128162306a36Sopenharmony_ci ida_free(&dma_ida, device->dev_id); 128262306a36Sopenharmony_ci dma_device_put(device); 128362306a36Sopenharmony_ci mutex_unlock(&dma_list_mutex); 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ciEXPORT_SYMBOL(dma_async_device_unregister); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic void dmaenginem_async_device_unregister(void *device) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci dma_async_device_unregister(device); 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci/** 129362306a36Sopenharmony_ci * dmaenginem_async_device_register - registers DMA devices found 129462306a36Sopenharmony_ci * @device: pointer to &struct dma_device 129562306a36Sopenharmony_ci * 129662306a36Sopenharmony_ci * The operation is managed and will be undone on driver detach. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_ciint dmaenginem_async_device_register(struct dma_device *device) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci int ret; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ret = dma_async_device_register(device); 130362306a36Sopenharmony_ci if (ret) 130462306a36Sopenharmony_ci return ret; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return devm_add_action_or_reset(device->dev, dmaenginem_async_device_unregister, device); 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ciEXPORT_SYMBOL(dmaenginem_async_device_register); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistruct dmaengine_unmap_pool { 131162306a36Sopenharmony_ci struct kmem_cache *cache; 131262306a36Sopenharmony_ci const char *name; 131362306a36Sopenharmony_ci mempool_t *pool; 131462306a36Sopenharmony_ci size_t size; 131562306a36Sopenharmony_ci}; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci#define __UNMAP_POOL(x) { .size = x, .name = "dmaengine-unmap-" __stringify(x) } 131862306a36Sopenharmony_cistatic struct dmaengine_unmap_pool unmap_pool[] = { 131962306a36Sopenharmony_ci __UNMAP_POOL(2), 132062306a36Sopenharmony_ci #if IS_ENABLED(CONFIG_DMA_ENGINE_RAID) 132162306a36Sopenharmony_ci __UNMAP_POOL(16), 132262306a36Sopenharmony_ci __UNMAP_POOL(128), 132362306a36Sopenharmony_ci __UNMAP_POOL(256), 132462306a36Sopenharmony_ci #endif 132562306a36Sopenharmony_ci}; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_cistatic struct dmaengine_unmap_pool *__get_unmap_pool(int nr) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci int order = get_count_order(nr); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci switch (order) { 133262306a36Sopenharmony_ci case 0 ... 1: 133362306a36Sopenharmony_ci return &unmap_pool[0]; 133462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DMA_ENGINE_RAID) 133562306a36Sopenharmony_ci case 2 ... 4: 133662306a36Sopenharmony_ci return &unmap_pool[1]; 133762306a36Sopenharmony_ci case 5 ... 7: 133862306a36Sopenharmony_ci return &unmap_pool[2]; 133962306a36Sopenharmony_ci case 8: 134062306a36Sopenharmony_ci return &unmap_pool[3]; 134162306a36Sopenharmony_ci#endif 134262306a36Sopenharmony_ci default: 134362306a36Sopenharmony_ci BUG(); 134462306a36Sopenharmony_ci return NULL; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic void dmaengine_unmap(struct kref *kref) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct dmaengine_unmap_data *unmap = container_of(kref, typeof(*unmap), kref); 135162306a36Sopenharmony_ci struct device *dev = unmap->dev; 135262306a36Sopenharmony_ci int cnt, i; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci cnt = unmap->to_cnt; 135562306a36Sopenharmony_ci for (i = 0; i < cnt; i++) 135662306a36Sopenharmony_ci dma_unmap_page(dev, unmap->addr[i], unmap->len, 135762306a36Sopenharmony_ci DMA_TO_DEVICE); 135862306a36Sopenharmony_ci cnt += unmap->from_cnt; 135962306a36Sopenharmony_ci for (; i < cnt; i++) 136062306a36Sopenharmony_ci dma_unmap_page(dev, unmap->addr[i], unmap->len, 136162306a36Sopenharmony_ci DMA_FROM_DEVICE); 136262306a36Sopenharmony_ci cnt += unmap->bidi_cnt; 136362306a36Sopenharmony_ci for (; i < cnt; i++) { 136462306a36Sopenharmony_ci if (unmap->addr[i] == 0) 136562306a36Sopenharmony_ci continue; 136662306a36Sopenharmony_ci dma_unmap_page(dev, unmap->addr[i], unmap->len, 136762306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci cnt = unmap->map_cnt; 137062306a36Sopenharmony_ci mempool_free(unmap, __get_unmap_pool(cnt)->pool); 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_civoid dmaengine_unmap_put(struct dmaengine_unmap_data *unmap) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci if (unmap) 137662306a36Sopenharmony_ci kref_put(&unmap->kref, dmaengine_unmap); 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dmaengine_unmap_put); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cistatic void dmaengine_destroy_unmap_pool(void) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci int i; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(unmap_pool); i++) { 138562306a36Sopenharmony_ci struct dmaengine_unmap_pool *p = &unmap_pool[i]; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci mempool_destroy(p->pool); 138862306a36Sopenharmony_ci p->pool = NULL; 138962306a36Sopenharmony_ci kmem_cache_destroy(p->cache); 139062306a36Sopenharmony_ci p->cache = NULL; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cistatic int __init dmaengine_init_unmap_pool(void) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci int i; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(unmap_pool); i++) { 139962306a36Sopenharmony_ci struct dmaengine_unmap_pool *p = &unmap_pool[i]; 140062306a36Sopenharmony_ci size_t size; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci size = sizeof(struct dmaengine_unmap_data) + 140362306a36Sopenharmony_ci sizeof(dma_addr_t) * p->size; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci p->cache = kmem_cache_create(p->name, size, 0, 140662306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 140762306a36Sopenharmony_ci if (!p->cache) 140862306a36Sopenharmony_ci break; 140962306a36Sopenharmony_ci p->pool = mempool_create_slab_pool(1, p->cache); 141062306a36Sopenharmony_ci if (!p->pool) 141162306a36Sopenharmony_ci break; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (i == ARRAY_SIZE(unmap_pool)) 141562306a36Sopenharmony_ci return 0; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci dmaengine_destroy_unmap_pool(); 141862306a36Sopenharmony_ci return -ENOMEM; 141962306a36Sopenharmony_ci} 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cistruct dmaengine_unmap_data * 142262306a36Sopenharmony_cidmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct dmaengine_unmap_data *unmap; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci unmap = mempool_alloc(__get_unmap_pool(nr)->pool, flags); 142762306a36Sopenharmony_ci if (!unmap) 142862306a36Sopenharmony_ci return NULL; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci memset(unmap, 0, sizeof(*unmap)); 143162306a36Sopenharmony_ci kref_init(&unmap->kref); 143262306a36Sopenharmony_ci unmap->dev = dev; 143362306a36Sopenharmony_ci unmap->map_cnt = nr; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci return unmap; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ciEXPORT_SYMBOL(dmaengine_get_unmap_data); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_civoid dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, 144062306a36Sopenharmony_ci struct dma_chan *chan) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci tx->chan = chan; 144362306a36Sopenharmony_ci #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH 144462306a36Sopenharmony_ci spin_lock_init(&tx->lock); 144562306a36Sopenharmony_ci #endif 144662306a36Sopenharmony_ci} 144762306a36Sopenharmony_ciEXPORT_SYMBOL(dma_async_tx_descriptor_init); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_cistatic inline int desc_check_and_set_metadata_mode( 145062306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc, enum dma_desc_metadata_mode mode) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci /* Make sure that the metadata mode is not mixed */ 145362306a36Sopenharmony_ci if (!desc->desc_metadata_mode) { 145462306a36Sopenharmony_ci if (dmaengine_is_metadata_mode_supported(desc->chan, mode)) 145562306a36Sopenharmony_ci desc->desc_metadata_mode = mode; 145662306a36Sopenharmony_ci else 145762306a36Sopenharmony_ci return -ENOTSUPP; 145862306a36Sopenharmony_ci } else if (desc->desc_metadata_mode != mode) { 145962306a36Sopenharmony_ci return -EINVAL; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return 0; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ciint dmaengine_desc_attach_metadata(struct dma_async_tx_descriptor *desc, 146662306a36Sopenharmony_ci void *data, size_t len) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci int ret; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (!desc) 147162306a36Sopenharmony_ci return -EINVAL; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_CLIENT); 147462306a36Sopenharmony_ci if (ret) 147562306a36Sopenharmony_ci return ret; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if (!desc->metadata_ops || !desc->metadata_ops->attach) 147862306a36Sopenharmony_ci return -ENOTSUPP; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return desc->metadata_ops->attach(desc, data, len); 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dmaengine_desc_attach_metadata); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_civoid *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc, 148562306a36Sopenharmony_ci size_t *payload_len, size_t *max_len) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci int ret; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (!desc) 149062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE); 149362306a36Sopenharmony_ci if (ret) 149462306a36Sopenharmony_ci return ERR_PTR(ret); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if (!desc->metadata_ops || !desc->metadata_ops->get_ptr) 149762306a36Sopenharmony_ci return ERR_PTR(-ENOTSUPP); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci return desc->metadata_ops->get_ptr(desc, payload_len, max_len); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dmaengine_desc_get_metadata_ptr); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ciint dmaengine_desc_set_metadata_len(struct dma_async_tx_descriptor *desc, 150462306a36Sopenharmony_ci size_t payload_len) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci int ret; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (!desc) 150962306a36Sopenharmony_ci return -EINVAL; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE); 151262306a36Sopenharmony_ci if (ret) 151362306a36Sopenharmony_ci return ret; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (!desc->metadata_ops || !desc->metadata_ops->set_len) 151662306a36Sopenharmony_ci return -ENOTSUPP; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci return desc->metadata_ops->set_len(desc, payload_len); 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dmaengine_desc_set_metadata_len); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci/** 152362306a36Sopenharmony_ci * dma_wait_for_async_tx - spin wait for a transaction to complete 152462306a36Sopenharmony_ci * @tx: in-flight transaction to wait on 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_cienum dma_status 152762306a36Sopenharmony_cidma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (!tx) 153262306a36Sopenharmony_ci return DMA_COMPLETE; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci while (tx->cookie == -EBUSY) { 153562306a36Sopenharmony_ci if (time_after_eq(jiffies, dma_sync_wait_timeout)) { 153662306a36Sopenharmony_ci dev_err(tx->chan->device->dev, 153762306a36Sopenharmony_ci "%s timeout waiting for descriptor submission\n", 153862306a36Sopenharmony_ci __func__); 153962306a36Sopenharmony_ci return DMA_ERROR; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci cpu_relax(); 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci return dma_sync_wait(tx->chan, tx->cookie); 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_wait_for_async_tx); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci/** 154862306a36Sopenharmony_ci * dma_run_dependencies - process dependent operations on the target channel 154962306a36Sopenharmony_ci * @tx: transaction with dependencies 155062306a36Sopenharmony_ci * 155162306a36Sopenharmony_ci * Helper routine for DMA drivers to process (start) dependent operations 155262306a36Sopenharmony_ci * on their target channel. 155362306a36Sopenharmony_ci */ 155462306a36Sopenharmony_civoid dma_run_dependencies(struct dma_async_tx_descriptor *tx) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct dma_async_tx_descriptor *dep = txd_next(tx); 155762306a36Sopenharmony_ci struct dma_async_tx_descriptor *dep_next; 155862306a36Sopenharmony_ci struct dma_chan *chan; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (!dep) 156162306a36Sopenharmony_ci return; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* we'll submit tx->next now, so clear the link */ 156462306a36Sopenharmony_ci txd_clear_next(tx); 156562306a36Sopenharmony_ci chan = dep->chan; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci /* keep submitting up until a channel switch is detected 156862306a36Sopenharmony_ci * in that case we will be called again as a result of 156962306a36Sopenharmony_ci * processing the interrupt from async_tx_channel_switch 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_ci for (; dep; dep = dep_next) { 157262306a36Sopenharmony_ci txd_lock(dep); 157362306a36Sopenharmony_ci txd_clear_parent(dep); 157462306a36Sopenharmony_ci dep_next = txd_next(dep); 157562306a36Sopenharmony_ci if (dep_next && dep_next->chan == chan) 157662306a36Sopenharmony_ci txd_clear_next(dep); /* ->next will be submitted */ 157762306a36Sopenharmony_ci else 157862306a36Sopenharmony_ci dep_next = NULL; /* submit current dep and terminate */ 157962306a36Sopenharmony_ci txd_unlock(dep); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci dep->tx_submit(dep); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci chan->device->device_issue_pending(chan); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_run_dependencies); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_cistatic int __init dma_bus_init(void) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci int err = dmaengine_init_unmap_pool(); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (err) 159362306a36Sopenharmony_ci return err; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci err = class_register(&dma_devclass); 159662306a36Sopenharmony_ci if (!err) 159762306a36Sopenharmony_ci dmaengine_debugfs_init(); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return err; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ciarch_initcall(dma_bus_init); 1602