Skip to content

Commit 2d026a3

Browse files
GuEe-GUImysterywolf
authored andcommitted
[FEATURE/OFW] add address reverse/translate for DMA/CPU's address
DMA and CPU address view is different, we need to convert them: +--------+ +--------+ +---------+ +--------+ | | | | | | | | | CPUs | | DEV0 | | IOMMU <----+ | DEV1 | | | | | | | | | | +----+---+ +----+---+ +----+----+ | +----+---+ | | | | | 0x200000 | 0x1000 | 0x1000 | | 0x8000 | | | | | | +-------------+-----------+ +----------+ | | +--------v----------------------------------------------------+ | | | Address BUS | | | +-------------------------------------------------------------+ Signed-off-by: GuEe-GUI <[email protected]>
1 parent 117e6ed commit 2d026a3

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

components/drivers/include/drivers/ofw_io.h

+21
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name,
2626
int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_regs);
2727

2828
rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address);
29+
rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address);
30+
31+
rt_inline rt_uint64_t rt_ofw_translate_dma2cpu(struct rt_ofw_node *np, rt_uint64_t address)
32+
{
33+
rt_uint64_t bus_addr, cpu_addr;
34+
35+
bus_addr = rt_ofw_reverse_address(np, "dma-ranges", address);
36+
cpu_addr = rt_ofw_translate_address(np, "ranges", bus_addr);
37+
38+
return cpu_addr != ~0ULL ? cpu_addr : address;
39+
}
40+
41+
rt_inline rt_uint64_t rt_ofw_translate_cpu2dma(struct rt_ofw_node *np, rt_uint64_t address)
42+
{
43+
rt_uint64_t bus_addr, dma_addr;
44+
45+
bus_addr = rt_ofw_reverse_address(np, "ranges", address);
46+
dma_addr = rt_ofw_translate_address(np, "dma-ranges", bus_addr);
47+
48+
return dma_addr != ~0ULL ? dma_addr : address;
49+
}
2950

3051
void *rt_ofw_iomap(struct rt_ofw_node *np, int index);
3152
void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name);

components/drivers/ofw/io.c

+69
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,75 @@ rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_t
407407
return cpu_addr;
408408
}
409409

410+
rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address)
411+
{
412+
rt_uint64_t bus_addr = address;
413+
414+
if (!range_type)
415+
{
416+
range_type = "ranges";
417+
}
418+
419+
rt_ofw_foreach_parent_node(np)
420+
{
421+
rt_ssize_t len;
422+
struct rt_ofw_prop *prop;
423+
struct bus_ranges *ranges = RT_NULL;
424+
425+
prop = rt_ofw_get_prop(np, range_type, &len);
426+
427+
if (!prop || !len)
428+
{
429+
continue;
430+
}
431+
432+
for (int i = 0; i < RT_ARRAY_SIZE(_bus_ranges); ++i)
433+
{
434+
if (!_bus_ranges[i])
435+
{
436+
break;
437+
}
438+
439+
if (_bus_ranges[i]->np == np)
440+
{
441+
ranges = _bus_ranges[i];
442+
break;
443+
}
444+
}
445+
446+
if (!ranges)
447+
{
448+
ranges = ofw_bus_ranges(np, prop);
449+
}
450+
451+
if (ranges)
452+
{
453+
for (int i = 0; i < ranges->nr; ++i)
454+
{
455+
rt_uint64_t parent_addr = ranges->parent_addr[i];
456+
rt_uint64_t child_size = ranges->child_size[i];
457+
458+
if (address >= parent_addr && address < parent_addr + child_size)
459+
{
460+
bus_addr = ranges->child_addr[i] + (address - parent_addr);
461+
462+
break;
463+
}
464+
}
465+
}
466+
else
467+
{
468+
bus_addr = ~0ULL;
469+
}
470+
471+
rt_ofw_node_put(np);
472+
473+
break;
474+
}
475+
476+
return bus_addr;
477+
}
478+
410479
#ifdef ARCH_CPU_64BIT
411480
#define ofw_address_cpu_cast(np, address) (void *)(address)
412481
#else

0 commit comments

Comments
 (0)