firewire: ohci: avoid reallocation of AR buffers
Freeing an AR buffer page just to allocate a new page immediately afterwards is not only a pointless effort but also dangerous because the allocation can fail, which would result in an oops later. Split ar_context_add_page() into two functions so that we can reuse the old page directly. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Tested-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
a1f805e5e7
commit
837596a61b
|
@ -577,17 +577,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ar_context_add_page(struct ar_context *ctx)
|
static void ar_context_link_page(struct ar_context *ctx,
|
||||||
|
struct ar_buffer *ab, dma_addr_t ab_bus)
|
||||||
{
|
{
|
||||||
struct device *dev = ctx->ohci->card.device;
|
|
||||||
struct ar_buffer *ab;
|
|
||||||
dma_addr_t uninitialized_var(ab_bus);
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
||||||
ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
|
|
||||||
if (ab == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ab->next = NULL;
|
ab->next = NULL;
|
||||||
memset(&ab->descriptor, 0, sizeof(ab->descriptor));
|
memset(&ab->descriptor, 0, sizeof(ab->descriptor));
|
||||||
ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
|
ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
|
||||||
|
@ -606,6 +600,19 @@ static int ar_context_add_page(struct ar_context *ctx)
|
||||||
|
|
||||||
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
|
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
|
||||||
flush_writes(ctx->ohci);
|
flush_writes(ctx->ohci);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ar_context_add_page(struct ar_context *ctx)
|
||||||
|
{
|
||||||
|
struct device *dev = ctx->ohci->card.device;
|
||||||
|
struct ar_buffer *ab;
|
||||||
|
dma_addr_t uninitialized_var(ab_bus);
|
||||||
|
|
||||||
|
ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
|
||||||
|
if (ab == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ar_context_link_page(ctx, ab, ab_bus);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -730,7 +737,6 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
|
||||||
static void ar_context_tasklet(unsigned long data)
|
static void ar_context_tasklet(unsigned long data)
|
||||||
{
|
{
|
||||||
struct ar_context *ctx = (struct ar_context *)data;
|
struct ar_context *ctx = (struct ar_context *)data;
|
||||||
struct fw_ohci *ohci = ctx->ohci;
|
|
||||||
struct ar_buffer *ab;
|
struct ar_buffer *ab;
|
||||||
struct descriptor *d;
|
struct descriptor *d;
|
||||||
void *buffer, *end;
|
void *buffer, *end;
|
||||||
|
@ -799,9 +805,7 @@ static void ar_context_tasklet(unsigned long data)
|
||||||
ctx->current_buffer = ab;
|
ctx->current_buffer = ab;
|
||||||
ctx->pointer = end;
|
ctx->pointer = end;
|
||||||
|
|
||||||
dma_free_coherent(ohci->card.device, PAGE_SIZE,
|
ar_context_link_page(ctx, start, start_bus);
|
||||||
start, start_bus);
|
|
||||||
ar_context_add_page(ctx);
|
|
||||||
} else {
|
} else {
|
||||||
ctx->pointer = start + PAGE_SIZE;
|
ctx->pointer = start + PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue