Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firewire: ohci: fix isochronous DMA synchronization

Add the dma_sync_single_* calls necessary to ensure proper cache
synchronization for isochronous data buffers on non-coherent
architectures.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

authored by

Clemens Ladisch and committed by
Stefan Richter
a572e688 32eaeae1

+73
+73
drivers/firewire/ohci.c
··· 126 126 struct fw_ohci *ohci; 127 127 u32 regs; 128 128 int total_allocation; 129 + u32 current_bus; 129 130 bool running; 130 131 bool flushing; 131 132 ··· 1058 1057 address = le32_to_cpu(last->branch_address); 1059 1058 z = address & 0xf; 1060 1059 address &= ~0xf; 1060 + ctx->current_bus = address; 1061 1061 1062 1062 /* If the branch address points to a buffer outside of the 1063 1063 * current buffer, advance to the next buffer. */ ··· 2699 2697 struct iso_context *ctx = 2700 2698 container_of(context, struct iso_context, context); 2701 2699 struct descriptor *pd; 2700 + u32 buffer_dma; 2702 2701 __le32 *ir_header; 2703 2702 void *p; 2704 2703 ··· 2709 2706 if (pd > last) 2710 2707 /* Descriptor(s) not done yet, stop iteration */ 2711 2708 return 0; 2709 + 2710 + while (!(d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))) { 2711 + d++; 2712 + buffer_dma = le32_to_cpu(d->data_address); 2713 + dma_sync_single_range_for_cpu(context->ohci->card.device, 2714 + buffer_dma & PAGE_MASK, 2715 + buffer_dma & ~PAGE_MASK, 2716 + le16_to_cpu(d->req_count), 2717 + DMA_FROM_DEVICE); 2718 + } 2712 2719 2713 2720 p = last + 1; 2714 2721 copy_iso_headers(ctx, p); ··· 2742 2729 { 2743 2730 struct iso_context *ctx = 2744 2731 container_of(context, struct iso_context, context); 2732 + u32 buffer_dma; 2745 2733 2746 2734 if (!last->transfer_status) 2747 2735 /* Descriptor(s) not done yet, stop iteration */ 2748 2736 return 0; 2737 + 2738 + buffer_dma = le32_to_cpu(last->data_address); 2739 + dma_sync_single_range_for_cpu(context->ohci->card.device, 2740 + buffer_dma & PAGE_MASK, 2741 + buffer_dma & ~PAGE_MASK, 2742 + le16_to_cpu(last->req_count), 2743 + DMA_FROM_DEVICE); 2749 2744 2750 2745 if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) 2751 2746 ctx->base.callback.mc(&ctx->base, ··· 2763 2742 ctx->base.callback_data); 2764 2743 2765 2744 return 1; 2745 + } 2746 + 2747 + static inline void sync_it_packet_for_cpu(struct context *context, 2748 + struct descriptor *pd) 2749 + { 2750 + __le16 control; 2751 + u32 buffer_dma; 2752 + 2753 + /* only packets beginning with OUTPUT_MORE* have data buffers */ 2754 + if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) 2755 + return; 2756 + 2757 + /* skip over the OUTPUT_MORE_IMMEDIATE descriptor */ 2758 + pd += 2; 2759 + 2760 + /* 2761 + * If the packet has a header, the first OUTPUT_MORE/LAST descriptor's 2762 + * data buffer is in the context program's coherent page and must not 2763 + * be synced. 2764 + */ 2765 + if ((le32_to_cpu(pd->data_address) & PAGE_MASK) == 2766 + (context->current_bus & PAGE_MASK)) { 2767 + if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) 2768 + return; 2769 + pd++; 2770 + } 2771 + 2772 + do { 2773 + buffer_dma = le32_to_cpu(pd->data_address); 2774 + dma_sync_single_range_for_cpu(context->ohci->card.device, 2775 + buffer_dma & PAGE_MASK, 2776 + buffer_dma & ~PAGE_MASK, 2777 + le16_to_cpu(pd->req_count), 2778 + DMA_TO_DEVICE); 2779 + control = pd->control; 2780 + pd++; 2781 + } while (!(control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))); 2766 2782 } 2767 2783 2768 2784 static int handle_it_packet(struct context *context, ··· 2817 2759 if (pd > last) 2818 2760 /* Descriptor(s) not done yet, stop iteration */ 2819 2761 return 0; 2762 + 2763 + sync_it_packet_for_cpu(context, d); 2820 2764 2821 2765 i = ctx->header_length; 2822 2766 if (i + 4 < PAGE_SIZE) { ··· 3189 3129 page_bus = page_private(buffer->pages[page]); 3190 3130 pd[i].data_address = cpu_to_le32(page_bus + offset); 3191 3131 3132 + dma_sync_single_range_for_device(ctx->context.ohci->card.device, 3133 + page_bus, offset, length, 3134 + DMA_TO_DEVICE); 3135 + 3192 3136 payload_index += length; 3193 3137 } 3194 3138 ··· 3217 3153 struct fw_iso_buffer *buffer, 3218 3154 unsigned long payload) 3219 3155 { 3156 + struct device *device = ctx->context.ohci->card.device; 3220 3157 struct descriptor *d, *pd; 3221 3158 dma_addr_t d_bus, page_bus; 3222 3159 u32 z, header_z, rest; ··· 3271 3206 3272 3207 page_bus = page_private(buffer->pages[page]); 3273 3208 pd->data_address = cpu_to_le32(page_bus + offset); 3209 + 3210 + dma_sync_single_range_for_device(device, page_bus, 3211 + offset, length, 3212 + DMA_FROM_DEVICE); 3274 3213 3275 3214 offset = (offset + length) & ~PAGE_MASK; 3276 3215 rest -= length; ··· 3334 3265 3335 3266 page_bus = page_private(buffer->pages[page]); 3336 3267 d->data_address = cpu_to_le32(page_bus + offset); 3268 + 3269 + dma_sync_single_range_for_device(ctx->context.ohci->card.device, 3270 + page_bus, offset, length, 3271 + DMA_FROM_DEVICE); 3337 3272 3338 3273 rest -= length; 3339 3274 offset = 0;