138fe3975SBrett Creeley // SPDX-License-Identifier: GPL-2.0 238fe3975SBrett Creeley /* Copyright(c) 2023 Advanced Micro Devices, Inc. */ 338fe3975SBrett Creeley 438fe3975SBrett Creeley #include <linux/vfio.h> 538fe3975SBrett Creeley #include <linux/vfio_pci_core.h> 638fe3975SBrett Creeley 7*bb500dbeSBrett Creeley #include "lm.h" 838fe3975SBrett Creeley #include "vfio_dev.h" 938fe3975SBrett Creeley 1063f77a71SBrett Creeley struct pci_dev *pds_vfio_to_pci_dev(struct pds_vfio_pci_device *pds_vfio) 1163f77a71SBrett Creeley { 1263f77a71SBrett Creeley return pds_vfio->vfio_coredev.pdev; 1363f77a71SBrett Creeley } 1463f77a71SBrett Creeley 15*bb500dbeSBrett Creeley struct device *pds_vfio_to_dev(struct pds_vfio_pci_device *pds_vfio) 16*bb500dbeSBrett Creeley { 17*bb500dbeSBrett Creeley return &pds_vfio_to_pci_dev(pds_vfio)->dev; 18*bb500dbeSBrett Creeley } 19*bb500dbeSBrett Creeley 2038fe3975SBrett Creeley struct pds_vfio_pci_device *pds_vfio_pci_drvdata(struct pci_dev *pdev) 2138fe3975SBrett Creeley { 2238fe3975SBrett Creeley struct vfio_pci_core_device *core_device = dev_get_drvdata(&pdev->dev); 2338fe3975SBrett Creeley 2438fe3975SBrett Creeley return container_of(core_device, struct pds_vfio_pci_device, 2538fe3975SBrett Creeley vfio_coredev); 2638fe3975SBrett Creeley } 2738fe3975SBrett Creeley 28*bb500dbeSBrett Creeley static void pds_vfio_state_mutex_unlock(struct pds_vfio_pci_device *pds_vfio) 29*bb500dbeSBrett Creeley { 30*bb500dbeSBrett Creeley again: 31*bb500dbeSBrett Creeley spin_lock(&pds_vfio->reset_lock); 32*bb500dbeSBrett Creeley if (pds_vfio->deferred_reset) { 33*bb500dbeSBrett Creeley pds_vfio->deferred_reset = false; 34*bb500dbeSBrett Creeley if (pds_vfio->state == VFIO_DEVICE_STATE_ERROR) { 35*bb500dbeSBrett Creeley pds_vfio->state = VFIO_DEVICE_STATE_RUNNING; 36*bb500dbeSBrett Creeley pds_vfio_put_restore_file(pds_vfio); 37*bb500dbeSBrett Creeley pds_vfio_put_save_file(pds_vfio); 38*bb500dbeSBrett Creeley } 39*bb500dbeSBrett Creeley spin_unlock(&pds_vfio->reset_lock); 40*bb500dbeSBrett Creeley goto again; 41*bb500dbeSBrett Creeley } 42*bb500dbeSBrett Creeley mutex_unlock(&pds_vfio->state_mutex); 43*bb500dbeSBrett Creeley spin_unlock(&pds_vfio->reset_lock); 44*bb500dbeSBrett Creeley } 45*bb500dbeSBrett Creeley 46*bb500dbeSBrett Creeley void pds_vfio_reset(struct pds_vfio_pci_device *pds_vfio) 47*bb500dbeSBrett Creeley { 48*bb500dbeSBrett Creeley spin_lock(&pds_vfio->reset_lock); 49*bb500dbeSBrett Creeley pds_vfio->deferred_reset = true; 50*bb500dbeSBrett Creeley if (!mutex_trylock(&pds_vfio->state_mutex)) { 51*bb500dbeSBrett Creeley spin_unlock(&pds_vfio->reset_lock); 52*bb500dbeSBrett Creeley return; 53*bb500dbeSBrett Creeley } 54*bb500dbeSBrett Creeley spin_unlock(&pds_vfio->reset_lock); 55*bb500dbeSBrett Creeley pds_vfio_state_mutex_unlock(pds_vfio); 56*bb500dbeSBrett Creeley } 57*bb500dbeSBrett Creeley 58*bb500dbeSBrett Creeley static struct file * 59*bb500dbeSBrett Creeley pds_vfio_set_device_state(struct vfio_device *vdev, 60*bb500dbeSBrett Creeley enum vfio_device_mig_state new_state) 61*bb500dbeSBrett Creeley { 62*bb500dbeSBrett Creeley struct pds_vfio_pci_device *pds_vfio = 63*bb500dbeSBrett Creeley container_of(vdev, struct pds_vfio_pci_device, 64*bb500dbeSBrett Creeley vfio_coredev.vdev); 65*bb500dbeSBrett Creeley struct file *res = NULL; 66*bb500dbeSBrett Creeley 67*bb500dbeSBrett Creeley mutex_lock(&pds_vfio->state_mutex); 68*bb500dbeSBrett Creeley while (new_state != pds_vfio->state) { 69*bb500dbeSBrett Creeley enum vfio_device_mig_state next_state; 70*bb500dbeSBrett Creeley 71*bb500dbeSBrett Creeley int err = vfio_mig_get_next_state(vdev, pds_vfio->state, 72*bb500dbeSBrett Creeley new_state, &next_state); 73*bb500dbeSBrett Creeley if (err) { 74*bb500dbeSBrett Creeley res = ERR_PTR(err); 75*bb500dbeSBrett Creeley break; 76*bb500dbeSBrett Creeley } 77*bb500dbeSBrett Creeley 78*bb500dbeSBrett Creeley res = pds_vfio_step_device_state_locked(pds_vfio, next_state); 79*bb500dbeSBrett Creeley if (IS_ERR(res)) 80*bb500dbeSBrett Creeley break; 81*bb500dbeSBrett Creeley 82*bb500dbeSBrett Creeley pds_vfio->state = next_state; 83*bb500dbeSBrett Creeley 84*bb500dbeSBrett Creeley if (WARN_ON(res && new_state != pds_vfio->state)) { 85*bb500dbeSBrett Creeley res = ERR_PTR(-EINVAL); 86*bb500dbeSBrett Creeley break; 87*bb500dbeSBrett Creeley } 88*bb500dbeSBrett Creeley } 89*bb500dbeSBrett Creeley pds_vfio_state_mutex_unlock(pds_vfio); 90*bb500dbeSBrett Creeley 91*bb500dbeSBrett Creeley return res; 92*bb500dbeSBrett Creeley } 93*bb500dbeSBrett Creeley 94*bb500dbeSBrett Creeley static int pds_vfio_get_device_state(struct vfio_device *vdev, 95*bb500dbeSBrett Creeley enum vfio_device_mig_state *current_state) 96*bb500dbeSBrett Creeley { 97*bb500dbeSBrett Creeley struct pds_vfio_pci_device *pds_vfio = 98*bb500dbeSBrett Creeley container_of(vdev, struct pds_vfio_pci_device, 99*bb500dbeSBrett Creeley vfio_coredev.vdev); 100*bb500dbeSBrett Creeley 101*bb500dbeSBrett Creeley mutex_lock(&pds_vfio->state_mutex); 102*bb500dbeSBrett Creeley *current_state = pds_vfio->state; 103*bb500dbeSBrett Creeley pds_vfio_state_mutex_unlock(pds_vfio); 104*bb500dbeSBrett Creeley return 0; 105*bb500dbeSBrett Creeley } 106*bb500dbeSBrett Creeley 107*bb500dbeSBrett Creeley static int pds_vfio_get_device_state_size(struct vfio_device *vdev, 108*bb500dbeSBrett Creeley unsigned long *stop_copy_length) 109*bb500dbeSBrett Creeley { 110*bb500dbeSBrett Creeley *stop_copy_length = PDS_LM_DEVICE_STATE_LENGTH; 111*bb500dbeSBrett Creeley return 0; 112*bb500dbeSBrett Creeley } 113*bb500dbeSBrett Creeley 114*bb500dbeSBrett Creeley static const struct vfio_migration_ops pds_vfio_lm_ops = { 115*bb500dbeSBrett Creeley .migration_set_state = pds_vfio_set_device_state, 116*bb500dbeSBrett Creeley .migration_get_state = pds_vfio_get_device_state, 117*bb500dbeSBrett Creeley .migration_get_data_size = pds_vfio_get_device_state_size 118*bb500dbeSBrett Creeley }; 119*bb500dbeSBrett Creeley 12038fe3975SBrett Creeley static int pds_vfio_init_device(struct vfio_device *vdev) 12138fe3975SBrett Creeley { 12238fe3975SBrett Creeley struct pds_vfio_pci_device *pds_vfio = 12338fe3975SBrett Creeley container_of(vdev, struct pds_vfio_pci_device, 12438fe3975SBrett Creeley vfio_coredev.vdev); 12538fe3975SBrett Creeley struct pci_dev *pdev = to_pci_dev(vdev->dev); 12663f77a71SBrett Creeley int err, vf_id, pci_id; 12738fe3975SBrett Creeley 12838fe3975SBrett Creeley vf_id = pci_iov_vf_id(pdev); 12938fe3975SBrett Creeley if (vf_id < 0) 13038fe3975SBrett Creeley return vf_id; 13138fe3975SBrett Creeley 13238fe3975SBrett Creeley err = vfio_pci_core_init_dev(vdev); 13338fe3975SBrett Creeley if (err) 13438fe3975SBrett Creeley return err; 13538fe3975SBrett Creeley 13638fe3975SBrett Creeley pds_vfio->vf_id = vf_id; 13738fe3975SBrett Creeley 138*bb500dbeSBrett Creeley vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P; 139*bb500dbeSBrett Creeley vdev->mig_ops = &pds_vfio_lm_ops; 140*bb500dbeSBrett Creeley 14163f77a71SBrett Creeley pci_id = PCI_DEVID(pdev->bus->number, pdev->devfn); 14263f77a71SBrett Creeley dev_dbg(&pdev->dev, 14363f77a71SBrett Creeley "%s: PF %#04x VF %#04x vf_id %d domain %d pds_vfio %p\n", 14463f77a71SBrett Creeley __func__, pci_dev_id(pdev->physfn), pci_id, vf_id, 14563f77a71SBrett Creeley pci_domain_nr(pdev->bus), pds_vfio); 14663f77a71SBrett Creeley 14738fe3975SBrett Creeley return 0; 14838fe3975SBrett Creeley } 14938fe3975SBrett Creeley 15038fe3975SBrett Creeley static int pds_vfio_open_device(struct vfio_device *vdev) 15138fe3975SBrett Creeley { 15238fe3975SBrett Creeley struct pds_vfio_pci_device *pds_vfio = 15338fe3975SBrett Creeley container_of(vdev, struct pds_vfio_pci_device, 15438fe3975SBrett Creeley vfio_coredev.vdev); 15538fe3975SBrett Creeley int err; 15638fe3975SBrett Creeley 15738fe3975SBrett Creeley err = vfio_pci_core_enable(&pds_vfio->vfio_coredev); 15838fe3975SBrett Creeley if (err) 15938fe3975SBrett Creeley return err; 16038fe3975SBrett Creeley 161*bb500dbeSBrett Creeley mutex_init(&pds_vfio->state_mutex); 162*bb500dbeSBrett Creeley pds_vfio->state = VFIO_DEVICE_STATE_RUNNING; 163*bb500dbeSBrett Creeley 16438fe3975SBrett Creeley vfio_pci_core_finish_enable(&pds_vfio->vfio_coredev); 16538fe3975SBrett Creeley 16638fe3975SBrett Creeley return 0; 16738fe3975SBrett Creeley } 16838fe3975SBrett Creeley 169*bb500dbeSBrett Creeley static void pds_vfio_close_device(struct vfio_device *vdev) 170*bb500dbeSBrett Creeley { 171*bb500dbeSBrett Creeley struct pds_vfio_pci_device *pds_vfio = 172*bb500dbeSBrett Creeley container_of(vdev, struct pds_vfio_pci_device, 173*bb500dbeSBrett Creeley vfio_coredev.vdev); 174*bb500dbeSBrett Creeley 175*bb500dbeSBrett Creeley mutex_lock(&pds_vfio->state_mutex); 176*bb500dbeSBrett Creeley pds_vfio_put_restore_file(pds_vfio); 177*bb500dbeSBrett Creeley pds_vfio_put_save_file(pds_vfio); 178*bb500dbeSBrett Creeley mutex_unlock(&pds_vfio->state_mutex); 179*bb500dbeSBrett Creeley mutex_destroy(&pds_vfio->state_mutex); 180*bb500dbeSBrett Creeley vfio_pci_core_close_device(vdev); 181*bb500dbeSBrett Creeley } 182*bb500dbeSBrett Creeley 18338fe3975SBrett Creeley static const struct vfio_device_ops pds_vfio_ops = { 18438fe3975SBrett Creeley .name = "pds-vfio", 18538fe3975SBrett Creeley .init = pds_vfio_init_device, 18638fe3975SBrett Creeley .release = vfio_pci_core_release_dev, 18738fe3975SBrett Creeley .open_device = pds_vfio_open_device, 188*bb500dbeSBrett Creeley .close_device = pds_vfio_close_device, 18938fe3975SBrett Creeley .ioctl = vfio_pci_core_ioctl, 19038fe3975SBrett Creeley .device_feature = vfio_pci_core_ioctl_feature, 19138fe3975SBrett Creeley .read = vfio_pci_core_read, 19238fe3975SBrett Creeley .write = vfio_pci_core_write, 19338fe3975SBrett Creeley .mmap = vfio_pci_core_mmap, 19438fe3975SBrett Creeley .request = vfio_pci_core_request, 19538fe3975SBrett Creeley .match = vfio_pci_core_match, 19638fe3975SBrett Creeley .bind_iommufd = vfio_iommufd_physical_bind, 19738fe3975SBrett Creeley .unbind_iommufd = vfio_iommufd_physical_unbind, 19838fe3975SBrett Creeley .attach_ioas = vfio_iommufd_physical_attach_ioas, 19938fe3975SBrett Creeley }; 20038fe3975SBrett Creeley 20138fe3975SBrett Creeley const struct vfio_device_ops *pds_vfio_ops_info(void) 20238fe3975SBrett Creeley { 20338fe3975SBrett Creeley return &pds_vfio_ops; 20438fe3975SBrett Creeley } 205