xref: /openbmc/linux/drivers/vfio/pci/mlx5/cmd.c (revision 08b7cf13)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved
4  */
5 
6 #include "cmd.h"
7 
8 int mlx5vf_cmd_suspend_vhca(struct pci_dev *pdev, u16 vhca_id, u16 op_mod)
9 {
10 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
11 	u32 out[MLX5_ST_SZ_DW(suspend_vhca_out)] = {};
12 	u32 in[MLX5_ST_SZ_DW(suspend_vhca_in)] = {};
13 	int ret;
14 
15 	if (!mdev)
16 		return -ENOTCONN;
17 
18 	MLX5_SET(suspend_vhca_in, in, opcode, MLX5_CMD_OP_SUSPEND_VHCA);
19 	MLX5_SET(suspend_vhca_in, in, vhca_id, vhca_id);
20 	MLX5_SET(suspend_vhca_in, in, op_mod, op_mod);
21 
22 	ret = mlx5_cmd_exec_inout(mdev, suspend_vhca, in, out);
23 	mlx5_vf_put_core_dev(mdev);
24 	return ret;
25 }
26 
27 int mlx5vf_cmd_resume_vhca(struct pci_dev *pdev, u16 vhca_id, u16 op_mod)
28 {
29 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
30 	u32 out[MLX5_ST_SZ_DW(resume_vhca_out)] = {};
31 	u32 in[MLX5_ST_SZ_DW(resume_vhca_in)] = {};
32 	int ret;
33 
34 	if (!mdev)
35 		return -ENOTCONN;
36 
37 	MLX5_SET(resume_vhca_in, in, opcode, MLX5_CMD_OP_RESUME_VHCA);
38 	MLX5_SET(resume_vhca_in, in, vhca_id, vhca_id);
39 	MLX5_SET(resume_vhca_in, in, op_mod, op_mod);
40 
41 	ret = mlx5_cmd_exec_inout(mdev, resume_vhca, in, out);
42 	mlx5_vf_put_core_dev(mdev);
43 	return ret;
44 }
45 
46 int mlx5vf_cmd_query_vhca_migration_state(struct pci_dev *pdev, u16 vhca_id,
47 					  size_t *state_size)
48 {
49 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
50 	u32 out[MLX5_ST_SZ_DW(query_vhca_migration_state_out)] = {};
51 	u32 in[MLX5_ST_SZ_DW(query_vhca_migration_state_in)] = {};
52 	int ret;
53 
54 	if (!mdev)
55 		return -ENOTCONN;
56 
57 	MLX5_SET(query_vhca_migration_state_in, in, opcode,
58 		 MLX5_CMD_OP_QUERY_VHCA_MIGRATION_STATE);
59 	MLX5_SET(query_vhca_migration_state_in, in, vhca_id, vhca_id);
60 	MLX5_SET(query_vhca_migration_state_in, in, op_mod, 0);
61 
62 	ret = mlx5_cmd_exec_inout(mdev, query_vhca_migration_state, in, out);
63 	if (ret)
64 		goto end;
65 
66 	*state_size = MLX5_GET(query_vhca_migration_state_out, out,
67 			       required_umem_size);
68 
69 end:
70 	mlx5_vf_put_core_dev(mdev);
71 	return ret;
72 }
73 
74 int mlx5vf_cmd_get_vhca_id(struct pci_dev *pdev, u16 function_id, u16 *vhca_id)
75 {
76 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
77 	u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {};
78 	int out_size;
79 	void *out;
80 	int ret;
81 
82 	if (!mdev)
83 		return -ENOTCONN;
84 
85 	out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out);
86 	out = kzalloc(out_size, GFP_KERNEL);
87 	if (!out) {
88 		ret = -ENOMEM;
89 		goto end;
90 	}
91 
92 	MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
93 	MLX5_SET(query_hca_cap_in, in, other_function, 1);
94 	MLX5_SET(query_hca_cap_in, in, function_id, function_id);
95 	MLX5_SET(query_hca_cap_in, in, op_mod,
96 		 MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 |
97 		 HCA_CAP_OPMOD_GET_CUR);
98 
99 	ret = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out);
100 	if (ret)
101 		goto err_exec;
102 
103 	*vhca_id = MLX5_GET(query_hca_cap_out, out,
104 			    capability.cmd_hca_cap.vhca_id);
105 
106 err_exec:
107 	kfree(out);
108 end:
109 	mlx5_vf_put_core_dev(mdev);
110 	return ret;
111 }
112 
113 static int _create_state_mkey(struct mlx5_core_dev *mdev, u32 pdn,
114 			      struct mlx5_vf_migration_file *migf, u32 *mkey)
115 {
116 	size_t npages = DIV_ROUND_UP(migf->total_length, PAGE_SIZE);
117 	struct sg_dma_page_iter dma_iter;
118 	int err = 0, inlen;
119 	__be64 *mtt;
120 	void *mkc;
121 	u32 *in;
122 
123 	inlen = MLX5_ST_SZ_BYTES(create_mkey_in) +
124 		sizeof(*mtt) * round_up(npages, 2);
125 
126 	in = kvzalloc(inlen, GFP_KERNEL);
127 	if (!in)
128 		return -ENOMEM;
129 
130 	MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
131 		 DIV_ROUND_UP(npages, 2));
132 	mtt = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
133 
134 	for_each_sgtable_dma_page(&migf->table.sgt, &dma_iter, 0)
135 		*mtt++ = cpu_to_be64(sg_page_iter_dma_address(&dma_iter));
136 
137 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
138 	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_MTT);
139 	MLX5_SET(mkc, mkc, lr, 1);
140 	MLX5_SET(mkc, mkc, lw, 1);
141 	MLX5_SET(mkc, mkc, rr, 1);
142 	MLX5_SET(mkc, mkc, rw, 1);
143 	MLX5_SET(mkc, mkc, pd, pdn);
144 	MLX5_SET(mkc, mkc, bsf_octword_size, 0);
145 	MLX5_SET(mkc, mkc, qpn, 0xffffff);
146 	MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT);
147 	MLX5_SET(mkc, mkc, translations_octword_size, DIV_ROUND_UP(npages, 2));
148 	MLX5_SET64(mkc, mkc, len, migf->total_length);
149 	err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
150 	kvfree(in);
151 	return err;
152 }
153 
154 int mlx5vf_cmd_save_vhca_state(struct pci_dev *pdev, u16 vhca_id,
155 			       struct mlx5_vf_migration_file *migf)
156 {
157 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
158 	u32 out[MLX5_ST_SZ_DW(save_vhca_state_out)] = {};
159 	u32 in[MLX5_ST_SZ_DW(save_vhca_state_in)] = {};
160 	u32 pdn, mkey;
161 	int err;
162 
163 	if (!mdev)
164 		return -ENOTCONN;
165 
166 	err = mlx5_core_alloc_pd(mdev, &pdn);
167 	if (err)
168 		goto end;
169 
170 	err = dma_map_sgtable(mdev->device, &migf->table.sgt, DMA_FROM_DEVICE,
171 			      0);
172 	if (err)
173 		goto err_dma_map;
174 
175 	err = _create_state_mkey(mdev, pdn, migf, &mkey);
176 	if (err)
177 		goto err_create_mkey;
178 
179 	MLX5_SET(save_vhca_state_in, in, opcode,
180 		 MLX5_CMD_OP_SAVE_VHCA_STATE);
181 	MLX5_SET(save_vhca_state_in, in, op_mod, 0);
182 	MLX5_SET(save_vhca_state_in, in, vhca_id, vhca_id);
183 	MLX5_SET(save_vhca_state_in, in, mkey, mkey);
184 	MLX5_SET(save_vhca_state_in, in, size, migf->total_length);
185 
186 	err = mlx5_cmd_exec_inout(mdev, save_vhca_state, in, out);
187 	if (err)
188 		goto err_exec;
189 
190 	migf->total_length =
191 		MLX5_GET(save_vhca_state_out, out, actual_image_size);
192 
193 	mlx5_core_destroy_mkey(mdev, mkey);
194 	mlx5_core_dealloc_pd(mdev, pdn);
195 	dma_unmap_sgtable(mdev->device, &migf->table.sgt, DMA_FROM_DEVICE, 0);
196 	mlx5_vf_put_core_dev(mdev);
197 
198 	return 0;
199 
200 err_exec:
201 	mlx5_core_destroy_mkey(mdev, mkey);
202 err_create_mkey:
203 	dma_unmap_sgtable(mdev->device, &migf->table.sgt, DMA_FROM_DEVICE, 0);
204 err_dma_map:
205 	mlx5_core_dealloc_pd(mdev, pdn);
206 end:
207 	mlx5_vf_put_core_dev(mdev);
208 	return err;
209 }
210 
211 int mlx5vf_cmd_load_vhca_state(struct pci_dev *pdev, u16 vhca_id,
212 			       struct mlx5_vf_migration_file *migf)
213 {
214 	struct mlx5_core_dev *mdev = mlx5_vf_get_core_dev(pdev);
215 	u32 out[MLX5_ST_SZ_DW(save_vhca_state_out)] = {};
216 	u32 in[MLX5_ST_SZ_DW(save_vhca_state_in)] = {};
217 	u32 pdn, mkey;
218 	int err;
219 
220 	if (!mdev)
221 		return -ENOTCONN;
222 
223 	mutex_lock(&migf->lock);
224 	if (!migf->total_length) {
225 		err = -EINVAL;
226 		goto end;
227 	}
228 
229 	err = mlx5_core_alloc_pd(mdev, &pdn);
230 	if (err)
231 		goto end;
232 
233 	err = dma_map_sgtable(mdev->device, &migf->table.sgt, DMA_TO_DEVICE, 0);
234 	if (err)
235 		goto err_reg;
236 
237 	err = _create_state_mkey(mdev, pdn, migf, &mkey);
238 	if (err)
239 		goto err_mkey;
240 
241 	MLX5_SET(load_vhca_state_in, in, opcode,
242 		 MLX5_CMD_OP_LOAD_VHCA_STATE);
243 	MLX5_SET(load_vhca_state_in, in, op_mod, 0);
244 	MLX5_SET(load_vhca_state_in, in, vhca_id, vhca_id);
245 	MLX5_SET(load_vhca_state_in, in, mkey, mkey);
246 	MLX5_SET(load_vhca_state_in, in, size, migf->total_length);
247 
248 	err = mlx5_cmd_exec_inout(mdev, load_vhca_state, in, out);
249 
250 	mlx5_core_destroy_mkey(mdev, mkey);
251 err_mkey:
252 	dma_unmap_sgtable(mdev->device, &migf->table.sgt, DMA_TO_DEVICE, 0);
253 err_reg:
254 	mlx5_core_dealloc_pd(mdev, pdn);
255 end:
256 	mlx5_vf_put_core_dev(mdev);
257 	mutex_unlock(&migf->lock);
258 	return err;
259 }
260