^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (C) 2020 Red Hat, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Author: Jason Wang <jasowang@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * IOTLB implementation for vhost.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/vhost_iotlb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define MOD_VERSION "0.1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define MOD_DESC "VHOST IOTLB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define MOD_AUTHOR "Jason Wang <jasowang@redhat.com>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define MOD_LICENSE "GPL v2"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define START(map) ((map)->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define LAST(map) ((map)->last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) rb, __u64, __subtree_last,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) START, LAST, static inline, vhost_iotlb_itree);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * vhost_iotlb_map_free - remove a map node and free it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * @iotlb: the IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * @map: the map that want to be remove and freed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct vhost_iotlb_map *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) vhost_iotlb_itree_remove(map, &iotlb->root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) list_del(&map->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) kfree(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) iotlb->nmaps--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * vhost_iotlb_add_range - add a new range to vhost IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * @iotlb: the IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * @start: start of the IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * @last: last of IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * @addr: the address that is mapped to @start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * @perm: access permission of this range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Returns an error last is smaller than start or memory allocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * fails
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) u64 start, u64 last,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u64 addr, unsigned int perm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct vhost_iotlb_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (last < start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (iotlb->limit &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) iotlb->nmaps == iotlb->limit &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) map = list_first_entry(&iotlb->list, typeof(*map), link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) vhost_iotlb_map_free(iotlb, map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) map = kmalloc(sizeof(*map), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) map->start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) map->size = last - start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) map->last = last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) map->addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) map->perm = perm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) iotlb->nmaps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) vhost_iotlb_itree_insert(map, &iotlb->root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) INIT_LIST_HEAD(&map->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) list_add_tail(&map->link, &iotlb->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) EXPORT_SYMBOL_GPL(vhost_iotlb_add_range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * vring_iotlb_del_range - delete overlapped ranges from vhost IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * @iotlb: the IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * @start: start of the IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * @last: last of IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) void vhost_iotlb_del_range(struct vhost_iotlb *iotlb, u64 start, u64 last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct vhost_iotlb_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) while ((map = vhost_iotlb_itree_iter_first(&iotlb->root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) start, last)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) vhost_iotlb_map_free(iotlb, map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) EXPORT_SYMBOL_GPL(vhost_iotlb_del_range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * vhost_iotlb_alloc - add a new vhost IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * @limit: maximum number of IOTLB entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * @flags: VHOST_IOTLB_FLAG_XXX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * Returns an error is memory allocation fails
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct vhost_iotlb *iotlb = kzalloc(sizeof(*iotlb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!iotlb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) iotlb->root = RB_ROOT_CACHED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) iotlb->limit = limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) iotlb->nmaps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) iotlb->flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) INIT_LIST_HEAD(&iotlb->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return iotlb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) EXPORT_SYMBOL_GPL(vhost_iotlb_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * vhost_iotlb_reset - reset vhost IOTLB (free all IOTLB entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * @iotlb: the IOTLB to be reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) void vhost_iotlb_reset(struct vhost_iotlb *iotlb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) vhost_iotlb_del_range(iotlb, 0ULL, 0ULL - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) EXPORT_SYMBOL_GPL(vhost_iotlb_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * vhost_iotlb_free - reset and free vhost IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @iotlb: the IOTLB to be freed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) void vhost_iotlb_free(struct vhost_iotlb *iotlb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (iotlb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) vhost_iotlb_reset(iotlb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) kfree(iotlb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) EXPORT_SYMBOL_GPL(vhost_iotlb_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * vhost_iotlb_itree_first - return the first overlapped range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * @iotlb: the IOTLB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * @start: start of IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * @last: last byte in IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct vhost_iotlb_map *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return vhost_iotlb_itree_iter_first(&iotlb->root, start, last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) EXPORT_SYMBOL_GPL(vhost_iotlb_itree_first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * vhost_iotlb_itree_next - return the next overlapped range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * @map: the starting map node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * @start: start of IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * @last: last byte IOVA range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct vhost_iotlb_map *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return vhost_iotlb_itree_iter_next(map, start, last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) EXPORT_SYMBOL_GPL(vhost_iotlb_itree_next);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) MODULE_VERSION(MOD_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) MODULE_DESCRIPTION(MOD_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) MODULE_AUTHOR(MOD_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) MODULE_LICENSE(MOD_LICENSE);