1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies Ltd. */
4 #include <linux/vhost_types.h>
5 #include <linux/vdpa.h>
7 #include <linux/string.h>
8 #include <linux/mlx5/qp.h>
11 /* DIV_ROUND_UP where the divider is a power of 2 give by its log base 2 value */
12 #define MLX5_DIV_ROUND_UP_POW2(_n, _s) \
16 _res = (((_n) + (1 << (__s)) - 1) >> (__s)); \
20 static int get_octo_len(u64 len, int page_shift)
22 u64 page_size = 1ULL << page_shift;
25 npages = ALIGN(len, page_size) >> page_shift;
26 return (npages + 1) / 2;
29 static void mlx5_set_access_mode(void *mkc, int mode)
31 MLX5_SET(mkc, mkc, access_mode_1_0, mode & 0x3);
32 MLX5_SET(mkc, mkc, access_mode_4_2, mode >> 2);
35 static void populate_mtts(struct mlx5_vdpa_direct_mr *mr, __be64 *mtt)
37 struct scatterlist *sg;
44 for_each_sg(mr->sg_head.sgl, sg, mr->nent, i) {
45 for (dma_addr = sg_dma_address(sg), dma_len = sg_dma_len(sg);
47 nsg--, dma_addr += BIT(mr->log_size), dma_len -= BIT(mr->log_size))
48 mtt[j++] = cpu_to_be64(dma_addr);
52 static int create_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
59 inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + roundup(MLX5_ST_SZ_BYTES(mtt) * mr->nsg, 16);
60 in = kvzalloc(inlen, GFP_KERNEL);
64 MLX5_SET(create_mkey_in, in, uid, mvdev->res.uid);
65 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
66 MLX5_SET(mkc, mkc, lw, !!(mr->perm & VHOST_MAP_WO));
67 MLX5_SET(mkc, mkc, lr, !!(mr->perm & VHOST_MAP_RO));
68 mlx5_set_access_mode(mkc, MLX5_MKC_ACCESS_MODE_MTT);
69 MLX5_SET(mkc, mkc, qpn, 0xffffff);
70 MLX5_SET(mkc, mkc, pd, mvdev->res.pdn);
71 MLX5_SET64(mkc, mkc, start_addr, mr->offset);
72 MLX5_SET64(mkc, mkc, len, mr->end - mr->start);
73 MLX5_SET(mkc, mkc, log_page_size, mr->log_size);
74 MLX5_SET(mkc, mkc, translations_octword_size,
75 get_octo_len(mr->end - mr->start, mr->log_size));
76 MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
77 get_octo_len(mr->end - mr->start, mr->log_size));
78 populate_mtts(mr, MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt));
79 err = mlx5_vdpa_create_mkey(mvdev, &mr->mr, in, inlen);
82 mlx5_vdpa_warn(mvdev, "Failed to create direct MR\n");
89 static void destroy_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
91 mlx5_vdpa_destroy_mkey(mvdev, &mr->mr);
94 static u64 map_start(struct vhost_iotlb_map *map, struct mlx5_vdpa_direct_mr *mr)
96 return max_t(u64, map->start, mr->start);
99 static u64 map_end(struct vhost_iotlb_map *map, struct mlx5_vdpa_direct_mr *mr)
101 return min_t(u64, map->last + 1, mr->end);
104 static u64 maplen(struct vhost_iotlb_map *map, struct mlx5_vdpa_direct_mr *mr)
106 return map_end(map, mr) - map_start(map, mr);
109 #define MLX5_VDPA_INVALID_START_ADDR ((u64)-1)
110 #define MLX5_VDPA_INVALID_LEN ((u64)-1)
112 static u64 indir_start_addr(struct mlx5_vdpa_mr *mkey)
114 struct mlx5_vdpa_direct_mr *s;
116 s = list_first_entry_or_null(&mkey->head, struct mlx5_vdpa_direct_mr, list);
118 return MLX5_VDPA_INVALID_START_ADDR;
123 static u64 indir_len(struct mlx5_vdpa_mr *mkey)
125 struct mlx5_vdpa_direct_mr *s;
126 struct mlx5_vdpa_direct_mr *e;
128 s = list_first_entry_or_null(&mkey->head, struct mlx5_vdpa_direct_mr, list);
130 return MLX5_VDPA_INVALID_LEN;
132 e = list_last_entry(&mkey->head, struct mlx5_vdpa_direct_mr, list);
134 return e->end - s->start;
137 #define LOG_MAX_KLM_SIZE 30
138 #define MAX_KLM_SIZE BIT(LOG_MAX_KLM_SIZE)
140 static u32 klm_bcount(u64 size)
145 static void fill_indir(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mkey, void *in)
147 struct mlx5_vdpa_direct_mr *dmr;
148 struct mlx5_klm *klmarr;
149 struct mlx5_klm *klm;
154 klmarr = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
156 list_for_each_entry(dmr, &mkey->head, list) {
164 if (preve == dmr->start) {
165 klm->key = cpu_to_be32(dmr->mr.key);
166 klm->bcount = cpu_to_be32(klm_bcount(dmr->end - dmr->start));
169 klm->key = cpu_to_be32(mvdev->res.null_mkey);
170 klm->bcount = cpu_to_be32(klm_bcount(dmr->start - preve));
177 static int klm_byte_size(int nklms)
179 return 16 * ALIGN(nklms, 4);
182 static int create_indirect_key(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
191 start = indir_start_addr(mr);
193 if (start == MLX5_VDPA_INVALID_START_ADDR || len == MLX5_VDPA_INVALID_LEN)
196 inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + klm_byte_size(mr->num_klms);
197 in = kzalloc(inlen, GFP_KERNEL);
201 MLX5_SET(create_mkey_in, in, uid, mvdev->res.uid);
202 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
203 MLX5_SET(mkc, mkc, lw, 1);
204 MLX5_SET(mkc, mkc, lr, 1);
205 mlx5_set_access_mode(mkc, MLX5_MKC_ACCESS_MODE_KLMS);
206 MLX5_SET(mkc, mkc, qpn, 0xffffff);
207 MLX5_SET(mkc, mkc, pd, mvdev->res.pdn);
208 MLX5_SET64(mkc, mkc, start_addr, start);
209 MLX5_SET64(mkc, mkc, len, len);
210 MLX5_SET(mkc, mkc, translations_octword_size, klm_byte_size(mr->num_klms) / 16);
211 MLX5_SET(create_mkey_in, in, translations_octword_actual_size, mr->num_klms);
212 fill_indir(mvdev, mr, in);
213 err = mlx5_vdpa_create_mkey(mvdev, &mr->mkey, in, inlen);
218 static void destroy_indirect_key(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mkey)
220 mlx5_vdpa_destroy_mkey(mvdev, &mkey->mkey);
223 static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr,
224 struct vhost_iotlb *iotlb)
226 struct vhost_iotlb_map *map;
227 unsigned long lgcd = 0;
237 struct scatterlist *sg;
238 struct device *dma = mvdev->vdev.dma_dev;
240 for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
241 map; map = vhost_iotlb_itree_next(map, start, mr->end - 1)) {
242 size = maplen(map, mr);
243 lgcd = gcd(lgcd, size);
246 log_entity_size = ilog2(lgcd);
248 sglen = 1 << log_entity_size;
249 nsg = MLX5_DIV_ROUND_UP_POW2(mr->end - mr->start, log_entity_size);
251 err = sg_alloc_table(&mr->sg_head, nsg, GFP_KERNEL);
255 sg = mr->sg_head.sgl;
256 for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
257 map; map = vhost_iotlb_itree_next(map, mr->start, mr->end - 1)) {
258 paend = map->addr + maplen(map, mr);
259 for (pa = map->addr; pa < paend; pa += sglen) {
260 pg = pfn_to_page(__phys_to_pfn(pa));
262 mlx5_vdpa_warn(mvdev, "sg null. start 0x%llx, end 0x%llx\n",
263 map->start, map->last + 1);
267 sg_set_page(sg, pg, sglen, 0);
274 mr->log_size = log_entity_size;
276 mr->nent = dma_map_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
282 err = create_direct_mr(mvdev, mr);
289 dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
291 sg_free_table(&mr->sg_head);
295 static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
297 struct device *dma = mvdev->vdev.dma_dev;
299 destroy_direct_mr(mvdev, mr);
300 dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
301 sg_free_table(&mr->sg_head);
304 static int add_direct_chain(struct mlx5_vdpa_dev *mvdev, u64 start, u64 size, u8 perm,
305 struct vhost_iotlb *iotlb)
307 struct mlx5_vdpa_mr *mr = &mvdev->mr;
308 struct mlx5_vdpa_direct_mr *dmr;
309 struct mlx5_vdpa_direct_mr *n;
318 sz = (u32)min_t(u64, MAX_KLM_SIZE, size);
319 dmr = kzalloc(sizeof(*dmr), GFP_KERNEL);
328 err = map_direct_mr(mvdev, dmr, iotlb);
334 list_add_tail(&dmr->list, &tmp);
341 list_splice_tail(&tmp, &mr->head);
345 list_for_each_entry_safe(dmr, n, &mr->head, list) {
346 list_del_init(&dmr->list);
347 unmap_direct_mr(mvdev, dmr);
353 /* The iotlb pointer contains a list of maps. Go over the maps, possibly
354 * merging mergeable maps, and create direct memory keys that provide the
355 * device access to memory. The direct mkeys are then referred to by the
356 * indirect memory key that provides access to the enitre address space given
359 static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
361 struct mlx5_vdpa_mr *mr = &mvdev->mr;
362 struct mlx5_vdpa_direct_mr *dmr;
363 struct mlx5_vdpa_direct_mr *n;
364 struct vhost_iotlb_map *map;
373 INIT_LIST_HEAD(&mr->head);
374 for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
375 map = vhost_iotlb_itree_next(map, start, last)) {
377 if (pe == map->start && pperm == map->perm) {
381 if (pe < map->start) {
382 /* We have a hole in the map. Check how
383 * many null keys are required to fill it.
385 nnuls = MLX5_DIV_ROUND_UP_POW2(map->start - pe,
387 mr->num_klms += nnuls;
389 err = add_direct_chain(mvdev, ps, pe - ps, pperm, iotlb);
398 err = add_direct_chain(mvdev, ps, pe - ps, pperm, iotlb);
402 /* Create the memory key that defines the guests's address space. This
403 * memory key refers to the direct keys that contain the MTT
406 err = create_indirect_key(mvdev, mr);
414 list_for_each_entry_safe_reverse(dmr, n, &mr->head, list) {
415 list_del_init(&dmr->list);
416 unmap_direct_mr(mvdev, dmr);
422 static int create_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
424 int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
429 in = kzalloc(inlen, GFP_KERNEL);
433 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
435 MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
436 MLX5_SET(mkc, mkc, length64, 1);
437 MLX5_SET(mkc, mkc, lw, 1);
438 MLX5_SET(mkc, mkc, lr, 1);
439 MLX5_SET(mkc, mkc, pd, mvdev->res.pdn);
440 MLX5_SET(mkc, mkc, qpn, 0xffffff);
442 err = mlx5_vdpa_create_mkey(mvdev, &mr->mkey, in, inlen);
450 static void destroy_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
452 mlx5_vdpa_destroy_mkey(mvdev, &mr->mkey);
455 static int dup_iotlb(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *src)
457 struct vhost_iotlb_map *map;
458 u64 start = 0, last = ULLONG_MAX;
462 err = vhost_iotlb_add_range(mvdev->cvq.iotlb, start, last, start, VHOST_ACCESS_RW);
466 for (map = vhost_iotlb_itree_first(src, start, last); map;
467 map = vhost_iotlb_itree_next(map, start, last)) {
468 err = vhost_iotlb_add_range(mvdev->cvq.iotlb, map->start, map->last,
469 map->addr, map->perm);
476 static void prune_iotlb(struct mlx5_vdpa_dev *mvdev)
478 vhost_iotlb_del_range(mvdev->cvq.iotlb, 0, ULLONG_MAX);
481 static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
483 struct mlx5_vdpa_direct_mr *dmr;
484 struct mlx5_vdpa_direct_mr *n;
486 destroy_indirect_key(mvdev, mr);
487 list_for_each_entry_safe_reverse(dmr, n, &mr->head, list) {
488 list_del_init(&dmr->list);
489 unmap_direct_mr(mvdev, dmr);
494 void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
496 struct mlx5_vdpa_mr *mr = &mvdev->mr;
498 mutex_lock(&mr->mkey_mtx);
499 if (!mr->initialized)
504 destroy_user_mr(mvdev, mr);
506 destroy_dma_mr(mvdev, mr);
508 memset(mr, 0, sizeof(*mr));
509 mr->initialized = false;
511 mutex_unlock(&mr->mkey_mtx);
514 static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
516 struct mlx5_vdpa_mr *mr = &mvdev->mr;
523 err = create_user_mr(mvdev, iotlb);
525 err = create_dma_mr(mvdev, mr);
530 err = dup_iotlb(mvdev, iotlb);
534 mr->initialized = true;
539 destroy_user_mr(mvdev, mr);
541 destroy_dma_mr(mvdev, mr);
546 int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
550 mutex_lock(&mvdev->mr.mkey_mtx);
551 err = _mlx5_vdpa_create_mr(mvdev, iotlb);
552 mutex_unlock(&mvdev->mr.mkey_mtx);
556 int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
559 struct mlx5_vdpa_mr *mr = &mvdev->mr;
563 mutex_lock(&mr->mkey_mtx);
564 if (mr->initialized) {
565 mlx5_vdpa_info(mvdev, "memory map update\n");
569 err = _mlx5_vdpa_create_mr(mvdev, iotlb);
570 mutex_unlock(&mr->mkey_mtx);