xref: /linux/drivers/vdpa/pds/aux_drv.c (revision 78c3925c048c752334873f56c3a3d1c9d53e0416)
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 	pds_vdpa_release_irqs(vdpa_aux->pdsv);
97 	vp_modern_remove(&vdpa_aux->vd_mdev);
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