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
18static const struct auxiliary_device_id pds_vdpa_id_table[] = {
19 { .name = PDS_VDPA_DEV_NAME, },
20 {},
21};
22
23static 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
32static 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(size: 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(dev: padev->vf_pdev);
48 auxiliary_set_drvdata(auxdev: aux_dev, data: 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(mdev: &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(mdev: &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
79err_free_virtio:
80 vp_modern_remove(mdev: &vdpa_aux->vd_mdev);
81err_free_mgmt_info:
82 pci_free_irq_vectors(dev: padev->vf_pdev);
83err_free_mem:
84 kfree(objp: vdpa_aux);
85 auxiliary_set_drvdata(auxdev: aux_dev, NULL);
86
87 return err;
88}
89
90static void pds_vdpa_remove(struct auxiliary_device *aux_dev)
91{
92 struct pds_vdpa_aux *vdpa_aux = auxiliary_get_drvdata(auxdev: aux_dev);
93 struct device *dev = &aux_dev->dev;
94
95 vdpa_mgmtdev_unregister(mdev: &vdpa_aux->vdpa_mdev);
96 pds_vdpa_release_irqs(pdsv: vdpa_aux->pdsv);
97 vp_modern_remove(mdev: &vdpa_aux->vd_mdev);
98
99 pds_vdpa_debugfs_del_vdpadev(vdpa_aux);
100 kfree(objp: vdpa_aux);
101 auxiliary_set_drvdata(auxdev: aux_dev, NULL);
102
103 dev_info(dev, "Removed\n");
104}
105
106static 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
113static void __exit pds_vdpa_cleanup(void)
114{
115 auxiliary_driver_unregister(auxdrv: &pds_vdpa_driver);
116
117 pds_vdpa_debugfs_destroy();
118}
119module_exit(pds_vdpa_cleanup);
120
121static 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}
136module_init(pds_vdpa_init);
137
138MODULE_DESCRIPTION(PDS_VDPA_DRV_DESCRIPTION);
139MODULE_AUTHOR("Advanced Micro Devices, Inc");
140MODULE_LICENSE("GPL");
141

source code of linux/drivers/vdpa/pds/aux_drv.c