diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-02-16 17:34:38 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-09 16:02:57 -0500 |
commit | 9aad8125389a7a2990dee72d7892e22330a945eb (patch) | |
tree | 2566a8985837b000990db7e16b17547d3747141b /drivers/firewire/fw-device-cdev.c | |
parent | 6e2e8424d310507fa044649435114217826ed78a (diff) |
firewire: Split the iso buffer out from fw_iso_context and avoid vmalloc.
This patch splits out the iso buffer so we can initialize it at mmap
time with the size provided in the mmap call. Furthermore, allocate
the backing pages using alloc_page to avoid setting up kernel side
virtual memory mappings for the pages.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-device-cdev.c')
-rw-r--r-- | drivers/firewire/fw-device-cdev.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c index 1b9e5f7c0129..6284375c6390 100644 --- a/drivers/firewire/fw-device-cdev.c +++ b/drivers/firewire/fw-device-cdev.c | |||
@@ -71,8 +71,10 @@ struct client { | |||
71 | struct list_head event_list; | 71 | struct list_head event_list; |
72 | struct semaphore event_list_sem; | 72 | struct semaphore event_list_sem; |
73 | wait_queue_head_t wait; | 73 | wait_queue_head_t wait; |
74 | unsigned long vm_start; | 74 | |
75 | struct fw_iso_context *iso_context; | 75 | struct fw_iso_context *iso_context; |
76 | struct fw_iso_buffer buffer; | ||
77 | unsigned long vm_start; | ||
76 | }; | 78 | }; |
77 | 79 | ||
78 | static inline void __user * | 80 | static inline void __user * |
@@ -406,7 +408,6 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) | |||
406 | 408 | ||
407 | client->iso_context = fw_iso_context_create(client->device->card, | 409 | client->iso_context = fw_iso_context_create(client->device->card, |
408 | FW_ISO_CONTEXT_TRANSMIT, | 410 | FW_ISO_CONTEXT_TRANSMIT, |
409 | request.buffer_size, | ||
410 | iso_callback, client); | 411 | iso_callback, client); |
411 | if (IS_ERR(client->iso_context)) | 412 | if (IS_ERR(client->iso_context)) |
412 | return PTR_ERR(client->iso_context); | 413 | return PTR_ERR(client->iso_context); |
@@ -418,8 +419,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) | |||
418 | { | 419 | { |
419 | struct fw_cdev_queue_iso request; | 420 | struct fw_cdev_queue_iso request; |
420 | struct fw_cdev_iso_packet __user *p, *end, *next; | 421 | struct fw_cdev_iso_packet __user *p, *end, *next; |
421 | void *payload, *payload_end; | 422 | unsigned long payload, payload_end; |
422 | unsigned long index; | ||
423 | int count; | 423 | int count; |
424 | struct { | 424 | struct { |
425 | struct fw_iso_packet packet; | 425 | struct fw_iso_packet packet; |
@@ -434,20 +434,17 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) | |||
434 | /* If the user passes a non-NULL data pointer, has mmap()'ed | 434 | /* If the user passes a non-NULL data pointer, has mmap()'ed |
435 | * the iso buffer, and the pointer points inside the buffer, | 435 | * the iso buffer, and the pointer points inside the buffer, |
436 | * we setup the payload pointers accordingly. Otherwise we | 436 | * we setup the payload pointers accordingly. Otherwise we |
437 | * set them both to NULL, which will still let packets with | 437 | * set them both to 0, which will still let packets with |
438 | * payload_length == 0 through. In other words, if no packets | 438 | * payload_length == 0 through. In other words, if no packets |
439 | * use the indirect payload, the iso buffer need not be mapped | 439 | * use the indirect payload, the iso buffer need not be mapped |
440 | * and the request.data pointer is ignored.*/ | 440 | * and the request.data pointer is ignored.*/ |
441 | 441 | ||
442 | index = (unsigned long)request.data - client->vm_start; | 442 | payload = (unsigned long)request.data - client->vm_start; |
443 | if (request.data != 0 && client->vm_start != 0 && | 443 | payload_end = payload + (client->buffer.page_count << PAGE_SHIFT); |
444 | index <= client->iso_context->buffer_size) { | 444 | if (request.data == 0 || client->buffer.pages == NULL || |
445 | payload = client->iso_context->buffer + index; | 445 | payload >= payload_end) { |
446 | payload_end = client->iso_context->buffer + | 446 | payload = 0; |
447 | client->iso_context->buffer_size; | 447 | payload_end = 0; |
448 | } else { | ||
449 | payload = NULL; | ||
450 | payload_end = NULL; | ||
451 | } | 448 | } |
452 | 449 | ||
453 | if (!access_ok(VERIFY_READ, request.packets, request.size)) | 450 | if (!access_ok(VERIFY_READ, request.packets, request.size)) |
@@ -473,7 +470,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) | |||
473 | return -EINVAL; | 470 | return -EINVAL; |
474 | 471 | ||
475 | if (fw_iso_context_queue(client->iso_context, | 472 | if (fw_iso_context_queue(client->iso_context, |
476 | &u.packet, payload)) | 473 | &u.packet, &client->buffer, payload)) |
477 | break; | 474 | break; |
478 | 475 | ||
479 | p = next; | 476 | p = next; |
@@ -483,8 +480,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) | |||
483 | 480 | ||
484 | request.size -= uptr_to_u64(p) - request.packets; | 481 | request.size -= uptr_to_u64(p) - request.packets; |
485 | request.packets = uptr_to_u64(p); | 482 | request.packets = uptr_to_u64(p); |
486 | request.data = | 483 | request.data = client->vm_start + payload; |
487 | client->vm_start + (payload - client->iso_context->buffer); | ||
488 | 484 | ||
489 | if (copy_to_user(arg, &request, sizeof request)) | 485 | if (copy_to_user(arg, &request, sizeof request)) |
490 | return -EFAULT; | 486 | return -EFAULT; |
@@ -549,13 +545,41 @@ fw_device_op_compat_ioctl(struct file *file, | |||
549 | static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) | 545 | static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) |
550 | { | 546 | { |
551 | struct client *client = file->private_data; | 547 | struct client *client = file->private_data; |
548 | enum dma_data_direction direction; | ||
549 | unsigned long size; | ||
550 | int page_count, retval; | ||
551 | |||
552 | /* FIXME: We could support multiple buffers, but we don't. */ | ||
553 | if (client->buffer.pages != NULL) | ||
554 | return -EBUSY; | ||
555 | |||
556 | if (!(vma->vm_flags & VM_SHARED)) | ||
557 | return -EINVAL; | ||
552 | 558 | ||
553 | if (client->iso_context->buffer == NULL) | 559 | if (vma->vm_start & ~PAGE_MASK) |
554 | return -EINVAL; | 560 | return -EINVAL; |
555 | 561 | ||
556 | client->vm_start = vma->vm_start; | 562 | client->vm_start = vma->vm_start; |
563 | size = vma->vm_end - vma->vm_start; | ||
564 | page_count = size >> PAGE_SHIFT; | ||
565 | if (size & ~PAGE_MASK) | ||
566 | return -EINVAL; | ||
567 | |||
568 | if (vma->vm_flags & VM_WRITE) | ||
569 | direction = DMA_TO_DEVICE; | ||
570 | else | ||
571 | direction = DMA_FROM_DEVICE; | ||
572 | |||
573 | retval = fw_iso_buffer_init(&client->buffer, client->device->card, | ||
574 | page_count, direction); | ||
575 | if (retval < 0) | ||
576 | return retval; | ||
557 | 577 | ||
558 | return remap_vmalloc_range(vma, client->iso_context->buffer, 0); | 578 | retval = fw_iso_buffer_map(&client->buffer, vma); |
579 | if (retval < 0) | ||
580 | fw_iso_buffer_destroy(&client->buffer, client->device->card); | ||
581 | |||
582 | return retval; | ||
559 | } | 583 | } |
560 | 584 | ||
561 | static int fw_device_op_release(struct inode *inode, struct file *file) | 585 | static int fw_device_op_release(struct inode *inode, struct file *file) |
@@ -564,6 +588,9 @@ static int fw_device_op_release(struct inode *inode, struct file *file) | |||
564 | struct address_handler *h, *next; | 588 | struct address_handler *h, *next; |
565 | struct request *r, *next_r; | 589 | struct request *r, *next_r; |
566 | 590 | ||
591 | if (client->buffer.pages) | ||
592 | fw_iso_buffer_destroy(&client->buffer, client->device->card); | ||
593 | |||
567 | if (client->iso_context) | 594 | if (client->iso_context) |
568 | fw_iso_context_destroy(client->iso_context); | 595 | fw_iso_context_destroy(client->iso_context); |
569 | 596 | ||