diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index f5f5a9706fcc..4cb27dc542ce 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -51,7 +51,7 @@ /* * ABI version history is documented in linux/firewire-cdev.h. */ -#define FW_CDEV_KERNEL_VERSION 4 +#define FW_CDEV_KERNEL_VERSION 5 #define FW_CDEV_VERSION_EVENT_REQUEST2 4 #define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 07d3c8d58b30..632562667a01 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2689,7 +2689,7 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) u32 *ctx_hdr; if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) - return; + flush_iso_completions(ctx); ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]); @@ -2826,16 +2826,16 @@ static int handle_it_packet(struct context *context, sync_it_packet_for_cpu(context, d); - if (ctx->header_length + 4 < PAGE_SIZE) { - ctx_hdr = ctx->header + ctx->header_length; - /* Present this value as big-endian to match the receive code */ - *ctx_hdr = cpu_to_be32( - ((u32)le16_to_cpu(pd->transfer_status) << 16) | - le16_to_cpu(pd->res_count)); - ctx->header_length += 4; - } + if (ctx->header_length + 4 > PAGE_SIZE) + flush_iso_completions(ctx); + ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = le16_to_cpu(last->res_count); + /* Present this value as big-endian to match the receive code */ + *ctx_hdr = cpu_to_be32((le16_to_cpu(pd->transfer_status) << 16) | + le16_to_cpu(pd->res_count)); + ctx->header_length += 4; + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) flush_iso_completions(ctx); diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index cc1b570a2eb3..b9bd349c6930 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -207,12 +207,15 @@ struct fw_cdev_event_request2 { * @closure: See &fw_cdev_event_common; * set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl * @type: See &fw_cdev_event_common; always %FW_CDEV_EVENT_ISO_INTERRUPT - * @cycle: Cycle counter of the interrupt packet + * @cycle: Cycle counter of the last completed packet * @header_length: Total length of following headers, in bytes * @header: Stripped headers, if any * * This event is sent when the controller has completed an &fw_cdev_iso_packet - * with the %FW_CDEV_ISO_INTERRUPT bit set. + * with the %FW_CDEV_ISO_INTERRUPT bit set, or when there have been so many + * completed packets without the interrupt bit set that the kernel's internal + * buffer for @header is about to overflow. (In the latter case, kernels with + * ABI version < 5 drop header data up to the next interrupt packet.) * * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT): * @@ -440,6 +443,8 @@ union fw_cdev_event { * - added %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL, * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL, and * %FW_CDEV_IOC_SET_ISO_CHANNELS + * 5 (3.4) - send %FW_CDEV_EVENT_ISO_INTERRUPT events when needed to + * avoid dropping data */ /**