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 | |
17 | struct 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 | |
27 | void 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(dev: pool->dev, size: pool->mem_size, cpu_addr: pool->cpumem, |
38 | dma_handle: pool->dma_addr); |
39 | |
40 | gen_pool_destroy(pool->gen_pool); /* frees pool->name */ |
41 | } |
42 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_destroy); |
43 | |
44 | struct k3_cppi_desc_pool * |
45 | k3_cppi_desc_pool_create_name(struct device *dev, size_t size, |
46 | size_t desc_size, |
47 | const char *name) |
48 | { |
49 | struct k3_cppi_desc_pool *pool; |
50 | const char *pool_name = NULL; |
51 | int ret = -ENOMEM; |
52 | |
53 | pool = devm_kzalloc(dev, size: sizeof(*pool), GFP_KERNEL); |
54 | if (!pool) |
55 | return ERR_PTR(error: ret); |
56 | |
57 | pool->dev = dev; |
58 | pool->desc_size = roundup_pow_of_two(desc_size); |
59 | pool->num_desc = size; |
60 | pool->mem_size = pool->num_desc * pool->desc_size; |
61 | |
62 | pool_name = kstrdup_const(s: name ? name : dev_name(dev: pool->dev), |
63 | GFP_KERNEL); |
64 | if (!pool_name) |
65 | return ERR_PTR(error: -ENOMEM); |
66 | |
67 | pool->gen_pool = gen_pool_create(ilog2(pool->desc_size), -1); |
68 | if (!pool->gen_pool) { |
69 | ret = -ENOMEM; |
70 | dev_err(pool->dev, "pool create failed %d\n" , ret); |
71 | kfree_const(x: pool_name); |
72 | goto gen_pool_create_fail; |
73 | } |
74 | |
75 | pool->gen_pool->name = pool_name; |
76 | |
77 | pool->cpumem = dma_alloc_coherent(dev: pool->dev, size: pool->mem_size, |
78 | dma_handle: &pool->dma_addr, GFP_KERNEL); |
79 | |
80 | if (!pool->cpumem) |
81 | goto dma_alloc_fail; |
82 | |
83 | ret = gen_pool_add_virt(pool: pool->gen_pool, addr: (unsigned long)pool->cpumem, |
84 | phys: (phys_addr_t)pool->dma_addr, size: pool->mem_size, |
85 | nid: -1); |
86 | if (ret < 0) { |
87 | dev_err(pool->dev, "pool add failed %d\n" , ret); |
88 | goto gen_pool_add_virt_fail; |
89 | } |
90 | |
91 | return pool; |
92 | |
93 | gen_pool_add_virt_fail: |
94 | dma_free_coherent(dev: pool->dev, size: pool->mem_size, cpu_addr: pool->cpumem, |
95 | dma_handle: pool->dma_addr); |
96 | dma_alloc_fail: |
97 | gen_pool_destroy(pool->gen_pool); /* frees pool->name */ |
98 | gen_pool_create_fail: |
99 | devm_kfree(dev: pool->dev, p: pool); |
100 | return ERR_PTR(error: ret); |
101 | } |
102 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_create_name); |
103 | |
104 | dma_addr_t k3_cppi_desc_pool_virt2dma(struct k3_cppi_desc_pool *pool, |
105 | void *addr) |
106 | { |
107 | return addr ? pool->dma_addr + (addr - pool->cpumem) : 0; |
108 | } |
109 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_virt2dma); |
110 | |
111 | void *k3_cppi_desc_pool_dma2virt(struct k3_cppi_desc_pool *pool, dma_addr_t dma) |
112 | { |
113 | return dma ? pool->cpumem + (dma - pool->dma_addr) : NULL; |
114 | } |
115 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_dma2virt); |
116 | |
117 | void *k3_cppi_desc_pool_alloc(struct k3_cppi_desc_pool *pool) |
118 | { |
119 | return (void *)gen_pool_alloc(pool: pool->gen_pool, size: pool->desc_size); |
120 | } |
121 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_alloc); |
122 | |
123 | void k3_cppi_desc_pool_free(struct k3_cppi_desc_pool *pool, void *addr) |
124 | { |
125 | gen_pool_free(pool: pool->gen_pool, addr: (unsigned long)addr, size: pool->desc_size); |
126 | } |
127 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_free); |
128 | |
129 | size_t k3_cppi_desc_pool_avail(struct k3_cppi_desc_pool *pool) |
130 | { |
131 | return gen_pool_avail(pool->gen_pool) / pool->desc_size; |
132 | } |
133 | EXPORT_SYMBOL_GPL(k3_cppi_desc_pool_avail); |
134 | |
135 | MODULE_LICENSE("GPL" ); |
136 | MODULE_DESCRIPTION("TI K3 CPPI5 descriptors pool API" ); |
137 | |