On 5/19/26 12:37 PM, Shameer Kolothum wrote:
> Some hardware accelerators DMA directly to the host physical address
s/DMA/perform DMA accesses
> of a guest-resident buffer (e.g. set up via IOMMUFD). The HPA is
> contiguous only within a single host backing page; a buffer larger
> than the smallest backing page in use may span non-contiguous host
> pages and fault.
>
> Introduce qemu_ram_backend_pagesize_min(), which returns the smallest
> page size among RAM regions backed by a memory-backend object. Falls
Don't you have means to be more precise? I mean you know the GPA of the
cmdq, can't you make sure it belongs to a specific ramblock and check
its min page_size?
By the way there is find_min_backend_pagesize() that exists. Can't you
reuse that?
Thanks
Eric
> back to qemu_real_host_page_size() if no memory-backend RAM blocks
> are found. Callers can use this to bound the size of buffers that
> must remain host-physically contiguous.
>
> A subsequent Tegra241 CMDQV support patch will use this to bound the
> command queue size exposed to the guest.
>
> Cc: Peter Xu <[email protected]>
> Cc: "Philippe Mathieu-Daudé" <[email protected]>
> Signed-off-by: Shameer Kolothum <[email protected]>
> ---
> include/system/ramblock.h | 1 +
> system/physmem.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 30 insertions(+)
>
> diff --git a/include/system/ramblock.h b/include/system/ramblock.h
> index 4435f8d55f..7f7ea53557 100644
> --- a/include/system/ramblock.h
> +++ b/include/system/ramblock.h
> @@ -175,6 +175,7 @@ int qemu_ram_get_fd(const RAMBlock *rb);
>
> size_t qemu_ram_pagesize(const RAMBlock *block);
> size_t qemu_ram_pagesize_largest(void);
> +size_t qemu_ram_backend_pagesize_min(void);
> #include "exec/target_page.h"
> #include "exec/hwaddr.h"
>
> diff --git a/system/physmem.c b/system/physmem.c
> index 46b36c7b10..7ccec52aa2 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -1999,6 +1999,35 @@ size_t qemu_ram_pagesize_largest(void)
> return largest;
> }
>
> +/*
> + * Returns the smallest page size among RAM regions backed by a
> + * memory-backend object. Falls back to qemu_real_host_page_size() if no
> + * memory-backend RAM blocks are found.
> + */
> +size_t qemu_ram_backend_pagesize_min(void)
> +{
> + RAMBlock *rb;
> + size_t pg, min_pg = SIZE_MAX;
> +
> + RAMBLOCK_FOREACH(rb) {
> + MemoryRegion *mr = rb->mr;
> +
> + if (!mr || !memory_region_is_ram(mr)) {
> + continue;
> + }
> + if (!object_dynamic_cast(mr->owner, TYPE_MEMORY_BACKEND)) {
> + continue;
> + }
> +
> + pg = qemu_ram_pagesize(rb);
> + if (pg && pg < min_pg) {
> + min_pg = pg;
> + }
> + }
> +
> + return (min_pg == SIZE_MAX) ? qemu_real_host_page_size() : min_pg;
> +}
> +
> static int memory_try_enable_merging(void *addr, size_t len)
> {
> if (!machine_mem_merge(current_machine)) {