0001
0002
0003
0004
0005
0006
0007 #include <linux/slab.h>
0008 #include <linux/vhost_iotlb.h>
0009 #include <linux/module.h>
0010
0011 #define MOD_VERSION "0.1"
0012 #define MOD_DESC "VHOST IOTLB"
0013 #define MOD_AUTHOR "Jason Wang <jasowang@redhat.com>"
0014 #define MOD_LICENSE "GPL v2"
0015
0016 #define START(map) ((map)->start)
0017 #define LAST(map) ((map)->last)
0018
0019 INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
0020 rb, __u64, __subtree_last,
0021 START, LAST, static inline, vhost_iotlb_itree);
0022
0023
0024
0025
0026
0027
0028 void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
0029 struct vhost_iotlb_map *map)
0030 {
0031 vhost_iotlb_itree_remove(map, &iotlb->root);
0032 list_del(&map->link);
0033 kfree(map);
0034 iotlb->nmaps--;
0035 }
0036 EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
0051 u64 start, u64 last,
0052 u64 addr, unsigned int perm,
0053 void *opaque)
0054 {
0055 struct vhost_iotlb_map *map;
0056
0057 if (last < start)
0058 return -EFAULT;
0059
0060
0061
0062
0063 if (start == 0 && last == ULONG_MAX) {
0064 u64 mid = last / 2;
0065 int err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
0066 perm, opaque);
0067
0068 if (err)
0069 return err;
0070
0071 addr += mid + 1;
0072 start = mid + 1;
0073 }
0074
0075 if (iotlb->limit &&
0076 iotlb->nmaps == iotlb->limit &&
0077 iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
0078 map = list_first_entry(&iotlb->list, typeof(*map), link);
0079 vhost_iotlb_map_free(iotlb, map);
0080 }
0081
0082 map = kmalloc(sizeof(*map), GFP_ATOMIC);
0083 if (!map)
0084 return -ENOMEM;
0085
0086 map->start = start;
0087 map->size = last - start + 1;
0088 map->last = last;
0089 map->addr = addr;
0090 map->perm = perm;
0091 map->opaque = opaque;
0092
0093 iotlb->nmaps++;
0094 vhost_iotlb_itree_insert(map, &iotlb->root);
0095
0096 INIT_LIST_HEAD(&map->link);
0097 list_add_tail(&map->link, &iotlb->list);
0098
0099 return 0;
0100 }
0101 EXPORT_SYMBOL_GPL(vhost_iotlb_add_range_ctx);
0102
0103 int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
0104 u64 start, u64 last,
0105 u64 addr, unsigned int perm)
0106 {
0107 return vhost_iotlb_add_range_ctx(iotlb, start, last,
0108 addr, perm, NULL);
0109 }
0110 EXPORT_SYMBOL_GPL(vhost_iotlb_add_range);
0111
0112
0113
0114
0115
0116
0117
0118 void vhost_iotlb_del_range(struct vhost_iotlb *iotlb, u64 start, u64 last)
0119 {
0120 struct vhost_iotlb_map *map;
0121
0122 while ((map = vhost_iotlb_itree_iter_first(&iotlb->root,
0123 start, last)))
0124 vhost_iotlb_map_free(iotlb, map);
0125 }
0126 EXPORT_SYMBOL_GPL(vhost_iotlb_del_range);
0127
0128
0129
0130
0131
0132
0133
0134 void vhost_iotlb_init(struct vhost_iotlb *iotlb, unsigned int limit,
0135 unsigned int flags)
0136 {
0137 iotlb->root = RB_ROOT_CACHED;
0138 iotlb->limit = limit;
0139 iotlb->nmaps = 0;
0140 iotlb->flags = flags;
0141 INIT_LIST_HEAD(&iotlb->list);
0142 }
0143 EXPORT_SYMBOL_GPL(vhost_iotlb_init);
0144
0145
0146
0147
0148
0149
0150
0151
0152 struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags)
0153 {
0154 struct vhost_iotlb *iotlb = kzalloc(sizeof(*iotlb), GFP_KERNEL);
0155
0156 if (!iotlb)
0157 return NULL;
0158
0159 vhost_iotlb_init(iotlb, limit, flags);
0160
0161 return iotlb;
0162 }
0163 EXPORT_SYMBOL_GPL(vhost_iotlb_alloc);
0164
0165
0166
0167
0168
0169 void vhost_iotlb_reset(struct vhost_iotlb *iotlb)
0170 {
0171 vhost_iotlb_del_range(iotlb, 0ULL, 0ULL - 1);
0172 }
0173 EXPORT_SYMBOL_GPL(vhost_iotlb_reset);
0174
0175
0176
0177
0178
0179 void vhost_iotlb_free(struct vhost_iotlb *iotlb)
0180 {
0181 if (iotlb) {
0182 vhost_iotlb_reset(iotlb);
0183 kfree(iotlb);
0184 }
0185 }
0186 EXPORT_SYMBOL_GPL(vhost_iotlb_free);
0187
0188
0189
0190
0191
0192
0193
0194 struct vhost_iotlb_map *
0195 vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
0196 {
0197 return vhost_iotlb_itree_iter_first(&iotlb->root, start, last);
0198 }
0199 EXPORT_SYMBOL_GPL(vhost_iotlb_itree_first);
0200
0201
0202
0203
0204
0205
0206
0207 struct vhost_iotlb_map *
0208 vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last)
0209 {
0210 return vhost_iotlb_itree_iter_next(map, start, last);
0211 }
0212 EXPORT_SYMBOL_GPL(vhost_iotlb_itree_next);
0213
0214 MODULE_VERSION(MOD_VERSION);
0215 MODULE_DESCRIPTION(MOD_DESC);
0216 MODULE_AUTHOR(MOD_AUTHOR);
0217 MODULE_LICENSE(MOD_LICENSE);