blob: 7fc041f1ff5d7a4057c6baaa8a62ae35b213274f [file] [log] [blame]
developer02e65912023-08-17 16:33:10 +08001/* dmares_lkm.c
2 *
3 * Linux Kernel-Mode implementation of the Driver Framework DMAResource API
4 *
5 */
6
7/*****************************************************************************
8* Copyright (c) 2010-2020 by Rambus, Inc. and/or its subsidiaries.
9*
10* This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 2 of the License, or
13* any later version.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details.
19*
20* You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>.
22*****************************************************************************/
23
24/*----------------------------------------------------------------------------
25 * This module implements (provides) some of the following interface(s):
26 */
27
28#include "dmares_mgmt.h"
29#include "dmares_buf.h"
30#include "dmares_rw.h"
31
32// Internal API implemented here
33#include "dmares_hwpal.h"
34
35
36/*----------------------------------------------------------------------------
37 * This module uses (requires) the following interface(s):
38 */
39
40// Default configuration
41#include "c_dmares_lkm.h"
42
43#include "dmares_gen.h" // Helpers from Generic DMAResource API
44
45#include "device_swap.h" // Device_SwapEndian32
46#include "device_mgmt.h" // Device_GetReference
47
48// Driver Framework C Run-Time Library API
49#include "clib.h" // memset
50
51// Driver Framework Basic Definitions API
52#include "basic_defs.h" // uint32_t, NULL, inline, bool,
53 // IDENTIFIER_NOT_USED
54
55// Logging API
56#include "log.h" // LOG_*
57
58// Linux Kernel API
59#include <linux/types.h> // phys_addr_t
60#include <linux/slab.h> // kmalloc, kfree
61#include <linux/dma-mapping.h> // dma_sync_single_for_cpu, dma_alloc_coherent,
62 // dma_free_coherent
63#include <linux/hardirq.h> // in_atomic
64#include <linux/ioport.h> // resource
65
66#ifdef HWPAL_LOCK_SLEEPABLE
67#include <linux/mutex.h> // mutex_*
68#else
69#include <linux/spinlock.h> // spinlock_*
70#endif
71#include <linux/version.h>
72
73
74/*----------------------------------------------------------------------------
75 * Definitions and macros
76 */
77#ifdef HWPAL_64BIT_HOST
78#ifdef HWPAL_DMARESOURCE_64BIT
79#define HWPAL_DMA_FLAGS 0 // No special requirements for address.
80#else
81#define HWPAL_DMA_FLAGS GFP_DMA // 64-bit host, 32-bit memory addresses
82#endif
83#else
84#define HWPAL_DMA_FLAGS 0 // No special requirements for address.
85#endif
86
87#define HWPAL_DMA_COHERENT_MAX_ATOMIC_SIZE 65536
88
89/*
90 Requirements on the records:
91 - pre-allocated array of records
92 - Total size of this array may not be limited by kmalloc size.
93 - valid between Create and Destroy
94 - re-use on a least-recently-used basis to make sure accidental continued
95 use after destroy does not cause crashes, allowing us to detect the
96 situation instead of crashing quickly.
97
98 Requirements on the handles:
99 - one handle per record
100 - valid between Create and Destroy
101 - quickly find the ptr-to-record belonging to the handle
102 - detect continued use of a handle after Destroy
103 - caller-hidden admin/status, thus not inside the record
104 - report leaking handles upon exit
105
106 Solution:
107 - handle cannot be a record number (no post-destroy use detection possible)
108 - Handle is a pointer into the Handles_p array. Each entry contains a record
109 index pair (or HWPAL_INVALID_INDEX if no record is associated with it).
110 - Array of records is divided into chunks, each chunk contains as many
111 records as fits into kmalloc buffer.
112 - Pointers to these chunks in RecordChunkPtrs_p array. Each record is
113 accessed via an index pair (chunk number and index within chunk).
114 - list of free locations in Handles_p: FreeHandles
115 - list of free record index pairs : FreeRecords
116 */
117
118typedef struct
119{
120 int ReadIndex;
121 int WriteIndex;
122 uint32_t * Nrs_p;
123} HWPAL_FreeList_t;
124
125typedef struct
126{
127 int CurIndex;
128} DMAResourceLib_InUseHandles_Iterator_t;
129
130
131/* Each chunk holds as many DMA resource records as will fit into a single
132 kmalloc buffer, but not more than 65536 as we use a 16-bit index */
133#define MAX_RECORDS_PER_CHUNK \
134 (KMALLOC_MAX_SIZE / sizeof(DMAResource_Record_t) > 65536 ? 65536 : \
135 KMALLOC_MAX_SIZE / sizeof(DMAResource_Record_t))
136
137/* Each DMA handle stores a 32-bit index pair consisting of two 16-bit
138 fields to refer to the DMA resource record via RecordChunkPtrs_p.
139 RecordChunkPtrs_p is an array of pointers to contiguous arrays
140 (chunks) of DMA resource records.
141
142 Those 16-bit fields (chunk number and record index) are combined into a
143 single uint32_t
144 Special value HWPAL_INVALID_INDEX (0xffffffff) represents destroyed records.
145*/
146
147#define COMPOSE_RECNR(chunk, recidx) (((chunk) << 16) | recidx)
148#define CHUNK_OF(recnr) (((recnr) >> 16) & 0xffff)
149#define RECIDX_OF(recnr) ((recnr) & 0xffff)
150#define HWPAL_INVALID_INDEX 0xffffffff
151
152// Note: dma_get_cache_alignment() can be used in place of L1_CACHE_BYTES
153// but it does not work on the 64-bit PowerPC Freescale P5020DS!
154#ifndef HWPAL_DMARESOURCE_DCACHE_LINE_SIZE
155#define HWPAL_DMARESOURCE_DCACHE_LINE_SIZE L1_CACHE_BYTES
156#endif
157
158#ifdef HWPAL_DMARESOURCE_UNCACHED_MAPPING
159// arm and arm64 support this, powerpc does not
160#define IOREMAP_CACHE ioremap_cache
161#else
162#define IOREMAP_CACHE ioremap
163#endif // HWPAL_DMARESOURCE_UNCACHED_MAPPING
164
165#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
166#define HWPAL_DMARESOURCE_SET_MASK dma_set_coherent_mask
167#else
168#define HWPAL_DMARESOURCE_SET_MASK dma_set_mask
169#endif
170
171
172/*----------------------------------------------------------------------------
173 * Local variables
174 */
175
176static int HandlesCount = 0; // remainder are valid only when this is != 0
177static int ChunksCount;
178
179static uint32_t * Handles_p;
180static DMAResource_Record_t ** RecordChunkPtrs_p;
181
182// array of pointers to arrays.
183static HWPAL_FreeList_t FreeHandles;
184static HWPAL_FreeList_t FreeRecords;
185
186static void * HWPAL_Lock_p;
187
188
189/*----------------------------------------------------------------------------
190 * DMAResourceLib_IdxPair2RecordPtr
191 *
192 */
193static inline DMAResource_Record_t *
194DMAResourceLib_IdxPair2RecordPtr(uint32_t IdxPair)
195{
196 if (IdxPair != HWPAL_INVALID_INDEX &&
197 CHUNK_OF(IdxPair) < ChunksCount &&
198 RECIDX_OF(IdxPair) < MAX_RECORDS_PER_CHUNK &&
199 CHUNK_OF(IdxPair) * MAX_RECORDS_PER_CHUNK +
200 RECIDX_OF(IdxPair) < HandlesCount
201 )
202 {
203 return RecordChunkPtrs_p[CHUNK_OF(IdxPair)] + RECIDX_OF(IdxPair);;
204 }
205 else
206 {
207 return NULL;
208 }
209}
210
211
212/*----------------------------------------------------------------------------
213 * DMAResourceLib_FreeList_Get
214 *
215 * Gets the next entry from the freelist. Returns HWPAL_INVALID_INDEX
216 * when the list is empty.
217 */
218static inline uint32_t
219DMAResourceLib_FreeList_Get(
220 HWPAL_FreeList_t * const List_p)
221{
222 uint32_t Nr = HWPAL_INVALID_INDEX;
223 int ReadIndex_Updated = List_p->ReadIndex + 1;
224
225 if (ReadIndex_Updated >= HandlesCount)
226 ReadIndex_Updated = 0;
227
228 // if post-increment ReadIndex == WriteIndex, the list is empty
229 if (ReadIndex_Updated != List_p->WriteIndex)
230 {
231 // grab the next number
232 Nr = List_p->Nrs_p[List_p->ReadIndex];
233 List_p->ReadIndex = ReadIndex_Updated;
234 }
235
236 return Nr;
237}
238
239
240/*----------------------------------------------------------------------------
241 * DMAResourceLib_FreeList_Add
242 *
243 * Adds an entry to the freelist.
244 */
245static inline void
246DMAResourceLib_FreeList_Add(
247 HWPAL_FreeList_t * const List_p,
248 uint32_t Nr)
249{
250 if (List_p->WriteIndex == List_p->ReadIndex)
251 {
252 LOG_WARN(
253 "DMAResourceLib_FreeList_Add: "
254 "Attempt to add value %u to full list\n",
255 Nr);
256 return;
257 }
258
259 if (Nr == HWPAL_INVALID_INDEX)
260 {
261 LOG_WARN(
262 "DMAResourceLib_FreeList_Add: "
263 "Attempt to put invalid value: %u\n",
264 Nr);
265 return;
266 }
267
268 {
269 int WriteIndex_Updated = List_p->WriteIndex + 1;
270 if (WriteIndex_Updated >= HandlesCount)
271 WriteIndex_Updated = 0;
272
273 // store the number
274 List_p->Nrs_p[List_p->WriteIndex] = Nr;
275 List_p->WriteIndex = WriteIndex_Updated;
276 }
277}
278
279/*----------------------------------------------------------------------------
280 * DMAResourceLib_InUseHandles_*
281 *
282 * Helper functions to iterate over all currently in-use handles.
283 *
284 * Usage:
285 * DMAResourceLib_InUseHandles_Iterator_t it;
286 * for (Handle = DMAResourceLib_InUseHandles_First(&it);
287 * Handle != NULL;
288 * Handle = DMAResourceLib_InUseHandles_Next(&it))
289 * { ...
290 *
291 */
292static inline DMAResource_Record_t *
293DMAResourceLib_InUseHandles_Get(
294 DMAResourceLib_InUseHandles_Iterator_t * const it)
295{
296 DMAResource_Record_t * Rec_p;
297
298 do
299 {
300 if (it->CurIndex >= HandlesCount)
301 return NULL;
302
303 Rec_p = DMAResourceLib_IdxPair2RecordPtr(Handles_p[it->CurIndex++]);
304
305 if (Rec_p != NULL && Rec_p->Magic != DMARES_RECORD_MAGIC)
306 Rec_p = NULL;
307 }
308 while(Rec_p == NULL);
309
310 return Rec_p;
311}
312
313
314static inline DMAResource_Record_t *
315DMAResourceLib_InUseHandles_First(
316 DMAResourceLib_InUseHandles_Iterator_t * const it)
317{
318 it->CurIndex = 0;
319 return DMAResourceLib_InUseHandles_Get(it);
320}
321
322
323static inline DMAResource_Record_t *
324DMAResourceLib_InUseHandles_Next(
325 DMAResourceLib_InUseHandles_Iterator_t * const it)
326{
327 return DMAResourceLib_InUseHandles_Get(it);
328}
329
330
331/*----------------------------------------------------------------------------
332 * DMAResourceLib_IsSubRangeOf
333 *
334 * Return true if the address range defined by `AddrPair1' and `Size1' is
335 * within the address range defined by `AddrPair2' and `Size2'.
336 */
337static bool
338DMAResourceLib_IsSubRangeOf(
339 const DMAResource_AddrPair_t * const AddrPair1,
340 const unsigned int Size1,
341 const DMAResource_AddrPair_t * const AddrPair2,
342 const unsigned int Size2)
343{
344 if (AddrPair1->Domain == AddrPair2->Domain)
345 {
346 const uint8_t * Addr1 = AddrPair1->Address_p;
347 const uint8_t * Addr2 = AddrPair2->Address_p;
348
349 if ((Size1 <= Size2) &&
350 (Addr2 <= Addr1) &&
351 ((Addr1 + Size1) <= (Addr2 + Size2)))
352 {
353 return true;
354 }
355 }
356
357 return false;
358}
359
360
361/*----------------------------------------------------------------------------
362 * DMAResourceLib_Find_Matching_DMAResource
363 *
364 * Return a pointer to the DMAResource record for a currently allocated or
365 * attached DMA buffer that matches the given `Properties' and `AddrPair'.
366 * The match can be either exact or indicate that the buffer defined by
367 * `Properties and `AddrPair' is a proper sub section of the allocated or
368 * attached buffer.
369 */
370static DMAResource_Record_t *
371DMAResourceLib_Find_Matching_DMAResource(
372 const DMAResource_Properties_t * const Properties,
373 const DMAResource_AddrPair_t AddrPair)
374{
375 DMAResourceLib_InUseHandles_Iterator_t it;
376 DMAResource_AddrPair_t * Pair_p;
377 DMAResource_Record_t * Rec_p;
378 unsigned int Size;
379
380 for (Rec_p = DMAResourceLib_InUseHandles_First(&it);
381 Rec_p != NULL;
382 Rec_p = DMAResourceLib_InUseHandles_Next(&it))
383 {
384 if (Rec_p->AllocatorRef == 'R' || Rec_p->AllocatorRef == 'N')
385 {
386 // skip registered buffers when looking for a match,
387 // i.e. only consider allocated buffers.
388 continue;
389 }
390
391 if (Properties->Bank != Rec_p->Props.Bank ||
392 Properties->Size > Rec_p->Props.Size ||
393 Properties->Alignment > Rec_p->Props.Alignment)
394 {
395 // obvious mismatch in properties
396 continue;
397 }
398
399 Size = Properties->Size;
400 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_HOST);
401 if (Pair_p != NULL &&
402 DMAResourceLib_IsSubRangeOf(&AddrPair, Size, Pair_p,
403 Rec_p->Props.Size))
404 {
405 return Rec_p;
406 }
407
408 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_BUS);
409 if (Pair_p != NULL &&
410 DMAResourceLib_IsSubRangeOf(&AddrPair, Size, Pair_p,
411 Rec_p->Props.Size))
412 {
413 return Rec_p;
414 }
415 } // for
416
417 return NULL;
418}
419
420
421
422/*----------------------------------------------------------------------------
423 * DMAResourceLib_Setup_Record
424 *
425 * Setup most fields of a given DMAResource record, except for the
426 * AddrPairs array.
427 */
428static void
429DMAResourceLib_Setup_Record(
430 const DMAResource_Properties_t * const Props_p,
431 const char AllocatorRef,
432 DMAResource_Record_t * const Rec_p,
433 const unsigned int AllocatedSize)
434{
435 Rec_p->Props = *Props_p;
436 Rec_p->AllocatorRef = AllocatorRef;
437 Rec_p->BufferSize = AllocatedSize;
438}
439
440
441/*----------------------------------------------------------------------------
442 * HWPAL_DMAResource_MaxAlignment_Get
443 */
444unsigned int
445HWPAL_DMAResource_MaxAlignment_Get(void)
446{
447 return (1 * 1024 * 1024); // 1 MB
448}
449
450
451/*----------------------------------------------------------------------------
452 * HWPAL_DMAResource_DCache_Alignment_Get
453 */
454unsigned int
455HWPAL_DMAResource_DCache_Alignment_Get(void)
456{
457#ifdef HWPAL_ARCH_COHERENT
458 unsigned int AlignTo = 1; // No cache line alignment required
459#else
460 unsigned int AlignTo = HWPAL_DMARESOURCE_DCACHE_LINE_SIZE;
461#endif // HWPAL_ARCH_COHERENT
462
463#if defined(HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT) || \
464 defined (HWPAL_DRMARESOURCE_ALLOW_UNALIGNED_ADDRESS)
465 AlignTo = 1; // No cache line alignment required
466#endif
467
468 return AlignTo;
469}
470
471
472/*----------------------------------------------------------------------------
473 * HWPAL_DMAResource_MemAlloc
474 */
475void *
476HWPAL_DMAResource_MemAlloc(
477 size_t ByteCount)
478{
479 gfp_t flags = 0;
480
481 if (in_atomic())
482 flags |= GFP_ATOMIC; // non-sleepable
483 else
484 flags |= GFP_KERNEL; // sleepable
485
486 return kmalloc(ByteCount, flags);
487}
488
489
490/*----------------------------------------------------------------------------
491 * HWPAL_DMAResource_MemFree
492 */
493void
494HWPAL_DMAResource_MemFree(
495 void * Buf_p)
496{
497 kfree (Buf_p);
498}
499
500
501/*----------------------------------------------------------------------------
502 * HWPAL_DMAResource_Lock_Alloc
503 */
504void *
505HWPAL_DMAResource_Lock_Alloc(void)
506{
507#ifdef HWPAL_LOCK_SLEEPABLE
508 struct mutex * HWPAL_Lock = HWPAL_DMAResource_MemAlloc(sizeof(mutex));
509 if (HWPAL_Lock == NULL)
510 return NULL;
511
512 LOG_INFO("HWPAL_DMAResource_Lock_Alloc: Lock = mutex\n");
513 mutex_init(HWPAL_Lock);
514
515 return HWPAL_Lock;
516#else
517 spinlock_t * HWPAL_SpinLock;
518
519 size_t LockSize = sizeof(spinlock_t);
520 if (LockSize == 0)
521 LockSize = 4;
522
523 HWPAL_SpinLock = HWPAL_DMAResource_MemAlloc(LockSize);
524 if (HWPAL_SpinLock == NULL)
525 return NULL;
526
527 LOG_INFO("HWPAL_DMAResource_Lock_Alloc: Lock = spinlock\n");
528 spin_lock_init(HWPAL_SpinLock);
529
530 return HWPAL_SpinLock;
531#endif
532}
533
534
535/*----------------------------------------------------------------------------
536 * HWPAL_DMAResource_Lock_Free
537 */
538void
539HWPAL_DMAResource_Lock_Free(void * Lock_p)
540{
541 HWPAL_DMAResource_MemFree(Lock_p);
542}
543
544
545/*----------------------------------------------------------------------------
546 * HWPAL_DMAResource_Lock_Acquire
547 */
548void
549HWPAL_DMAResource_Lock_Acquire(
550 void * Lock_p,
551 unsigned long * Flags)
552{
553#ifdef HWPAL_LOCK_SLEEPABLE
554 IDENTIFIER_NOT_USED(Flags);
555 mutex_lock((struct mutex*)Lock_p);
556#else
557 spin_lock_irqsave((spinlock_t *)Lock_p, *Flags);
558#endif
559}
560
561
562/*----------------------------------------------------------------------------
563 * HWPAL_DMAResource_Lock_Release
564 */
565void
566HWPAL_DMAResource_Lock_Release(
567 void * Lock_p,
568 unsigned long * Flags)
569{
570#ifdef HWPAL_LOCK_SLEEPABLE
571 IDENTIFIER_NOT_USED(Flags);
572 mutex_unlock((struct mutex*)Lock_p);
573#else
574 spin_unlock_irqrestore((spinlock_t *)Lock_p, *Flags);
575#endif
576}
577
578
579/*----------------------------------------------------------------------------
580 * HWPAL_DMAResource_Alloc
581 */
582int
583HWPAL_DMAResource_Alloc(
584 const DMAResource_Properties_t RequestedProperties,
585 const HWPAL_DMAResource_Properties_Ext_t RequestedPropertiesExt,
586 DMAResource_AddrPair_t * const AddrPair_p,
587 DMAResource_Handle_t * const Handle_p)
588{
589 DMAResource_Properties_t ActualProperties;
590 DMAResource_AddrPair_t * Pair_p;
591 DMAResource_Handle_t Handle;
592 DMAResource_Record_t * Rec_p = NULL;
593
594 unsigned int AlignTo = RequestedProperties.Alignment;
595
596 ZEROINIT(ActualProperties);
597
598#ifdef HWPAL_DMARESOURCE_STRICT_ARGS_CHECKS
599 if ((NULL == AddrPair_p) || (NULL == Handle_p))
600 return -1;
601
602 if (!DMAResourceLib_IsSaneInput(NULL, NULL, &RequestedProperties))
603 return -1;
604#endif
605
606#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
607 if (RequestedPropertiesExt.BankType ==
608 HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
609 {
610 LOG_CRIT("DMAResource_Alloc: fixed address DMA banks not supported for"
611 " cache-coherent allocations with "
612 "HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT\n");
613 return -1;
614 }
615#endif // HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
616
617 // Allocate record
618 Handle = DMAResource_CreateRecord();
619 if (NULL == Handle)
620 return -1;
621
622 Rec_p = DMAResource_Handle2RecordPtr(Handle);
623 if (NULL == Rec_p)
624 {
625 DMAResource_DestroyRecord(Handle);
626 return -1;
627 }
628
629 ActualProperties.Bank = RequestedProperties.Bank;
630
631#ifdef HWPAL_ARCH_COHERENT
632 ActualProperties.fCached = false;
633#else
634 if (RequestedPropertiesExt.BankType ==
635 HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
636 ActualProperties.fCached = RequestedProperties.fCached;
637 else
638 // This implementation does not allocate to non-cached resources
639 ActualProperties.fCached = true;
640#endif // HWPAL_ARCH_COHERENT
641
642#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
643 ActualProperties.fCached = false;
644#endif // HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
645
646#ifdef HWPAL_TRACE_DMARESOURCE_BUF
647 if (ActualProperties.fCached != RequestedProperties.fCached)
648 {
649 LOG_INFO("%s: changing requested resource caching from %d to %d "
650 "for bank %d\n",
651 __func__,
652 RequestedProperties.fCached,
653 ActualProperties.fCached,
654 RequestedProperties.Bank);
655 }
656#endif // HWPAL_TRACE_DMARESOURCE_BUF
657
658 if (ActualProperties.fCached &&
659 HWPAL_DMAResource_DCache_Alignment_Get() > AlignTo)
660 {
661 AlignTo = HWPAL_DMAResource_DCache_Alignment_Get();
662 }
663
664 ActualProperties.Alignment = AlignTo;
665
666 // Hide the allocated size from the caller, since (s)he is not
667 // supposed to access/use any space beyond what was requested
668 ActualProperties.Size = RequestedProperties.Size;
669
670 Rec_p->BankType = RequestedPropertiesExt.BankType;
671
672 // Allocate DMA resource
673 {
674 struct device * DMADevice_p;
675 size_t n = 0;
676 void * UnalignedAddr_p = NULL;
677 void * AlignedAddr_p = NULL;
678 dma_addr_t DMAAddr = 0;
679 phys_addr_t PhysAddr = 0;
680 Device_Data_t DevData;
681
682 ZEROINIT(DevData);
683
684 // Get device reference for this resource
685 DMADevice_p = Device_GetReference(NULL, &DevData);
686
687 // Step 1: Allocate a buffer
688 if (RequestedPropertiesExt.BankType ==
689 HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
690 {
691 struct resource * Resource_p;
692 void __iomem * IOMem_p;
693
694 // Option 1: Fixed address buffer allocation
695
696 PhysAddr = (phys_addr_t)(uintptr_t)RequestedPropertiesExt.Addr +
697 (phys_addr_t)(uintptr_t)DevData.PhysAddr;
698
699 // Check bank address alignment
700 if (PhysAddr & (PAGE_SIZE-1))
701 {
702 DMAResource_DestroyRecord(Handle);
703 LOG_CRIT("DMAResource_Alloc: unaligned fixed address for "
704 "bank %d, address 0x%p, page size %lu\n",
705 RequestedProperties.Bank,
706 (void *)(uintptr_t)PhysAddr,
707 PAGE_SIZE);
708 return -1;
709 }
710
711 // Round size up to a multiple of PAGE_SIZE
712 n = (RequestedProperties.Size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
713
714 Resource_p = request_mem_region(PhysAddr, n, "DMA-bank");
715 if (!Resource_p)
716 {
717 DMAResource_DestroyRecord(Handle);
718 LOG_CRIT("DMAResource_Alloc: request_mem_region() failed, "
719 "resource addr 0x%p, size %d\n",
720 (void *)(uintptr_t)PhysAddr,
721 (unsigned int)n);
722 return -1;
723 }
724
725 if (RequestedProperties.fCached)
726 IOMem_p = IOREMAP_CACHE(PhysAddr, n);
727 else
728#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
729 IOMem_p = ioremap_cache(PhysAddr, n);
730#else
731 IOMem_p = ioremap_nocache(PhysAddr, n);
732#endif
733 // Ignore __iomem address space
734 UnalignedAddr_p = (void *)(uintptr_t)IOMem_p;
735
736 if (!UnalignedAddr_p)
737 {
738 release_mem_region(PhysAddr, n);
739 DMAResource_DestroyRecord(Handle);
740 LOG_CRIT("DMAResource_Alloc: ioremap() failed, resource "
741 "addr 0x%p, cached %d, size %d\n",
742 (void *)(uintptr_t)PhysAddr,
743 RequestedProperties.fCached,
744 (unsigned int)n);
745 return -1;
746 }
747
748#ifdef HWPAL_TRACE_DMARESOURCE_BUF
749 LOG_INFO("DMAResource_Alloc: allocated static bank at "
750 "phys addr 0x%p, offset 0x%p, size %d\n",
751 (void*)PhysAddr,
752 (void*)RequestedPropertiesExt.Addr,
753 (unsigned int)n);
754#endif // HWPAL_TRACE_DMARESOURCE_BUF
755
756 if (PAGE_SIZE > AlignTo)
757 {
758 // ioremap granularity is PAGE_SIZE
759 ActualProperties.Alignment = AlignTo = PAGE_SIZE;
760 }
761 }
762 else
763 {
764 gfp_t flags = HWPAL_DMA_FLAGS;
765
766 // Option 2: Non-fixed dynamic address buffer allocation
767
768 // Align if required
769 n = DMAResourceLib_AlignForAddress(
770 DMAResourceLib_AlignForSize(RequestedProperties.Size,
771 AlignTo),
772 AlignTo);
773
774 if (in_atomic())
775 flags |= GFP_ATOMIC; // non-sleepable
776 else
777 flags |= GFP_KERNEL; // sleepable
778
779#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
780 if (n <= HWPAL_DMA_COHERENT_MAX_ATOMIC_SIZE)
781 flags = GFP_ATOMIC;
782 UnalignedAddr_p = dma_alloc_coherent(
783 DMADevice_p, n, &DMAAddr, flags);
784#else
785 UnalignedAddr_p = kmalloc(n, flags);
786#endif // HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
787
788 if (UnalignedAddr_p == NULL)
789 {
790 LOG_CRIT("DMAResource_Alloc: failed for handle 0x%p,"
791 " size %d\n",
792 Handle,(unsigned int)n);
793 DMAResource_DestroyRecord(Handle);
794 return -1;
795 }
796 }
797
798 DMAResourceLib_Setup_Record(&ActualProperties, 'A', Rec_p, n);
799
800 // Step 2: Align the allocated buffer
801 {
802 unsigned long AlignmentOffset;
803 unsigned long UnalignedAddress = ((unsigned long)UnalignedAddr_p);
804
805 AlignmentOffset = UnalignedAddress % AlignTo;
806
807 // Check if address needs to be aligned
808 if( AlignmentOffset )
809 AlignedAddr_p =
810 (void*)(UnalignedAddress + AlignTo - AlignmentOffset);
811 else
812 AlignedAddr_p = UnalignedAddr_p; // No alignment required
813 }
814
815 // Step 3: Get the DMA address of the allocated buffer
816 if (RequestedPropertiesExt.BankType ==
817 HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
818 {
819 DMAAddr = PhysAddr - (phys_addr_t)(uintptr_t)DevData.PhysAddr -
820 HWPAL_DMARESOURCE_BANK_STATIC_OFFSET;
821
822#ifdef HWPAL_TRACE_DMARESOURCE_BUF
823 LOG_INFO("DMAResource_Alloc: Handle 0x%p, "
824 "bus address requested/actual 0x%p/0x%p\n",
825 Handle,
826 RequestedPropertiesExt.Addr,
827 (void*)DMAAddr);
828#endif // HWPAL_TRACE_DMARESOURCE_BUF
829 }
830 else
831 {
832#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
833 DMAAddr = virt_to_phys (AlignedAddr_p);
834#else
835
836#ifndef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
837 DMAAddr = dma_map_single(DMADevice_p, AlignedAddr_p, n,
838 DMA_BIDIRECTIONAL);
839 if (dma_mapping_error(DMADevice_p, DMAAddr))
840 {
841 kfree(AlignedAddr_p);
842
843 DMAResource_DestroyRecord(Handle);
844
845 LOG_WARN(
846 "DMAResource_Alloc: "
847 "Failed to map DMA address for host address 0x%p, "
848 "for handle 0x%p\n",
849 AlignedAddr_p,
850 Handle);
851
852 return -1;
853 }
854#endif // !HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
855
856#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
857
858 if (DMAAddr == 0)
859 {
860#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
861 dma_free_coherent(DMADevice_p, n, UnalignedAddr_p, DMAAddr);
862#else
863 kfree(UnalignedAddr_p);
864#endif
865
866 DMAResource_DestroyRecord(Handle);
867 LOG_CRIT(
868 "DMAResource_Alloc: "
869 "Failed to obtain DMA address for host address 0x%p, "
870 "for handle 0x%p\n",
871 AlignedAddr_p,
872 Handle);
873
874 return -1;
875 }
876
877#ifdef HWPAL_TRACE_DMARESOURCE_BUF
878 LOG_INFO("DMAResource_Alloc: Handle 0x%p, "
879 "bus address allocated/adjusted 0x%p / 0x%p\n",
880 Handle,
881 (void*)DMAAddr,
882 (void*)(DMAAddr - HWPAL_DMARESOURCE_BANK_STATIC_OFFSET));
883#endif // HWPAL_TRACE_DMARESOURCE_BUF
884
885 DMAAddr -= HWPAL_DMARESOURCE_BANK_STATIC_OFFSET;
886 }
887
888 // put the bus address first, presumably being the most
889 // frequently looked-up domain.
890 Pair_p = Rec_p->AddrPairs;
891 Pair_p->Address_p = (void *)(uintptr_t)DMAAddr;
892 Pair_p->Domain = DMARES_DOMAIN_BUS;
893
894 ++Pair_p;
895 Pair_p->Address_p = AlignedAddr_p;
896 Pair_p->Domain = DMARES_DOMAIN_HOST;
897
898 // Return this address
899 *AddrPair_p = *Pair_p;
900
901 // This host address will be used for freeing the allocated buffer
902 ++Pair_p;
903 Pair_p->Address_p = UnalignedAddr_p;
904 Pair_p->Domain = DMARES_DOMAIN_HOST_UNALIGNED;
905
906#ifdef HWPAL_TRACE_DMARESOURCE_BUF
907 LOG_INFO("DMAResource_Alloc (1/2): handle = 0x%p, allocator='%c', "
908 "size allocated/requested=%d/%d, \n"
909 "DMAResource_Alloc (2/2): alignment/bank/cached=%d/%d/%d, "
910 "bus addr=0x%p, host addr un-/aligned=0x%p/0x%p\n",
911 Handle, Rec_p->AllocatorRef,
912 Rec_p->BufferSize, Rec_p->Props.Size,
913 Rec_p->Props.Alignment,Rec_p->Props.Bank,Rec_p->Props.fCached,
914 (void*)DMAAddr,UnalignedAddr_p,AlignedAddr_p);
915#endif
916 } // Allocated DMA resource
917
918 // return results
919 *Handle_p = Handle;
920
921 return 0;
922}
923
924
925/*----------------------------------------------------------------------------
926 * HWPAL_DMAResource_Release
927 */
928int
929HWPAL_DMAResource_Release(
930 const DMAResource_Handle_t Handle)
931{
932 DMAResource_Record_t * Rec_p;
933 dma_addr_t DMAAddr = 0;
934
935#ifdef HWPAL_TRACE_DMARESOURCE_BUF
936 void* UnalignedAddr_p = NULL;
937#endif
938
939 Rec_p = DMAResource_Handle2RecordPtr(Handle);
940 if (Rec_p == NULL)
941 {
942 LOG_WARN(
943 "DMAResource_Release: "
944 "Invalid handle %p\n",
945 Handle);
946 return -1;
947 }
948
949 // request the kernel to unmap the DMA resource
950 if (Rec_p->AllocatorRef == 'A' || Rec_p->AllocatorRef == 'k' ||
951 Rec_p->AllocatorRef == 'R')
952 {
953 DMAResource_AddrPair_t * Pair_p;
954 struct device * DMADevice_p;
955
956 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_BUS);
957 if (Pair_p == NULL)
958 {
959 LOG_WARN(
960 "DMAResource_Release: "
961 "No bus address found for Handle %p?\n",
962 Handle);
963 return -1;
964 }
965
966 DMAAddr = (dma_addr_t)(uintptr_t)Pair_p->Address_p;
967
968 Pair_p = DMAResourceLib_LookupDomain(Rec_p,
969 DMARES_DOMAIN_HOST_UNALIGNED);
970 if (Pair_p == NULL)
971 {
972 LOG_WARN(
973 "DMAResource_Release: "
974 "No host address found for Handle %p?\n",
975 Handle);
976 return -1;
977 }
978
979 // Get device reference for this resource
980 DMADevice_p = Device_GetReference(NULL, NULL);
981
982#ifndef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
983
984#ifndef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
985 if(Rec_p->AllocatorRef != 'R' &&
986 Rec_p->BankType != HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
987 {
988 dma_unmap_single(DMADevice_p,
989 DMAAddr + HWPAL_DMARESOURCE_BANK_STATIC_OFFSET,
990 Rec_p->BufferSize, DMA_BIDIRECTIONAL);
991#ifdef HWPAL_TRACE_DMARESOURCE_BUF
992 LOG_INFO("DMAResource_Release: Handle 0x%p, "
993 "bus address freed/adjusted 0x%p / 0x%p\n",
994 Handle,
995 (void*)(DMAAddr + HWPAL_DMARESOURCE_BANK_STATIC_OFFSET),
996 (void*)DMAAddr);
997#endif // HWPAL_TRACE_DMARESOURCE_BUF
998 }
999#endif // !HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
1000
1001#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
1002
1003 if(Rec_p->AllocatorRef == 'A')
1004 {
1005#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
1006
1007 #ifdef HWPAL_TRACE_DMARESOURCE_BUF
1008 LOG_INFO("DMAResource_Release: Handle 0x%p, "
1009 "bus address freed/adjusted 0x%p / 0x%p\n",
1010 Handle,
1011 (void*)(DMAAddr + HWPAL_DMARESOURCE_BANK_STATIC_OFFSET),
1012 (void*)DMAAddr);
1013#endif // HWPAL_TRACE_DMARESOURCE_BUF
1014
1015 dma_free_coherent(DMADevice_p,
1016 Rec_p->BufferSize,
1017 Pair_p->Address_p,
1018 DMAAddr + HWPAL_DMARESOURCE_BANK_STATIC_OFFSET);
1019#else
1020 if (Rec_p->BankType == HWPAL_DMARESOURCE_BANK_STATIC_FIXED_ADDR)
1021 {
1022 Device_Data_t DevData;
1023
1024 ZEROINIT(DevData);
1025 Device_GetReference(NULL, &DevData);
1026
1027 iounmap((void __iomem *)Pair_p->Address_p);
1028
1029#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1030 LOG_INFO("DMAResource_Release: Handle 0x%p, "
1031 "bus address freed/adjusted 0x%p / 0x%p\n",
1032 Handle,
1033 (void*)(DMAAddr + (phys_addr_t)DevData.PhysAddr +
1034 HWPAL_DMARESOURCE_BANK_STATIC_OFFSET),
1035 (void*)DMAAddr);
1036#endif // HWPAL_TRACE_DMARESOURCE_BUF
1037
1038 release_mem_region(DMAAddr + (phys_addr_t)(uintptr_t)DevData.PhysAddr +
1039 HWPAL_DMARESOURCE_BANK_STATIC_OFFSET,
1040 Rec_p->BufferSize);
1041 }
1042 else
1043 kfree(Pair_p->Address_p);
1044#endif
1045 }
1046
1047#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1048 UnalignedAddr_p = Pair_p->Address_p;
1049#endif
1050 }
1051
1052#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1053 LOG_INFO("DMAResource_Release (1/2): "
1054 "handle = 0x%p, allocator='%c', "
1055 "size allocated/requested=%d/%d, \n"
1056 "DMAResource_Release (2/2): "
1057 "alignment/bank/cached=%d/%d/%d, "
1058 "bus addr=0x%p, unaligned host addr=0x%p\n",
1059 Handle, Rec_p->AllocatorRef,
1060 Rec_p->BufferSize, Rec_p->Props.Size,
1061 Rec_p->Props.Alignment, Rec_p->Props.Bank, Rec_p->Props.fCached,
1062 (void*)DMAAddr, UnalignedAddr_p);
1063#endif
1064
1065 // free administration resources
1066 Rec_p->Magic = 0;
1067 DMAResource_DestroyRecord(Handle);
1068
1069 return 0;
1070}
1071
1072
1073/*----------------------------------------------------------------------------
1074 * HWPAL_DMAResource_Init
1075 */
1076bool
1077HWPAL_DMAResource_Init(void)
1078{
1079 bool AllocFailed = false;
1080 unsigned int MaxHandles = HWPAL_DMA_NRESOURCES;
1081
1082 {
1083 struct device * DMADevice_p;
1084 int res;
1085
1086
1087 // Get device reference for this resource
1088 DMADevice_p = Device_GetReference(NULL, NULL);
1089
1090 LOG_INFO("%s: Device DMA address mask 0x%016Lx\n",
1091 __func__,
1092 (long long unsigned int)HWPAL_DMARESOURCE_ADDR_MASK);
1093
1094 // Set DMA mask wider, so the DMA API will not try to bounce
1095 res = HWPAL_DMARESOURCE_SET_MASK(DMADevice_p,
1096 HWPAL_DMARESOURCE_ADDR_MASK);
1097 if ( res != 0)
1098 {
1099 LOG_CRIT("%s: failed, host does not support DMA address "
1100 "mask 0x%016Lx\n",
1101 __func__,
1102 (long long unsigned int)HWPAL_DMARESOURCE_ADDR_MASK);
1103 return false;
1104 }
1105 }
1106
1107 // already initialized?
1108 if (HandlesCount != 0)
1109 return false;
1110
1111 HWPAL_Lock_p = HWPAL_DMAResource_Lock_Alloc();
1112 if (HWPAL_Lock_p == NULL)
1113 {
1114 LOG_CRIT("HWPAL_DMAResource_Init: record lock allocation failed\n");
1115 return false;
1116 }
1117
1118 ChunksCount = (MaxHandles + MAX_RECORDS_PER_CHUNK - 1) /
1119 MAX_RECORDS_PER_CHUNK;
1120
1121 if (ChunksCount > 65535 ||
1122 ChunksCount * sizeof(void *) > KMALLOC_MAX_SIZE)
1123 {
1124 LOG_CRIT(
1125 "HWPAL_DMAResource_Init: "
1126 "Too many chunks desired: %u\n",
1127 ChunksCount);
1128 return false;
1129 }
1130
1131 LOG_INFO(
1132 "HWPAL_DMAResource_Init: "
1133 "Allocate %d records in %d chunks, "
1134 "DMA address size (bytes) %d, host address size (bytes) %d\n",
1135 MaxHandles, ChunksCount,
1136 (int)sizeof(dma_addr_t),
1137 (int)sizeof(void*));
1138
1139 LOG_INFO("HWPAL_DMAResource_Init: D-cache line size %d\n",
1140 HWPAL_DMARESOURCE_DCACHE_LINE_SIZE);
1141
1142#ifdef HWPAL_64BIT_HOST
1143 if (sizeof(void*) != 8 || sizeof(long) < 8)
1144 {
1145 LOG_CRIT("\n\nHWPAL_DMAResource_Init: ERROR, 64-bit host specified, "
1146 "but data sizes do not agree\n");
1147 return false;
1148 }
1149#else
1150 if (sizeof(void*) != 4)
1151 {
1152 LOG_CRIT("\n\nHWPAL_DMAResource_Init: ERROR, 32-bit host specified, "
1153 "but data sizes do not agree\n");
1154 return false;
1155 }
1156#endif
1157
1158 if (sizeof(dma_addr_t) > sizeof(void*))
1159 {
1160 LOG_WARN(
1161 "\n\nHWPAL_DMAResource_Init: WARNING, "
1162 "unsupported host DMA address size %d\n\n",
1163 (int)sizeof(dma_addr_t));
1164 }
1165
1166 RecordChunkPtrs_p =
1167 HWPAL_DMAResource_MemAlloc(ChunksCount * sizeof(void *));
1168 if (RecordChunkPtrs_p)
1169 {
1170 // Allocate each of the chunks in the RecordChunkPtrs_p array,
1171 // all of size MAX_RECORDS_PER_CHUNK, except the last one.
1172 int RecordsLeft, RecordsThisChunk, i;
1173
1174 // Pre-initialize with null, in case of early error exit
1175 memset(
1176 RecordChunkPtrs_p,
1177 0,
1178 ChunksCount * sizeof(DMAResource_Record_t*));
1179
1180 i=0;
1181 RecordsLeft = MaxHandles;
1182
1183 while ( RecordsLeft )
1184 {
1185 if (RecordsLeft > MAX_RECORDS_PER_CHUNK)
1186 RecordsThisChunk = MAX_RECORDS_PER_CHUNK;
1187 else
1188 RecordsThisChunk = RecordsLeft;
1189
1190 RecordChunkPtrs_p[i] =
1191 HWPAL_DMAResource_MemAlloc(RecordsThisChunk *
1192 sizeof(DMAResource_Record_t));
1193 if( RecordChunkPtrs_p[i] == NULL )
1194 {
1195 LOG_CRIT(
1196 "HWPAL_DMAResource_Init:"
1197 "Allocation failed chunk %d\n",i);
1198 AllocFailed = true;
1199 break;
1200 }
1201
1202 RecordsLeft -= RecordsThisChunk;
1203 i++;
1204 }
1205 LOG_INFO(
1206 "HWPAL_DMAResource_Init:"
1207 "Allocated %d chunks last one=%d others=%d, total=%d\n",
1208 i,
1209 RecordsThisChunk,
1210 (int)MAX_RECORDS_PER_CHUNK,
1211 (int)((i-1) * MAX_RECORDS_PER_CHUNK + RecordsThisChunk));
1212 }
1213
1214 if (MaxHandles * sizeof(uint32_t) > KMALLOC_MAX_SIZE)
1215 { // Too many handles for kmalloc, allocate with get_free_pages.
1216 int order = get_order(MaxHandles * sizeof(uint32_t));
1217
1218 pr_notice("FreeHandles: get_free_page\n");
1219 LOG_INFO(
1220 "HWPAL_DMAResource_Init: "
1221 "Handles & freelist allocated by get_free_pages order=%d\n",
1222 order);
1223
1224 Handles_p = (void*) __get_free_pages(GFP_KERNEL, order);
1225 FreeHandles.Nrs_p = (void*) __get_free_pages(GFP_KERNEL, order);
1226 FreeRecords.Nrs_p = (void*) __get_free_pages(GFP_KERNEL, order);
1227 }
1228 else
1229 {
1230 pr_notice("FreeHandles: kmalloc\n");
1231 Handles_p = HWPAL_DMAResource_MemAlloc(MaxHandles * sizeof(uint32_t));
1232 FreeHandles.Nrs_p =
1233 HWPAL_DMAResource_MemAlloc(MaxHandles * sizeof(uint32_t));
1234 FreeRecords.Nrs_p =
1235 HWPAL_DMAResource_MemAlloc(MaxHandles * sizeof(uint32_t));
1236 }
1237
1238 // if any allocation failed, free the whole lot
1239 if (RecordChunkPtrs_p == NULL ||
1240 Handles_p == NULL ||
1241 FreeHandles.Nrs_p == NULL ||
1242 FreeRecords.Nrs_p == NULL ||
1243 AllocFailed)
1244 {
1245 LOG_CRIT(
1246 "HWPAL_DMAResource_Init: "
1247 "RP=%p HP=%p FH=%p FR=%p AF=%d\n",
1248 RecordChunkPtrs_p,
1249 Handles_p,
1250 FreeHandles.Nrs_p,
1251 FreeRecords.Nrs_p,
1252 AllocFailed);
1253
1254 if (RecordChunkPtrs_p)
1255 {
1256 int i;
1257 for (i = 0; i < ChunksCount; i++)
1258 {
1259 if(RecordChunkPtrs_p[i])
1260 HWPAL_DMAResource_MemFree(RecordChunkPtrs_p[i]);
1261 }
1262 HWPAL_DMAResource_MemFree(RecordChunkPtrs_p);
1263 }
1264
1265 if (MaxHandles * sizeof(uint32_t) > KMALLOC_MAX_SIZE)
1266 { // Were allocated with get_free pages.
1267 int order = get_order(MaxHandles * sizeof(uint32_t));
1268
1269 if (Handles_p)
1270 free_pages((unsigned long)Handles_p, order);
1271
1272 if (FreeHandles.Nrs_p)
1273 free_pages((unsigned long)FreeHandles.Nrs_p, order);
1274
1275 if (FreeRecords.Nrs_p)
1276 free_pages((unsigned long)FreeRecords.Nrs_p, order);
1277 }
1278 else
1279 {
1280 if (Handles_p)
1281 HWPAL_DMAResource_MemFree(Handles_p);
1282
1283 if (FreeHandles.Nrs_p)
1284 HWPAL_DMAResource_MemFree(FreeHandles.Nrs_p);
1285
1286 if (FreeRecords.Nrs_p)
1287 HWPAL_DMAResource_MemFree(FreeRecords.Nrs_p);
1288 }
1289 RecordChunkPtrs_p = NULL;
1290 Handles_p = NULL;
1291 FreeHandles.Nrs_p = NULL;
1292 FreeRecords.Nrs_p = NULL;
1293
1294 if (HWPAL_Lock_p != NULL)
1295 HWPAL_DMAResource_Lock_Free(HWPAL_Lock_p);
1296
1297 return false;
1298 }
1299
1300 // initialize the record numbers freelist
1301 // initialize the handle numbers freelist
1302 // initialize the handles array
1303 {
1304 unsigned int i;
1305 unsigned int chunk=0;
1306 unsigned int recidx=0;
1307
1308 for (i = 0; i < MaxHandles; i++)
1309 {
1310 Handles_p[i] = HWPAL_INVALID_INDEX;
1311 FreeHandles.Nrs_p[i] = MaxHandles - 1 - i;
1312 FreeRecords.Nrs_p[i] = COMPOSE_RECNR(chunk,recidx);
1313 recidx++;
1314 if(recidx == MAX_RECORDS_PER_CHUNK)
1315 {
1316 chunk++;
1317 recidx = 0;
1318 }
1319 }
1320
1321 FreeHandles.ReadIndex = 0;
1322 FreeHandles.WriteIndex = 0;
1323
1324 FreeRecords.ReadIndex = 0;
1325 FreeRecords.WriteIndex = 0;
1326 }
1327
1328 HandlesCount = MaxHandles;
1329
1330 return true;
1331}
1332
1333
1334/*----------------------------------------------------------------------------
1335 * HWPAL_DMAResource_UnInit
1336 *
1337 * This function can be used to uninitialize the DMAResource administration.
1338 * The caller must make sure that handles will not be used after this function
1339 * returns.
1340 * If memory was allocated by HWPAL_DMAResource_Init, this function will
1341 * free it.
1342 */
1343void
1344HWPAL_DMAResource_UnInit(void)
1345{
1346 // exit if not initialized
1347 if (HandlesCount == 0)
1348 return;
1349
1350 // find resource leaks
1351#ifdef HWPAL_TRACE_DMARESOURCE_LEAKS
1352 {
1353 int i;
1354 bool fFirstPrint = true;
1355
1356 for (i = 0; i < HandlesCount; i++)
1357 {
1358 uint32_t IdxPair = Handles_p[i];
1359
1360 if (IdxPair != HWPAL_INVALID_INDEX)
1361 {
1362 if (fFirstPrint)
1363 {
1364 fFirstPrint = false;
1365 Log_FormattedMessage(
1366 "HWPAL_DMAResource_UnInit found leaking handles:\n");
1367 }
1368
1369 Log_FormattedMessage(
1370 "Handle %p => "
1371 "Record %u\n",
1372 Handles_p + i,
1373 IdxPair);
1374
1375 {
1376 DMAResource_AddrPair_t * Pair_p;
1377 DMAResource_Record_t * Rec_p =
1378 DMAResourceLib_IdxPair2RecordPtr(IdxPair);
1379
1380 if(Rec_p != NULL)
1381 {
1382 Pair_p = DMAResourceLib_LookupDomain(Rec_p,
1383 DMARES_DOMAIN_HOST);
1384
1385 Log_FormattedMessage(
1386 " AllocatedSize = %d\n"
1387 " Alignment = %d\n"
1388 " Bank = %d\n"
1389 " BankType = %d\n"
1390 " Host address = %p\n",
1391 Rec_p->BufferSize,
1392 Rec_p->Props.Alignment,
1393 Rec_p->Props.Bank,
1394 Rec_p->BankType,
1395 Pair_p->Address_p);
1396 }
1397 else
1398 {
1399 Log_FormattedMessage(" bad index pair\n");
1400 }
1401 }
1402 } // if
1403 } // for
1404
1405 if (fFirstPrint)
1406 Log_FormattedMessage(
1407 "HWPAL_DMAResource_UnInit: no leaks found\n");
1408 }
1409#endif /* HWPAL_TRACE_DMARESOURCE_LEAKS */
1410
1411 {
1412 int i;
1413
1414 for (i = 0; i < ChunksCount; i++)
1415 HWPAL_DMAResource_MemFree(RecordChunkPtrs_p[i]);
1416 }
1417 HWPAL_DMAResource_MemFree(RecordChunkPtrs_p);
1418
1419 if (HandlesCount * sizeof(uint32_t) > KMALLOC_MAX_SIZE)
1420 { // Were allocated with get_free pages.
1421 int order = get_order(HandlesCount * sizeof(uint32_t));
1422
1423 free_pages((unsigned long)Handles_p, order);
1424 free_pages((unsigned long)FreeHandles.Nrs_p, order);
1425 free_pages((unsigned long)FreeRecords.Nrs_p, order);
1426 }
1427 else
1428 {
1429 HWPAL_DMAResource_MemFree(FreeHandles.Nrs_p);
1430 HWPAL_DMAResource_MemFree(FreeRecords.Nrs_p);
1431 HWPAL_DMAResource_MemFree(Handles_p);
1432 }
1433
1434 if (HWPAL_Lock_p != NULL)
1435 HWPAL_DMAResource_Lock_Free(HWPAL_Lock_p);
1436
1437 FreeHandles.Nrs_p = NULL;
1438 FreeRecords.Nrs_p = NULL;
1439 Handles_p = NULL;
1440 RecordChunkPtrs_p = NULL;
1441
1442 HandlesCount = 0;
1443}
1444
1445
1446/*----------------------------------------------------------------------------
1447 * HWPAL_DMAResource_CheckAndRegister
1448 */
1449int
1450HWPAL_DMAResource_CheckAndRegister(
1451 const DMAResource_Properties_t RequestedProperties,
1452 const DMAResource_AddrPair_t AddrPair,
1453 const char AllocatorRef,
1454 DMAResource_Handle_t * const Handle_p)
1455{
1456 DMAResource_Properties_t ActualProperties = RequestedProperties;
1457 DMAResource_AddrPair_t * Pair_p;
1458 DMAResource_Record_t * Rec_p;
1459 DMAResource_Handle_t Handle;
1460 dma_addr_t DMAAddr = 0;
1461
1462#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1463 void* HostAddr = NULL;
1464#endif
1465
1466#ifdef HWPAL_DMARESOURCE_STRICT_ARGS_CHECKS
1467 if(AllocatorRef != 'N' &&
1468 ((uintptr_t)AddrPair.Address_p & (ActualProperties.Alignment - 1)) !=0)
1469 {
1470 // Warn against unaligned addresses, but do not fail.
1471 LOG_WARN("DMAResource_CheckAndRegister: "
1472 "address not aligned to %d\n",ActualProperties.Alignment);
1473 ActualProperties.Alignment = 1;
1474 }
1475
1476 if (NULL == Handle_p)
1477 {
1478 return -1;
1479 }
1480
1481 if (!DMAResourceLib_IsSaneInput(&AddrPair,
1482 &AllocatorRef,
1483 &ActualProperties))
1484 {
1485 return 1;
1486 }
1487
1488 if (AddrPair.Domain != DMARES_DOMAIN_HOST)
1489 {
1490 LOG_WARN(
1491 "HWPAL_DMAResource_CheckAndRegister: "
1492 "Unsupported domain: %u\n",
1493 AddrPair.Domain);
1494 return 1;
1495 }
1496#endif
1497
1498 if (AllocatorRef != 'k' && AllocatorRef != 'R' &&
1499 AllocatorRef != 'N' && AllocatorRef != 'C')
1500 {
1501 LOG_WARN(
1502 "HWPAL_DMAResource_CheckAndRegister: "
1503 "Unsupported AllocatorRef: %c\n",
1504 AllocatorRef);
1505
1506 return 1;
1507 }
1508
1509 // allocate record -> Handle & Rec_p
1510 Handle = DMAResource_CreateRecord();
1511 if (Handle == NULL)
1512 {
1513 return -1;
1514 }
1515
1516 Rec_p = DMAResource_Handle2RecordPtr(Handle);
1517 if (Rec_p == NULL)
1518 {
1519 return -1;
1520 }
1521
1522#ifdef HWPAL_ARCH_COHERENT
1523 ActualProperties.fCached = false;
1524#else
1525 ActualProperties.fCached = RequestedProperties.fCached;
1526#endif // HWPAL_ARCH_COHERENT
1527
1528#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
1529 ActualProperties.fCached = false;
1530#endif // HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
1531
1532 if (AllocatorRef == 'k' &&
1533 ((uintptr_t)AddrPair.Address_p &
1534 (HWPAL_DMAResource_DCache_Alignment_Get()-1)) != 0)
1535 {
1536 DMAResource_DestroyRecord(Handle);
1537 LOG_CRIT("DMAResource_CheckAndRegister: "
1538 "address not aligned to cache line size %d\n",
1539 HWPAL_DMAResource_DCache_Alignment_Get());
1540 return -1;
1541 }
1542
1543
1544 DMAResourceLib_Setup_Record(
1545 &ActualProperties,
1546 AllocatorRef,
1547 Rec_p,
1548 ActualProperties.Size);
1549
1550 Pair_p = Rec_p->AddrPairs;
1551 if (AllocatorRef == 'k' || AllocatorRef == 'R')
1552 {
1553 struct device * DMADevice_p;
1554
1555 // Get device reference for this resource
1556 DMADevice_p = Device_GetReference(NULL, NULL);
1557
1558#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
1559 if (!is_kernel_addr ((unsigned long)AddrPair.Address_p))
1560 {
1561 DMAResource_DestroyRecord(Handle);
1562 LOG_WARN(
1563 "HWPAL_DMAResource_CheckAndRegister: "
1564 "Unsupported host address: 0x%p\n",
1565 AddrPair.Address_p);
1566
1567 return -1;
1568 }
1569
1570 DMAAddr = (dma_addr_t)virt_to_phys (AddrPair.Address_p);
1571#else
1572 if (AllocatorRef == 'k')
1573 {
1574 // Note: this function can create a bounce buffer!
1575 DMAAddr = dma_map_single(DMADevice_p,
1576 AddrPair.Address_p,
1577 ActualProperties.Size,
1578 DMA_BIDIRECTIONAL);
1579 if (dma_mapping_error(DMADevice_p, DMAAddr))
1580 {
1581 if (DMAAddr)
1582 kfree(AddrPair.Address_p);
1583
1584 LOG_WARN(
1585 "HWPAL_DMAResource_CheckAndRegister: "
1586 "Failed to map DMA address for host address 0x%p, "
1587 "for handle 0x%p\n",
1588 AddrPair.Address_p,
1589 Handle);
1590
1591 return -1;
1592 }
1593
1594 Rec_p->Props.fCached = true; // always cached for kmalloc()
1595
1596#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1597 LOG_INFO("DMAResource_Alloc: Handle 0x%p, "
1598 "bus address requested/adjusted 0x%p / 0x%p\n",
1599 Handle,
1600 (void*)DMAAddr,
1601 (void*)(DMAAddr - HWPAL_DMARESOURCE_BANK_STATIC_OFFSET));
1602#endif // HWPAL_TRACE_DMARESOURCE_BUF
1603
1604 DMAAddr -= HWPAL_DMARESOURCE_BANK_STATIC_OFFSET;
1605 }
1606 else if (AllocatorRef == 'R')
1607 {
1608 DMAResource_Record_t * ParentRec_p;
1609 DMAResource_AddrPair_t *ParentHostPair_p,*ParentBusPair_p;
1610 uint32_t SubsetOffset;
1611
1612 ParentRec_p = DMAResourceLib_Find_Matching_DMAResource(
1613 &ActualProperties,
1614 AddrPair);
1615 if (ParentRec_p == NULL)
1616 {
1617 DMAAddr = 0;
1618 LOG_CRIT("HWPAL_DMAResource_CheckAndRegister: "
1619 "Failed to match DMA resource, "
1620 "alignment/bank/size %d/%d/%d, host addr 0x%p\n",
1621 ActualProperties.Alignment,
1622 ActualProperties.Bank,
1623 ActualProperties.Size,
1624 AddrPair.Address_p);
1625 }
1626 else
1627 {
1628 Rec_p->Props.fCached = ParentRec_p->Props.fCached;
1629 Rec_p->BankType = ParentRec_p->BankType;
1630
1631 ParentHostPair_p = DMAResourceLib_LookupDomain(
1632 ParentRec_p,
1633 DMARES_DOMAIN_HOST);
1634
1635 ParentBusPair_p = DMAResourceLib_LookupDomain(
1636 ParentRec_p,
1637 DMARES_DOMAIN_BUS);
1638
1639 if (ParentHostPair_p == NULL || ParentBusPair_p == NULL)
1640 {
1641 DMAAddr = 0;
1642 LOG_CRIT("HWPAL_DMAResource_CheckAndRegister: "
1643 "Failed to lookup parent DMA domain, "
1644 "alignment/bank/size %d/%d/%d, "
1645 "domain host/bus %p/%p\n",
1646 ActualProperties.Alignment,
1647 ActualProperties.Bank,
1648 ActualProperties.Size,
1649 ParentHostPair_p,
1650 ParentBusPair_p);
1651 }
1652 else
1653 {
1654 SubsetOffset = (uint32_t)((uint8_t *)AddrPair.Address_p -
1655 (uint8_t *)ParentHostPair_p->Address_p);
1656 DMAAddr = (dma_addr_t)(uintptr_t)ParentBusPair_p->Address_p +
1657 SubsetOffset;
1658#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1659 LOG_INFO("HWPAL_DMAResource_CheckAndRegister: "
1660 "Registered subset buffer, "
1661 "parent bus addr 0x%p, child offset %u\n",
1662 ParentBusPair_p->Address_p,
1663 SubsetOffset);
1664#endif // HWPAL_TRACE_DMARESOURCE_BUF
1665 }
1666 }
1667 }
1668#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
1669
1670 if (0 == DMAAddr)
1671 {
1672 DMAResource_DestroyRecord(Handle);
1673 LOG_CRIT("HWPAL_DMAResource_CheckAndRegister: "
1674 "Failed to obtain DMA address for host address 0x%p, "
1675 "for handle 0x%p\n",
1676 AddrPair.Address_p,
1677 Handle);
1678
1679 return -1;
1680 }
1681
1682 Pair_p->Address_p = (void *)(uintptr_t)DMAAddr;
1683 Pair_p->Domain = DMARES_DOMAIN_BUS;
1684
1685 ++Pair_p;
1686 Pair_p->Address_p = AddrPair.Address_p;
1687 Pair_p->Domain = DMARES_DOMAIN_HOST;
1688
1689 // This host address will be used for freeing the allocated buffer
1690 ++Pair_p;
1691 Pair_p->Address_p = AddrPair.Address_p;
1692 Pair_p->Domain = DMARES_DOMAIN_HOST_UNALIGNED;
1693
1694#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1695 HostAddr = AddrPair.Address_p;
1696#endif
1697 }
1698 else if (AllocatorRef == 'N' || AllocatorRef == 'C')
1699 {
1700 Pair_p->Address_p = AddrPair.Address_p;
1701 Pair_p->Domain = DMARES_DOMAIN_HOST;
1702
1703 // This host address will be used for freeing the allocated buffer
1704 ++Pair_p;
1705 Pair_p->Address_p = AddrPair.Address_p;
1706 Pair_p->Domain = DMARES_DOMAIN_HOST_UNALIGNED;
1707
1708#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1709 HostAddr = AddrPair.Address_p;
1710 DMAAddr = 0;
1711#endif
1712 }
1713
1714#ifdef HWPAL_TRACE_DMARESOURCE_BUF
1715 LOG_INFO("HWPAL_DMAResource_CheckAndRegister (1/2): "
1716 "handle = 0x%p, allocator='%c', "
1717 "size allocated/requested=%d/%d, \n"
1718 "HWPAL_DMAResource_CheckAndRegister (2/2): "
1719 "alignment/bank/cached=%d/%d/%d, "
1720 "bus addr=0x%p, host addr=0x%p\n",
1721 Handle, Rec_p->AllocatorRef,
1722 Rec_p->BufferSize, Rec_p->Props.Size,
1723 Rec_p->Props.Alignment, Rec_p->Props.Bank, Rec_p->Props.fCached,
1724 (void*)DMAAddr, HostAddr);
1725#endif
1726
1727 *Handle_p = Handle;
1728 return 0;
1729}
1730
1731
1732/*----------------------------------------------------------------------------
1733 * HWPAL_DMAResource_Record_Update
1734 */
1735int
1736HWPAL_DMAResource_Record_Update(
1737 const int Identifier,
1738 DMAResource_Record_t * const Rec_p)
1739{
1740 IDENTIFIER_NOT_USED(Identifier);
1741 IDENTIFIER_NOT_USED(Rec_p);
1742
1743 return 0; // Success, empty implementation
1744}
1745
1746/*----------------------------------------------------------------------------
1747 * DMAResource_CreateRecord
1748 *
1749 * This function can be used to create a record. The function returns a handle
1750 * for the record. Use DMAResource_Handle2RecordPtr to access the record.
1751 * Destroy the record when no longer required, see DMAResource_Destroy.
1752 * This function initializes the record to all zeros.
1753 *
1754 * Return Values
1755 * Handle for the DMA Resource.
1756 * NULL is returned when the creation failed.
1757 */
1758DMAResource_Handle_t
1759DMAResource_CreateRecord(void)
1760{
1761 unsigned long flags;
1762 uint32_t HandleNr;
1763 uint32_t IdxPair = 0;
1764
1765 // return NULL when not initialized
1766 if (HandlesCount == 0)
1767 return NULL;
1768
1769 HWPAL_DMAResource_Lock_Acquire(HWPAL_Lock_p, &flags);
1770
1771 HandleNr = DMAResourceLib_FreeList_Get(&FreeHandles);
1772 if (HandleNr != HWPAL_INVALID_INDEX)
1773 {
1774 IdxPair = DMAResourceLib_FreeList_Get(&FreeRecords);
1775 if (IdxPair == HWPAL_INVALID_INDEX)
1776 {
1777 DMAResourceLib_FreeList_Add(&FreeHandles, HandleNr);
1778 HandleNr = HWPAL_INVALID_INDEX;
1779 }
1780 }
1781
1782 HWPAL_DMAResource_Lock_Release(HWPAL_Lock_p, &flags);
1783
1784 // return NULL when reservation failed
1785 if (HandleNr == HWPAL_INVALID_INDEX)
1786 {
1787 LOG_CRIT("DMAResource_Create_Record: "
1788 "reservation failed, out of handles\n");
1789 return NULL;
1790 }
1791
1792 // initialize the record
1793 {
1794 DMAResource_Record_t * Rec_p =
1795 DMAResourceLib_IdxPair2RecordPtr(IdxPair);
1796 if(Rec_p == NULL)
1797 {
1798 LOG_CRIT(
1799 "DMAResource_Create_Record: "
1800 "Bad index pair returned %u\n",IdxPair);
1801 return NULL;
1802 }
1803 memset(Rec_p, 0, sizeof(DMAResource_Record_t));
1804 Rec_p->Magic = DMARES_RECORD_MAGIC;
1805 }
1806
1807 // initialize the handle
1808 Handles_p[HandleNr] = IdxPair;
1809
1810 // fill in the handle position
1811 return Handles_p + HandleNr;
1812}
1813
1814
1815/*----------------------------------------------------------------------------
1816 * DMAResource_DestroyRecord
1817 *
1818 * This function invalidates the handle and the record instance.
1819 *
1820 * Handle
1821 * A valid handle that was once returned by DMAResource_CreateRecord or
1822 * one of the DMA Buffer Management functions (Alloc/Register/Attach).
1823 *
1824 * Return Values
1825 * None
1826 */
1827void
1828DMAResource_DestroyRecord(
1829 const DMAResource_Handle_t Handle)
1830{
1831 if (DMAResource_IsValidHandle(Handle))
1832 {
1833 uint32_t * p = (uint32_t *)Handle;
1834 uint32_t IdxPair = *p;
1835
1836 if (DMAResourceLib_IdxPair2RecordPtr(IdxPair) != NULL)
1837 {
1838 unsigned long flags;
1839 int HandleNr = p - Handles_p;
1840
1841 // note handle is no longer value
1842 *p = HWPAL_INVALID_INDEX;
1843
1844 HWPAL_DMAResource_Lock_Acquire(HWPAL_Lock_p, &flags);
1845
1846 // add the HandleNr and IdxPair to respective LRU lists
1847 DMAResourceLib_FreeList_Add(&FreeHandles, HandleNr);
1848 DMAResourceLib_FreeList_Add(&FreeRecords, IdxPair);
1849
1850 HWPAL_DMAResource_Lock_Release(HWPAL_Lock_p, &flags);
1851 }
1852 else
1853 {
1854 LOG_WARN(
1855 "DMAResource_Destroy: "
1856 "Handle %p was already destroyed\n",
1857 Handle);
1858 }
1859 }
1860 else
1861 {
1862 LOG_WARN(
1863 "DMAResource_Destroy: "
1864 "Invalid handle %p\n",
1865 Handle);
1866 }
1867}
1868
1869
1870/*----------------------------------------------------------------------------
1871 * DMAResource_IsValidHandle
1872 *
1873 * This function tells whether a handle is valid.
1874 *
1875 * Handle
1876 * A valid handle that was once returned by DMAResource_CreateRecord or
1877 * one of the DMA Buffer Management functions (Alloc/Register/Attach).
1878 *
1879 * Return Value
1880 * true The handle is valid
1881 * false The handle is NOT valid
1882 */
1883bool
1884DMAResource_IsValidHandle(
1885 const DMAResource_Handle_t Handle)
1886{
1887 uint32_t * p = (uint32_t *)Handle;
1888
1889 if (p < Handles_p ||
1890 p >= Handles_p + HandlesCount)
1891 {
1892 return false;
1893 }
1894
1895 // check that the handle has not been destroyed yet
1896 if (*p == HWPAL_INVALID_INDEX)
1897 {
1898 return false;
1899 }
1900
1901 return true;
1902}
1903
1904
1905/*----------------------------------------------------------------------------
1906 * DMAResource_Handle2RecordPtr
1907 *
1908 * This function can be used to get a pointer to the DMA resource record
1909 * (DMAResource_Record_t) for the provided handle. The pointer is valid until
1910 * the record and handle are destroyed.
1911 *
1912 * Handle
1913 * A valid handle that was once returned by DMAResource_CreateRecord or
1914 * one of the DMA Buffer Management functions (Alloc/Register/Attach).
1915 *
1916 * Return Value
1917 * Pointer to the DMAResource_Record_t memory for this handle.
1918 * NULL is returned if the handle is invalid.
1919 */
1920DMAResource_Record_t *
1921DMAResource_Handle2RecordPtr(
1922 const DMAResource_Handle_t Handle)
1923{
1924 uint32_t * p = (uint32_t *)Handle;
1925
1926#ifdef HWPAL_DMARESOURCE_STRICT_ARGS_CHECKS
1927 if(!DMAResource_IsValidHandle(Handle))
1928 {
1929 return NULL;
1930 }
1931
1932 if (p != NULL)
1933 {
1934 uint32_t IdxPair = *p;
1935
1936 DMAResource_Record_t* Rec_p =
1937 DMAResourceLib_IdxPair2RecordPtr(IdxPair);
1938
1939 if(Rec_p != NULL && Rec_p->Magic == DMARES_RECORD_MAGIC)
1940 {
1941 return Rec_p; // ## RETURN ##
1942 }
1943 else
1944 {
1945 return NULL; // ## RETURN ##
1946 }
1947 }
1948#else
1949 return RecordChunkPtrs_p[CHUNK_OF(*p)] + RECIDX_OF(*p);
1950#endif
1951
1952 return NULL;
1953}
1954
1955
1956/*----------------------------------------------------------------------------
1957 * DMAResource_PreDMA
1958 */
1959void
1960DMAResource_PreDMA(
1961 const DMAResource_Handle_t Handle,
1962 const unsigned int ByteOffset,
1963 const unsigned int ByteCount)
1964{
1965 DMAResource_Record_t *Rec_p;
1966 unsigned int NBytes = ByteCount;
1967 unsigned int Offset = ByteOffset;
1968
1969 Rec_p = DMAResource_Handle2RecordPtr(Handle);
1970 if (Rec_p == NULL)
1971 {
1972 LOG_WARN(
1973 "DMAResource_PreDMA: "
1974 "Invalid handle %p\n",
1975 Handle);
1976 return;
1977 }
1978
1979 if (NBytes == 0)
1980 {
1981 // Prepare the whole resource for the DMA operation
1982 NBytes = Rec_p->Props.Size;
1983 Offset = 0;
1984 }
1985
1986 if ((Offset >= Rec_p->Props.Size) ||
1987 (NBytes > Rec_p->Props.Size) ||
1988 (Offset + NBytes > Rec_p->Props.Size))
1989 {
1990 LOG_CRIT(
1991 "DMAResource_PreDMA: "
1992 "Invalid range 0x%08x-0x%08x (not in 0x0-0x%08x)\n",
1993 ByteOffset,
1994 ByteOffset + ByteCount,
1995 Rec_p->Props.Size);
1996 return;
1997 }
1998
1999 if (Rec_p->Props.fCached &&
2000 (Rec_p->AllocatorRef == 'k' || Rec_p->AllocatorRef == 'A' ||
2001 Rec_p->AllocatorRef == 'R'))
2002 {
2003 DMAResource_AddrPair_t * Pair_p;
2004
2005#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2006 dma_addr_t DMAAddr;
2007
2008 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_HOST);
2009 if (Pair_p == NULL)
2010 {
2011 LOG_WARN(
2012 "DMAResource_PreDMA: "
2013 "No host address found for Handle %p?\n",
2014 Handle);
2015
2016 return;
2017 }
2018
2019 DMAAddr = (dma_addr_t)Pair_p->Address_p;
2020#else
2021 dma_addr_t DMAAddr;
2022
2023 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_BUS);
2024 if (Pair_p == NULL)
2025 {
2026 LOG_WARN(
2027 "DMAResource_PreDMA: "
2028 "No bus address found for Handle %p?\n",
2029 Handle);
2030
2031 return;
2032 }
2033
2034 DMAAddr = (dma_addr_t)(uintptr_t)Pair_p->Address_p;
2035#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2036 IDENTIFIER_NOT_USED(DMAAddr);
2037
2038#ifdef HWPAL_TRACE_DMARESOURCE_PREPOSTDMA
2039 Log_FormattedMessage(
2040 "DMAResource_PreDMA: "
2041 "Handle=%p, "
2042 "offset=%u, size=%u, "
2043 "allocator='%c', "
2044 "addr=0x%p\n",
2045 Handle,
2046 Offset, NBytes,
2047 Rec_p->AllocatorRef,
2048 (void*)DMAAddr);
2049#endif
2050
2051#ifndef HWPAL_ARCH_COHERENT
2052 {
2053 struct device * DMADevice_p;
2054 size_t size = NBytes;
2055
2056 // Get device reference for this resource
2057 DMADevice_p = Device_GetReference(NULL, NULL);
2058
2059#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2060 {
2061 uint8_t* DMABuffer_p = (uint8_t*)DMAAddr;
2062
2063 dma_cache_sync(DMADevice_p, DMABuffer_p + Offset,
2064 size, DMA_TO_DEVICE);
2065 }
2066#else
2067 dma_sync_single_range_for_device(DMADevice_p, DMAAddr,
2068 Offset, size, DMA_BIDIRECTIONAL);
2069#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2070 }
2071#endif
2072 }
2073}
2074
2075
2076/*----------------------------------------------------------------------------
2077 * DMAResource_PostDMA
2078 */
2079void
2080DMAResource_PostDMA(
2081 const DMAResource_Handle_t Handle,
2082 const unsigned int ByteOffset,
2083 const unsigned int ByteCount)
2084{
2085 DMAResource_Record_t *Rec_p;
2086 unsigned int NBytes = ByteCount;
2087 unsigned int Offset = ByteOffset;
2088
2089 Rec_p = DMAResource_Handle2RecordPtr(Handle);
2090 if (Rec_p == NULL)
2091 {
2092 LOG_WARN(
2093 "DMAResource_PostDMA: "
2094 "Invalid handle %p\n",
2095 Handle);
2096 return;
2097 }
2098
2099 if (NBytes == 0)
2100 {
2101 // Prepare the whole resource for the DMA operation
2102 NBytes = Rec_p->Props.Size;
2103 Offset = 0;
2104 }
2105
2106 if ((ByteOffset >= Rec_p->Props.Size) ||
2107 (NBytes > Rec_p->Props.Size) ||
2108 (ByteOffset + NBytes > Rec_p->Props.Size))
2109 {
2110 LOG_CRIT(
2111 "DMAResource_PostDMA: "
2112 "Invalid range 0x%08x-0x%08x (not in 0x0-0x%08x)\n",
2113 ByteOffset,
2114 ByteOffset + NBytes,
2115 Rec_p->Props.Size);
2116 return;
2117 }
2118
2119 if (Rec_p->Props.fCached &&
2120 (Rec_p->AllocatorRef == 'k' || Rec_p->AllocatorRef == 'A' ||
2121 Rec_p->AllocatorRef == 'R'))
2122 {
2123 DMAResource_AddrPair_t * Pair_p;
2124#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2125 dma_addr_t DMAAddr;
2126
2127 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_HOST);
2128 if (Pair_p == NULL)
2129 {
2130 LOG_WARN(
2131 "DMAResource_PostDMA: "
2132 "No host address found for Handle %p?\n",
2133 Handle);
2134
2135 return;
2136 }
2137
2138 DMAAddr = (dma_addr_t)Pair_p->Address_p;
2139#else
2140 dma_addr_t DMAAddr;
2141
2142 Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_BUS);
2143 if (Pair_p == NULL)
2144 {
2145 LOG_WARN(
2146 "DMAResource_PostDMA: "
2147 "No bus address found for Handle %p?\n",
2148 Handle);
2149
2150 return;
2151 }
2152
2153 DMAAddr = (dma_addr_t)(uintptr_t)Pair_p->Address_p;
2154#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2155
2156 IDENTIFIER_NOT_USED(DMAAddr);
2157 IDENTIFIER_NOT_USED(Offset);
2158
2159#ifdef HWPAL_TRACE_DMARESOURCE_PREPOSTDMA
2160 Log_FormattedMessage(
2161 "DMAResource_PostDMA: "
2162 "Handle=%p, "
2163 "offset=%u, size=%u), "
2164 "allocator='%c', "
2165 "addr 0x%p\n",
2166 Handle,
2167 Offset, NBytes,
2168 Rec_p->AllocatorRef,
2169 (void*)DMAAddr);
2170#endif
2171
2172#ifndef HWPAL_ARCH_COHERENT
2173 {
2174 struct device * DMADevice_p;
2175 size_t size = NBytes;
2176
2177 // Get device reference for this resource
2178 DMADevice_p = Device_GetReference(NULL, NULL);
2179
2180#ifdef HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2181 {
2182 uint8_t* DMABuffer_p = (uint8_t*)DMAAddr;
2183
2184 dma_cache_sync(DMADevice_p, DMABuffer_p + Offset,
2185 size, DMA_FROM_DEVICE);
2186 }
2187#else
2188 dma_sync_single_range_for_cpu(DMADevice_p, DMAAddr, Offset,
2189 size, DMA_BIDIRECTIONAL);
2190#endif // HWPAL_DMARESOURCE_MINIMUM_CACHE_CONTROL
2191 }
2192#endif
2193 }
2194}
2195
2196
2197/*----------------------------------------------------------------------------
2198 * DMAResource_Attach
2199 */
2200int
2201DMAResource_Attach(
2202 const DMAResource_Properties_t ActualProperties,
2203 const DMAResource_AddrPair_t AddrPair,
2204 DMAResource_Handle_t * const Handle_p)
2205{
2206 IDENTIFIER_NOT_USED(Handle_p);
2207 IDENTIFIER_NOT_USED(AddrPair.Address_p);
2208 IDENTIFIER_NOT_USED(ActualProperties.Alignment);
2209
2210 return -1; // Not implemented
2211}
2212
2213
2214/* end of file dmares_lkm.c */