162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2023 Advanced Micro Devices, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/anon_inodes.h> 562306a36Sopenharmony_ci#include <linux/file.h> 662306a36Sopenharmony_ci#include <linux/fs.h> 762306a36Sopenharmony_ci#include <linux/highmem.h> 862306a36Sopenharmony_ci#include <linux/vfio.h> 962306a36Sopenharmony_ci#include <linux/vfio_pci_core.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "vfio_dev.h" 1262306a36Sopenharmony_ci#include "cmds.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic struct pds_vfio_lm_file * 1562306a36Sopenharmony_cipds_vfio_get_lm_file(const struct file_operations *fops, int flags, u64 size) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file = NULL; 1862306a36Sopenharmony_ci unsigned long long npages; 1962306a36Sopenharmony_ci struct page **pages; 2062306a36Sopenharmony_ci void *page_mem; 2162306a36Sopenharmony_ci const void *p; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (!size) 2462306a36Sopenharmony_ci return NULL; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* Alloc file structure */ 2762306a36Sopenharmony_ci lm_file = kzalloc(sizeof(*lm_file), GFP_KERNEL); 2862306a36Sopenharmony_ci if (!lm_file) 2962306a36Sopenharmony_ci return NULL; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* Create file */ 3262306a36Sopenharmony_ci lm_file->filep = 3362306a36Sopenharmony_ci anon_inode_getfile("pds_vfio_lm", fops, lm_file, flags); 3462306a36Sopenharmony_ci if (IS_ERR(lm_file->filep)) 3562306a36Sopenharmony_ci goto out_free_file; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci stream_open(lm_file->filep->f_inode, lm_file->filep); 3862306a36Sopenharmony_ci mutex_init(&lm_file->lock); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* prevent file from being released before we are done with it */ 4162306a36Sopenharmony_ci get_file(lm_file->filep); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Allocate memory for file pages */ 4462306a36Sopenharmony_ci npages = DIV_ROUND_UP_ULL(size, PAGE_SIZE); 4562306a36Sopenharmony_ci pages = kmalloc_array(npages, sizeof(*pages), GFP_KERNEL); 4662306a36Sopenharmony_ci if (!pages) 4762306a36Sopenharmony_ci goto out_put_file; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci page_mem = kvzalloc(ALIGN(size, PAGE_SIZE), GFP_KERNEL); 5062306a36Sopenharmony_ci if (!page_mem) 5162306a36Sopenharmony_ci goto out_free_pages_array; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci p = page_mem - offset_in_page(page_mem); 5462306a36Sopenharmony_ci for (unsigned long long i = 0; i < npages; i++) { 5562306a36Sopenharmony_ci if (is_vmalloc_addr(p)) 5662306a36Sopenharmony_ci pages[i] = vmalloc_to_page(p); 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci pages[i] = kmap_to_page((void *)p); 5962306a36Sopenharmony_ci if (!pages[i]) 6062306a36Sopenharmony_ci goto out_free_page_mem; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci p += PAGE_SIZE; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Create scatterlist of file pages to use for DMA mapping later */ 6662306a36Sopenharmony_ci if (sg_alloc_table_from_pages(&lm_file->sg_table, pages, npages, 0, 6762306a36Sopenharmony_ci size, GFP_KERNEL)) 6862306a36Sopenharmony_ci goto out_free_page_mem; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci lm_file->size = size; 7162306a36Sopenharmony_ci lm_file->pages = pages; 7262306a36Sopenharmony_ci lm_file->npages = npages; 7362306a36Sopenharmony_ci lm_file->page_mem = page_mem; 7462306a36Sopenharmony_ci lm_file->alloc_size = npages * PAGE_SIZE; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return lm_file; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciout_free_page_mem: 7962306a36Sopenharmony_ci kvfree(page_mem); 8062306a36Sopenharmony_ciout_free_pages_array: 8162306a36Sopenharmony_ci kfree(pages); 8262306a36Sopenharmony_ciout_put_file: 8362306a36Sopenharmony_ci fput(lm_file->filep); 8462306a36Sopenharmony_ci mutex_destroy(&lm_file->lock); 8562306a36Sopenharmony_ciout_free_file: 8662306a36Sopenharmony_ci kfree(lm_file); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return NULL; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void pds_vfio_put_lm_file(struct pds_vfio_lm_file *lm_file) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci mutex_lock(&lm_file->lock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci lm_file->size = 0; 9662306a36Sopenharmony_ci lm_file->alloc_size = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Free scatter list of file pages */ 9962306a36Sopenharmony_ci sg_free_table(&lm_file->sg_table); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci kvfree(lm_file->page_mem); 10262306a36Sopenharmony_ci lm_file->page_mem = NULL; 10362306a36Sopenharmony_ci kfree(lm_file->pages); 10462306a36Sopenharmony_ci lm_file->pages = NULL; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci mutex_unlock(&lm_file->lock); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* allow file to be released since we are done with it */ 10962306a36Sopenharmony_ci fput(lm_file->filep); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid pds_vfio_put_save_file(struct pds_vfio_pci_device *pds_vfio) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci if (!pds_vfio->save_file) 11562306a36Sopenharmony_ci return; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci pds_vfio_put_lm_file(pds_vfio->save_file); 11862306a36Sopenharmony_ci pds_vfio->save_file = NULL; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_civoid pds_vfio_put_restore_file(struct pds_vfio_pci_device *pds_vfio) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (!pds_vfio->restore_file) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pds_vfio_put_lm_file(pds_vfio->restore_file); 12762306a36Sopenharmony_ci pds_vfio->restore_file = NULL; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct page *pds_vfio_get_file_page(struct pds_vfio_lm_file *lm_file, 13162306a36Sopenharmony_ci unsigned long offset) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci unsigned long cur_offset = 0; 13462306a36Sopenharmony_ci struct scatterlist *sg; 13562306a36Sopenharmony_ci unsigned int i; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* All accesses are sequential */ 13862306a36Sopenharmony_ci if (offset < lm_file->last_offset || !lm_file->last_offset_sg) { 13962306a36Sopenharmony_ci lm_file->last_offset = 0; 14062306a36Sopenharmony_ci lm_file->last_offset_sg = lm_file->sg_table.sgl; 14162306a36Sopenharmony_ci lm_file->sg_last_entry = 0; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci cur_offset = lm_file->last_offset; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci for_each_sg(lm_file->last_offset_sg, sg, 14762306a36Sopenharmony_ci lm_file->sg_table.orig_nents - lm_file->sg_last_entry, i) { 14862306a36Sopenharmony_ci if (offset < sg->length + cur_offset) { 14962306a36Sopenharmony_ci lm_file->last_offset_sg = sg; 15062306a36Sopenharmony_ci lm_file->sg_last_entry += i; 15162306a36Sopenharmony_ci lm_file->last_offset = cur_offset; 15262306a36Sopenharmony_ci return nth_page(sg_page(sg), 15362306a36Sopenharmony_ci (offset - cur_offset) / PAGE_SIZE); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci cur_offset += sg->length; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return NULL; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int pds_vfio_release_file(struct inode *inode, struct file *filp) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file = filp->private_data; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci mutex_lock(&lm_file->lock); 16662306a36Sopenharmony_ci lm_file->filep->f_pos = 0; 16762306a36Sopenharmony_ci lm_file->size = 0; 16862306a36Sopenharmony_ci mutex_unlock(&lm_file->lock); 16962306a36Sopenharmony_ci mutex_destroy(&lm_file->lock); 17062306a36Sopenharmony_ci kfree(lm_file); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic ssize_t pds_vfio_save_read(struct file *filp, char __user *buf, 17662306a36Sopenharmony_ci size_t len, loff_t *pos) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file = filp->private_data; 17962306a36Sopenharmony_ci ssize_t done = 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (pos) 18262306a36Sopenharmony_ci return -ESPIPE; 18362306a36Sopenharmony_ci pos = &filp->f_pos; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci mutex_lock(&lm_file->lock); 18662306a36Sopenharmony_ci if (*pos > lm_file->size) { 18762306a36Sopenharmony_ci done = -EINVAL; 18862306a36Sopenharmony_ci goto out_unlock; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci len = min_t(size_t, lm_file->size - *pos, len); 19262306a36Sopenharmony_ci while (len) { 19362306a36Sopenharmony_ci size_t page_offset; 19462306a36Sopenharmony_ci struct page *page; 19562306a36Sopenharmony_ci size_t page_len; 19662306a36Sopenharmony_ci u8 *from_buff; 19762306a36Sopenharmony_ci int err; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci page_offset = (*pos) % PAGE_SIZE; 20062306a36Sopenharmony_ci page = pds_vfio_get_file_page(lm_file, *pos - page_offset); 20162306a36Sopenharmony_ci if (!page) { 20262306a36Sopenharmony_ci if (done == 0) 20362306a36Sopenharmony_ci done = -EINVAL; 20462306a36Sopenharmony_ci goto out_unlock; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci page_len = min_t(size_t, len, PAGE_SIZE - page_offset); 20862306a36Sopenharmony_ci from_buff = kmap_local_page(page); 20962306a36Sopenharmony_ci err = copy_to_user(buf, from_buff + page_offset, page_len); 21062306a36Sopenharmony_ci kunmap_local(from_buff); 21162306a36Sopenharmony_ci if (err) { 21262306a36Sopenharmony_ci done = -EFAULT; 21362306a36Sopenharmony_ci goto out_unlock; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci *pos += page_len; 21662306a36Sopenharmony_ci len -= page_len; 21762306a36Sopenharmony_ci done += page_len; 21862306a36Sopenharmony_ci buf += page_len; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciout_unlock: 22262306a36Sopenharmony_ci mutex_unlock(&lm_file->lock); 22362306a36Sopenharmony_ci return done; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic const struct file_operations pds_vfio_save_fops = { 22762306a36Sopenharmony_ci .owner = THIS_MODULE, 22862306a36Sopenharmony_ci .read = pds_vfio_save_read, 22962306a36Sopenharmony_ci .release = pds_vfio_release_file, 23062306a36Sopenharmony_ci .llseek = no_llseek, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int pds_vfio_get_save_file(struct pds_vfio_pci_device *pds_vfio) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct device *dev = &pds_vfio->vfio_coredev.pdev->dev; 23662306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file; 23762306a36Sopenharmony_ci u64 size; 23862306a36Sopenharmony_ci int err; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Get live migration state size in this state */ 24162306a36Sopenharmony_ci err = pds_vfio_get_lm_state_size_cmd(pds_vfio, &size); 24262306a36Sopenharmony_ci if (err) { 24362306a36Sopenharmony_ci dev_err(dev, "failed to get save status: %pe\n", ERR_PTR(err)); 24462306a36Sopenharmony_ci return err; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci dev_dbg(dev, "save status, size = %lld\n", size); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!size) { 25062306a36Sopenharmony_ci dev_err(dev, "invalid state size\n"); 25162306a36Sopenharmony_ci return -EIO; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci lm_file = pds_vfio_get_lm_file(&pds_vfio_save_fops, O_RDONLY, size); 25562306a36Sopenharmony_ci if (!lm_file) { 25662306a36Sopenharmony_ci dev_err(dev, "failed to create save file\n"); 25762306a36Sopenharmony_ci return -ENOENT; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci dev_dbg(dev, "size = %lld, alloc_size = %lld, npages = %lld\n", 26162306a36Sopenharmony_ci lm_file->size, lm_file->alloc_size, lm_file->npages); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci pds_vfio->save_file = lm_file; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic ssize_t pds_vfio_restore_write(struct file *filp, const char __user *buf, 26962306a36Sopenharmony_ci size_t len, loff_t *pos) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file = filp->private_data; 27262306a36Sopenharmony_ci loff_t requested_length; 27362306a36Sopenharmony_ci ssize_t done = 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (pos) 27662306a36Sopenharmony_ci return -ESPIPE; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pos = &filp->f_pos; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (*pos < 0 || 28162306a36Sopenharmony_ci check_add_overflow((loff_t)len, *pos, &requested_length)) 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci mutex_lock(&lm_file->lock); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci while (len) { 28762306a36Sopenharmony_ci size_t page_offset; 28862306a36Sopenharmony_ci struct page *page; 28962306a36Sopenharmony_ci size_t page_len; 29062306a36Sopenharmony_ci u8 *to_buff; 29162306a36Sopenharmony_ci int err; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci page_offset = (*pos) % PAGE_SIZE; 29462306a36Sopenharmony_ci page = pds_vfio_get_file_page(lm_file, *pos - page_offset); 29562306a36Sopenharmony_ci if (!page) { 29662306a36Sopenharmony_ci if (done == 0) 29762306a36Sopenharmony_ci done = -EINVAL; 29862306a36Sopenharmony_ci goto out_unlock; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci page_len = min_t(size_t, len, PAGE_SIZE - page_offset); 30262306a36Sopenharmony_ci to_buff = kmap_local_page(page); 30362306a36Sopenharmony_ci err = copy_from_user(to_buff + page_offset, buf, page_len); 30462306a36Sopenharmony_ci kunmap_local(to_buff); 30562306a36Sopenharmony_ci if (err) { 30662306a36Sopenharmony_ci done = -EFAULT; 30762306a36Sopenharmony_ci goto out_unlock; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci *pos += page_len; 31062306a36Sopenharmony_ci len -= page_len; 31162306a36Sopenharmony_ci done += page_len; 31262306a36Sopenharmony_ci buf += page_len; 31362306a36Sopenharmony_ci lm_file->size += page_len; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ciout_unlock: 31662306a36Sopenharmony_ci mutex_unlock(&lm_file->lock); 31762306a36Sopenharmony_ci return done; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic const struct file_operations pds_vfio_restore_fops = { 32162306a36Sopenharmony_ci .owner = THIS_MODULE, 32262306a36Sopenharmony_ci .write = pds_vfio_restore_write, 32362306a36Sopenharmony_ci .release = pds_vfio_release_file, 32462306a36Sopenharmony_ci .llseek = no_llseek, 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int pds_vfio_get_restore_file(struct pds_vfio_pci_device *pds_vfio) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct device *dev = &pds_vfio->vfio_coredev.pdev->dev; 33062306a36Sopenharmony_ci struct pds_vfio_lm_file *lm_file; 33162306a36Sopenharmony_ci u64 size; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci size = sizeof(union pds_lm_dev_state); 33462306a36Sopenharmony_ci dev_dbg(dev, "restore status, size = %lld\n", size); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!size) { 33762306a36Sopenharmony_ci dev_err(dev, "invalid state size"); 33862306a36Sopenharmony_ci return -EIO; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci lm_file = pds_vfio_get_lm_file(&pds_vfio_restore_fops, O_WRONLY, size); 34262306a36Sopenharmony_ci if (!lm_file) { 34362306a36Sopenharmony_ci dev_err(dev, "failed to create restore file"); 34462306a36Sopenharmony_ci return -ENOENT; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci pds_vfio->restore_file = lm_file; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistruct file * 35262306a36Sopenharmony_cipds_vfio_step_device_state_locked(struct pds_vfio_pci_device *pds_vfio, 35362306a36Sopenharmony_ci enum vfio_device_mig_state next) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci enum vfio_device_mig_state cur = pds_vfio->state; 35662306a36Sopenharmony_ci int err; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_STOP && next == VFIO_DEVICE_STATE_STOP_COPY) { 35962306a36Sopenharmony_ci err = pds_vfio_get_save_file(pds_vfio); 36062306a36Sopenharmony_ci if (err) 36162306a36Sopenharmony_ci return ERR_PTR(err); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci err = pds_vfio_get_lm_state_cmd(pds_vfio); 36462306a36Sopenharmony_ci if (err) { 36562306a36Sopenharmony_ci pds_vfio_put_save_file(pds_vfio); 36662306a36Sopenharmony_ci return ERR_PTR(err); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return pds_vfio->save_file->filep; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_STOP_COPY && next == VFIO_DEVICE_STATE_STOP) { 37362306a36Sopenharmony_ci pds_vfio_put_save_file(pds_vfio); 37462306a36Sopenharmony_ci pds_vfio_dirty_disable(pds_vfio, true); 37562306a36Sopenharmony_ci return NULL; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_STOP && next == VFIO_DEVICE_STATE_RESUMING) { 37962306a36Sopenharmony_ci err = pds_vfio_get_restore_file(pds_vfio); 38062306a36Sopenharmony_ci if (err) 38162306a36Sopenharmony_ci return ERR_PTR(err); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return pds_vfio->restore_file->filep; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_RESUMING && next == VFIO_DEVICE_STATE_STOP) { 38762306a36Sopenharmony_ci err = pds_vfio_set_lm_state_cmd(pds_vfio); 38862306a36Sopenharmony_ci if (err) 38962306a36Sopenharmony_ci return ERR_PTR(err); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci pds_vfio_put_restore_file(pds_vfio); 39262306a36Sopenharmony_ci return NULL; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_RUNNING && next == VFIO_DEVICE_STATE_RUNNING_P2P) { 39662306a36Sopenharmony_ci pds_vfio_send_host_vf_lm_status_cmd(pds_vfio, 39762306a36Sopenharmony_ci PDS_LM_STA_IN_PROGRESS); 39862306a36Sopenharmony_ci err = pds_vfio_suspend_device_cmd(pds_vfio, 39962306a36Sopenharmony_ci PDS_LM_SUSPEND_RESUME_TYPE_P2P); 40062306a36Sopenharmony_ci if (err) 40162306a36Sopenharmony_ci return ERR_PTR(err); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return NULL; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_RUNNING_P2P && next == VFIO_DEVICE_STATE_RUNNING) { 40762306a36Sopenharmony_ci err = pds_vfio_resume_device_cmd(pds_vfio, 40862306a36Sopenharmony_ci PDS_LM_SUSPEND_RESUME_TYPE_FULL); 40962306a36Sopenharmony_ci if (err) 41062306a36Sopenharmony_ci return ERR_PTR(err); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci pds_vfio_send_host_vf_lm_status_cmd(pds_vfio, PDS_LM_STA_NONE); 41362306a36Sopenharmony_ci return NULL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_STOP && next == VFIO_DEVICE_STATE_RUNNING_P2P) { 41762306a36Sopenharmony_ci err = pds_vfio_resume_device_cmd(pds_vfio, 41862306a36Sopenharmony_ci PDS_LM_SUSPEND_RESUME_TYPE_P2P); 41962306a36Sopenharmony_ci if (err) 42062306a36Sopenharmony_ci return ERR_PTR(err); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return NULL; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (cur == VFIO_DEVICE_STATE_RUNNING_P2P && next == VFIO_DEVICE_STATE_STOP) { 42662306a36Sopenharmony_ci err = pds_vfio_suspend_device_cmd(pds_vfio, 42762306a36Sopenharmony_ci PDS_LM_SUSPEND_RESUME_TYPE_FULL); 42862306a36Sopenharmony_ci if (err) 42962306a36Sopenharmony_ci return ERR_PTR(err); 43062306a36Sopenharmony_ci return NULL; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 43462306a36Sopenharmony_ci} 435