162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright(c) 2023 Advanced Micro Devices, Inc */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/auxiliary_bus.h> 562306a36Sopenharmony_ci#include <linux/pci.h> 662306a36Sopenharmony_ci#include <linux/vdpa.h> 762306a36Sopenharmony_ci#include <linux/virtio_pci_modern.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/pds/pds_common.h> 1062306a36Sopenharmony_ci#include <linux/pds/pds_core_if.h> 1162306a36Sopenharmony_ci#include <linux/pds/pds_adminq.h> 1262306a36Sopenharmony_ci#include <linux/pds/pds_auxbus.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "aux_drv.h" 1562306a36Sopenharmony_ci#include "debugfs.h" 1662306a36Sopenharmony_ci#include "vdpa_dev.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const struct auxiliary_device_id pds_vdpa_id_table[] = { 1962306a36Sopenharmony_ci { .name = PDS_VDPA_DEV_NAME, }, 2062306a36Sopenharmony_ci {}, 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int pds_vdpa_device_id_check(struct pci_dev *pdev) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci if (pdev->device != PCI_DEVICE_ID_PENSANDO_VDPA_VF || 2662306a36Sopenharmony_ci pdev->vendor != PCI_VENDOR_ID_PENSANDO) 2762306a36Sopenharmony_ci return -ENODEV; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return PCI_DEVICE_ID_PENSANDO_VDPA_VF; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int pds_vdpa_probe(struct auxiliary_device *aux_dev, 3362306a36Sopenharmony_ci const struct auxiliary_device_id *id) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct pds_auxiliary_dev *padev = 3762306a36Sopenharmony_ci container_of(aux_dev, struct pds_auxiliary_dev, aux_dev); 3862306a36Sopenharmony_ci struct device *dev = &aux_dev->dev; 3962306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux; 4062306a36Sopenharmony_ci int err; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci vdpa_aux = kzalloc(sizeof(*vdpa_aux), GFP_KERNEL); 4362306a36Sopenharmony_ci if (!vdpa_aux) 4462306a36Sopenharmony_ci return -ENOMEM; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci vdpa_aux->padev = padev; 4762306a36Sopenharmony_ci vdpa_aux->vf_id = pci_iov_vf_id(padev->vf_pdev); 4862306a36Sopenharmony_ci auxiliary_set_drvdata(aux_dev, vdpa_aux); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Get device ident info and set up the vdpa_mgmt_dev */ 5162306a36Sopenharmony_ci err = pds_vdpa_get_mgmt_info(vdpa_aux); 5262306a36Sopenharmony_ci if (err) 5362306a36Sopenharmony_ci goto err_free_mem; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Find the virtio configuration */ 5662306a36Sopenharmony_ci vdpa_aux->vd_mdev.pci_dev = padev->vf_pdev; 5762306a36Sopenharmony_ci vdpa_aux->vd_mdev.device_id_check = pds_vdpa_device_id_check; 5862306a36Sopenharmony_ci vdpa_aux->vd_mdev.dma_mask = DMA_BIT_MASK(PDS_CORE_ADDR_LEN); 5962306a36Sopenharmony_ci err = vp_modern_probe(&vdpa_aux->vd_mdev); 6062306a36Sopenharmony_ci if (err) { 6162306a36Sopenharmony_ci dev_err(dev, "Unable to probe for virtio configuration: %pe\n", 6262306a36Sopenharmony_ci ERR_PTR(err)); 6362306a36Sopenharmony_ci goto err_free_mgmt_info; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Let vdpa know that we can provide devices */ 6762306a36Sopenharmony_ci err = vdpa_mgmtdev_register(&vdpa_aux->vdpa_mdev); 6862306a36Sopenharmony_ci if (err) { 6962306a36Sopenharmony_ci dev_err(dev, "%s: Failed to initialize vdpa_mgmt interface: %pe\n", 7062306a36Sopenharmony_ci __func__, ERR_PTR(err)); 7162306a36Sopenharmony_ci goto err_free_virtio; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci pds_vdpa_debugfs_add_pcidev(vdpa_aux); 7562306a36Sopenharmony_ci pds_vdpa_debugfs_add_ident(vdpa_aux); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cierr_free_virtio: 8062306a36Sopenharmony_ci vp_modern_remove(&vdpa_aux->vd_mdev); 8162306a36Sopenharmony_cierr_free_mgmt_info: 8262306a36Sopenharmony_ci pci_free_irq_vectors(padev->vf_pdev); 8362306a36Sopenharmony_cierr_free_mem: 8462306a36Sopenharmony_ci kfree(vdpa_aux); 8562306a36Sopenharmony_ci auxiliary_set_drvdata(aux_dev, NULL); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return err; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void pds_vdpa_remove(struct auxiliary_device *aux_dev) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct pds_vdpa_aux *vdpa_aux = auxiliary_get_drvdata(aux_dev); 9362306a36Sopenharmony_ci struct device *dev = &aux_dev->dev; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci vdpa_mgmtdev_unregister(&vdpa_aux->vdpa_mdev); 9662306a36Sopenharmony_ci vp_modern_remove(&vdpa_aux->vd_mdev); 9762306a36Sopenharmony_ci pci_free_irq_vectors(vdpa_aux->padev->vf_pdev); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci pds_vdpa_debugfs_del_vdpadev(vdpa_aux); 10062306a36Sopenharmony_ci kfree(vdpa_aux); 10162306a36Sopenharmony_ci auxiliary_set_drvdata(aux_dev, NULL); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci dev_info(dev, "Removed\n"); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic struct auxiliary_driver pds_vdpa_driver = { 10762306a36Sopenharmony_ci .name = PDS_DEV_TYPE_VDPA_STR, 10862306a36Sopenharmony_ci .probe = pds_vdpa_probe, 10962306a36Sopenharmony_ci .remove = pds_vdpa_remove, 11062306a36Sopenharmony_ci .id_table = pds_vdpa_id_table, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void __exit pds_vdpa_cleanup(void) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci auxiliary_driver_unregister(&pds_vdpa_driver); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci pds_vdpa_debugfs_destroy(); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_cimodule_exit(pds_vdpa_cleanup); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int __init pds_vdpa_init(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int err; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci pds_vdpa_debugfs_create(); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci err = auxiliary_driver_register(&pds_vdpa_driver); 12862306a36Sopenharmony_ci if (err) { 12962306a36Sopenharmony_ci pr_err("%s: aux driver register failed: %pe\n", 13062306a36Sopenharmony_ci PDS_VDPA_DRV_NAME, ERR_PTR(err)); 13162306a36Sopenharmony_ci pds_vdpa_debugfs_destroy(); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return err; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_cimodule_init(pds_vdpa_init); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciMODULE_DESCRIPTION(PDS_VDPA_DRV_DESCRIPTION); 13962306a36Sopenharmony_ciMODULE_AUTHOR("Advanced Micro Devices, Inc"); 14062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 141