Skip to content

Commit

Permalink
io: Add support for address translation from driver physical address …
Browse files Browse the repository at this point in the history
…to device physical address

There are SoCs that have different memory maps for device and driver.
Therefore the shared memory between them has different values and we
need to convert the addresses.

Add support to convert a driver physical address to device
physical address.

Signed-off-by: Iuliana Prodan <[email protected]>
  • Loading branch information
iuliana-prodan committed Feb 3, 2025
1 parent 465fcf0 commit 41421df
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

void metal_io_init(struct metal_io_region *io, void *virt,
const metal_phys_addr_t *physmap, size_t size,
const metal_phys_addr_t *physmap_drv,
unsigned int page_shift, unsigned int mem_flags,
const struct metal_io_ops *ops)
{
Expand All @@ -21,6 +22,7 @@ void metal_io_init(struct metal_io_region *io, void *virt,
io->virt = virt;
io->physmap = physmap;
io->size = size;
io->physmap_drv = physmap_drv;
io->page_shift = page_shift;
if (page_shift >= sizeof(io->page_mask) * CHAR_BIT)
/* avoid overflow */
Expand Down
44 changes: 44 additions & 0 deletions lib/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct metal_io_region {
of each of the pages in the I/O
region */
size_t size; /**< size of the I/O region */
const metal_phys_addr_t *physmap_drv;/**< table of base physical address
of each of the pages in the I/O

Check warning on line 80 in lib/io.h

View workflow job for this annotation

GitHub Actions / compliance review

BLOCK_COMMENT_STYLE

lib/io.h:80 Block comments use * on subsequent lines
region, for driver */

Check warning on line 81 in lib/io.h

View workflow job for this annotation

GitHub Actions / compliance review

BLOCK_COMMENT_STYLE

lib/io.h:81 Block comments use a trailing */ on a separate line
unsigned long page_shift; /**< page shift of I/O region */
metal_phys_addr_t page_mask; /**< page mask of I/O region */
unsigned int mem_flags; /**< memory attribute of the
Expand All @@ -90,13 +93,15 @@ struct metal_io_region {
* @param[in] virt Virtual address of region.
* @param[in] physmap Array of physical addresses per page.
* @param[in] size Size of region.
* @param[in] physmap_drv Array of physical addresses for driver.
* @param[in] page_shift Log2 of page size (-1 for single page).
* @param[in] mem_flags Memory flags
* @param[in] ops ops
*/
void
metal_io_init(struct metal_io_region *io, void *virt,
const metal_phys_addr_t *physmap, size_t size,
const metal_phys_addr_t *physmap_drv,
unsigned int page_shift, unsigned int mem_flags,
const struct metal_io_ops *ops);

Expand Down Expand Up @@ -196,6 +201,39 @@ metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
return (*io->ops.phys_to_offset)(io, phys);
}

/**
* @brief Convert a driver physical address to a device physical address.
* @param[in] io I/O region handle.
* @param[in] phys_drv Driver physical address
* @return METAL_BAD_PHYS if invalid driver physical address,
* or device physical address
*/
static inline metal_phys_addr_t
metal_io_phys_drv_to_phys(struct metal_io_region *io, metal_phys_addr_t phys_drv)
{
size_t p;
size_t page_cnt = 1;
size_t page_size = io->size;

if (!io->physmap_drv || !io->size) {
return METAL_BAD_PHYS;
}

if (io->page_mask != (metal_phys_addr_t)(-1)) {
page_cnt = (io->size + io->page_mask) >> io->page_shift;
page_size = io->page_mask + 1;
}

for (p = 0; p < page_cnt; p++) {
if (phys_drv >= io->physmap_drv[p] &&
phys_drv < io->physmap_drv[p] + page_size) {
return phys_drv - io->physmap_drv[p] + io->physmap[p];
}
}

return METAL_BAD_PHYS;
}

/**
* @brief Convert a physical address to virtual address.
* @param[in] io Shared memory segment handle.
Expand All @@ -205,6 +243,12 @@ metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
static inline void *
metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys)
{
metal_phys_addr_t tmp_phys = metal_io_phys_drv_to_phys(io, phys);

if (tmp_phys != METAL_BAD_PHYS) {
phys = tmp_phys;
}

return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
}

Expand Down

0 comments on commit 41421df

Please sign in to comment.