raw/dpaa2_qdma: introduce the DPAA2 QDMA driver
[dpdk.git] / drivers / raw / dpaa2_qdma / dpaa2_qdma.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 NXP
3  */
4
5 #include <string.h>
6
7 #include <rte_eal.h>
8 #include <rte_fslmc.h>
9 #include <rte_atomic.h>
10 #include <rte_lcore.h>
11 #include <rte_rawdev.h>
12 #include <rte_rawdev_pmd.h>
13 #include <rte_malloc.h>
14 #include <rte_ring.h>
15 #include <rte_mempool.h>
16
17 #include <mc/fsl_dpdmai.h>
18 #include <portal/dpaa2_hw_pvt.h>
19 #include <portal/dpaa2_hw_dpio.h>
20
21 #include "dpaa2_qdma.h"
22 #include "dpaa2_qdma_logs.h"
23
24 /* Dynamic log type identifier */
25 int dpaa2_qdma_logtype;
26
27 /* QDMA device */
28 static struct qdma_device qdma_dev;
29
30 /* QDMA H/W queues list */
31 TAILQ_HEAD(qdma_hw_queue_list, qdma_hw_queue);
32 static struct qdma_hw_queue_list qdma_queue_list
33         = TAILQ_HEAD_INITIALIZER(qdma_queue_list);
34
35 static const struct rte_rawdev_ops dpaa2_qdma_ops;
36
37 static int
38 add_hw_queues_to_list(struct dpaa2_dpdmai_dev *dpdmai_dev)
39 {
40         struct qdma_hw_queue *queue;
41         int i;
42
43         DPAA2_QDMA_FUNC_TRACE();
44
45         for (i = 0; i < dpdmai_dev->num_queues; i++) {
46                 queue = rte_zmalloc(NULL, sizeof(struct qdma_hw_queue), 0);
47                 if (!queue) {
48                         DPAA2_QDMA_ERR(
49                                 "Memory allocation failed for QDMA queue");
50                         return -ENOMEM;
51                 }
52
53                 queue->dpdmai_dev = dpdmai_dev;
54                 queue->queue_id = i;
55
56                 TAILQ_INSERT_TAIL(&qdma_queue_list, queue, next);
57                 qdma_dev.num_hw_queues++;
58         }
59
60         return 0;
61 }
62
63 static void
64 remove_hw_queues_from_list(struct dpaa2_dpdmai_dev *dpdmai_dev)
65 {
66         struct qdma_hw_queue *queue = NULL;
67         struct qdma_hw_queue *tqueue = NULL;
68
69         DPAA2_QDMA_FUNC_TRACE();
70
71         TAILQ_FOREACH_SAFE(queue, &qdma_queue_list, next, tqueue) {
72                 if (queue->dpdmai_dev == dpdmai_dev) {
73                         TAILQ_REMOVE(&qdma_queue_list, queue, next);
74                         rte_free(queue);
75                         queue = NULL;
76                 }
77         }
78 }
79
80 static int
81 dpaa2_dpdmai_dev_uninit(struct rte_rawdev *rawdev)
82 {
83         struct dpaa2_dpdmai_dev *dpdmai_dev = rawdev->dev_private;
84         int ret, i;
85
86         DPAA2_QDMA_FUNC_TRACE();
87
88         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
89                 return 0;
90
91         /* Remove HW queues from global list */
92         remove_hw_queues_from_list(dpdmai_dev);
93
94         ret = dpdmai_disable(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
95                              dpdmai_dev->token);
96         if (ret)
97                 DPAA2_QDMA_ERR("dmdmai disable failed");
98
99         /* Set up the DQRR storage for Rx */
100         for (i = 0; i < DPDMAI_PRIO_NUM; i++) {
101                 struct dpaa2_queue *rxq = &(dpdmai_dev->rx_queue[i]);
102
103                 if (rxq->q_storage) {
104                         dpaa2_free_dq_storage(rxq->q_storage);
105                         rte_free(rxq->q_storage);
106                 }
107         }
108
109         /* Close the device at underlying layer*/
110         ret = dpdmai_close(&dpdmai_dev->dpdmai, CMD_PRI_LOW, dpdmai_dev->token);
111         if (ret)
112                 DPAA2_QDMA_ERR("Failure closing dpdmai device");
113
114         return 0;
115 }
116
117 static int
118 dpaa2_dpdmai_dev_init(struct rte_rawdev *rawdev, int dpdmai_id)
119 {
120         struct dpaa2_dpdmai_dev *dpdmai_dev = rawdev->dev_private;
121         struct dpdmai_rx_queue_cfg rx_queue_cfg;
122         struct dpdmai_attr attr;
123         struct dpdmai_rx_queue_attr rx_attr;
124         struct dpdmai_tx_queue_attr tx_attr;
125         int ret, i;
126
127         DPAA2_QDMA_FUNC_TRACE();
128
129         /* For secondary processes, the primary has done all the work */
130         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
131                 return 0;
132
133         /* Open DPDMAI device */
134         dpdmai_dev->dpdmai_id = dpdmai_id;
135         dpdmai_dev->dpdmai.regs = rte_mcp_ptr_list[MC_PORTAL_INDEX];
136         ret = dpdmai_open(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
137                           dpdmai_dev->dpdmai_id, &dpdmai_dev->token);
138         if (ret) {
139                 DPAA2_QDMA_ERR("dpdmai_open() failed with err: %d", ret);
140                 return ret;
141         }
142
143         /* Get DPDMAI attributes */
144         ret = dpdmai_get_attributes(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
145                                     dpdmai_dev->token, &attr);
146         if (ret) {
147                 DPAA2_QDMA_ERR("dpdmai get attributes failed with err: %d",
148                                ret);
149                 goto init_err;
150         }
151         dpdmai_dev->num_queues = attr.num_of_priorities;
152
153         /* Set up Rx Queues */
154         for (i = 0; i < attr.num_of_priorities; i++) {
155                 struct dpaa2_queue *rxq;
156
157                 memset(&rx_queue_cfg, 0, sizeof(struct dpdmai_rx_queue_cfg));
158                 ret = dpdmai_set_rx_queue(&dpdmai_dev->dpdmai,
159                                           CMD_PRI_LOW,
160                                           dpdmai_dev->token,
161                                           i, &rx_queue_cfg);
162                 if (ret) {
163                         DPAA2_QDMA_ERR("Setting Rx queue failed with err: %d",
164                                        ret);
165                         goto init_err;
166                 }
167
168                 /* Allocate DQ storage for the DPDMAI Rx queues */
169                 rxq = &(dpdmai_dev->rx_queue[i]);
170                 rxq->q_storage = rte_malloc("dq_storage",
171                                             sizeof(struct queue_storage_info_t),
172                                             RTE_CACHE_LINE_SIZE);
173                 if (!rxq->q_storage) {
174                         DPAA2_QDMA_ERR("q_storage allocation failed");
175                         ret = -ENOMEM;
176                         goto init_err;
177                 }
178
179                 memset(rxq->q_storage, 0, sizeof(struct queue_storage_info_t));
180                 ret = dpaa2_alloc_dq_storage(rxq->q_storage);
181                 if (ret) {
182                         DPAA2_QDMA_ERR("dpaa2_alloc_dq_storage failed");
183                         goto init_err;
184                 }
185         }
186
187         /* Get Rx and Tx queues FQID's */
188         for (i = 0; i < DPDMAI_PRIO_NUM; i++) {
189                 ret = dpdmai_get_rx_queue(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
190                                           dpdmai_dev->token, i, &rx_attr);
191                 if (ret) {
192                         DPAA2_QDMA_ERR("Reading device failed with err: %d",
193                                        ret);
194                         goto init_err;
195                 }
196                 dpdmai_dev->rx_queue[i].fqid = rx_attr.fqid;
197
198                 ret = dpdmai_get_tx_queue(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
199                                           dpdmai_dev->token, i, &tx_attr);
200                 if (ret) {
201                         DPAA2_QDMA_ERR("Reading device failed with err: %d",
202                                        ret);
203                         goto init_err;
204                 }
205                 dpdmai_dev->tx_queue[i].fqid = tx_attr.fqid;
206         }
207
208         /* Enable the device */
209         ret = dpdmai_enable(&dpdmai_dev->dpdmai, CMD_PRI_LOW,
210                             dpdmai_dev->token);
211         if (ret) {
212                 DPAA2_QDMA_ERR("Enabling device failed with err: %d", ret);
213                 goto init_err;
214         }
215
216         /* Add the HW queue to the global list */
217         ret = add_hw_queues_to_list(dpdmai_dev);
218         if (ret) {
219                 DPAA2_QDMA_ERR("Adding H/W queue to list failed");
220                 goto init_err;
221         }
222         DPAA2_QDMA_DEBUG("Initialized dpdmai object successfully");
223
224         return 0;
225 init_err:
226         dpaa2_dpdmai_dev_uninit(rawdev);
227         return ret;
228 }
229
230 static int
231 rte_dpaa2_qdma_probe(struct rte_dpaa2_driver *dpaa2_drv,
232                      struct rte_dpaa2_device *dpaa2_dev)
233 {
234         struct rte_rawdev *rawdev;
235         int ret;
236
237         DPAA2_QDMA_FUNC_TRACE();
238
239         rawdev = rte_rawdev_pmd_allocate(dpaa2_dev->device.name,
240                         sizeof(struct dpaa2_dpdmai_dev),
241                         rte_socket_id());
242         if (!rawdev) {
243                 DPAA2_QDMA_ERR("Unable to allocate rawdevice");
244                 return -EINVAL;
245         }
246
247         dpaa2_dev->rawdev = rawdev;
248         rawdev->dev_ops = &dpaa2_qdma_ops;
249         rawdev->device = &dpaa2_dev->device;
250         rawdev->driver_name = dpaa2_drv->driver.name;
251
252         /* Invoke PMD device initialization function */
253         ret = dpaa2_dpdmai_dev_init(rawdev, dpaa2_dev->object_id);
254         if (ret) {
255                 rte_rawdev_pmd_release(rawdev);
256                 return ret;
257         }
258
259         return 0;
260 }
261
262 static int
263 rte_dpaa2_qdma_remove(struct rte_dpaa2_device *dpaa2_dev)
264 {
265         struct rte_rawdev *rawdev = dpaa2_dev->rawdev;
266         int ret;
267
268         DPAA2_QDMA_FUNC_TRACE();
269
270         dpaa2_dpdmai_dev_uninit(rawdev);
271
272         ret = rte_rawdev_pmd_release(rawdev);
273         if (ret)
274                 DPAA2_QDMA_ERR("Device cleanup failed");
275
276         return 0;
277 }
278
279 static struct rte_dpaa2_driver rte_dpaa2_qdma_pmd = {
280         .drv_type = DPAA2_QDMA,
281         .probe = rte_dpaa2_qdma_probe,
282         .remove = rte_dpaa2_qdma_remove,
283 };
284
285 RTE_PMD_REGISTER_DPAA2(dpaa2_qdma, rte_dpaa2_qdma_pmd);
286
287 RTE_INIT(dpaa2_qdma_init_log);
288 static void
289 dpaa2_qdma_init_log(void)
290 {
291         dpaa2_qdma_logtype = rte_log_register("pmd.raw.dpaa2.qdma");
292         if (dpaa2_qdma_logtype >= 0)
293                 rte_log_set_level(dpaa2_qdma_logtype, RTE_LOG_INFO);
294 }