xref: /linux/drivers/fwctl/pds/main.c (revision 4d09dd11d7d0e7e7f535c0abc7de19b9da6612e9)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) Advanced Micro Devices, Inc */
3 
4 #include <linux/module.h>
5 #include <linux/auxiliary_bus.h>
6 #include <linux/pci.h>
7 #include <linux/vmalloc.h>
8 
9 #include <uapi/fwctl/fwctl.h>
10 #include <uapi/fwctl/pds.h>
11 #include <linux/fwctl.h>
12 
13 #include <linux/pds/pds_common.h>
14 #include <linux/pds/pds_core_if.h>
15 #include <linux/pds/pds_adminq.h>
16 #include <linux/pds/pds_auxbus.h>
17 
18 struct pdsfc_uctx {
19 	struct fwctl_uctx uctx;
20 	u32 uctx_caps;
21 };
22 
23 struct pdsfc_dev {
24 	struct fwctl_device fwctl;
25 	struct pds_auxiliary_dev *padev;
26 	u32 caps;
27 	struct pds_fwctl_ident ident;
28 };
29 
30 static int pdsfc_open_uctx(struct fwctl_uctx *uctx)
31 {
32 	struct pdsfc_dev *pdsfc = container_of(uctx->fwctl, struct pdsfc_dev, fwctl);
33 	struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
34 
35 	pdsfc_uctx->uctx_caps = pdsfc->caps;
36 
37 	return 0;
38 }
39 
40 static void pdsfc_close_uctx(struct fwctl_uctx *uctx)
41 {
42 }
43 
44 static void *pdsfc_info(struct fwctl_uctx *uctx, size_t *length)
45 {
46 	struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
47 	struct fwctl_info_pds *info;
48 
49 	info = kzalloc(sizeof(*info), GFP_KERNEL);
50 	if (!info)
51 		return ERR_PTR(-ENOMEM);
52 
53 	info->uctx_caps = pdsfc_uctx->uctx_caps;
54 
55 	return info;
56 }
57 
58 static int pdsfc_identify(struct pdsfc_dev *pdsfc)
59 {
60 	struct device *dev = &pdsfc->fwctl.dev;
61 	union pds_core_adminq_comp comp = {0};
62 	union pds_core_adminq_cmd cmd;
63 	struct pds_fwctl_ident *ident;
64 	dma_addr_t ident_pa;
65 	int err;
66 
67 	ident = dma_alloc_coherent(dev->parent, sizeof(*ident), &ident_pa, GFP_KERNEL);
68 	if (!ident) {
69 		dev_err(dev, "Failed to map ident buffer\n");
70 		return -ENOMEM;
71 	}
72 
73 	cmd = (union pds_core_adminq_cmd) {
74 		.fwctl_ident = {
75 			.opcode = PDS_FWCTL_CMD_IDENT,
76 			.version = 0,
77 			.len = cpu_to_le32(sizeof(*ident)),
78 			.ident_pa = cpu_to_le64(ident_pa),
79 		}
80 	};
81 
82 	err = pds_client_adminq_cmd(pdsfc->padev, &cmd, sizeof(cmd), &comp, 0);
83 	if (err)
84 		dev_err(dev, "Failed to send adminq cmd opcode: %u err: %d\n",
85 			cmd.fwctl_ident.opcode, err);
86 	else
87 		pdsfc->ident = *ident;
88 
89 	dma_free_coherent(dev->parent, sizeof(*ident), ident, ident_pa);
90 
91 	return err;
92 }
93 
94 static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
95 			  void *in, size_t in_len, size_t *out_len)
96 {
97 	return NULL;
98 }
99 
100 static const struct fwctl_ops pdsfc_ops = {
101 	.device_type = FWCTL_DEVICE_TYPE_PDS,
102 	.uctx_size = sizeof(struct pdsfc_uctx),
103 	.open_uctx = pdsfc_open_uctx,
104 	.close_uctx = pdsfc_close_uctx,
105 	.info = pdsfc_info,
106 	.fw_rpc = pdsfc_fw_rpc,
107 };
108 
109 static int pdsfc_probe(struct auxiliary_device *adev,
110 		       const struct auxiliary_device_id *id)
111 {
112 	struct pds_auxiliary_dev *padev =
113 			container_of(adev, struct pds_auxiliary_dev, aux_dev);
114 	struct device *dev = &adev->dev;
115 	struct pdsfc_dev *pdsfc;
116 	int err;
117 
118 	pdsfc = fwctl_alloc_device(&padev->vf_pdev->dev, &pdsfc_ops,
119 				   struct pdsfc_dev, fwctl);
120 	if (!pdsfc)
121 		return dev_err_probe(dev, -ENOMEM, "Failed to allocate fwctl device struct\n");
122 	pdsfc->padev = padev;
123 
124 	err = pdsfc_identify(pdsfc);
125 	if (err) {
126 		fwctl_put(&pdsfc->fwctl);
127 		return dev_err_probe(dev, err, "Failed to identify device\n");
128 	}
129 
130 	err = fwctl_register(&pdsfc->fwctl);
131 	if (err) {
132 		fwctl_put(&pdsfc->fwctl);
133 		return dev_err_probe(dev, err, "Failed to register device\n");
134 	}
135 
136 	auxiliary_set_drvdata(adev, pdsfc);
137 
138 	return 0;
139 }
140 
141 static void pdsfc_remove(struct auxiliary_device *adev)
142 {
143 	struct pdsfc_dev *pdsfc = auxiliary_get_drvdata(adev);
144 
145 	fwctl_unregister(&pdsfc->fwctl);
146 	fwctl_put(&pdsfc->fwctl);
147 }
148 
149 static const struct auxiliary_device_id pdsfc_id_table[] = {
150 	{.name = PDS_CORE_DRV_NAME "." PDS_DEV_TYPE_FWCTL_STR },
151 	{}
152 };
153 MODULE_DEVICE_TABLE(auxiliary, pdsfc_id_table);
154 
155 static struct auxiliary_driver pdsfc_driver = {
156 	.name = "pds_fwctl",
157 	.probe = pdsfc_probe,
158 	.remove = pdsfc_remove,
159 	.id_table = pdsfc_id_table,
160 };
161 
162 module_auxiliary_driver(pdsfc_driver);
163 
164 MODULE_IMPORT_NS("FWCTL");
165 MODULE_DESCRIPTION("pds fwctl driver");
166 MODULE_AUTHOR("Shannon Nelson <shannon.nelson@amd.com>");
167 MODULE_AUTHOR("Brett Creeley <brett.creeley@amd.com>");
168 MODULE_LICENSE("GPL");
169