qemu/hw/virtio/vhost-iova-tree.c
<<
>>
Prefs
   1/*
   2 * vhost software live migration iova tree
   3 *
   4 * SPDX-FileCopyrightText: Red Hat, Inc. 2021
   5 * SPDX-FileContributor: Author: Eugenio PĂ©rez <eperezma@redhat.com>
   6 *
   7 * SPDX-License-Identifier: GPL-2.0-or-later
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "qemu/iova-tree.h"
  12#include "vhost-iova-tree.h"
  13
  14#define iova_min_addr qemu_real_host_page_size()
  15
  16/**
  17 * VhostIOVATree, able to:
  18 * - Translate iova address
  19 * - Reverse translate iova address (from translated to iova)
  20 * - Allocate IOVA regions for translated range (linear operation)
  21 */
  22struct VhostIOVATree {
  23    /* First addressable iova address in the device */
  24    uint64_t iova_first;
  25
  26    /* Last addressable iova address in the device */
  27    uint64_t iova_last;
  28
  29    /* IOVA address to qemu memory maps. */
  30    IOVATree *iova_taddr_map;
  31};
  32
  33/**
  34 * Create a new IOVA tree
  35 *
  36 * Returns the new IOVA tree
  37 */
  38VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
  39{
  40    VhostIOVATree *tree = g_new(VhostIOVATree, 1);
  41
  42    /* Some devices do not like 0 addresses */
  43    tree->iova_first = MAX(iova_first, iova_min_addr);
  44    tree->iova_last = iova_last;
  45
  46    tree->iova_taddr_map = iova_tree_new();
  47    return tree;
  48}
  49
  50/**
  51 * Delete an iova tree
  52 */
  53void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
  54{
  55    iova_tree_destroy(iova_tree->iova_taddr_map);
  56    g_free(iova_tree);
  57}
  58
  59/**
  60 * Find the IOVA address stored from a memory address
  61 *
  62 * @tree: The iova tree
  63 * @map: The map with the memory address
  64 *
  65 * Return the stored mapping, or NULL if not found.
  66 */
  67const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
  68                                        const DMAMap *map)
  69{
  70    return iova_tree_find_iova(tree->iova_taddr_map, map);
  71}
  72
  73/**
  74 * Allocate a new mapping
  75 *
  76 * @tree: The iova tree
  77 * @map: The iova map
  78 *
  79 * Returns:
  80 * - IOVA_OK if the map fits in the container
  81 * - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
  82 * - IOVA_ERR_NOMEM if tree cannot allocate more space.
  83 *
  84 * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK.
  85 */
  86int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
  87{
  88    /* Some vhost devices do not like addr 0. Skip first page */
  89    hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size();
  90
  91    if (map->translated_addr + map->size < map->translated_addr ||
  92        map->perm == IOMMU_NONE) {
  93        return IOVA_ERR_INVALID;
  94    }
  95
  96    /* Allocate a node in IOVA address */
  97    return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
  98                               tree->iova_last);
  99}
 100
 101/**
 102 * Remove existing mappings from iova tree
 103 *
 104 * @iova_tree: The vhost iova tree
 105 * @map: The map to remove
 106 */
 107void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map)
 108{
 109    iova_tree_remove(iova_tree->iova_taddr_map, map);
 110}
 111