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