Skip to content

Commit 13882a8

Browse files
cladischStefan Richter
authored andcommitted
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>
1 parent f30e6d3 commit 13882a8

File tree

9 files changed

+35
-5
lines changed

9 files changed

+35
-5
lines changed

drivers/firewire/core-card.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
630630
return -ENODEV;
631631
}
632632

633+
static void dummy_flush_queue_iso(struct fw_iso_context *ctx)
634+
{
635+
}
636+
633637
static const struct fw_card_driver dummy_driver_template = {
634638
.read_phy_reg = dummy_read_phy_reg,
635639
.update_phy_reg = dummy_update_phy_reg,
@@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = {
641645
.start_iso = dummy_start_iso,
642646
.set_iso_channels = dummy_set_iso_channels,
643647
.queue_iso = dummy_queue_iso,
648+
.flush_queue_iso = dummy_flush_queue_iso,
644649
};
645650

646651
void fw_card_release(struct kref *kref)

drivers/firewire/core-cdev.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
11071107
payload += u.packet.payload_length;
11081108
count++;
11091109
}
1110+
fw_iso_context_queue_flush(ctx);
11101111

11111112
a->size -= uptr_to_u64(p) - a->packets;
11121113
a->packets = uptr_to_u64(p);

drivers/firewire/core-iso.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
185185
}
186186
EXPORT_SYMBOL(fw_iso_context_queue);
187187

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+
188194
int fw_iso_context_stop(struct fw_iso_context *ctx)
189195
{
190196
return ctx->card->driver->stop_iso(ctx);

drivers/firewire/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ struct fw_card_driver {
9797
struct fw_iso_buffer *buffer,
9898
unsigned long payload);
9999

100+
void (*flush_queue_iso)(struct fw_iso_context *ctx);
101+
100102
int (*stop_iso)(struct fw_iso_context *ctx);
101103
};
102104

drivers/firewire/net.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,9 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
881881

882882
spin_unlock_irqrestore(&dev->lock, flags);
883883

884-
if (retval < 0)
884+
if (retval >= 0)
885+
fw_iso_context_queue_flush(dev->broadcast_rcv_context);
886+
else
885887
fw_error("requeue failed\n");
886888
}
887889

drivers/firewire/ohci.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,9 +1192,6 @@ static void context_append(struct context *ctx,
11921192
wmb(); /* finish init of new descriptors before branch_address update */
11931193
ctx->prev->branch_address = cpu_to_le32(d_bus | z);
11941194
ctx->prev = find_branch_descriptor(d, z);
1195-
1196-
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
1197-
flush_writes(ctx->ohci);
11981195
}
11991196

12001197
static void context_stop(struct context *ctx)
@@ -1348,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx,
13481345

13491346
context_append(ctx, d, z, 4 - z);
13501347

1351-
if (!ctx->running)
1348+
if (ctx->running) {
1349+
reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
1350+
flush_writes(ohci);
1351+
} else {
13521352
context_run(ctx, 0);
1353+
}
13531354

13541355
return 0;
13551356
}
@@ -3121,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base,
31213122
return ret;
31223123
}
31233124

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+
31243134
static const struct fw_card_driver ohci_driver = {
31253135
.enable = ohci_enable,
31263136
.read_phy_reg = ohci_read_phy_reg,
@@ -3137,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = {
31373147
.free_iso_context = ohci_free_iso_context,
31383148
.set_iso_channels = ohci_set_iso_channels,
31393149
.queue_iso = ohci_queue_iso,
3150+
.flush_queue_iso = ohci_flush_queue_iso,
31403151
.start_iso = ohci_start_iso,
31413152
.stop_iso = ohci_stop_iso,
31423153
};

drivers/media/dvb/firewire/firedtv-fw.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
125125

126126
i = (i + 1) & (N_PACKETS - 1);
127127
}
128+
fw_iso_context_queue_flush(ctx->context);
128129
ctx->current_packet = i;
129130
}
130131

include/linux/firewire.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
440440
struct fw_iso_packet *packet,
441441
struct fw_iso_buffer *buffer,
442442
unsigned long payload);
443+
void fw_iso_context_queue_flush(struct fw_iso_context *ctx);
443444
int fw_iso_context_start(struct fw_iso_context *ctx,
444445
int cycle, int sync, int tags);
445446
int fw_iso_context_stop(struct fw_iso_context *ctx);

sound/firewire/amdtp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
396396

397397
for (i = 0; i < packets; ++i)
398398
queue_out_packet(s, ++cycle);
399+
fw_iso_context_queue_flush(s->context);
399400
}
400401

401402
static int queue_initial_skip_packets(struct amdtp_out_stream *s)

0 commit comments

Comments
 (0)