Commit 13882a82ee1646336c3996c93b4a560a55d2a419
Committed by
Stefan Richter
1 parent
f30e6d3e41
Exists in
master
and in
7 other branches
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
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
drivers/firewire/net.c
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
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