Commit 13882a82ee1646336c3996c93b4a560a55d2a419

Authored by Clemens Ladisch
Committed by Stefan Richter
1 parent f30e6d3e41

firewire: optimize iso queueing by setting wake only after the last packet

When queueing iso packets, the run time is dominated by the two
MMIO accesses that set the DMA context's wake bit.  Because most
drivers submit packets in batches, we can save much time by
removing all but the last wakeup.

The internal kernel API is changed to require a call to
fw_iso_context_queue_flush() after a batch of queued packets.
The user space API does not change, so one call to
FW_CDEV_IOC_QUEUE_ISO must specify multiple packets to take
advantage of this optimization.

In my measurements, this patch reduces the time needed to queue
fifty skip packets from userspace to one sixth on a 2.5 GHz CPU,
or to one third at 800 MHz.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

Showing 9 changed files with 35 additions and 5 deletions Side-by-side Diff

drivers/firewire/core-card.c
... ... @@ -630,6 +630,10 @@
630 630 return -ENODEV;
631 631 }
632 632  
  633 +static void dummy_flush_queue_iso(struct fw_iso_context *ctx)
  634 +{
  635 +}
  636 +
633 637 static const struct fw_card_driver dummy_driver_template = {
634 638 .read_phy_reg = dummy_read_phy_reg,
635 639 .update_phy_reg = dummy_update_phy_reg,
... ... @@ -641,6 +645,7 @@
641 645 .start_iso = dummy_start_iso,
642 646 .set_iso_channels = dummy_set_iso_channels,
643 647 .queue_iso = dummy_queue_iso,
  648 + .flush_queue_iso = dummy_flush_queue_iso,
644 649 };
645 650  
646 651 void fw_card_release(struct kref *kref)
drivers/firewire/core-cdev.c
... ... @@ -1107,6 +1107,7 @@
1107 1107 payload += u.packet.payload_length;
1108 1108 count++;
1109 1109 }
  1110 + fw_iso_context_queue_flush(ctx);
1110 1111  
1111 1112 a->size -= uptr_to_u64(p) - a->packets;
1112 1113 a->packets = uptr_to_u64(p);
drivers/firewire/core-iso.c
... ... @@ -185,6 +185,12 @@
185 185 }
186 186 EXPORT_SYMBOL(fw_iso_context_queue);
187 187  
  188 +void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
  189 +{
  190 + ctx->card->driver->flush_queue_iso(ctx);
  191 +}
  192 +EXPORT_SYMBOL(fw_iso_context_queue_flush);
  193 +
188 194 int fw_iso_context_stop(struct fw_iso_context *ctx)
189 195 {
190 196 return ctx->card->driver->stop_iso(ctx);
drivers/firewire/core.h
... ... @@ -97,6 +97,8 @@
97 97 struct fw_iso_buffer *buffer,
98 98 unsigned long payload);
99 99  
  100 + void (*flush_queue_iso)(struct fw_iso_context *ctx);
  101 +
100 102 int (*stop_iso)(struct fw_iso_context *ctx);
101 103 };
102 104  
drivers/firewire/net.c
... ... @@ -881,7 +881,9 @@
881 881  
882 882 spin_unlock_irqrestore(&dev->lock, flags);
883 883  
884   - if (retval < 0)
  884 + if (retval >= 0)
  885 + fw_iso_context_queue_flush(dev->broadcast_rcv_context);
  886 + else
885 887 fw_error("requeue failed\n");
886 888 }
887 889  
drivers/firewire/ohci.c
... ... @@ -1192,9 +1192,6 @@
1192 1192 wmb(); /* finish init of new descriptors before branch_address update */
1193 1193 ctx->prev->branch_address = cpu_to_le32(d_bus | z);
1194 1194 ctx->prev = find_branch_descriptor(d, z);
1195   -
1196   - reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
1197   - flush_writes(ctx->ohci);
1198 1195 }
1199 1196  
1200 1197 static void context_stop(struct context *ctx)
1201 1198  
... ... @@ -1348,8 +1345,12 @@
1348 1345  
1349 1346 context_append(ctx, d, z, 4 - z);
1350 1347  
1351   - if (!ctx->running)
  1348 + if (ctx->running) {
  1349 + reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
  1350 + flush_writes(ohci);
  1351 + } else {
1352 1352 context_run(ctx, 0);
  1353 + }
1353 1354  
1354 1355 return 0;
1355 1356 }
... ... @@ -3121,6 +3122,15 @@
3121 3122 return ret;
3122 3123 }
3123 3124  
  3125 +static void ohci_flush_queue_iso(struct fw_iso_context *base)
  3126 +{
  3127 + struct context *ctx =
  3128 + &container_of(base, struct iso_context, base)->context;
  3129 +
  3130 + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
  3131 + flush_writes(ctx->ohci);
  3132 +}
  3133 +
3124 3134 static const struct fw_card_driver ohci_driver = {
3125 3135 .enable = ohci_enable,
3126 3136 .read_phy_reg = ohci_read_phy_reg,
... ... @@ -3137,6 +3147,7 @@
3137 3147 .free_iso_context = ohci_free_iso_context,
3138 3148 .set_iso_channels = ohci_set_iso_channels,
3139 3149 .queue_iso = ohci_queue_iso,
  3150 + .flush_queue_iso = ohci_flush_queue_iso,
3140 3151 .start_iso = ohci_start_iso,
3141 3152 .stop_iso = ohci_stop_iso,
3142 3153 };
drivers/media/dvb/firewire/firedtv-fw.c
... ... @@ -125,6 +125,7 @@
125 125  
126 126 i = (i + 1) & (N_PACKETS - 1);
127 127 }
  128 + fw_iso_context_queue_flush(ctx->context);
128 129 ctx->current_packet = i;
129 130 }
130 131  
include/linux/firewire.h
... ... @@ -440,6 +440,7 @@
440 440 struct fw_iso_packet *packet,
441 441 struct fw_iso_buffer *buffer,
442 442 unsigned long payload);
  443 +void fw_iso_context_queue_flush(struct fw_iso_context *ctx);
443 444 int fw_iso_context_start(struct fw_iso_context *ctx,
444 445 int cycle, int sync, int tags);
445 446 int fw_iso_context_stop(struct fw_iso_context *ctx);
sound/firewire/amdtp.c
... ... @@ -396,6 +396,7 @@
396 396  
397 397 for (i = 0; i < packets; ++i)
398 398 queue_out_packet(s, ++cycle);
  399 + fw_iso_context_queue_flush(s->context);
399 400 }
400 401  
401 402 static int queue_initial_skip_packets(struct amdtp_out_stream *s)