[ARM] 3537/1: Rework DMA-bounce locking for finer granularity
Patch from Kevin Hilman This time with IRQ versions of locks. Rework also enables compatability with realtime-preemption patch. With the current locking via interrupt disabling, under RT, potentially sleeping functions can be called with interrupts disabled. Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Deepak Saxena <dsaxena@plexity.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Родитель
fa3e686a34
Коммит
823588c186
|
@ -77,6 +77,8 @@ struct dmabounce_device_info {
|
|||
#endif
|
||||
struct dmabounce_pool small;
|
||||
struct dmabounce_pool large;
|
||||
|
||||
rwlock_t lock;
|
||||
};
|
||||
|
||||
static LIST_HEAD(dmabounce_devs);
|
||||
|
@ -116,6 +118,7 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
|
|||
struct safe_buffer *buf;
|
||||
struct dmabounce_pool *pool;
|
||||
struct device *dev = device_info->dev;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n",
|
||||
__func__, ptr, size, dir);
|
||||
|
@ -163,8 +166,12 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
|
|||
print_alloc_stats(device_info);
|
||||
#endif
|
||||
|
||||
write_lock_irqsave(&device_info->lock, flags);
|
||||
|
||||
list_add(&buf->node, &device_info->safe_buffers);
|
||||
|
||||
write_unlock_irqrestore(&device_info->lock, flags);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -172,22 +179,32 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
|
|||
static inline struct safe_buffer *
|
||||
find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_addr)
|
||||
{
|
||||
struct safe_buffer *b;
|
||||
struct safe_buffer *b = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&device_info->lock, flags);
|
||||
|
||||
list_for_each_entry(b, &device_info->safe_buffers, node)
|
||||
if (b->safe_dma_addr == safe_dma_addr)
|
||||
return b;
|
||||
break;
|
||||
|
||||
return NULL;
|
||||
read_unlock_irqrestore(&device_info->lock, flags);
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *buf)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(device_info->dev, "%s(buf=%p)\n", __func__, buf);
|
||||
|
||||
write_lock_irqsave(&device_info->lock, flags);
|
||||
|
||||
list_del(&buf->node);
|
||||
|
||||
write_unlock_irqrestore(&device_info->lock, flags);
|
||||
|
||||
if (buf->pool)
|
||||
dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
|
||||
else
|
||||
|
@ -396,7 +413,6 @@ dma_addr_t
|
|||
dma_map_single(struct device *dev, void *ptr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
||||
|
@ -404,12 +420,8 @@ dma_map_single(struct device *dev, void *ptr, size_t size,
|
|||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
dma_addr = map_single(dev, ptr, size, dir);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return dma_addr;
|
||||
}
|
||||
|
||||
|
@ -424,25 +436,18 @@ void
|
|||
dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
||||
__func__, (void *) dma_addr, size, dir);
|
||||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
unmap_single(dev, dma_addr, size, dir);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
int
|
||||
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
|
||||
|
@ -450,8 +455,6 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
|||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < nents; i++, sg++) {
|
||||
struct page *page = sg->page;
|
||||
unsigned int offset = sg->offset;
|
||||
|
@ -462,8 +465,6 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
|||
map_single(dev, ptr, length, dir);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return nents;
|
||||
}
|
||||
|
||||
|
@ -471,7 +472,6 @@ void
|
|||
dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
|
||||
|
@ -479,55 +479,38 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
|
|||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < nents; i++, sg++) {
|
||||
dma_addr_t dma_addr = sg->dma_address;
|
||||
unsigned int length = sg->length;
|
||||
|
||||
unmap_single(dev, dma_addr, length, dir);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void
|
||||
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
||||
__func__, (void *) dma_addr, size, dir);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
sync_single(dev, dma_addr, size, dir);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void
|
||||
dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
||||
__func__, (void *) dma_addr, size, dir);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
sync_single(dev, dma_addr, size, dir);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void
|
||||
dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
|
||||
|
@ -535,23 +518,18 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
|
|||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < nents; i++, sg++) {
|
||||
dma_addr_t dma_addr = sg->dma_address;
|
||||
unsigned int length = sg->length;
|
||||
|
||||
sync_single(dev, dma_addr, length, dir);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void
|
||||
dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
|
||||
|
@ -559,16 +537,12 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
|
|||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < nents; i++, sg++) {
|
||||
dma_addr_t dma_addr = sg->dma_address;
|
||||
unsigned int length = sg->length;
|
||||
|
||||
sync_single(dev, dma_addr, length, dir);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -622,6 +596,7 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
|
|||
|
||||
device_info->dev = dev;
|
||||
INIT_LIST_HEAD(&device_info->safe_buffers);
|
||||
rwlock_init(&device_info->lock);
|
||||
|
||||
#ifdef STATS
|
||||
device_info->total_allocs = 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче