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(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 | |
79 | err_free_virtio: |
80 | vp_modern_remove(mdev: &vdpa_aux->vd_mdev); |
81 | err_free_mgmt_info: |
82 | pci_free_irq_vectors(dev: padev->vf_pdev); |
83 | err_free_mem: |
84 | kfree(objp: vdpa_aux); |
85 | auxiliary_set_drvdata(auxdev: 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(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 | |
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(auxdrv: &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 | |