1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2023 Advanced Micro Devices, Inc. */
5 #include <linux/types.h>
6 #include <linux/delay.h>
8 #include <linux/pds/pds_common.h>
9 #include <linux/pds/pds_core_if.h>
10 #include <linux/pds/pds_adminq.h>
15 #define SUSPEND_TIMEOUT_S 5
16 #define SUSPEND_CHECK_INTERVAL_MS 1
18 static int pds_vfio_client_adminq_cmd(struct pds_vfio_pci_device
*pds_vfio
,
19 union pds_core_adminq_cmd
*req
,
20 union pds_core_adminq_comp
*resp
,
23 struct pci_dev
*pdev
= pds_vfio_to_pci_dev(pds_vfio
);
24 union pds_core_adminq_cmd cmd
= {};
28 /* Wrap the client request */
29 cmd
.client_request
.opcode
= PDS_AQ_CMD_CLIENT_CMD
;
30 cmd
.client_request
.client_id
= cpu_to_le16(pds_vfio
->client_id
);
31 memcpy(cmd
.client_request
.client_cmd
, req
,
32 sizeof(cmd
.client_request
.client_cmd
));
34 pdsc
= pdsc_get_pf_struct(pdev
);
38 err
= pdsc_adminq_post(pdsc
, &cmd
, resp
, fast_poll
);
39 if (err
&& err
!= -EAGAIN
)
40 dev_err(pds_vfio_to_dev(pds_vfio
),
41 "client admin cmd failed: %pe\n", ERR_PTR(err
));
46 int pds_vfio_register_client_cmd(struct pds_vfio_pci_device
*pds_vfio
)
48 struct pci_dev
*pdev
= pds_vfio_to_pci_dev(pds_vfio
);
49 char devname
[PDS_DEVNAME_LEN
];
53 snprintf(devname
, sizeof(devname
), "%s.%d-%u", PDS_VFIO_LM_DEV_NAME
,
54 pci_domain_nr(pdev
->bus
),
55 PCI_DEVID(pdev
->bus
->number
, pdev
->devfn
));
57 pdsc
= pdsc_get_pf_struct(pdev
);
61 ci
= pds_client_register(pdsc
, devname
);
65 pds_vfio
->client_id
= ci
;
70 void pds_vfio_unregister_client_cmd(struct pds_vfio_pci_device
*pds_vfio
)
72 struct pci_dev
*pdev
= pds_vfio_to_pci_dev(pds_vfio
);
76 pdsc
= pdsc_get_pf_struct(pdev
);
80 err
= pds_client_unregister(pdsc
, pds_vfio
->client_id
);
82 dev_err(&pdev
->dev
, "unregister from DSC failed: %pe\n",
85 pds_vfio
->client_id
= 0;
89 pds_vfio_suspend_wait_device_cmd(struct pds_vfio_pci_device
*pds_vfio
, u8 type
)
91 union pds_core_adminq_cmd cmd
= {
92 .lm_suspend_status
= {
93 .opcode
= PDS_LM_CMD_SUSPEND_STATUS
,
94 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
98 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
99 union pds_core_adminq_comp comp
= {};
100 unsigned long time_limit
;
101 unsigned long time_start
;
102 unsigned long time_done
;
105 time_start
= jiffies
;
106 time_limit
= time_start
+ HZ
* SUSPEND_TIMEOUT_S
;
108 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, true);
112 msleep(SUSPEND_CHECK_INTERVAL_MS
);
113 } while (time_before(jiffies
, time_limit
));
116 dev_dbg(dev
, "%s: vf%u: Suspend comp received in %d msecs\n", __func__
,
117 pds_vfio
->vf_id
, jiffies_to_msecs(time_done
- time_start
));
119 /* Check the results */
120 if (time_after_eq(time_done
, time_limit
)) {
121 dev_err(dev
, "%s: vf%u: Suspend comp timeout\n", __func__
,
129 int pds_vfio_suspend_device_cmd(struct pds_vfio_pci_device
*pds_vfio
, u8 type
)
131 union pds_core_adminq_cmd cmd
= {
133 .opcode
= PDS_LM_CMD_SUSPEND
,
134 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
138 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
139 union pds_core_adminq_comp comp
= {};
142 dev_dbg(dev
, "vf%u: Suspend device\n", pds_vfio
->vf_id
);
145 * The initial suspend request to the firmware starts the device suspend
146 * operation and the firmware returns success if it's started
149 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, true);
151 dev_err(dev
, "vf%u: Suspend failed: %pe\n", pds_vfio
->vf_id
,
157 * The subsequent suspend status request(s) check if the firmware has
158 * completed the device suspend process.
160 return pds_vfio_suspend_wait_device_cmd(pds_vfio
, type
);
163 int pds_vfio_resume_device_cmd(struct pds_vfio_pci_device
*pds_vfio
, u8 type
)
165 union pds_core_adminq_cmd cmd
= {
167 .opcode
= PDS_LM_CMD_RESUME
,
168 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
172 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
173 union pds_core_adminq_comp comp
= {};
175 dev_dbg(dev
, "vf%u: Resume device\n", pds_vfio
->vf_id
);
177 return pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, true);
180 int pds_vfio_get_lm_state_size_cmd(struct pds_vfio_pci_device
*pds_vfio
, u64
*size
)
182 union pds_core_adminq_cmd cmd
= {
184 .opcode
= PDS_LM_CMD_STATE_SIZE
,
185 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
188 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
189 union pds_core_adminq_comp comp
= {};
192 dev_dbg(dev
, "vf%u: Get migration status\n", pds_vfio
->vf_id
);
194 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
198 *size
= le64_to_cpu(comp
.lm_state_size
.size
);
202 static int pds_vfio_dma_map_lm_file(struct device
*dev
,
203 enum dma_data_direction dir
,
204 struct pds_vfio_lm_file
*lm_file
)
206 struct pds_lm_sg_elem
*sgl
, *sge
;
207 struct scatterlist
*sg
;
216 /* dma map file pages */
217 err
= dma_map_sgtable(dev
, &lm_file
->sg_table
, dir
, 0);
221 lm_file
->num_sge
= lm_file
->sg_table
.nents
;
224 sgl_size
= lm_file
->num_sge
* sizeof(struct pds_lm_sg_elem
);
225 sgl
= kzalloc(sgl_size
, GFP_KERNEL
);
228 goto out_unmap_sgtable
;
233 for_each_sgtable_dma_sg(&lm_file
->sg_table
, sg
, i
) {
234 sge
->addr
= cpu_to_le64(sg_dma_address(sg
));
235 sge
->len
= cpu_to_le32(sg_dma_len(sg
));
236 dev_dbg(dev
, "addr = %llx, len = %u\n", sge
->addr
, sge
->len
);
240 sgl_addr
= dma_map_single(dev
, sgl
, sgl_size
, DMA_TO_DEVICE
);
241 if (dma_mapping_error(dev
, sgl_addr
)) {
247 lm_file
->sgl_addr
= sgl_addr
;
254 lm_file
->num_sge
= 0;
255 dma_unmap_sgtable(dev
, &lm_file
->sg_table
, dir
, 0);
259 static void pds_vfio_dma_unmap_lm_file(struct device
*dev
,
260 enum dma_data_direction dir
,
261 struct pds_vfio_lm_file
*lm_file
)
268 dma_unmap_single(dev
, lm_file
->sgl_addr
,
269 lm_file
->num_sge
* sizeof(*lm_file
->sgl
),
273 lm_file
->sgl_addr
= DMA_MAPPING_ERROR
;
274 lm_file
->num_sge
= 0;
277 /* dma unmap file pages */
278 dma_unmap_sgtable(dev
, &lm_file
->sg_table
, dir
, 0);
281 int pds_vfio_get_lm_state_cmd(struct pds_vfio_pci_device
*pds_vfio
)
283 union pds_core_adminq_cmd cmd
= {
285 .opcode
= PDS_LM_CMD_SAVE
,
286 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
289 struct pci_dev
*pdev
= pds_vfio_to_pci_dev(pds_vfio
);
290 struct device
*pdsc_dev
= &pci_physfn(pdev
)->dev
;
291 union pds_core_adminq_comp comp
= {};
292 struct pds_vfio_lm_file
*lm_file
;
295 dev_dbg(&pdev
->dev
, "vf%u: Get migration state\n", pds_vfio
->vf_id
);
297 lm_file
= pds_vfio
->save_file
;
299 err
= pds_vfio_dma_map_lm_file(pdsc_dev
, DMA_FROM_DEVICE
, lm_file
);
301 dev_err(&pdev
->dev
, "failed to map save migration file: %pe\n",
306 cmd
.lm_save
.sgl_addr
= cpu_to_le64(lm_file
->sgl_addr
);
307 cmd
.lm_save
.num_sge
= cpu_to_le32(lm_file
->num_sge
);
309 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
311 dev_err(&pdev
->dev
, "failed to get migration state: %pe\n",
314 pds_vfio_dma_unmap_lm_file(pdsc_dev
, DMA_FROM_DEVICE
, lm_file
);
319 int pds_vfio_set_lm_state_cmd(struct pds_vfio_pci_device
*pds_vfio
)
321 union pds_core_adminq_cmd cmd
= {
323 .opcode
= PDS_LM_CMD_RESTORE
,
324 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
327 struct pci_dev
*pdev
= pds_vfio_to_pci_dev(pds_vfio
);
328 struct device
*pdsc_dev
= &pci_physfn(pdev
)->dev
;
329 union pds_core_adminq_comp comp
= {};
330 struct pds_vfio_lm_file
*lm_file
;
333 dev_dbg(&pdev
->dev
, "vf%u: Set migration state\n", pds_vfio
->vf_id
);
335 lm_file
= pds_vfio
->restore_file
;
337 err
= pds_vfio_dma_map_lm_file(pdsc_dev
, DMA_TO_DEVICE
, lm_file
);
340 "failed to map restore migration file: %pe\n",
345 cmd
.lm_restore
.sgl_addr
= cpu_to_le64(lm_file
->sgl_addr
);
346 cmd
.lm_restore
.num_sge
= cpu_to_le32(lm_file
->num_sge
);
348 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
350 dev_err(&pdev
->dev
, "failed to set migration state: %pe\n",
353 pds_vfio_dma_unmap_lm_file(pdsc_dev
, DMA_TO_DEVICE
, lm_file
);
358 void pds_vfio_send_host_vf_lm_status_cmd(struct pds_vfio_pci_device
*pds_vfio
,
359 enum pds_lm_host_vf_status vf_status
)
361 union pds_core_adminq_cmd cmd
= {
362 .lm_host_vf_status
= {
363 .opcode
= PDS_LM_CMD_HOST_VF_STATUS
,
364 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
368 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
369 union pds_core_adminq_comp comp
= {};
372 dev_dbg(dev
, "vf%u: Set host VF LM status: %u", pds_vfio
->vf_id
,
374 if (vf_status
!= PDS_LM_STA_IN_PROGRESS
&&
375 vf_status
!= PDS_LM_STA_NONE
) {
376 dev_warn(dev
, "Invalid host VF migration status, %d\n",
381 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
383 dev_warn(dev
, "failed to send host VF migration status: %pe\n",
387 int pds_vfio_dirty_status_cmd(struct pds_vfio_pci_device
*pds_vfio
,
388 u64 regions_dma
, u8
*max_regions
, u8
*num_regions
)
390 union pds_core_adminq_cmd cmd
= {
392 .opcode
= PDS_LM_CMD_DIRTY_STATUS
,
393 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
396 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
397 union pds_core_adminq_comp comp
= {};
400 dev_dbg(dev
, "vf%u: Dirty status\n", pds_vfio
->vf_id
);
402 cmd
.lm_dirty_status
.regions_dma
= cpu_to_le64(regions_dma
);
403 cmd
.lm_dirty_status
.max_regions
= *max_regions
;
405 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
407 dev_err(dev
, "failed to get dirty status: %pe\n", ERR_PTR(err
));
411 /* only support seq_ack approach for now */
412 if (!(le32_to_cpu(comp
.lm_dirty_status
.bmp_type_mask
) &
413 BIT(PDS_LM_DIRTY_BMP_TYPE_SEQ_ACK
))) {
414 dev_err(dev
, "Dirty bitmap tracking SEQ_ACK not supported\n");
418 *num_regions
= comp
.lm_dirty_status
.num_regions
;
419 *max_regions
= comp
.lm_dirty_status
.max_regions
;
422 "Page Tracking Status command successful, max_regions: %d, num_regions: %d, bmp_type: %s\n",
423 *max_regions
, *num_regions
, "PDS_LM_DIRTY_BMP_TYPE_SEQ_ACK");
428 int pds_vfio_dirty_enable_cmd(struct pds_vfio_pci_device
*pds_vfio
,
429 u64 regions_dma
, u8 num_regions
)
431 union pds_core_adminq_cmd cmd
= {
433 .opcode
= PDS_LM_CMD_DIRTY_ENABLE
,
434 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
435 .regions_dma
= cpu_to_le64(regions_dma
),
436 .bmp_type
= PDS_LM_DIRTY_BMP_TYPE_SEQ_ACK
,
437 .num_regions
= num_regions
,
440 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
441 union pds_core_adminq_comp comp
= {};
444 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
446 dev_err(dev
, "failed dirty tracking enable: %pe\n",
454 int pds_vfio_dirty_disable_cmd(struct pds_vfio_pci_device
*pds_vfio
)
456 union pds_core_adminq_cmd cmd
= {
457 .lm_dirty_disable
= {
458 .opcode
= PDS_LM_CMD_DIRTY_DISABLE
,
459 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
462 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
463 union pds_core_adminq_comp comp
= {};
466 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
467 if (err
|| comp
.lm_dirty_status
.num_regions
!= 0) {
468 /* in case num_regions is still non-zero after disable */
469 err
= err
? err
: -EIO
;
471 "failed dirty tracking disable: %pe, num_regions %d\n",
472 ERR_PTR(err
), comp
.lm_dirty_status
.num_regions
);
479 int pds_vfio_dirty_seq_ack_cmd(struct pds_vfio_pci_device
*pds_vfio
,
480 u64 sgl_dma
, u16 num_sge
, u32 offset
,
481 u32 total_len
, bool read_seq
)
483 const char *cmd_type_str
= read_seq
? "read_seq" : "write_ack";
484 union pds_core_adminq_cmd cmd
= {
485 .lm_dirty_seq_ack
= {
486 .vf_id
= cpu_to_le16(pds_vfio
->vf_id
),
487 .len_bytes
= cpu_to_le32(total_len
),
488 .off_bytes
= cpu_to_le32(offset
),
489 .sgl_addr
= cpu_to_le64(sgl_dma
),
490 .num_sge
= cpu_to_le16(num_sge
),
493 struct device
*dev
= pds_vfio_to_dev(pds_vfio
);
494 union pds_core_adminq_comp comp
= {};
498 cmd
.lm_dirty_seq_ack
.opcode
= PDS_LM_CMD_DIRTY_READ_SEQ
;
500 cmd
.lm_dirty_seq_ack
.opcode
= PDS_LM_CMD_DIRTY_WRITE_ACK
;
502 err
= pds_vfio_client_adminq_cmd(pds_vfio
, &cmd
, &comp
, false);
504 dev_err(dev
, "failed cmd Page Tracking %s: %pe\n", cmd_type_str
,