dmaengine: remove 'bigref' infrastructure
Reference counting is done at the module level so clients need not worry that a channel will leave while they are actively using dmaengine. Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
aa1e6f1a38
commit
f27c580c36
|
@ -34,26 +34,15 @@
|
||||||
* The subsystem keeps a global list of dma_device structs it is protected by a
|
* The subsystem keeps a global list of dma_device structs it is protected by a
|
||||||
* mutex, dma_list_mutex.
|
* mutex, dma_list_mutex.
|
||||||
*
|
*
|
||||||
|
* A subsystem can get access to a channel by calling dmaengine_get() followed
|
||||||
|
* by dma_find_channel(), or if it has need for an exclusive channel it can call
|
||||||
|
* dma_request_channel(). Once a channel is allocated a reference is taken
|
||||||
|
* against its corresponding driver to disable removal.
|
||||||
|
*
|
||||||
* Each device has a channels list, which runs unlocked but is never modified
|
* Each device has a channels list, which runs unlocked but is never modified
|
||||||
* once the device is registered, it's just setup by the driver.
|
* once the device is registered, it's just setup by the driver.
|
||||||
*
|
*
|
||||||
* Each device has a kref, which is initialized to 1 when the device is
|
* See Documentation/dmaengine.txt for more details
|
||||||
* registered. A kref_get is done for each device registered. When the
|
|
||||||
* device is released, the corresponding kref_put is done in the release
|
|
||||||
* method. Every time one of the device's channels is allocated to a client,
|
|
||||||
* a kref_get occurs. When the channel is freed, the corresponding kref_put
|
|
||||||
* happens. The device's release function does a completion, so
|
|
||||||
* unregister_device does a remove event, device_unregister, a kref_put
|
|
||||||
* for the first reference, then waits on the completion for all other
|
|
||||||
* references to finish.
|
|
||||||
*
|
|
||||||
* Each channel has an open-coded implementation of Rusty Russell's "bigref,"
|
|
||||||
* with a kref and a per_cpu local_t. A dma_chan_get is called when a client
|
|
||||||
* signals that it wants to use a channel, and dma_chan_put is called when
|
|
||||||
* a channel is removed or a client using it is unregistered. A client can
|
|
||||||
* take extra references per outstanding transaction, as is the case with
|
|
||||||
* the NET DMA client. The release function does a kref_put on the device.
|
|
||||||
* -ChrisL, DanW
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -114,18 +103,9 @@ static struct device_attribute dma_attrs[] = {
|
||||||
__ATTR_NULL
|
__ATTR_NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dma_async_device_cleanup(struct kref *kref);
|
|
||||||
|
|
||||||
static void dma_dev_release(struct device *dev)
|
|
||||||
{
|
|
||||||
struct dma_chan *chan = to_dma_chan(dev);
|
|
||||||
kref_put(&chan->device->refcount, dma_async_device_cleanup);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct class dma_devclass = {
|
static struct class dma_devclass = {
|
||||||
.name = "dma",
|
.name = "dma",
|
||||||
.dev_attrs = dma_attrs,
|
.dev_attrs = dma_attrs,
|
||||||
.dev_release = dma_dev_release,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* --- client and device registration --- */
|
/* --- client and device registration --- */
|
||||||
|
@ -232,29 +212,6 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_sync_wait);
|
EXPORT_SYMBOL(dma_sync_wait);
|
||||||
|
|
||||||
/**
|
|
||||||
* dma_chan_cleanup - release a DMA channel's resources
|
|
||||||
* @kref: kernel reference structure that contains the DMA channel device
|
|
||||||
*/
|
|
||||||
void dma_chan_cleanup(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct dma_chan *chan = container_of(kref, struct dma_chan, refcount);
|
|
||||||
kref_put(&chan->device->refcount, dma_async_device_cleanup);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(dma_chan_cleanup);
|
|
||||||
|
|
||||||
static void dma_chan_free_rcu(struct rcu_head *rcu)
|
|
||||||
{
|
|
||||||
struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu);
|
|
||||||
|
|
||||||
kref_put(&chan->refcount, dma_chan_cleanup);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dma_chan_release(struct dma_chan *chan)
|
|
||||||
{
|
|
||||||
call_rcu(&chan->rcu, dma_chan_free_rcu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dma_cap_mask_all - enable iteration over all operation types
|
* dma_cap_mask_all - enable iteration over all operation types
|
||||||
*/
|
*/
|
||||||
|
@ -641,9 +598,6 @@ int dma_async_device_register(struct dma_device *device)
|
||||||
BUG_ON(!device->device_issue_pending);
|
BUG_ON(!device->device_issue_pending);
|
||||||
BUG_ON(!device->dev);
|
BUG_ON(!device->dev);
|
||||||
|
|
||||||
init_completion(&device->done);
|
|
||||||
kref_init(&device->refcount);
|
|
||||||
|
|
||||||
mutex_lock(&dma_list_mutex);
|
mutex_lock(&dma_list_mutex);
|
||||||
device->dev_id = id++;
|
device->dev_id = id++;
|
||||||
mutex_unlock(&dma_list_mutex);
|
mutex_unlock(&dma_list_mutex);
|
||||||
|
@ -662,19 +616,11 @@ int dma_async_device_register(struct dma_device *device)
|
||||||
|
|
||||||
rc = device_register(&chan->dev);
|
rc = device_register(&chan->dev);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
chancnt--;
|
|
||||||
free_percpu(chan->local);
|
free_percpu(chan->local);
|
||||||
chan->local = NULL;
|
chan->local = NULL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One for the channel, one of the class device */
|
|
||||||
kref_get(&device->refcount);
|
|
||||||
kref_get(&device->refcount);
|
|
||||||
kref_init(&chan->refcount);
|
|
||||||
chan->client_count = 0;
|
chan->client_count = 0;
|
||||||
chan->slow_ref = 0;
|
|
||||||
INIT_RCU_HEAD(&chan->rcu);
|
|
||||||
}
|
}
|
||||||
device->chancnt = chancnt;
|
device->chancnt = chancnt;
|
||||||
|
|
||||||
|
@ -705,30 +651,19 @@ err_out:
|
||||||
list_for_each_entry(chan, &device->channels, device_node) {
|
list_for_each_entry(chan, &device->channels, device_node) {
|
||||||
if (chan->local == NULL)
|
if (chan->local == NULL)
|
||||||
continue;
|
continue;
|
||||||
kref_put(&device->refcount, dma_async_device_cleanup);
|
|
||||||
device_unregister(&chan->dev);
|
device_unregister(&chan->dev);
|
||||||
chancnt--;
|
|
||||||
free_percpu(chan->local);
|
free_percpu(chan->local);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_async_device_register);
|
EXPORT_SYMBOL(dma_async_device_register);
|
||||||
|
|
||||||
/**
|
|
||||||
* dma_async_device_cleanup - function called when all references are released
|
|
||||||
* @kref: kernel reference object
|
|
||||||
*/
|
|
||||||
static void dma_async_device_cleanup(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct dma_device *device;
|
|
||||||
|
|
||||||
device = container_of(kref, struct dma_device, refcount);
|
|
||||||
complete(&device->done);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dma_async_device_unregister - unregister a DMA device
|
* dma_async_device_unregister - unregister a DMA device
|
||||||
* @device: &dma_device
|
* @device: &dma_device
|
||||||
|
*
|
||||||
|
* This routine is called by dma driver exit routines, dmaengine holds module
|
||||||
|
* references to prevent it being called while channels are in use.
|
||||||
*/
|
*/
|
||||||
void dma_async_device_unregister(struct dma_device *device)
|
void dma_async_device_unregister(struct dma_device *device)
|
||||||
{
|
{
|
||||||
|
@ -744,11 +679,7 @@ void dma_async_device_unregister(struct dma_device *device)
|
||||||
"%s called while %d clients hold a reference\n",
|
"%s called while %d clients hold a reference\n",
|
||||||
__func__, chan->client_count);
|
__func__, chan->client_count);
|
||||||
device_unregister(&chan->dev);
|
device_unregister(&chan->dev);
|
||||||
dma_chan_release(chan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_put(&device->refcount, dma_async_device_cleanup);
|
|
||||||
wait_for_completion(&device->done);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_async_device_unregister);
|
EXPORT_SYMBOL(dma_async_device_unregister);
|
||||||
|
|
||||||
|
|
|
@ -1253,7 +1253,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
|
||||||
spin_lock_init(&iop_chan->lock);
|
spin_lock_init(&iop_chan->lock);
|
||||||
INIT_LIST_HEAD(&iop_chan->chain);
|
INIT_LIST_HEAD(&iop_chan->chain);
|
||||||
INIT_LIST_HEAD(&iop_chan->all_slots);
|
INIT_LIST_HEAD(&iop_chan->all_slots);
|
||||||
INIT_RCU_HEAD(&iop_chan->common.rcu);
|
|
||||||
iop_chan->common.device = dma_dev;
|
iop_chan->common.device = dma_dev;
|
||||||
list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
|
list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
|
||||||
|
|
||||||
|
|
|
@ -1219,7 +1219,6 @@ static int __devinit mv_xor_probe(struct platform_device *pdev)
|
||||||
INIT_LIST_HEAD(&mv_chan->chain);
|
INIT_LIST_HEAD(&mv_chan->chain);
|
||||||
INIT_LIST_HEAD(&mv_chan->completed_slots);
|
INIT_LIST_HEAD(&mv_chan->completed_slots);
|
||||||
INIT_LIST_HEAD(&mv_chan->all_slots);
|
INIT_LIST_HEAD(&mv_chan->all_slots);
|
||||||
INIT_RCU_HEAD(&mv_chan->common.rcu);
|
|
||||||
mv_chan->common.device = dma_dev;
|
mv_chan->common.device = dma_dev;
|
||||||
|
|
||||||
list_add_tail(&mv_chan->common.device_node, &dma_dev->channels);
|
list_add_tail(&mv_chan->common.device_node, &dma_dev->channels);
|
||||||
|
|
|
@ -142,10 +142,6 @@ struct dma_chan {
|
||||||
int chan_id;
|
int chan_id;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
|
|
||||||
struct kref refcount;
|
|
||||||
int slow_ref;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
|
|
||||||
struct list_head device_node;
|
struct list_head device_node;
|
||||||
struct dma_chan_percpu *local;
|
struct dma_chan_percpu *local;
|
||||||
int client_count;
|
int client_count;
|
||||||
|
@ -233,9 +229,6 @@ struct dma_device {
|
||||||
dma_cap_mask_t cap_mask;
|
dma_cap_mask_t cap_mask;
|
||||||
int max_xor;
|
int max_xor;
|
||||||
|
|
||||||
struct kref refcount;
|
|
||||||
struct completion done;
|
|
||||||
|
|
||||||
int dev_id;
|
int dev_id;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue