Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Dec 2009 16:13:10 +0000 (08:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Dec 2009 16:13:10 +0000 (08:13 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  ieee1394: Use hweight32
  firewire: cdev: reduce stack usage by ioctl_dispatch
  firewire: ohci: 0 may be a valid DMA address
  firewire: core: WARN on wrong usage of core transaction functions
  firewire: core: optimize Topology Map creation
  firewire: core: clarify generate_config_rom usage
  firewire: optimize config ROM creation
  firewire: cdev: normalize variable names
  firewire: normalize style of queue_work wrappers
  firewire: cdev: fix memory leak in an error path

1  2 
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c

index 5089331544ed5336e682fdec039be94068314102,e7290928a900227f35e53728b0f64d6db399f6de..231e6ee5ba4397c6aa511ad8ff2df4f54129799b
@@@ -33,7 -33,6 +33,7 @@@
  #include <linux/mutex.h>
  #include <linux/poll.h>
  #include <linux/preempt.h>
 +#include <linux/sched.h>
  #include <linux/spinlock.h>
  #include <linux/time.h>
  #include <linux/uaccess.h>
@@@ -130,9 -129,22 +130,22 @@@ struct iso_resource 
        struct iso_resource_event *e_alloc, *e_dealloc;
  };
  
- static void schedule_iso_resource(struct iso_resource *);
  static void release_iso_resource(struct client *, struct client_resource *);
  
+ static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
+ {
+       client_get(r->client);
+       if (!schedule_delayed_work(&r->work, delay))
+               client_put(r->client);
+ }
+ static void schedule_if_iso_resource(struct client_resource *resource)
+ {
+       if (resource->release == release_iso_resource)
+               schedule_iso_resource(container_of(resource,
+                                       struct iso_resource, resource), 0);
+ }
  /*
   * dequeue_event() just kfree()'s the event, so the event has to be
   * the first field in a struct XYZ_event.
@@@ -166,7 -178,7 +179,7 @@@ struct iso_interrupt_event 
  
  struct iso_resource_event {
        struct event event;
-       struct fw_cdev_event_iso_resource resource;
+       struct fw_cdev_event_iso_resource iso_resource;
  };
  
  static inline void __user *u64_to_uptr(__u64 value)
@@@ -314,11 -326,8 +327,8 @@@ static void for_each_client(struct fw_d
  
  static int schedule_reallocations(int id, void *p, void *data)
  {
-       struct client_resource *r = p;
+       schedule_if_iso_resource(p);
  
-       if (r->release == release_iso_resource)
-               schedule_iso_resource(container_of(r,
-                                       struct iso_resource, resource));
        return 0;
  }
  
@@@ -414,9 -423,7 +424,7 @@@ static int add_client_resource(struct c
                                  &resource->handle);
        if (ret >= 0) {
                client_get(client);
-               if (resource->release == release_iso_resource)
-                       schedule_iso_resource(container_of(resource,
-                                               struct iso_resource, resource));
+               schedule_if_iso_resource(resource);
        }
        spin_unlock_irqrestore(&client->lock, flags);
  
  
  static int release_client_resource(struct client *client, u32 handle,
                                   client_resource_release_fn_t release,
-                                  struct client_resource **resource)
+                                  struct client_resource **return_resource)
  {
-       struct client_resource *r;
+       struct client_resource *resource;
  
        spin_lock_irq(&client->lock);
        if (client->in_shutdown)
-               r = NULL;
+               resource = NULL;
        else
-               r = idr_find(&client->resource_idr, handle);
-       if (r && r->release == release)
+               resource = idr_find(&client->resource_idr, handle);
+       if (resource && resource->release == release)
                idr_remove(&client->resource_idr, handle);
        spin_unlock_irq(&client->lock);
  
-       if (!(r && r->release == release))
+       if (!(resource && resource->release == release))
                return -EINVAL;
  
-       if (resource)
-               *resource = r;
+       if (return_resource)
+               *return_resource = resource;
        else
-               r->release(client, r);
+               resource->release(client, resource);
  
        client_put(client);
  
@@@ -699,6 -706,7 +707,7 @@@ static int ioctl_send_response(struct c
        struct fw_cdev_send_response *request = buffer;
        struct client_resource *resource;
        struct inbound_transaction_resource *r;
+       int ret = 0;
  
        if (release_client_resource(client, request->handle,
                                    release_request, &resource) < 0)
                         resource);
        if (request->length < r->length)
                r->length = request->length;
-       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
-               return -EFAULT;
+       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
+               ret = -EFAULT;
+               goto out;
+       }
  
        fw_send_response(client->device->card, r->request, request->rcode);
+  out:
        kfree(r);
  
-       return 0;
+       return ret;
  }
  
  static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
@@@ -1028,8 -1040,7 +1041,7 @@@ static void iso_resource_work(struct wo
        /* Allow 1000ms grace period for other reallocations. */
        if (todo == ISO_RES_ALLOC &&
            time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
-               if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
-                       client_get(client);
+               schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
                skip = true;
        } else {
                /* We could be called twice within the same generation. */
                e = r->e_dealloc;
                r->e_dealloc = NULL;
        }
-       e->resource.handle      = r->resource.handle;
-       e->resource.channel     = channel;
-       e->resource.bandwidth   = bandwidth;
+       e->iso_resource.handle    = r->resource.handle;
+       e->iso_resource.channel   = channel;
+       e->iso_resource.bandwidth = bandwidth;
  
        queue_event(client, &e->event,
-                   &e->resource, sizeof(e->resource), NULL, 0);
+                   &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
  
        if (free) {
                cancel_delayed_work(&r->work);
        client_put(client);
  }
  
- static void schedule_iso_resource(struct iso_resource *r)
- {
-       client_get(r->client);
-       if (!schedule_delayed_work(&r->work, 0))
-               client_put(r->client);
- }
  static void release_iso_resource(struct client *client,
                                 struct client_resource *resource)
  {
  
        spin_lock_irq(&client->lock);
        r->todo = ISO_RES_DEALLOC;
-       schedule_iso_resource(r);
+       schedule_iso_resource(r, 0);
        spin_unlock_irq(&client->lock);
  }
  
@@@ -1162,10 -1166,10 +1167,10 @@@ static int init_iso_resource(struct cli
        r->e_alloc      = e1;
        r->e_dealloc    = e2;
  
-       e1->resource.closure    = request->closure;
-       e1->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
-       e2->resource.closure    = request->closure;
-       e2->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+       e1->iso_resource.closure = request->closure;
+       e1->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+       e2->iso_resource.closure = request->closure;
+       e2->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
  
        if (todo == ISO_RES_ALLOC) {
                r->resource.release = release_iso_resource;
        } else {
                r->resource.release = NULL;
                r->resource.handle = -1;
-               schedule_iso_resource(r);
+               schedule_iso_resource(r, 0);
        }
        request->handle = r->resource.handle;
  
@@@ -1295,7 -1299,23 +1300,23 @@@ static int (* const ioctl_handlers[])(s
  static int dispatch_ioctl(struct client *client,
                          unsigned int cmd, void __user *arg)
  {
-       char buffer[256];
+       char buffer[sizeof(union {
+               struct fw_cdev_get_info                 _00;
+               struct fw_cdev_send_request             _01;
+               struct fw_cdev_allocate                 _02;
+               struct fw_cdev_deallocate               _03;
+               struct fw_cdev_send_response            _04;
+               struct fw_cdev_initiate_bus_reset       _05;
+               struct fw_cdev_add_descriptor           _06;
+               struct fw_cdev_remove_descriptor        _07;
+               struct fw_cdev_create_iso_context       _08;
+               struct fw_cdev_queue_iso                _09;
+               struct fw_cdev_start_iso                _0a;
+               struct fw_cdev_stop_iso                 _0b;
+               struct fw_cdev_get_cycle_timer          _0c;
+               struct fw_cdev_allocate_iso_resource    _0d;
+               struct fw_cdev_send_stream_packet       _13;
+       })];
        int ret;
  
        if (_IOC_TYPE(cmd) != '#' ||
@@@ -1390,10 -1410,10 +1411,10 @@@ static int fw_device_op_mmap(struct fil
  
  static int shutdown_resource(int id, void *p, void *data)
  {
-       struct client_resource *r = p;
+       struct client_resource *resource = p;
        struct client *client = data;
  
-       r->release(client, r);
+       resource->release(client, resource);
        client_put(client);
  
        return 0;
  static int fw_device_op_release(struct inode *inode, struct file *file)
  {
        struct client *client = file->private_data;
-       struct event *e, *next_e;
+       struct event *event, *next_event;
  
        mutex_lock(&client->device->client_list_mutex);
        list_del(&client->link);
        idr_remove_all(&client->resource_idr);
        idr_destroy(&client->resource_idr);
  
-       list_for_each_entry_safe(e, next_e, &client->event_list, link)
-               kfree(e);
+       list_for_each_entry_safe(event, next_event, &client->event_list, link)
+               kfree(event);
  
        client_put(client);
  
diff --combined drivers/firewire/ohci.c
index 94260aa76aa3a88c87a2d3f805ed1abee38d7d44,a71477541dc7e300d40a9e40e667eb57dbbb5551..ae4556f0c0c14aac573610566764230d77333321
@@@ -205,7 -205,7 +205,7 @@@ struct fw_ohci 
        dma_addr_t config_rom_bus;
        __be32 *next_config_rom;
        dma_addr_t next_config_rom_bus;
-       u32 next_header;
+       __be32 next_header;
  
        struct ar_context ar_request_ctx;
        struct ar_context ar_response_ctx;
@@@ -275,7 -275,7 +275,7 @@@ static void log_irqs(u32 evt
            !(evt & OHCI1394_busReset))
                return;
  
 -      fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
 +      fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
            evt & OHCI1394_selfIDComplete       ? " selfID"             : "",
            evt & OHCI1394_RQPkt                ? " AR_req"             : "",
            evt & OHCI1394_RSPkt                ? " AR_resp"            : "",
            evt & OHCI1394_postedWriteErr       ? " postedWriteErr"     : "",
            evt & OHCI1394_cycleTooLong         ? " cycleTooLong"       : "",
            evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
 +          evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
            evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
                    OHCI1394_respTxComplete | OHCI1394_isochRx |
                    OHCI1394_isochTx | OHCI1394_postedWriteErr |
                    OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
 +                  OHCI1394_cycleInconsistent |
                    OHCI1394_regAccessFail | OHCI1394_busReset)
                                                ? " ?"                  : "");
  }
@@@ -997,7 -995,8 +997,8 @@@ static int at_context_queue_packet(stru
                        packet->ack = RCODE_SEND_ERROR;
                        return -1;
                }
-               packet->payload_bus = payload_bus;
+               packet->payload_bus     = payload_bus;
+               packet->payload_mapped  = true;
  
                d[2].req_count    = cpu_to_le16(packet->payload_length);
                d[2].data_address = cpu_to_le32(payload_bus);
         */
        if (ohci->generation != packet->generation ||
            reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-               if (packet->payload_length > 0)
+               if (packet->payload_mapped)
                        dma_unmap_single(ohci->card.device, payload_bus,
                                         packet->payload_length, DMA_TO_DEVICE);
                packet->ack = RCODE_GENERATION;
@@@ -1061,7 -1060,7 +1062,7 @@@ static int handle_at_packet(struct cont
                /* This packet was cancelled, just continue. */
                return 1;
  
-       if (packet->payload_bus)
+       if (packet->payload_mapped)
                dma_unmap_single(ohci->card.device, packet->payload_bus,
                                 packet->payload_length, DMA_TO_DEVICE);
  
@@@ -1357,8 -1356,9 +1358,9 @@@ static void bus_reset_tasklet(unsigned 
                 */
                reg_write(ohci, OHCI1394_BusOptions,
                          be32_to_cpu(ohci->config_rom[2]));
-               ohci->config_rom[0] = cpu_to_be32(ohci->next_header);
-               reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header);
+               ohci->config_rom[0] = ohci->next_header;
+               reg_write(ohci, OHCI1394_ConfigROMhdr,
+                         be32_to_cpu(ohci->next_header));
        }
  
  #ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
@@@ -1441,17 -1441,6 +1443,17 @@@ static irqreturn_t irq_handler(int irq
                          OHCI1394_LinkControl_cycleMaster);
        }
  
 +      if (unlikely(event & OHCI1394_cycleInconsistent)) {
 +              /*
 +               * We need to clear this event bit in order to make
 +               * cycleMatch isochronous I/O work.  In theory we should
 +               * stop active cycleMatch iso contexts now and restart
 +               * them at least two cycles later.  (FIXME?)
 +               */
 +              if (printk_ratelimit())
 +                      fw_notify("isochronous cycle inconsistent\n");
 +      }
 +
        if (event & OHCI1394_cycle64Seconds) {
                cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
                if ((cycle_time & 0x80000000) == 0)
@@@ -1477,7 -1466,17 +1479,17 @@@ static int software_reset(struct fw_ohc
        return -EBUSY;
  }
  
- static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
+ static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length)
+ {
+       size_t size = length * 4;
+       memcpy(dest, src, size);
+       if (size < CONFIG_ROM_SIZE)
+               memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
+ }
+ static int ohci_enable(struct fw_card *card,
+                      const __be32 *config_rom, size_t length)
  {
        struct fw_ohci *ohci = fw_ohci(card);
        struct pci_dev *dev = to_pci_dev(card->device);
                  OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
                  OHCI1394_isochRx | OHCI1394_isochTx |
                  OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
 +                OHCI1394_cycleInconsistent |
                  OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |
                  OHCI1394_masterIntEnable);
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                if (ohci->next_config_rom == NULL)
                        return -ENOMEM;
  
-               memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
-               fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+               copy_config_rom(ohci->next_config_rom, config_rom, length);
        } else {
                /*
                 * In the suspend case, config_rom is NULL, which
                ohci->next_config_rom_bus = ohci->config_rom_bus;
        }
  
-       ohci->next_header = be32_to_cpu(ohci->next_config_rom[0]);
+       ohci->next_header = ohci->next_config_rom[0];
        ohci->next_config_rom[0] = 0;
        reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
        reg_write(ohci, OHCI1394_BusOptions,
  }
  
  static int ohci_set_config_rom(struct fw_card *card,
-                              u32 *config_rom, size_t length)
+                              const __be32 *config_rom, size_t length)
  {
        struct fw_ohci *ohci;
        unsigned long flags;
                ohci->next_config_rom = next_config_rom;
                ohci->next_config_rom_bus = next_config_rom_bus;
  
-               memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
-               fw_memcpy_to_be32(ohci->next_config_rom, config_rom,
-                                 length * 4);
+               copy_config_rom(ohci->next_config_rom, config_rom, length);
  
                ohci->next_header = config_rom[0];
                ohci->next_config_rom[0] = 0;
@@@ -1729,7 -1724,7 +1738,7 @@@ static int ohci_cancel_packet(struct fw
        if (packet->ack != 0)
                goto out;
  
-       if (packet->payload_bus)
+       if (packet->payload_mapped)
                dma_unmap_single(ohci->card.device, packet->payload_bus,
                                 packet->payload_length, DMA_TO_DEVICE);
  
@@@ -1904,30 -1899,15 +1913,30 @@@ static int handle_it_packet(struct cont
  {
        struct iso_context *ctx =
                container_of(context, struct iso_context, context);
 +      int i;
 +      struct descriptor *pd;
  
 -      if (last->transfer_status == 0)
 -              /* This descriptor isn't done yet, stop iteration. */
 +      for (pd = d; pd <= last; pd++)
 +              if (pd->transfer_status)
 +                      break;
 +      if (pd > last)
 +              /* Descriptor(s) not done yet, stop iteration */
                return 0;
  
 -      if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
 +      i = ctx->header_length;
 +      if (i + 4 < PAGE_SIZE) {
 +              /* Present this value as big-endian to match the receive code */
 +              *(__be32 *)(ctx->header + i) = cpu_to_be32(
 +                              ((u32)le16_to_cpu(pd->transfer_status) << 16) |
 +                              le16_to_cpu(pd->res_count));
 +              ctx->header_length += 4;
 +      }
 +      if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
                ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
 -                                 0, NULL, ctx->base.callback_data);
 -
 +                                 ctx->header_length, ctx->header,
 +                                 ctx->base.callback_data);
 +              ctx->header_length = 0;
 +      }
        return 1;
  }