1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 4 #include <linux/auxiliary_bus.h> 5 #include <linux/pci.h> 6 #include <linux/vdpa.h> 7 #include <linux/virtio_pci_modern.h> 8 9 #include <linux/pds/pds_common.h> 10 #include <linux/pds/pds_core_if.h> 11 #include <linux/pds/pds_adminq.h> 12 #include <linux/pds/pds_auxbus.h> 13 14 #include "aux_drv.h" 15 #include "debugfs.h" 16 #include "vdpa_dev.h" 17 18 static const struct auxiliary_device_id pds_vdpa_id_table[] = { 19 { .name = PDS_VDPA_DEV_NAME, }, 20 {}, 21 }; 22 23 static int pds_vdpa_device_id_check(struct pci_dev *pdev) 24 { 25 if (pdev->device != PCI_DEVICE_ID_PENSANDO_VDPA_VF || 26 pdev->vendor != PCI_VENDOR_ID_PENSANDO) 27 return -ENODEV; 28 29 return PCI_DEVICE_ID_PENSANDO_VDPA_VF; 30 } 31 32 static int pds_vdpa_probe(struct auxiliary_device *aux_dev, 33 const struct auxiliary_device_id *id) 34 35 { 36 struct pds_auxiliary_dev *padev = 37 container_of(aux_dev, struct pds_auxiliary_dev, aux_dev); 38 struct device *dev = &aux_dev->dev; 39 struct pds_vdpa_aux *vdpa_aux; 40 int err; 41 42 vdpa_aux = kzalloc(sizeof(*vdpa_aux), GFP_KERNEL); 43 if (!vdpa_aux) 44 return -ENOMEM; 45 46 vdpa_aux->padev = padev; 47 vdpa_aux->vf_id = pci_iov_vf_id(padev->vf_pdev); 48 auxiliary_set_drvdata(aux_dev, vdpa_aux); 49 50 /* Get device ident info and set up the vdpa_mgmt_dev */ 51 err = pds_vdpa_get_mgmt_info(vdpa_aux); 52 if (err) 53 goto err_free_mem; 54 55 /* Find the virtio configuration */ 56 vdpa_aux->vd_mdev.pci_dev = padev->vf_pdev; 57 vdpa_aux->vd_mdev.device_id_check = pds_vdpa_device_id_check; 58 vdpa_aux->vd_mdev.dma_mask = DMA_BIT_MASK(PDS_CORE_ADDR_LEN); 59 err = vp_modern_probe(&vdpa_aux->vd_mdev); 60 if (err) { 61 dev_err(dev, "Unable to probe for virtio configuration: %pe\n", 62 ERR_PTR(err)); 63 goto err_free_mgmt_info; 64 } 65 66 /* Let vdpa know that we can provide devices */ 67 err = vdpa_mgmtdev_register(&vdpa_aux->vdpa_mdev); 68 if (err) { 69 dev_err(dev, "%s: Failed to initialize vdpa_mgmt interface: %pe\n", 70 __func__, ERR_PTR(err)); 71 goto err_free_virtio; 72 } 73 74 pds_vdpa_debugfs_add_pcidev(vdpa_aux); 75 pds_vdpa_debugfs_add_ident(vdpa_aux); 76 77 return 0; 78 79 err_free_virtio: 80 vp_modern_remove(&vdpa_aux->vd_mdev); 81 err_free_mgmt_info: 82 pci_free_irq_vectors(padev->vf_pdev); 83 err_free_mem: 84 kfree(vdpa_aux); 85 auxiliary_set_drvdata(aux_dev, NULL); 86 87 return err; 88 } 89 90 static void pds_vdpa_remove(struct auxiliary_device *aux_dev) 91 { 92 struct pds_vdpa_aux *vdpa_aux = auxiliary_get_drvdata(aux_dev); 93 struct device *dev = &aux_dev->dev; 94 95 vdpa_mgmtdev_unregister(&vdpa_aux->vdpa_mdev); 96 vp_modern_remove(&vdpa_aux->vd_mdev); 97 pci_free_irq_vectors(vdpa_aux->padev->vf_pdev); 98 99 pds_vdpa_debugfs_del_vdpadev(vdpa_aux); 100 kfree(vdpa_aux); 101 auxiliary_set_drvdata(aux_dev, NULL); 102 103 dev_info(dev, "Removed\n"); 104 } 105 106 static struct auxiliary_driver pds_vdpa_driver = { 107 .name = PDS_DEV_TYPE_VDPA_STR, 108 .probe = pds_vdpa_probe, 109 .remove = pds_vdpa_remove, 110 .id_table = pds_vdpa_id_table, 111 }; 112 113 static void __exit pds_vdpa_cleanup(void) 114 { 115 auxiliary_driver_unregister(&pds_vdpa_driver); 116 117 pds_vdpa_debugfs_destroy(); 118 } 119 module_exit(pds_vdpa_cleanup); 120 121 static int __init pds_vdpa_init(void) 122 { 123 int err; 124 125 pds_vdpa_debugfs_create(); 126 127 err = auxiliary_driver_register(&pds_vdpa_driver); 128 if (err) { 129 pr_err("%s: aux driver register failed: %pe\n", 130 PDS_VDPA_DRV_NAME, ERR_PTR(err)); 131 pds_vdpa_debugfs_destroy(); 132 } 133 134 return err; 135 } 136 module_init(pds_vdpa_init); 137 138 MODULE_DESCRIPTION(PDS_VDPA_DRV_DESCRIPTION); 139 MODULE_AUTHOR("Advanced Micro Devices, Inc"); 140 MODULE_LICENSE("GPL"); 141