1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020-2021 NXP
12 #include <rte_common.h>
13 #include <rte_bus_vdev.h>
14 #include <rte_malloc.h>
16 #include <rte_kvargs.h>
18 #include <rte_bbdev.h>
19 #include <rte_bbdev_pmd.h>
21 #include <bbdev_la12xx_pmd_logs.h>
22 #include <bbdev_la12xx_ipc.h>
23 #include <bbdev_la12xx.h>
25 #define DRIVER_NAME baseband_la12xx
27 /* Initialisation params structure that can be used by LA12xx BBDEV driver */
28 struct bbdev_la12xx_params {
29 uint8_t queues_num; /*< LA12xx BBDEV queues number */
30 int8_t modem_id; /*< LA12xx modem instance id */
33 #define LA12XX_MAX_NB_QUEUES_ARG "max_nb_queues"
34 #define LA12XX_VDEV_MODEM_ID_ARG "modem"
35 #define LA12XX_MAX_MODEM 4
37 #define LA12XX_MAX_CORES 4
38 #define LA12XX_LDPC_ENC_CORE 0
39 #define LA12XX_LDPC_DEC_CORE 1
41 #define LA12XX_MAX_LDPC_ENC_QUEUES 4
42 #define LA12XX_MAX_LDPC_DEC_QUEUES 4
44 static const char * const bbdev_la12xx_valid_params[] = {
45 LA12XX_MAX_NB_QUEUES_ARG,
46 LA12XX_VDEV_MODEM_ID_ARG,
49 static const struct rte_bbdev_op_cap bbdev_capabilities[] = {
51 .type = RTE_BBDEV_OP_LDPC_ENC,
54 RTE_BBDEV_LDPC_RATE_MATCH |
55 RTE_BBDEV_LDPC_CRC_24A_ATTACH |
56 RTE_BBDEV_LDPC_CRC_24B_ATTACH,
58 RTE_BBDEV_LDPC_MAX_CODE_BLOCKS,
60 RTE_BBDEV_LDPC_MAX_CODE_BLOCKS,
64 .type = RTE_BBDEV_OP_LDPC_DEC,
67 RTE_BBDEV_LDPC_CRC_TYPE_24A_CHECK |
68 RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK |
69 RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP,
71 RTE_BBDEV_LDPC_MAX_CODE_BLOCKS,
72 .num_buffers_hard_out =
73 RTE_BBDEV_LDPC_MAX_CODE_BLOCKS,
78 RTE_BBDEV_END_OF_CAPABILITIES_LIST()
81 static struct rte_bbdev_queue_conf default_queue_conf = {
82 .queue_size = MAX_CHANNEL_DEPTH,
87 la12xx_info_get(struct rte_bbdev *dev __rte_unused,
88 struct rte_bbdev_driver_info *dev_info)
90 PMD_INIT_FUNC_TRACE();
92 dev_info->driver_name = RTE_STR(DRIVER_NAME);
93 dev_info->max_num_queues = LA12XX_MAX_QUEUES;
94 dev_info->queue_size_lim = MAX_CHANNEL_DEPTH;
95 dev_info->hardware_accelerated = true;
96 dev_info->max_dl_queue_priority = 0;
97 dev_info->max_ul_queue_priority = 0;
98 dev_info->data_endianness = RTE_BIG_ENDIAN;
99 dev_info->default_queue_conf = default_queue_conf;
100 dev_info->capabilities = bbdev_capabilities;
101 dev_info->cpu_flag_reqs = NULL;
102 dev_info->min_alignment = 64;
104 rte_bbdev_log_debug("got device info from %u", dev->data->dev_id);
109 la12xx_queue_release(struct rte_bbdev *dev, uint16_t q_id)
114 PMD_INIT_FUNC_TRACE();
119 #define HUGEPG_OFFSET(A) \
120 ((uint64_t) ((unsigned long) (A) \
121 - ((uint64_t)ipc_priv->hugepg_start.host_vaddr)))
124 ipc_queue_configure(uint32_t channel_id,
126 struct bbdev_la12xx_q_priv *q_priv)
128 ipc_userspace_t *ipc_priv = (ipc_userspace_t *)instance;
129 ipc_instance_t *ipc_instance = ipc_priv->instance;
133 uint32_t msg_size = sizeof(struct bbdev_ipc_enqueue_op);
135 PMD_INIT_FUNC_TRACE();
137 rte_bbdev_log_debug("%x %p", ipc_instance->initialized,
139 ch = &(ipc_instance->ch_list[channel_id]);
141 rte_bbdev_log_debug("channel: %u, depth: %u, msg size: %u",
142 channel_id, q_priv->queue_size, msg_size);
144 /* Start init of channel */
145 ch->md.ring_size = rte_cpu_to_be_32(q_priv->queue_size);
148 ch->md.msg_size = msg_size;
149 for (i = 0; i < q_priv->queue_size; i++) {
150 vaddr = rte_malloc(NULL, msg_size, RTE_CACHE_LINE_SIZE);
152 return IPC_HOST_BUF_ALLOC_FAIL;
153 /* Only offset now */
154 ch->bd_h[i].modem_ptr =
155 rte_cpu_to_be_32(HUGEPG_OFFSET(vaddr));
156 ch->bd_h[i].host_virt_l = lower_32_bits(vaddr);
157 ch->bd_h[i].host_virt_h = upper_32_bits(vaddr);
158 q_priv->msg_ch_vaddr[i] = vaddr;
159 /* Not sure use of this len may be for CRC*/
162 ch->host_ipc_params =
163 rte_cpu_to_be_32(HUGEPG_OFFSET(q_priv->host_params));
165 rte_bbdev_log_debug("Channel configured");
170 la12xx_e200_queue_setup(struct rte_bbdev *dev,
171 struct bbdev_la12xx_q_priv *q_priv)
173 struct bbdev_la12xx_private *priv = dev->data->dev_private;
174 ipc_userspace_t *ipc_priv = priv->ipc_priv;
175 struct gul_hif *mhif;
176 ipc_metadata_t *ipc_md;
178 int instance_id = 0, i;
181 PMD_INIT_FUNC_TRACE();
183 switch (q_priv->op_type) {
184 case RTE_BBDEV_OP_LDPC_ENC:
185 q_priv->la12xx_core_id = LA12XX_LDPC_ENC_CORE;
187 case RTE_BBDEV_OP_LDPC_DEC:
188 q_priv->la12xx_core_id = LA12XX_LDPC_DEC_CORE;
191 rte_bbdev_log(ERR, "Unsupported op type\n");
195 mhif = (struct gul_hif *)ipc_priv->mhif_start.host_vaddr;
196 /* offset is from start of PEB */
197 ipc_md = (ipc_metadata_t *)((uintptr_t)ipc_priv->peb_start.host_vaddr +
198 mhif->ipc_regs.ipc_mdata_offset);
199 ch = &ipc_md->instance_list[instance_id].ch_list[q_priv->q_id];
201 if (q_priv->q_id < priv->num_valid_queues) {
202 ipc_br_md_t *md = &(ch->md);
204 q_priv->feca_blk_id = rte_cpu_to_be_32(ch->feca_blk_id);
205 q_priv->feca_blk_id_be32 = ch->feca_blk_id;
206 q_priv->host_pi = rte_be_to_cpu_32(md->pi);
207 q_priv->host_ci = rte_be_to_cpu_32(md->ci);
208 q_priv->host_params = (host_ipc_params_t *)(uintptr_t)
209 (rte_be_to_cpu_32(ch->host_ipc_params) +
210 ((uint64_t)ipc_priv->hugepg_start.host_vaddr));
212 for (i = 0; i < q_priv->queue_size; i++) {
215 h = ch->bd_h[i].host_virt_h;
216 l = ch->bd_h[i].host_virt_l;
217 q_priv->msg_ch_vaddr[i] = (void *)join_32_bits(h, l);
220 rte_bbdev_log(WARNING,
221 "Queue [%d] already configured, not configuring again",
226 rte_bbdev_log_debug("setting up queue %d", q_priv->q_id);
228 /* Call ipc_configure_channel */
229 ret = ipc_queue_configure(q_priv->q_id, ipc_priv, q_priv);
231 rte_bbdev_log(ERR, "Unable to setup queue (%d) (err=%d)",
236 /* Set queue properties for LA12xx device */
237 switch (q_priv->op_type) {
238 case RTE_BBDEV_OP_LDPC_ENC:
239 if (priv->num_ldpc_enc_queues >= LA12XX_MAX_LDPC_ENC_QUEUES) {
241 "num_ldpc_enc_queues reached max value");
245 rte_cpu_to_be_32(LA12XX_LDPC_ENC_CORE);
246 ch->feca_blk_id = rte_cpu_to_be_32(priv->num_ldpc_enc_queues++);
248 case RTE_BBDEV_OP_LDPC_DEC:
249 if (priv->num_ldpc_dec_queues >= LA12XX_MAX_LDPC_DEC_QUEUES) {
251 "num_ldpc_dec_queues reached max value");
255 rte_cpu_to_be_32(LA12XX_LDPC_DEC_CORE);
256 ch->feca_blk_id = rte_cpu_to_be_32(priv->num_ldpc_dec_queues++);
259 rte_bbdev_log(ERR, "Not supported op type\n");
262 ch->op_type = rte_cpu_to_be_32(q_priv->op_type);
263 ch->depth = rte_cpu_to_be_32(q_priv->queue_size);
265 /* Store queue config here */
266 q_priv->feca_blk_id = rte_cpu_to_be_32(ch->feca_blk_id);
267 q_priv->feca_blk_id_be32 = ch->feca_blk_id;
274 la12xx_queue_setup(struct rte_bbdev *dev, uint16_t q_id,
275 const struct rte_bbdev_queue_conf *queue_conf)
277 struct bbdev_la12xx_private *priv = dev->data->dev_private;
278 struct rte_bbdev_queue_data *q_data;
279 struct bbdev_la12xx_q_priv *q_priv;
282 PMD_INIT_FUNC_TRACE();
284 /* Move to setup_queues callback */
285 q_data = &dev->data->queues[q_id];
286 q_data->queue_private = rte_zmalloc(NULL,
287 sizeof(struct bbdev_la12xx_q_priv), 0);
288 if (!q_data->queue_private) {
289 rte_bbdev_log(ERR, "Memory allocation failed for qpriv");
292 q_priv = q_data->queue_private;
294 q_priv->bbdev_priv = dev->data->dev_private;
295 q_priv->queue_size = queue_conf->queue_size;
296 q_priv->op_type = queue_conf->op_type;
298 ret = la12xx_e200_queue_setup(dev, q_priv);
300 rte_bbdev_log(ERR, "e200_queue_setup failed for qid: %d",
305 /* Store queue config here */
306 priv->num_valid_queues++;
312 la12xx_start(struct rte_bbdev *dev)
314 struct bbdev_la12xx_private *priv = dev->data->dev_private;
315 ipc_userspace_t *ipc_priv = priv->ipc_priv;
317 struct gul_hif *hif_start;
319 PMD_INIT_FUNC_TRACE();
321 hif_start = (struct gul_hif *)ipc_priv->mhif_start.host_vaddr;
323 /* Set Host Read bit */
324 SET_HIF_HOST_RDY(hif_start, HIF_HOST_READY_IPC_APP);
326 /* Now wait for modem ready bit */
328 ready = CHK_HIF_MOD_RDY(hif_start, HIF_MOD_READY_IPC_APP);
333 static const struct rte_bbdev_ops pmd_ops = {
334 .info_get = la12xx_info_get,
335 .queue_setup = la12xx_queue_setup,
336 .queue_release = la12xx_queue_release,
337 .start = la12xx_start
339 static struct hugepage_info *
340 get_hugepage_info(void)
342 struct hugepage_info *hp_info;
343 struct rte_memseg *mseg;
345 PMD_INIT_FUNC_TRACE();
347 /* TODO - find a better way */
348 hp_info = rte_malloc(NULL, sizeof(struct hugepage_info), 0);
350 rte_bbdev_log(ERR, "Unable to allocate on local heap");
354 mseg = rte_mem_virt2memseg(hp_info, NULL);
355 hp_info->vaddr = mseg->addr;
356 hp_info->paddr = rte_mem_virt2phy(mseg->addr);
357 hp_info->len = mseg->len;
363 open_ipc_dev(int modem_id)
365 char dev_initials[16], dev_path[PATH_MAX];
366 struct dirent *entry;
370 dir = opendir("/dev/");
372 rte_bbdev_log(ERR, "Unable to open /dev/");
376 sprintf(dev_initials, "gulipcgul%d", modem_id);
378 while ((entry = readdir(dir)) != NULL) {
379 if (!strncmp(dev_initials, entry->d_name,
380 sizeof(dev_initials) - 1))
385 rte_bbdev_log(ERR, "Error: No gulipcgul%d device", modem_id);
389 sprintf(dev_path, "/dev/%s", entry->d_name);
390 dev_ipc = open(dev_path, O_RDWR);
392 rte_bbdev_log(ERR, "Error: Cannot open %s", dev_path);
400 setup_la12xx_dev(struct rte_bbdev *dev)
402 struct bbdev_la12xx_private *priv = dev->data->dev_private;
403 ipc_userspace_t *ipc_priv = priv->ipc_priv;
404 struct hugepage_info *hp = NULL;
405 ipc_channel_us_t *ipc_priv_ch = NULL;
406 int dev_ipc = 0, dev_mem = 0, i;
407 ipc_metadata_t *ipc_md;
408 struct gul_hif *mhif;
409 uint32_t phy_align = 0;
412 PMD_INIT_FUNC_TRACE();
415 /* TODO - get a better way */
416 /* Get the hugepage info against it */
417 hp = get_hugepage_info();
419 rte_bbdev_log(ERR, "Unable to get hugepage info");
424 rte_bbdev_log_debug("0x%" PRIx64 " %p 0x%" PRIx64,
425 hp->paddr, hp->vaddr, hp->len);
427 ipc_priv = rte_zmalloc(0, sizeof(ipc_userspace_t), 0);
428 if (ipc_priv == NULL) {
430 "Unable to allocate memory for ipc priv");
435 for (i = 0; i < IPC_MAX_CHANNEL_COUNT; i++) {
436 ipc_priv_ch = rte_zmalloc(0,
437 sizeof(ipc_channel_us_t), 0);
438 if (ipc_priv_ch == NULL) {
440 "Unable to allocate memory for channels");
443 ipc_priv->channels[i] = ipc_priv_ch;
446 dev_mem = open("/dev/mem", O_RDWR);
448 rte_bbdev_log(ERR, "Error: Cannot open /dev/mem");
453 ipc_priv->instance_id = 0;
454 ipc_priv->dev_mem = dev_mem;
456 rte_bbdev_log_debug("hugepg input 0x%" PRIx64 "%p 0x%" PRIx64,
457 hp->paddr, hp->vaddr, hp->len);
459 ipc_priv->sys_map.hugepg_start.host_phys = hp->paddr;
460 ipc_priv->sys_map.hugepg_start.size = hp->len;
462 ipc_priv->hugepg_start.host_phys = hp->paddr;
463 ipc_priv->hugepg_start.host_vaddr = hp->vaddr;
464 ipc_priv->hugepg_start.size = hp->len;
469 dev_ipc = open_ipc_dev(priv->modem_id);
471 rte_bbdev_log(ERR, "Error: open_ipc_dev failed");
474 ipc_priv->dev_ipc = dev_ipc;
476 ret = ioctl(ipc_priv->dev_ipc, IOCTL_GUL_IPC_GET_SYS_MAP,
480 "IOCTL_GUL_IPC_GET_SYS_MAP ioctl failed");
484 phy_align = (ipc_priv->sys_map.mhif_start.host_phys % 0x1000);
485 ipc_priv->mhif_start.host_vaddr =
486 mmap(0, ipc_priv->sys_map.mhif_start.size + phy_align,
487 (PROT_READ | PROT_WRITE), MAP_SHARED, ipc_priv->dev_mem,
488 (ipc_priv->sys_map.mhif_start.host_phys - phy_align));
489 if (ipc_priv->mhif_start.host_vaddr == MAP_FAILED) {
490 rte_bbdev_log(ERR, "MAP failed:");
495 ipc_priv->mhif_start.host_vaddr = (void *) ((uintptr_t)
496 (ipc_priv->mhif_start.host_vaddr) + phy_align);
498 phy_align = (ipc_priv->sys_map.peb_start.host_phys % 0x1000);
499 ipc_priv->peb_start.host_vaddr =
500 mmap(0, ipc_priv->sys_map.peb_start.size + phy_align,
501 (PROT_READ | PROT_WRITE), MAP_SHARED, ipc_priv->dev_mem,
502 (ipc_priv->sys_map.peb_start.host_phys - phy_align));
503 if (ipc_priv->peb_start.host_vaddr == MAP_FAILED) {
504 rte_bbdev_log(ERR, "MAP failed:");
509 ipc_priv->peb_start.host_vaddr = (void *)((uintptr_t)
510 (ipc_priv->peb_start.host_vaddr) + phy_align);
512 phy_align = (ipc_priv->sys_map.modem_ccsrbar.host_phys % 0x1000);
513 ipc_priv->modem_ccsrbar.host_vaddr =
514 mmap(0, ipc_priv->sys_map.modem_ccsrbar.size + phy_align,
515 (PROT_READ | PROT_WRITE), MAP_SHARED, ipc_priv->dev_mem,
516 (ipc_priv->sys_map.modem_ccsrbar.host_phys - phy_align));
517 if (ipc_priv->modem_ccsrbar.host_vaddr == MAP_FAILED) {
518 rte_bbdev_log(ERR, "MAP failed:");
523 ipc_priv->modem_ccsrbar.host_vaddr = (void *)((uintptr_t)
524 (ipc_priv->modem_ccsrbar.host_vaddr) + phy_align);
526 ipc_priv->hugepg_start.modem_phys =
527 ipc_priv->sys_map.hugepg_start.modem_phys;
529 ipc_priv->mhif_start.host_phys =
530 ipc_priv->sys_map.mhif_start.host_phys;
531 ipc_priv->mhif_start.size = ipc_priv->sys_map.mhif_start.size;
532 ipc_priv->peb_start.host_phys = ipc_priv->sys_map.peb_start.host_phys;
533 ipc_priv->peb_start.size = ipc_priv->sys_map.peb_start.size;
535 rte_bbdev_log(INFO, "peb 0x%" PRIx64 "%p 0x%" PRIx32,
536 ipc_priv->peb_start.host_phys,
537 ipc_priv->peb_start.host_vaddr,
538 ipc_priv->peb_start.size);
539 rte_bbdev_log(INFO, "hugepg 0x%" PRIx64 "%p 0x%" PRIx32,
540 ipc_priv->hugepg_start.host_phys,
541 ipc_priv->hugepg_start.host_vaddr,
542 ipc_priv->hugepg_start.size);
543 rte_bbdev_log(INFO, "mhif 0x%" PRIx64 "%p 0x%" PRIx32,
544 ipc_priv->mhif_start.host_phys,
545 ipc_priv->mhif_start.host_vaddr,
546 ipc_priv->mhif_start.size);
547 mhif = (struct gul_hif *)ipc_priv->mhif_start.host_vaddr;
549 /* offset is from start of PEB */
550 ipc_md = (ipc_metadata_t *)((uintptr_t)ipc_priv->peb_start.host_vaddr +
551 mhif->ipc_regs.ipc_mdata_offset);
553 if (sizeof(ipc_metadata_t) != mhif->ipc_regs.ipc_mdata_size) {
555 "ipc_metadata_t =0x%" PRIx64
556 ", mhif->ipc_regs.ipc_mdata_size=0x%" PRIx32,
557 (uint64_t)(sizeof(ipc_metadata_t)),
558 mhif->ipc_regs.ipc_mdata_size);
559 rte_bbdev_log(ERR, "--> mhif->ipc_regs.ipc_mdata_offset= 0x%"
560 PRIx32, mhif->ipc_regs.ipc_mdata_offset);
561 rte_bbdev_log(ERR, "gul_hif size=0x%" PRIx64,
562 (uint64_t)(sizeof(struct gul_hif)));
563 return IPC_MD_SZ_MISS_MATCH;
566 ipc_priv->instance = (ipc_instance_t *)
567 (&ipc_md->instance_list[ipc_priv->instance_id]);
569 rte_bbdev_log_debug("finish host init");
571 priv->ipc_priv = ipc_priv;
578 rte_free(ipc_priv_ch);
588 parse_u16_arg(const char *key, const char *value, void *extra_args)
590 uint16_t *u16 = extra_args;
593 if ((value == NULL) || (extra_args == NULL))
596 result = strtoul(value, NULL, 0);
597 if ((result >= (1 << 16)) || (errno != 0)) {
598 rte_bbdev_log(ERR, "Invalid value %" PRIu64 " for %s",
602 *u16 = (uint16_t)result;
606 /* Parse integer from integer argument */
608 parse_integer_arg(const char *key __rte_unused,
609 const char *value, void *extra_args)
616 i = strtol(value, &end, 10);
617 if (*end != 0 || errno != 0 || i < 0 || i > LA12XX_MAX_MODEM) {
618 rte_bbdev_log(ERR, "Supported Port IDS are 0 to %d",
619 LA12XX_MAX_MODEM - 1);
623 *((uint32_t *)extra_args) = i;
628 /* Parse parameters used to create device */
630 parse_bbdev_la12xx_params(struct bbdev_la12xx_params *params,
631 const char *input_args)
633 struct rte_kvargs *kvlist = NULL;
639 kvlist = rte_kvargs_parse(input_args,
640 bbdev_la12xx_valid_params);
644 ret = rte_kvargs_process(kvlist, bbdev_la12xx_valid_params[0],
645 &parse_u16_arg, ¶ms->queues_num);
649 ret = rte_kvargs_process(kvlist,
650 bbdev_la12xx_valid_params[1],
654 if (params->modem_id >= LA12XX_MAX_MODEM) {
655 rte_bbdev_log(ERR, "Invalid modem id, must be < %u",
663 rte_kvargs_free(kvlist);
669 la12xx_bbdev_create(struct rte_vdev_device *vdev,
670 struct bbdev_la12xx_params *init_params)
672 struct rte_bbdev *bbdev;
673 const char *name = rte_vdev_device_name(vdev);
674 struct bbdev_la12xx_private *priv;
677 PMD_INIT_FUNC_TRACE();
679 bbdev = rte_bbdev_allocate(name);
683 bbdev->data->dev_private = rte_zmalloc(name,
684 sizeof(struct bbdev_la12xx_private),
685 RTE_CACHE_LINE_SIZE);
686 if (bbdev->data->dev_private == NULL) {
687 rte_bbdev_release(bbdev);
691 priv = bbdev->data->dev_private;
692 priv->modem_id = init_params->modem_id;
693 /* if modem id is not configured */
694 if (priv->modem_id == -1)
695 priv->modem_id = bbdev->data->dev_id;
697 /* Reset Global variables */
698 priv->num_ldpc_enc_queues = 0;
699 priv->num_ldpc_dec_queues = 0;
700 priv->num_valid_queues = 0;
701 priv->max_nb_queues = init_params->queues_num;
703 rte_bbdev_log(INFO, "Setting Up %s: DevId=%d, ModemId=%d",
704 name, bbdev->data->dev_id, priv->modem_id);
705 ret = setup_la12xx_dev(bbdev);
707 rte_bbdev_log(ERR, "IPC Setup failed for %s", name);
708 rte_free(bbdev->data->dev_private);
711 bbdev->dev_ops = &pmd_ops;
712 bbdev->device = &vdev->device;
713 bbdev->data->socket_id = 0;
714 bbdev->intr_handle = NULL;
716 /* register rx/tx burst functions for data path */
717 bbdev->dequeue_enc_ops = NULL;
718 bbdev->dequeue_dec_ops = NULL;
719 bbdev->enqueue_enc_ops = NULL;
720 bbdev->enqueue_dec_ops = NULL;
725 /* Initialise device */
727 la12xx_bbdev_probe(struct rte_vdev_device *vdev)
729 struct bbdev_la12xx_params init_params = {
733 const char *input_args;
735 PMD_INIT_FUNC_TRACE();
740 name = rte_vdev_device_name(vdev);
744 input_args = rte_vdev_device_args(vdev);
745 parse_bbdev_la12xx_params(&init_params, input_args);
747 return la12xx_bbdev_create(vdev, &init_params);
750 /* Uninitialise device */
752 la12xx_bbdev_remove(struct rte_vdev_device *vdev)
754 struct rte_bbdev *bbdev;
757 PMD_INIT_FUNC_TRACE();
762 name = rte_vdev_device_name(vdev);
766 bbdev = rte_bbdev_get_named_dev(name);
770 rte_free(bbdev->data->dev_private);
772 return rte_bbdev_release(bbdev);
775 static struct rte_vdev_driver bbdev_la12xx_pmd_drv = {
776 .probe = la12xx_bbdev_probe,
777 .remove = la12xx_bbdev_remove
780 RTE_PMD_REGISTER_VDEV(DRIVER_NAME, bbdev_la12xx_pmd_drv);
781 RTE_PMD_REGISTER_PARAM_STRING(DRIVER_NAME,
782 LA12XX_MAX_NB_QUEUES_ARG"=<int>"
783 LA12XX_VDEV_MODEM_ID_ARG "=<int> ");
784 RTE_LOG_REGISTER_DEFAULT(bbdev_la12xx_logtype, NOTICE);