linux/drivers/net/ethernet/ti/k3-cppi-desc-pool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* TI K3 CPPI5 descriptors pool API
   3 *
   4 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
   5 */
   6
   7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8
   9#include <linux/device.h>
  10#include <linux/dma-mapping.h>
  11#include <linux/err.h>
  12#include <linux/genalloc.h>
  13#include <linux/kernel.h>
  14
  15#include "k3-cppi-desc-pool.h"
  16
  17struct k3_cppi_desc_pool {
  18        struct device           *dev;
  19        dma_addr_t              dma_addr;
  20        void                    *cpumem;        /* dma_alloc map */
  21        size_t                  desc_size;
  22        size_t                  mem_size;
  23        size_t                  num_desc;
  24        struct gen_pool         *gen_pool;
  25};
  26
  27void k3_cppi_desc_pool_destroy(struct k3_cppi_desc_pool *pool)
  28{
  29        if (!pool)
  30                return;
  31
  32        WARN(gen_pool_size(pool->gen_pool) != gen_pool_avail(pool->gen_pool),
  33             "k3_knav_desc_pool size %zu != avail %zu",
  34             gen_pool_size(pool->gen_pool),
  35             gen_pool_avail(pool->gen_pool));
  36        if (pool->cpumem)
  37                dma_free_coherent(pool->dev, pool->mem_size, pool->cpumem,
  38                                  pool->dma_addr);
  39
  40        gen_pool_destroy(pool->gen_pool);       /* frees pool->name */
  41}
  42
  43struct k3_cppi_desc_pool *
  44k3_cppi_desc_pool_create_name(struct device *dev, size_t size,
  45                              size_t desc_size,
  46                              const char *name)
  47{
  48        struct k3_cppi_desc_pool *pool;
  49        const char *pool_name = NULL;
  50        int ret = -ENOMEM;
  51
  52        pool = devm_kzalloc(dev, sizeof(*pool), GFP_KERNEL);
  53        if (!pool)
  54                return ERR_PTR(ret);
  55
  56        pool->dev = dev;
  57        pool->desc_size = roundup_pow_of_two(desc_size);
  58        pool->num_desc  = size;
  59        pool->mem_size  = pool->num_desc * pool->desc_size;
  60
  61        pool_name = kstrdup_const(name ? name : dev_name(pool->dev),
  62                                  GFP_KERNEL);
  63        if (!pool_name)
  64                return ERR_PTR(-ENOMEM);
  65
  66        pool->gen_pool = gen_pool_create(ilog2(pool->desc_size), -1);
  67        if (!pool->gen_pool) {
  68                ret = -ENOMEM;
  69                dev_err(pool->dev, "pool create failed %d\n", ret);
  70                kfree_const(pool_name);
  71                goto gen_pool_create_fail;
  72        }
  73
  74        pool->gen_pool->name = pool_name;
  75
  76        pool->cpumem = dma_alloc_coherent(pool->dev, pool->mem_size,
  77                                          &pool->dma_addr, GFP_KERNEL);
  78
  79        if (!pool->cpumem)
  80                goto dma_alloc_fail;
  81
  82        ret = gen_pool_add_virt(pool->gen_pool, (unsigned long)pool->cpumem,
  83                                (phys_addr_t)pool->dma_addr, pool->mem_size,
  84                                -1);
  85        if (ret < 0) {
  86                dev_err(pool->dev, "pool add failed %d\n", ret);
  87                goto gen_pool_add_virt_fail;
  88        }
  89
  90        return pool;
  91
  92gen_pool_add_virt_fail:
  93        dma_free_coherent(pool->dev, pool->mem_size, pool->cpumem,
  94                          pool->dma_addr);
  95dma_alloc_fail:
  96        gen_pool_destroy(pool->gen_pool);       /* frees pool->name */
  97gen_pool_create_fail:
  98        devm_kfree(pool->dev, pool);
  99        return ERR_PTR(ret);
 100}
 101
 102dma_addr_t k3_cppi_desc_pool_virt2dma(struct k3_cppi_desc_pool *pool,
 103                                      void *addr)
 104{
 105        return addr ? pool->dma_addr + (addr - pool->cpumem) : 0;
 106}
 107
 108void *k3_cppi_desc_pool_dma2virt(struct k3_cppi_desc_pool *pool, dma_addr_t dma)
 109{
 110        return dma ? pool->cpumem + (dma - pool->dma_addr) : NULL;
 111}
 112
 113void *k3_cppi_desc_pool_alloc(struct k3_cppi_desc_pool *pool)
 114{
 115        return (void *)gen_pool_alloc(pool->gen_pool, pool->desc_size);
 116}
 117
 118void k3_cppi_desc_pool_free(struct k3_cppi_desc_pool *pool, void *addr)
 119{
 120        gen_pool_free(pool->gen_pool, (unsigned long)addr, pool->desc_size);
 121}
 122
 123size_t k3_cppi_desc_pool_avail(struct k3_cppi_desc_pool *pool)
 124{
 125        return gen_pool_avail(pool->gen_pool) / pool->desc_size;
 126}
 127