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