Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 307575
b: refs/heads/master
c: 0b6c485
h: refs/heads/master
i:
  307573: 9b3610a
  307571: 7dbe758
  307567: 7de4552
v: v3
  • Loading branch information
Stefan Richter committed Apr 17, 2012
1 parent 5bc2cb9 commit 09e51c8
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 40 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fe2af11c220c7bb3a67f7aec0594811e5c59e019
refs/heads/master: 0b6c4857f7684f6d3f59e0506f62953575346978
51 changes: 41 additions & 10 deletions trunk/drivers/firewire/core-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/firewire.h>
#include <linux/firewire-cdev.h>
Expand Down Expand Up @@ -70,6 +71,7 @@ struct client {
u64 iso_closure;
struct fw_iso_buffer buffer;
unsigned long vm_start;
bool buffer_is_mapped;

struct list_head phy_receiver_link;
u64 phy_receiver_closure;
Expand Down Expand Up @@ -959,11 +961,20 @@ static void iso_mc_callback(struct fw_iso_context *context,
sizeof(e->interrupt), NULL, 0);
}

static enum dma_data_direction iso_dma_direction(struct fw_iso_context *context)
{
if (context->type == FW_ISO_CONTEXT_TRANSMIT)
return DMA_TO_DEVICE;
else
return DMA_FROM_DEVICE;
}

static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
struct fw_iso_context *context;
fw_iso_callback_t cb;
int ret;

BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT ||
FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE ||
Expand Down Expand Up @@ -1004,8 +1015,21 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
if (client->iso_context != NULL) {
spin_unlock_irq(&client->lock);
fw_iso_context_destroy(context);

return -EBUSY;
}
if (!client->buffer_is_mapped) {
ret = fw_iso_buffer_map_dma(&client->buffer,
client->device->card,
iso_dma_direction(context));
if (ret < 0) {
spin_unlock_irq(&client->lock);
fw_iso_context_destroy(context);

return ret;
}
client->buffer_is_mapped = true;
}
client->iso_closure = a->closure;
client->iso_context = context;
spin_unlock_irq(&client->lock);
Expand Down Expand Up @@ -1651,7 +1675,6 @@ static long fw_device_op_compat_ioctl(struct file *file,
static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
{
struct client *client = file->private_data;
enum dma_data_direction direction;
unsigned long size;
int page_count, ret;

Expand All @@ -1674,20 +1697,28 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
if (size & ~PAGE_MASK)
return -EINVAL;

if (vma->vm_flags & VM_WRITE)
direction = DMA_TO_DEVICE;
else
direction = DMA_FROM_DEVICE;

ret = fw_iso_buffer_init(&client->buffer, client->device->card,
page_count, direction);
ret = fw_iso_buffer_alloc(&client->buffer, page_count);
if (ret < 0)
return ret;

ret = fw_iso_buffer_map(&client->buffer, vma);
spin_lock_irq(&client->lock);
if (client->iso_context) {
ret = fw_iso_buffer_map_dma(&client->buffer,
client->device->card,
iso_dma_direction(client->iso_context));
client->buffer_is_mapped = (ret == 0);
}
spin_unlock_irq(&client->lock);
if (ret < 0)
fw_iso_buffer_destroy(&client->buffer, client->device->card);
goto fail;

ret = fw_iso_buffer_map_vma(&client->buffer, vma);
if (ret < 0)
goto fail;

return 0;
fail:
fw_iso_buffer_destroy(&client->buffer, client->device->card);
return ret;
}

Expand Down
80 changes: 52 additions & 28 deletions trunk/drivers/firewire/core-iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,52 +39,73 @@
* Isochronous DMA context management
*/

int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int page_count, enum dma_data_direction direction)
int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count)
{
int i, j;
dma_addr_t address;

buffer->page_count = page_count;
buffer->direction = direction;
int i;

buffer->page_count = 0;
buffer->page_count_mapped = 0;
buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
GFP_KERNEL);
if (buffer->pages == NULL)
goto out;
return -ENOMEM;

for (i = 0; i < buffer->page_count; i++) {
for (i = 0; i < page_count; i++) {
buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
if (buffer->pages[i] == NULL)
goto out_pages;
break;
}
buffer->page_count = i;
if (i < page_count) {
fw_iso_buffer_destroy(buffer, NULL);
return -ENOMEM;
}

return 0;
}

int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
enum dma_data_direction direction)
{
dma_addr_t address;
int i;

buffer->direction = direction;

for (i = 0; i < buffer->page_count; i++) {
address = dma_map_page(card->device, buffer->pages[i],
0, PAGE_SIZE, direction);
if (dma_mapping_error(card->device, address)) {
__free_page(buffer->pages[i]);
goto out_pages;
}
if (dma_mapping_error(card->device, address))
break;

set_page_private(buffer->pages[i], address);
}
buffer->page_count_mapped = i;
if (i < buffer->page_count)
return -ENOMEM;

return 0;
}

out_pages:
for (j = 0; j < i; j++) {
address = page_private(buffer->pages[j]);
dma_unmap_page(card->device, address,
PAGE_SIZE, direction);
__free_page(buffer->pages[j]);
}
kfree(buffer->pages);
out:
buffer->pages = NULL;
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int page_count, enum dma_data_direction direction)
{
int ret;

ret = fw_iso_buffer_alloc(buffer, page_count);
if (ret < 0)
return ret;

ret = fw_iso_buffer_map_dma(buffer, card, direction);
if (ret < 0)
fw_iso_buffer_destroy(buffer, card);

return -ENOMEM;
return ret;
}
EXPORT_SYMBOL(fw_iso_buffer_init);

int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
struct vm_area_struct *vma)
{
unsigned long uaddr;
int i, err;
Expand All @@ -107,15 +128,18 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
int i;
dma_addr_t address;

for (i = 0; i < buffer->page_count; i++) {
for (i = 0; i < buffer->page_count_mapped; i++) {
address = page_private(buffer->pages[i]);
dma_unmap_page(card->device, address,
PAGE_SIZE, buffer->direction);
__free_page(buffer->pages[i]);
}
for (i = 0; i < buffer->page_count; i++)
__free_page(buffer->pages[i]);

kfree(buffer->pages);
buffer->pages = NULL;
buffer->page_count = 0;
buffer->page_count_mapped = 0;
}
EXPORT_SYMBOL(fw_iso_buffer_destroy);

Expand Down
7 changes: 6 additions & 1 deletion trunk/drivers/firewire/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/compiler.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/idr.h>
Expand Down Expand Up @@ -169,7 +170,11 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);

/* -iso */

int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count);
int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
enum dma_data_direction direction);
int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
struct vm_area_struct *vma);


/* -topology */
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ struct fw_iso_buffer {
enum dma_data_direction direction;
struct page **pages;
int page_count;
int page_count_mapped;
};

int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
Expand Down

0 comments on commit 09e51c8

Please sign in to comment.