1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Buffers for USB device support
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_UDC_BUF_H
13 #define ZEPHYR_INCLUDE_UDC_BUF_H
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/net_buf.h>
17 
18 #if defined(CONFIG_DCACHE) && !defined(CONFIG_UDC_BUF_FORCE_NOCACHE)
19 /*
20  * Here we try to get DMA-safe buffers, but we lack a consistent source of
21  * information about data cache properties, such as line cache size, and a
22  * consistent source of information about what part of memory is DMA'able.
23  * For now, we simply assume that all available memory is DMA'able and use
24  * Kconfig option DCACHE_LINE_SIZE for alignment and granularity.
25  */
26 #define Z_UDC_BUF_ALIGN		CONFIG_DCACHE_LINE_SIZE
27 #define Z_UDC_BUF_GRANULARITY	CONFIG_DCACHE_LINE_SIZE
28 #else
29 /*
30  * Default alignment and granularity to pointer size if the platform does not
31  * have a data cache or buffers are placed in nocache memory region.
32  */
33 #define Z_UDC_BUF_ALIGN		sizeof(void *)
34 #define Z_UDC_BUF_GRANULARITY	sizeof(void *)
35 #endif
36 
37 
38 #if defined(CONFIG_UDC_BUF_FORCE_NOCACHE)
39 /*
40  * The usb transfer buffer needs to be in __nocache section
41  */
42 #define Z_UDC_BUF_SECTION	__nocache
43 #else
44 #define Z_UDC_BUF_SECTION
45 #endif
46 
47 /**
48  * @brief Buffer macros and definitions used in USB device support
49  * @defgroup udc_buf Buffer macros and definitions used in USB device support
50  * @ingroup usb
51  * @since 4.0
52  * @version 0.1.0
53  * @{
54  */
55 
56 /** Buffer alignment required by the UDC driver */
57 #define UDC_BUF_ALIGN		Z_UDC_BUF_ALIGN
58 
59 /** Buffer granularity required by the UDC driver */
60 #define UDC_BUF_GRANULARITY	Z_UDC_BUF_GRANULARITY
61 
62 /**
63  * @brief Define a UDC driver-compliant static buffer
64  *
65  * This macro should be used if the application defines its own buffers to be
66  * used for USB transfers.
67  *
68  * @param name Buffer name
69  * @param size Buffer size
70  */
71 #define UDC_STATIC_BUF_DEFINE(name, size)					\
72 	static uint8_t Z_UDC_BUF_SECTION __aligned(UDC_BUF_ALIGN)		\
73 	name[ROUND_UP(size, UDC_BUF_GRANULARITY)];
74 
75 /**
76  * @brief Verify that the buffer is aligned as required by the UDC driver
77  *
78  * @see IS_ALIGNED
79  *
80  * @param buf Buffer pointer
81  */
82 #define IS_UDC_ALIGNED(buf) IS_ALIGNED(buf, UDC_BUF_ALIGN)
83 
84 /**
85  * @cond INTERNAL_HIDDEN
86  */
87 #define UDC_HEAP_DEFINE(name, bytes, in_section)				\
88 	uint8_t in_section __aligned(UDC_BUF_ALIGN)				\
89 		kheap_##name[MAX(bytes, Z_HEAP_MIN_SIZE)];			\
90 	STRUCT_SECTION_ITERABLE(k_heap, name) = {				\
91 		.heap = {							\
92 			.init_mem = kheap_##name,				\
93 			.init_bytes = MAX(bytes, Z_HEAP_MIN_SIZE),		\
94 		 },								\
95 	}
96 
97 #define UDC_K_HEAP_DEFINE(name, size)						\
98 	COND_CODE_1(CONFIG_UDC_BUF_FORCE_NOCACHE,				\
99 		    (UDC_HEAP_DEFINE(name, size, __nocache)),			\
100 		    (UDC_HEAP_DEFINE(name, size, __noinit)))
101 
102 extern const struct net_buf_data_cb net_buf_dma_cb;
103 /** @endcond */
104 
105 /**
106  * @brief Define a new pool for UDC buffers with variable-size payloads
107  *
108  * This macro is similar to `NET_BUF_POOL_VAR_DEFINE`, but provides buffers
109  * with alignment and granularity suitable for use by UDC driver.
110  *
111  * @see NET_BUF_POOL_VAR_DEFINE
112  *
113  * @param pname      Name of the pool variable.
114  * @param count      Number of buffers in the pool.
115  * @param size       Maximum data payload per buffer.
116  * @param ud_size    User data space to reserve per buffer.
117  * @param fdestroy   Optional destroy callback when buffer is freed.
118  */
119 #define UDC_BUF_POOL_VAR_DEFINE(pname, count, size, ud_size, fdestroy)		\
120 	_NET_BUF_ARRAY_DEFINE(pname, count, ud_size);				\
121 	UDC_K_HEAP_DEFINE(net_buf_mem_pool_##pname, size);			\
122 	static const struct net_buf_data_alloc net_buf_data_alloc_##pname = {	\
123 		.cb = &net_buf_dma_cb,						\
124 		.alloc_data = &net_buf_mem_pool_##pname,			\
125 		.max_alloc_size = 0,						\
126 	};									\
127 	static STRUCT_SECTION_ITERABLE(net_buf_pool, pname) =			\
128 		NET_BUF_POOL_INITIALIZER(pname, &net_buf_data_alloc_##pname,	\
129 					 _net_buf_##pname, count, ud_size,	\
130 					 fdestroy)
131 
132 /**
133  * @brief Define a new pool for UDC buffers based on fixed-size data
134  *
135  * This macro is similar to `NET_BUF_POOL_DEFINE`, but provides buffers
136  * with alignment and granularity suitable for use by UDC driver.
137  *
138  * @see NET_BUF_POOL_DEFINE
139 
140  * @param pname      Name of the pool variable.
141  * @param count      Number of buffers in the pool.
142  * @param size       Maximum data payload per buffer.
143  * @param ud_size    User data space to reserve per buffer.
144  * @param fdestroy   Optional destroy callback when buffer is freed.
145  */
146 #define UDC_BUF_POOL_DEFINE(pname, count, size, ud_size, fdestroy)		\
147 	_NET_BUF_ARRAY_DEFINE(pname, count, ud_size);				\
148 	BUILD_ASSERT((UDC_BUF_GRANULARITY) % (UDC_BUF_ALIGN) == 0,		\
149 		     "Code assumes granurality is multiple of alignment");	\
150 	static uint8_t Z_UDC_BUF_SECTION __aligned(UDC_BUF_ALIGN)		\
151 		net_buf_data_##pname[count][ROUND_UP(size, UDC_BUF_GRANULARITY)];\
152 	static const struct net_buf_pool_fixed net_buf_fixed_##pname = {	\
153 		.data_pool = (uint8_t *)net_buf_data_##pname,			\
154 	};									\
155 	static const struct net_buf_data_alloc net_buf_fixed_alloc_##pname = {	\
156 		.cb = &net_buf_fixed_cb,					\
157 		.alloc_data = (void *)&net_buf_fixed_##pname,			\
158 		.max_alloc_size = ROUND_UP(size, UDC_BUF_GRANULARITY),		\
159 	};									\
160 	static STRUCT_SECTION_ITERABLE(net_buf_pool, pname) =			\
161 		NET_BUF_POOL_INITIALIZER(pname, &net_buf_fixed_alloc_##pname,	\
162 					 _net_buf_##pname, count, ud_size,	\
163 					 fdestroy)
164 
165 /**
166  * @}
167  */
168 
169 #endif /* ZEPHYR_INCLUDE_UDC_BUF_H */
170