summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2011-05-02 09:33:56 +0200
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-10 22:53:45 +0200
commit13882a82ee1646336c3996c93b4a560a55d2a419 (patch)
tree8a144d874a0ac46273a7e2f2dd344458d7eb4bfa /drivers
parentf30e6d3e419bfb5540fa82ba7eca01d578556e6b (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/core-card.c5
-rw-r--r--drivers/firewire/core-cdev.c1
-rw-r--r--drivers/firewire/core-iso.c6
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/net.c4
-rw-r--r--drivers/firewire/ohci.c19
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c1
7 files changed, 33 insertions, 5 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index e119f1e6ba4..f05fc7bfcee 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
return -ENODEV;
}
+static void dummy_flush_queue_iso(struct fw_iso_context *ctx)
+{
+}
+
static const struct fw_card_driver dummy_driver_template = {
.read_phy_reg = dummy_read_phy_reg,
.update_phy_reg = dummy_update_phy_reg,
@@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = {
.start_iso = dummy_start_iso,
.set_iso_channels = dummy_set_iso_channels,
.queue_iso = dummy_queue_iso,
+ .flush_queue_iso = dummy_flush_queue_iso,
};
void fw_card_release(struct kref *kref)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 2a3f1c4d690..64768c2194f 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -1107,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
payload += u.packet.payload_length;
count++;
}
+ fw_iso_context_queue_flush(ctx);
a->size -= uptr_to_u64(p) - a->packets;
a->packets = uptr_to_u64(p);
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index f872ede5af3..57c3973093a 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
}
EXPORT_SYMBOL(fw_iso_context_queue);
+void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
+{
+ ctx->card->driver->flush_queue_iso(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_queue_flush);
+
int fw_iso_context_stop(struct fw_iso_context *ctx)
{
return ctx->card->driver->stop_iso(ctx);
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 25e729cde2f..0fe4e4e6eda 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -97,6 +97,8 @@ struct fw_card_driver {
struct fw_iso_buffer *buffer,
unsigned long payload);
+ void (*flush_queue_iso)(struct fw_iso_context *ctx);
+
int (*stop_iso)(struct fw_iso_context *ctx);
};
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 3f04dd3681c..b9762d07198 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -881,7 +881,9 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
spin_unlock_irqrestore(&dev->lock, flags);
- if (retval < 0)
+ if (retval >= 0)
+ fw_iso_context_queue_flush(dev->broadcast_rcv_context);
+ else
fw_error("requeue failed\n");
}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index f9f55703375..438e6c83117 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1192,9 +1192,6 @@ static void context_append(struct context *ctx,
wmb(); /* finish init of new descriptors before branch_address update */
ctx->prev->branch_address = cpu_to_le32(d_bus | z);
ctx->prev = find_branch_descriptor(d, z);
-
- reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
- flush_writes(ctx->ohci);
}
static void context_stop(struct context *ctx)
@@ -1348,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx,
context_append(ctx, d, z, 4 - z);
- if (!ctx->running)
+ if (ctx->running) {
+ reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ohci);
+ } else {
context_run(ctx, 0);
+ }
return 0;
}
@@ -3121,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base,
return ret;
}
+static void ohci_flush_queue_iso(struct fw_iso_context *base)
+{
+ struct context *ctx =
+ &container_of(base, struct iso_context, base)->context;
+
+ reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ctx->ohci);
+}
+
static const struct fw_card_driver ohci_driver = {
.enable = ohci_enable,
.read_phy_reg = ohci_read_phy_reg,
@@ -3137,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = {
.free_iso_context = ohci_free_iso_context,
.set_iso_channels = ohci_set_iso_channels,
.queue_iso = ohci_queue_iso,
+ .flush_queue_iso = ohci_flush_queue_iso,
.start_iso = ohci_start_iso,
.stop_iso = ohci_stop_iso,
};
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 8022b743af9..864b6274c72 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -125,6 +125,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
i = (i + 1) & (N_PACKETS - 1);
}
+ fw_iso_context_queue_flush(ctx->context);
ctx->current_packet = i;
}