@@ -559,6 +559,28 @@ static inline void release_scanline_irqs_enabled(int buffers_to_free_count,
559
559
}
560
560
}
561
561
562
+ // Note that this is not a general purpose function. It must be called by a caller
563
+ // who can guarantee that a DMA completion IRQ will not be taken during this method
564
+ static inline void abort_all_dma_channels_assuming_no_irq_preemption () {
565
+ // the reason the above requirements are in place is that the DMA controller may cause
566
+ // a completion IRQ during (or immediately the abort). There are *slower* ways to
567
+ // work around it in software, but we want to suppress the IRQ afterwards anyway, so
568
+ // as long as the spurious IRQ doesn't get taken here, then the h/w issue is of no problem
569
+ dma_hw -> abort = PICO_SCANVIDEO_SCANLINE_DMA_CHANNELS_MASK ;
570
+ // note that relying on the abort bits is no longer safe, as it may get cleared before the spurious IRQ happens
571
+ // // wait for abort(s) to complete
572
+ // while (dma_hw->abort & PICO_SCANVIDEO_SCANLINE_DMA_CHANNELS_MASK) tight_loop_contents();
573
+ while (dma_channel_is_busy (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL )) tight_loop_contents ();
574
+ #if PICO_SCANVIDEO_PLANE_COUNT > 1
575
+ while (dma_channel_is_busy (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL2 )) tight_loop_contents ();
576
+ #if PICO_SCANVIDEO_PLANE_COUNT > 2
577
+ while (dma_channel_is_busy (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL3 )) tight_loop_contents ();
578
+ #endif
579
+ #endif
580
+ // we don't want any pending completion IRQ which may have happened in the interim
581
+ dma_hw -> ints0 = PICO_SCANVIDEO_SCANLINE_DMA_CHANNELS_MASK ;
582
+ }
583
+
562
584
static inline bool update_dma_transfer_state_irqs_enabled (bool cancel_if_not_complete ,
563
585
int * scanline_buffers_to_release ) {
564
586
uint32_t save = spin_lock_blocking (shared_state .dma .lock );
@@ -612,13 +634,9 @@ static inline bool update_dma_transfer_state_irqs_enabled(bool cancel_if_not_com
612
634
shared_state .dma .buffers_to_release = 0 ;
613
635
DEBUG_PINS_XOR (video_in_use , 4 );
614
636
}
615
- dma_channel_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL );
616
- #if PICO_SCANVIDEO_PLANE_COUNT > 1
617
- dma_channel_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL2 );
618
- #if PICO_SCANVIDEO_PLANE_COUNT > 2
619
- dma_channel_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL3 );
620
- #endif
621
- #endif
637
+ // note that we guarantee no IRQ preemption because this method is always called within some
638
+ // type of video IRQ handle, and of those the DMA IRQ is the lowest priority.
639
+ abort_all_dma_channels_assuming_no_irq_preemption ();
622
640
#else
623
641
panic ("need VIDEO_RECOVERY" );
624
642
#endif
@@ -630,13 +648,9 @@ static inline bool update_dma_transfer_state_irqs_enabled(bool cancel_if_not_com
630
648
shared_state .dma .scanline_in_progress = 0 ;
631
649
* scanline_buffers_to_release = shared_state .dma .buffers_to_release ;
632
650
shared_state .dma .buffers_to_release = 0 ;
633
- dma_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL );
634
- #if PICO_SCANVIDEO_PLANE_COUNT > 1
635
- dma_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL2 );
636
- #if PICO_SCANVIDEO_PLANE_COUNT > 2
637
- dma_channel_abort (PICO_SCANVIDEO_SCANLINE_DMA_CHANNEL3 );
638
- #endif
639
- #endif
651
+ // note that we guarantee no IRQ preemption because this method is always called within some
652
+ // type of video IRQ handle, and of those the DMA IRQ is the lowest priority.
653
+ abort_all_dma_channels_assuming_no_irq_preemption ();
640
654
}
641
655
spin_unlock (shared_state .dma .lock , save );
642
656
return false;
@@ -1050,7 +1064,7 @@ extern bool scanvideo_in_vblank() {
1050
1064
return * (volatile bool * ) & shared_state .scanline .in_vblank ;
1051
1065
}
1052
1066
1053
- static uint default_scanvideo_scanline_repeat_count_fn (uint32_t scanline_id ) {
1067
+ static uint __no_inline_not_in_flash_func ( default_scanvideo_scanline_repeat_count_fn ) (uint32_t scanline_id ) {
1054
1068
return 1 ;
1055
1069
}
1056
1070
@@ -1097,7 +1111,10 @@ extern scanvideo_scanline_buffer_t *__video_time_critical_func(scanvideo_begin_s
1097
1111
DEBUG_PINS_CLR (video_link , 1 );
1098
1112
DEBUG_PINS_CLR (video_generation , 1 );
1099
1113
#if PICO_SCANVIDEO_LINKED_SCANLINE_BUFFERS
1100
- if (fsb ) fsb -> core .link_after = 0 ;
1114
+ if (fsb ) {
1115
+ fsb -> core .link = 0 ;
1116
+ fsb -> core .link_after = 0 ;
1117
+ }
1101
1118
#endif
1102
1119
return (scanvideo_scanline_buffer_t * ) fsb ;
1103
1120
}
0 commit comments