dpdk/drivers/dma/skeleton/skeleton_dmadev.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2021 HiSilicon Limited
   3 */
   4
   5#include <inttypes.h>
   6#include <stdlib.h>
   7
   8#include <bus_vdev_driver.h>
   9#include <rte_cycles.h>
  10#include <rte_eal.h>
  11#include <rte_kvargs.h>
  12#include <rte_lcore.h>
  13#include <rte_log.h>
  14#include <rte_malloc.h>
  15#include <rte_memcpy.h>
  16
  17#include <rte_dmadev_pmd.h>
  18
  19#include "skeleton_dmadev.h"
  20
  21RTE_LOG_REGISTER_DEFAULT(skeldma_logtype, INFO);
  22#define SKELDMA_LOG(level, fmt, args...) \
  23        rte_log(RTE_LOG_ ## level, skeldma_logtype, "%s(): " fmt "\n", \
  24                __func__, ##args)
  25
  26static int
  27skeldma_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *dev_info,
  28                 uint32_t info_sz)
  29{
  30#define SKELDMA_MAX_DESC        8192
  31#define SKELDMA_MIN_DESC        32
  32
  33        RTE_SET_USED(dev);
  34        RTE_SET_USED(info_sz);
  35
  36        dev_info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM |
  37                             RTE_DMA_CAPA_SVA |
  38                             RTE_DMA_CAPA_OPS_COPY;
  39        dev_info->max_vchans = 1;
  40        dev_info->max_desc = SKELDMA_MAX_DESC;
  41        dev_info->min_desc = SKELDMA_MIN_DESC;
  42
  43        return 0;
  44}
  45
  46static int
  47skeldma_configure(struct rte_dma_dev *dev, const struct rte_dma_conf *conf,
  48                  uint32_t conf_sz)
  49{
  50        RTE_SET_USED(dev);
  51        RTE_SET_USED(conf);
  52        RTE_SET_USED(conf_sz);
  53        return 0;
  54}
  55
  56static void *
  57cpucopy_thread(void *param)
  58{
  59#define SLEEP_THRESHOLD         10000
  60#define SLEEP_US_VAL            10
  61
  62        struct rte_dma_dev *dev = param;
  63        struct skeldma_hw *hw = dev->data->dev_private;
  64        struct skeldma_desc *desc = NULL;
  65        int ret;
  66
  67        while (!hw->exit_flag) {
  68                ret = rte_ring_dequeue(hw->desc_running, (void **)&desc);
  69                if (ret) {
  70                        hw->zero_req_count++;
  71                        if (hw->zero_req_count == 0)
  72                                hw->zero_req_count = SLEEP_THRESHOLD;
  73                        if (hw->zero_req_count >= SLEEP_THRESHOLD)
  74                                rte_delay_us_sleep(SLEEP_US_VAL);
  75                        continue;
  76                }
  77
  78                hw->zero_req_count = 0;
  79                rte_memcpy(desc->dst, desc->src, desc->len);
  80                __atomic_add_fetch(&hw->completed_count, 1, __ATOMIC_RELEASE);
  81                (void)rte_ring_enqueue(hw->desc_completed, (void *)desc);
  82        }
  83
  84        return NULL;
  85}
  86
  87static void
  88fflush_ring(struct skeldma_hw *hw, struct rte_ring *ring)
  89{
  90        struct skeldma_desc *desc = NULL;
  91        while (rte_ring_count(ring) > 0) {
  92                (void)rte_ring_dequeue(ring, (void **)&desc);
  93                (void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
  94        }
  95}
  96
  97static int
  98skeldma_start(struct rte_dma_dev *dev)
  99{
 100        struct skeldma_hw *hw = dev->data->dev_private;
 101        char name[RTE_MAX_THREAD_NAME_LEN];
 102        rte_cpuset_t cpuset;
 103        int ret;
 104
 105        if (hw->desc_mem == NULL) {
 106                SKELDMA_LOG(ERR, "Vchan was not setup, start fail!");
 107                return -EINVAL;
 108        }
 109
 110        /* Reset the dmadev to a known state, include:
 111         * 1) fflush pending/running/completed ring to empty ring.
 112         * 2) init ring idx to zero.
 113         * 3) init running statistics.
 114         * 4) mark cpucopy task exit_flag to false.
 115         */
 116        fflush_ring(hw, hw->desc_pending);
 117        fflush_ring(hw, hw->desc_running);
 118        fflush_ring(hw, hw->desc_completed);
 119        hw->ridx = 0;
 120        hw->last_ridx = hw->ridx - 1;
 121        hw->submitted_count = 0;
 122        hw->zero_req_count = 0;
 123        hw->completed_count = 0;
 124        hw->exit_flag = false;
 125
 126        rte_mb();
 127
 128        snprintf(name, sizeof(name), "dma_skel_%d", dev->data->dev_id);
 129        ret = rte_ctrl_thread_create(&hw->thread, name, NULL,
 130                                     cpucopy_thread, dev);
 131        if (ret) {
 132                SKELDMA_LOG(ERR, "Start cpucopy thread fail!");
 133                return -EINVAL;
 134        }
 135
 136        if (hw->lcore_id != -1) {
 137                cpuset = rte_lcore_cpuset(hw->lcore_id);
 138                ret = pthread_setaffinity_np(hw->thread, sizeof(cpuset),
 139                                             &cpuset);
 140                if (ret)
 141                        SKELDMA_LOG(WARNING,
 142                                "Set thread affinity lcore = %d fail!",
 143                                hw->lcore_id);
 144        }
 145
 146        return 0;
 147}
 148
 149static int
 150skeldma_stop(struct rte_dma_dev *dev)
 151{
 152        struct skeldma_hw *hw = dev->data->dev_private;
 153
 154        hw->exit_flag = true;
 155        rte_delay_ms(1);
 156
 157        (void)pthread_cancel(hw->thread);
 158        pthread_join(hw->thread, NULL);
 159
 160        return 0;
 161}
 162
 163static int
 164vchan_setup(struct skeldma_hw *hw, int16_t dev_id, uint16_t nb_desc)
 165{
 166        char name[RTE_RING_NAMESIZE];
 167        struct skeldma_desc *desc;
 168        struct rte_ring *empty;
 169        struct rte_ring *pending;
 170        struct rte_ring *running;
 171        struct rte_ring *completed;
 172        uint16_t i;
 173
 174        desc = rte_zmalloc_socket(NULL, nb_desc * sizeof(struct skeldma_desc),
 175                                  RTE_CACHE_LINE_SIZE, hw->socket_id);
 176        if (desc == NULL) {
 177                SKELDMA_LOG(ERR, "Malloc dma skeleton desc fail!");
 178                return -ENOMEM;
 179        }
 180
 181        snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_empty_%d", dev_id);
 182        empty = rte_ring_create(name, nb_desc, hw->socket_id,
 183                                RING_F_SP_ENQ | RING_F_SC_DEQ);
 184        snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_pend_%d", dev_id);
 185        pending = rte_ring_create(name, nb_desc, hw->socket_id,
 186                                  RING_F_SP_ENQ | RING_F_SC_DEQ);
 187        snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_run_%d", dev_id);
 188        running = rte_ring_create(name, nb_desc, hw->socket_id,
 189                                  RING_F_SP_ENQ | RING_F_SC_DEQ);
 190        snprintf(name, RTE_RING_NAMESIZE, "dma_skel_desc_comp_%d", dev_id);
 191        completed = rte_ring_create(name, nb_desc, hw->socket_id,
 192                                    RING_F_SP_ENQ | RING_F_SC_DEQ);
 193        if (empty == NULL || pending == NULL || running == NULL ||
 194            completed == NULL) {
 195                SKELDMA_LOG(ERR, "Create dma skeleton desc ring fail!");
 196                rte_ring_free(empty);
 197                rte_ring_free(pending);
 198                rte_ring_free(running);
 199                rte_ring_free(completed);
 200                rte_free(desc);
 201                return -ENOMEM;
 202        }
 203
 204        /* The real usable ring size is *count-1* instead of *count* to
 205         * differentiate a free ring from an empty ring.
 206         * @see rte_ring_create
 207         */
 208        for (i = 0; i < nb_desc - 1; i++)
 209                (void)rte_ring_enqueue(empty, (void *)(desc + i));
 210
 211        hw->desc_mem = desc;
 212        hw->desc_empty = empty;
 213        hw->desc_pending = pending;
 214        hw->desc_running = running;
 215        hw->desc_completed = completed;
 216
 217        return 0;
 218}
 219
 220static void
 221vchan_release(struct skeldma_hw *hw)
 222{
 223        if (hw->desc_mem == NULL)
 224                return;
 225
 226        rte_free(hw->desc_mem);
 227        hw->desc_mem = NULL;
 228        rte_ring_free(hw->desc_empty);
 229        hw->desc_empty = NULL;
 230        rte_ring_free(hw->desc_pending);
 231        hw->desc_pending = NULL;
 232        rte_ring_free(hw->desc_running);
 233        hw->desc_running = NULL;
 234        rte_ring_free(hw->desc_completed);
 235        hw->desc_completed = NULL;
 236}
 237
 238static int
 239skeldma_close(struct rte_dma_dev *dev)
 240{
 241        /* The device already stopped */
 242        vchan_release(dev->data->dev_private);
 243        return 0;
 244}
 245
 246static int
 247skeldma_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan,
 248                    const struct rte_dma_vchan_conf *conf,
 249                    uint32_t conf_sz)
 250{
 251        struct skeldma_hw *hw = dev->data->dev_private;
 252
 253        RTE_SET_USED(vchan);
 254        RTE_SET_USED(conf_sz);
 255
 256        if (!rte_is_power_of_2(conf->nb_desc)) {
 257                SKELDMA_LOG(ERR, "Number of desc must be power of 2!");
 258                return -EINVAL;
 259        }
 260
 261        vchan_release(hw);
 262        return vchan_setup(hw, dev->data->dev_id, conf->nb_desc);
 263}
 264
 265static int
 266skeldma_vchan_status(const struct rte_dma_dev *dev,
 267                uint16_t vchan, enum rte_dma_vchan_status *status)
 268{
 269        struct skeldma_hw *hw = dev->data->dev_private;
 270
 271        RTE_SET_USED(vchan);
 272
 273        *status = RTE_DMA_VCHAN_IDLE;
 274        if (hw->submitted_count != __atomic_load_n(&hw->completed_count, __ATOMIC_ACQUIRE)
 275                        || hw->zero_req_count == 0)
 276                *status = RTE_DMA_VCHAN_ACTIVE;
 277        return 0;
 278}
 279
 280static int
 281skeldma_stats_get(const struct rte_dma_dev *dev, uint16_t vchan,
 282                  struct rte_dma_stats *stats, uint32_t stats_sz)
 283{
 284        struct skeldma_hw *hw = dev->data->dev_private;
 285
 286        RTE_SET_USED(vchan);
 287        RTE_SET_USED(stats_sz);
 288
 289        stats->submitted = hw->submitted_count;
 290        stats->completed = hw->completed_count;
 291        stats->errors = 0;
 292
 293        return 0;
 294}
 295
 296static int
 297skeldma_stats_reset(struct rte_dma_dev *dev, uint16_t vchan)
 298{
 299        struct skeldma_hw *hw = dev->data->dev_private;
 300
 301        RTE_SET_USED(vchan);
 302
 303        hw->submitted_count = 0;
 304        hw->completed_count = 0;
 305
 306        return 0;
 307}
 308
 309static int
 310skeldma_dump(const struct rte_dma_dev *dev, FILE *f)
 311{
 312#define GET_RING_COUNT(ring)    ((ring) ? (rte_ring_count(ring)) : 0)
 313
 314        struct skeldma_hw *hw = dev->data->dev_private;
 315
 316        (void)fprintf(f,
 317                "    lcore_id: %d\n"
 318                "    socket_id: %d\n"
 319                "    desc_empty_ring_count: %u\n"
 320                "    desc_pending_ring_count: %u\n"
 321                "    desc_running_ring_count: %u\n"
 322                "    desc_completed_ring_count: %u\n",
 323                hw->lcore_id, hw->socket_id,
 324                GET_RING_COUNT(hw->desc_empty),
 325                GET_RING_COUNT(hw->desc_pending),
 326                GET_RING_COUNT(hw->desc_running),
 327                GET_RING_COUNT(hw->desc_completed));
 328        (void)fprintf(f,
 329                "    next_ring_idx: %u\n"
 330                "    last_ring_idx: %u\n"
 331                "    submitted_count: %" PRIu64 "\n"
 332                "    completed_count: %" PRIu64 "\n",
 333                hw->ridx, hw->last_ridx,
 334                hw->submitted_count, hw->completed_count);
 335
 336        return 0;
 337}
 338
 339static inline void
 340submit(struct skeldma_hw *hw, struct skeldma_desc *desc)
 341{
 342        uint16_t count = rte_ring_count(hw->desc_pending);
 343        struct skeldma_desc *pend_desc = NULL;
 344
 345        while (count > 0) {
 346                (void)rte_ring_dequeue(hw->desc_pending, (void **)&pend_desc);
 347                (void)rte_ring_enqueue(hw->desc_running, (void *)pend_desc);
 348                count--;
 349        }
 350
 351        if (desc)
 352                (void)rte_ring_enqueue(hw->desc_running, (void *)desc);
 353}
 354
 355static int
 356skeldma_copy(void *dev_private, uint16_t vchan,
 357             rte_iova_t src, rte_iova_t dst,
 358             uint32_t length, uint64_t flags)
 359{
 360        struct skeldma_hw *hw = dev_private;
 361        struct skeldma_desc *desc;
 362        int ret;
 363
 364        RTE_SET_USED(vchan);
 365        RTE_SET_USED(flags);
 366
 367        ret = rte_ring_dequeue(hw->desc_empty, (void **)&desc);
 368        if (ret)
 369                return -ENOSPC;
 370        desc->src = (void *)(uintptr_t)src;
 371        desc->dst = (void *)(uintptr_t)dst;
 372        desc->len = length;
 373        desc->ridx = hw->ridx;
 374        if (flags & RTE_DMA_OP_FLAG_SUBMIT)
 375                submit(hw, desc);
 376        else
 377                (void)rte_ring_enqueue(hw->desc_pending, (void *)desc);
 378        hw->submitted_count++;
 379
 380        return hw->ridx++;
 381}
 382
 383static int
 384skeldma_submit(void *dev_private, uint16_t vchan)
 385{
 386        struct skeldma_hw *hw = dev_private;
 387        RTE_SET_USED(vchan);
 388        submit(hw, NULL);
 389        return 0;
 390}
 391
 392static uint16_t
 393skeldma_completed(void *dev_private,
 394                  uint16_t vchan, const uint16_t nb_cpls,
 395                  uint16_t *last_idx, bool *has_error)
 396{
 397        struct skeldma_hw *hw = dev_private;
 398        struct skeldma_desc *desc = NULL;
 399        uint16_t index = 0;
 400        uint16_t count;
 401
 402        RTE_SET_USED(vchan);
 403        RTE_SET_USED(has_error);
 404
 405        count = RTE_MIN(nb_cpls, rte_ring_count(hw->desc_completed));
 406        while (index < count) {
 407                (void)rte_ring_dequeue(hw->desc_completed, (void **)&desc);
 408                if (index == count - 1) {
 409                        hw->last_ridx = desc->ridx;
 410                        *last_idx = desc->ridx;
 411                }
 412                index++;
 413                (void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
 414        }
 415        if (unlikely(count == 0))
 416                *last_idx = hw->last_ridx;
 417
 418        return count;
 419}
 420
 421static uint16_t
 422skeldma_completed_status(void *dev_private,
 423                         uint16_t vchan, const uint16_t nb_cpls,
 424                         uint16_t *last_idx, enum rte_dma_status_code *status)
 425{
 426        struct skeldma_hw *hw = dev_private;
 427        struct skeldma_desc *desc = NULL;
 428        uint16_t index = 0;
 429        uint16_t count;
 430
 431        RTE_SET_USED(vchan);
 432
 433        count = RTE_MIN(nb_cpls, rte_ring_count(hw->desc_completed));
 434        while (index < count) {
 435                (void)rte_ring_dequeue(hw->desc_completed, (void **)&desc);
 436                if (index == count - 1) {
 437                        hw->last_ridx = desc->ridx;
 438                        *last_idx = desc->ridx;
 439                }
 440                status[index++] = RTE_DMA_STATUS_SUCCESSFUL;
 441                (void)rte_ring_enqueue(hw->desc_empty, (void *)desc);
 442        }
 443        if (unlikely(count == 0))
 444                *last_idx = hw->last_ridx;
 445
 446        return count;
 447}
 448
 449static uint16_t
 450skeldma_burst_capacity(const void *dev_private, uint16_t vchan)
 451{
 452        const struct skeldma_hw *hw = dev_private;
 453
 454        RTE_SET_USED(vchan);
 455        return rte_ring_count(hw->desc_empty);
 456}
 457
 458static const struct rte_dma_dev_ops skeldma_ops = {
 459        .dev_info_get     = skeldma_info_get,
 460        .dev_configure    = skeldma_configure,
 461        .dev_start        = skeldma_start,
 462        .dev_stop         = skeldma_stop,
 463        .dev_close        = skeldma_close,
 464
 465        .vchan_setup      = skeldma_vchan_setup,
 466        .vchan_status     = skeldma_vchan_status,
 467
 468        .stats_get        = skeldma_stats_get,
 469        .stats_reset      = skeldma_stats_reset,
 470
 471        .dev_dump         = skeldma_dump,
 472};
 473
 474static int
 475skeldma_create(const char *name, struct rte_vdev_device *vdev, int lcore_id)
 476{
 477        struct rte_dma_dev *dev;
 478        struct skeldma_hw *hw;
 479        int socket_id;
 480
 481        socket_id = (lcore_id < 0) ? rte_socket_id() :
 482                                     rte_lcore_to_socket_id(lcore_id);
 483        dev = rte_dma_pmd_allocate(name, socket_id, sizeof(struct skeldma_hw));
 484        if (dev == NULL) {
 485                SKELDMA_LOG(ERR, "Unable to allocate dmadev: %s", name);
 486                return -EINVAL;
 487        }
 488
 489        dev->device = &vdev->device;
 490        dev->dev_ops = &skeldma_ops;
 491        dev->fp_obj->dev_private = dev->data->dev_private;
 492        dev->fp_obj->copy = skeldma_copy;
 493        dev->fp_obj->submit = skeldma_submit;
 494        dev->fp_obj->completed = skeldma_completed;
 495        dev->fp_obj->completed_status = skeldma_completed_status;
 496        dev->fp_obj->burst_capacity = skeldma_burst_capacity;
 497
 498        hw = dev->data->dev_private;
 499        hw->lcore_id = lcore_id;
 500        hw->socket_id = socket_id;
 501
 502        dev->state = RTE_DMA_DEV_READY;
 503
 504        return dev->data->dev_id;
 505}
 506
 507static int
 508skeldma_destroy(const char *name)
 509{
 510        return rte_dma_pmd_release(name);
 511}
 512
 513static int
 514skeldma_parse_lcore(const char *key __rte_unused,
 515                    const char *value,
 516                    void *opaque)
 517{
 518        int lcore_id = atoi(value);
 519        if (lcore_id >= 0 && lcore_id < RTE_MAX_LCORE)
 520                *(int *)opaque = lcore_id;
 521        return 0;
 522}
 523
 524static void
 525skeldma_parse_vdev_args(struct rte_vdev_device *vdev, int *lcore_id)
 526{
 527        static const char *const args[] = {
 528                SKELDMA_ARG_LCORE,
 529                NULL
 530        };
 531
 532        struct rte_kvargs *kvlist;
 533        const char *params;
 534
 535        params = rte_vdev_device_args(vdev);
 536        if (params == NULL || params[0] == '\0')
 537                return;
 538
 539        kvlist = rte_kvargs_parse(params, args);
 540        if (!kvlist)
 541                return;
 542
 543        (void)rte_kvargs_process(kvlist, SKELDMA_ARG_LCORE,
 544                                 skeldma_parse_lcore, lcore_id);
 545        SKELDMA_LOG(INFO, "Parse lcore_id = %d", *lcore_id);
 546
 547        rte_kvargs_free(kvlist);
 548}
 549
 550static int
 551skeldma_probe(struct rte_vdev_device *vdev)
 552{
 553        const char *name;
 554        int lcore_id = -1;
 555        int ret;
 556
 557        name = rte_vdev_device_name(vdev);
 558        if (name == NULL)
 559                return -EINVAL;
 560
 561        if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 562                SKELDMA_LOG(ERR, "Multiple process not supported for %s", name);
 563                return -EINVAL;
 564        }
 565
 566        skeldma_parse_vdev_args(vdev, &lcore_id);
 567
 568        ret = skeldma_create(name, vdev, lcore_id);
 569        if (ret >= 0)
 570                SKELDMA_LOG(INFO, "Create %s dmadev with lcore-id %d",
 571                        name, lcore_id);
 572
 573        return ret < 0 ? ret : 0;
 574}
 575
 576static int
 577skeldma_remove(struct rte_vdev_device *vdev)
 578{
 579        const char *name;
 580        int ret;
 581
 582        name = rte_vdev_device_name(vdev);
 583        if (name == NULL)
 584                return -1;
 585
 586        ret = skeldma_destroy(name);
 587        if (!ret)
 588                SKELDMA_LOG(INFO, "Remove %s dmadev", name);
 589
 590        return ret;
 591}
 592
 593static struct rte_vdev_driver skeldma_pmd_drv = {
 594        .probe = skeldma_probe,
 595        .remove = skeldma_remove,
 596        .drv_flags = RTE_VDEV_DRV_NEED_IOVA_AS_VA,
 597};
 598
 599RTE_PMD_REGISTER_VDEV(dma_skeleton, skeldma_pmd_drv);
 600RTE_PMD_REGISTER_PARAM_STRING(dma_skeleton,
 601                SKELDMA_ARG_LCORE "=<uint16> ");
 602