Commits (3)
  • Robert Sprowson's avatar
    Fix to argument mixup · d4994499
    Robert Sprowson authored
    When reprogramming a buffer due to early overrun, R2 should be the length not the physical address.
    Version 0.22. Tagged as 'DMA-0_22'
  • Jeffrey Lee's avatar
    Documentation update · 4dae20b0
    Jeffrey Lee authored
      Doc/HAL_DMAAPI - Document the requirements of HAL devices and DMAManager clients with respect to memory barriers
      Documentation change, not tagged
    Version 0.22. Not tagged
  • ROOL's avatar
    Add support for double buffered NoInitIRQ type DMA controllers · f683cb12
    ROOL authored
      Preprogram the current and next transfers before kicking off the first. Note that it is no longer possible to infer from the status call whether it's a double or single buffered controller, so a new HAL device flag is added to signal this. The new flag is only required for NoInitIRQ type DMA controllers, but other double buffered controllers may set it for information purposes.
      Submission from Elesar. Tested on Titanium HAL.
    Version 0.23. Tagged as 'DMA-0_23'
......@@ -377,3 +377,49 @@ CurtailListTransfer
returned from the DMASync callback).
Returns the number of bytes that will have been transferred when the transfer
Memory barriers
DMAManager considers it to be the responsibility of the HAL device to ensure
that the correct data read/write barriers are used where appropriate. Typically
this means that:
* Whenever a memory -> device transfer is about to be started, a write barrier
should be used to ensure that any buffered writes have reached RAM (pages
involved in a DMA transfer will never be cacheable, but they will typically
be bufferable).
* Whenever the progress of a device -> memory transfer is being reported (e.g.
TransferState and Status calls), a read barrier should be used to ensure the
CPU hasn't prefetched any stale data from the destination buffer.
* For list-based controllers, the transfer descriptor list will typically be
located in bufferable memory, and so barriers will be needed whenever it is
being accessed. E.g. a write barrier is needed after the list has been fully
populated by the CPU, and if the DMA controller updates the descriptors with
progress information then a read barrier should be used before the CPU reads
from the descriptors.
The above covers situations where the HAL device should use barriers. The
following covers situations where the DMAManager client should use barriers:
* If DMA is being used to transfer code, an instruction synchronisation barrier
(e.g. ARMv7 ISB instruction) may be required to ensure any stale prefetched
instructions are flushed before the new code is executed. Calling
OS_SynchroniseCodeAreas for the affected range is a safe and valid method of
doing this. Other methods may fail on future systems (e.g. consider a DMA
controller which is able to perform cache-coherent DMA to/from the CPU data
cache, but not to the instruction cache).
* If the contents of a circular buffer are being updated on-the-fly by the CPU
(e.g. audio playback as used by SoundDMA) then it is the responsibility of
the client to ensure any freshly written data is flushed to RAM. However, in
this case barriers are only likely to be needed in exceptional
circumstances - e.g. if the CPU is repeatedly writing to the same location,
and the hardware keeps merging the data into the write buffer but never
flushing it to RAM.
For software running within RISC OS, OS_MMUControl 2 can be used to gain access
to barrier routines suitable for DMA. These routines aren't currently exposed
to the HAL, and so bespoke barrier routines will be required for code running
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "0.21"
Module_Version SETA 21
Module_MajorVersion SETS "0.23"
Module_Version SETA 23
Module_MinorVersion SETS ""
Module_Date SETS "18 Oct 2014"
Module_ApplicationDate SETS "18-Oct-14"
Module_Date SETS "07 Nov 2015"
Module_ApplicationDate SETS "07-Nov-15"
Module_ComponentName SETS "DMA"
Module_ComponentPath SETS "castle/RiscOS/Sources/HWSupport/DMA"
Module_FullVersion SETS "0.21"
Module_HelpVersion SETS "0.21 (18 Oct 2014)"
Module_FullVersion SETS "0.23"
Module_HelpVersion SETS "0.23 (07 Nov 2015)"
/* (0.21)
/* (0.23)
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
#define Module_MajorVersion_CMHG 0.21
#define Module_MajorVersion_CMHG 0.23
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 18 Oct 2014
#define Module_Date_CMHG 07 Nov 2015
#define Module_MajorVersion "0.21"
#define Module_Version 21
#define Module_MajorVersion "0.23"
#define Module_Version 23
#define Module_MinorVersion ""
#define Module_Date "18 Oct 2014"
#define Module_Date "07 Nov 2015"
#define Module_ApplicationDate "18-Oct-14"
#define Module_ApplicationDate "07-Nov-15"
#define Module_ComponentName "DMA"
#define Module_ComponentPath "castle/RiscOS/Sources/HWSupport/DMA"
#define Module_FullVersion "0.21"
#define Module_HelpVersion "0.21 (18 Oct 2014)"
#define Module_LibraryVersionInfo "0:21"
#define Module_FullVersion "0.23"
#define Module_HelpVersion "0.23 (07 Nov 2015)"
#define Module_LibraryVersionInfo "0:23"
......@@ -59,7 +59,8 @@ DMAFeaturesFlag_DualAddress * 1 :SHL: 0 ; reserved for i
DMAFeaturesFlag_NotCircular * 1 :SHL: 1 ; (list type only)
DMAFeaturesFlag_NotInfinite * 1 :SHL: 2 ; (list type only)
DMAFeaturesFlag_NoSyncIRQs * 1 :SHL: 3 ; (list type only)
DMAFeaturesFlag_NoInitIRQ * 1 :SHL: 4 ; Doesn't generate an IRQ if 'Activate' is called with no pending transfers (API 1.0+)
DMAFeaturesFlag_NoInitIRQ * 1 :SHL: 4 ; doesn't generate an IRQ if 'Activate' is called with no pending transfers (API 1.0+)
DMAFeaturesFlag_DoubleBuffered * 1 :SHL: 5 ; implements SetNextTransfer, used in conjunction with NoInitIRQ
DMASetOptionsFlag_Write * 1 :SHL: 0
DMASetOptionsShift_Width * 1
......@@ -958,6 +958,27 @@ DMAForceActivate
ADD r5, r10, #dmar_CurrBuff
LDR r8, [r10, #dmar_Flags]
BL program
; Calling 'program' also updates the request structure and sets the first buffer running.
; So now we've no way of inferring from DMAStatus whether this controller supports a
; second buffer, and single buffered HAL implementations of DMASetNextTransfer are a
; dummy function, the feature flag is the only safe was to see if a next transfer is possible.
LDR r9, [sp, #4*4]
LDR lr, [r9, #dmaq_DeviceFeatures]
TST lr, #DMAFeaturesFlag_DoubleBuffered
BEQ %FT31 ; Never call DMASetNextTransfer on a single buffered controller
LDR r10, [sp, #5*4]
LDR r8, [r10, #dmar_Flags]
TST r8, #dmarf_Infinite
LDR r0, [r10, #dmar_Length]
TEQEQ r0, #0
BEQ %FT31 ; Finite with no bytes remaining
LDR r11, [sp, #0*4] ; Infinite, or finite with bytes remaining
LDR r7, [r11, #HALDevice_DMASetNextTransfer]
ADD r3, r10, #dmar_CurrBuff
ADD r5, r10, #dmar_NextBuff
BL program
STR r5, [r9, #dmaq_LastBuff]
Pull "r0,r6-r10" ; Reload device ptr in R0 so we can call the device
CallHAL Activate
......@@ -2352,7 +2373,7 @@ DMASync
MOV lr, pc ; Call DMASync routine.
LDR pc, [r3, #vector_DMASync]
SUB r1, r1, r2
SUB r1, r1, r2 ; Gap remaining
TEQ r0, #0
......@@ -2871,6 +2892,8 @@ finished
; r10 = ptr to DMA request block
; [ :LNOT: HAL
; r11 = IOMD base address
; |
; r11 = ptr to HAL device
; ]
Debug int," finished"
......@@ -3240,7 +3263,7 @@ reprogram
LDR r3, [r0, #ptab_Physical] ; Get physical address from page table.
ADD r1, r3, r1 ; r1 = start address
ADD r2, r1, r2 ; r2 = end address
; r2 = length already
MOV r3, #0 ; Default flag contents.
TST r8, #dmarf_Infinite ; If finite transfer and