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  * @brief Buffer macros and definitions used in USB device support
39  * @defgroup udc_buf Buffer macros and definitions used in USB device support
40  * @ingroup usb
41  * @since 4.0
42  * @version 0.1.0
43  * @{
44  */
45 
46 /** Buffer alignment required by the UDC driver */
47 #define UDC_BUF_ALIGN		Z_UDC_BUF_ALIGN
48 
49 /** Buffer granularity required by the UDC driver */
50 #define UDC_BUF_GRANULARITY	Z_UDC_BUF_GRANULARITY
51 
52 /**
53  * @brief Define a UDC driver-compliant static buffer
54  *
55  * This macro should be used if the application defines its own buffers to be
56  * used for USB transfers.
57  *
58  * @param name Buffer name
59  * @param size Buffer size
60  */
61 #define UDC_STATIC_BUF_DEFINE(name, size)					\
62 	static uint8_t __aligned(UDC_BUF_ALIGN) name[ROUND_UP(size, UDC_BUF_GRANULARITY)];
63 
64 /**
65  * @brief Verify that the buffer is aligned as required by the UDC driver
66  *
67  * @see IS_ALIGNED
68  *
69  * @param buf Buffer pointer
70  */
71 #define IS_UDC_ALIGNED(buf) IS_ALIGNED(buf, UDC_BUF_ALIGN)
72 
73 /**
74  * @cond INTERNAL_HIDDEN
75  */
76 #define UDC_HEAP_DEFINE(name, bytes, in_section)				\
77 	uint8_t in_section __aligned(UDC_BUF_ALIGN)				\
78 		kheap_##name[MAX(bytes, Z_HEAP_MIN_SIZE)];			\
79 	STRUCT_SECTION_ITERABLE(k_heap, name) = {				\
80 		.heap = {							\
81 			.init_mem = kheap_##name,				\
82 			.init_bytes = MAX(bytes, Z_HEAP_MIN_SIZE),		\
83 		 },								\
84 	}
85 
86 #define UDC_K_HEAP_DEFINE(name, size)						\
87 	COND_CODE_1(CONFIG_UDC_BUF_FORCE_NOCACHE,				\
88 		    (UDC_HEAP_DEFINE(name, size, __nocache)),			\
89 		    (UDC_HEAP_DEFINE(name, size, __noinit)))
90 
91 extern const struct net_buf_data_cb net_buf_dma_cb;
92 /** @endcond */
93 
94 /**
95  * @brief Define a new pool for UDC buffers with variable-size payloads
96  *
97  * This macro is similar to `NET_BUF_POOL_VAR_DEFINE`, but provides buffers
98  * with alignment and granularity suitable for use by UDC driver.
99  *
100  * @see NET_BUF_POOL_VAR_DEFINE
101  *
102  * @param pname      Name of the pool variable.
103  * @param count      Number of buffers in the pool.
104  * @param size       Maximum data payload per buffer.
105  * @param ud_size    User data space to reserve per buffer.
106  * @param fdestroy   Optional destroy callback when buffer is freed.
107  */
108 #define UDC_BUF_POOL_VAR_DEFINE(pname, count, size, ud_size, fdestroy)		\
109 	_NET_BUF_ARRAY_DEFINE(pname, count, ud_size);				\
110 	UDC_K_HEAP_DEFINE(net_buf_mem_pool_##pname, size);			\
111 	static const struct net_buf_data_alloc net_buf_data_alloc_##pname = {	\
112 		.cb = &net_buf_dma_cb,						\
113 		.alloc_data = &net_buf_mem_pool_##pname,			\
114 		.max_alloc_size = 0,						\
115 	};									\
116 	static STRUCT_SECTION_ITERABLE(net_buf_pool, pname) =			\
117 		NET_BUF_POOL_INITIALIZER(pname, &net_buf_data_alloc_##pname,	\
118 					 _net_buf_##pname, count, ud_size,	\
119 					 fdestroy)
120 
121 /**
122  * @brief Define a new pool for UDC buffers based on fixed-size data
123  *
124  * This macro is similar to `NET_BUF_POOL_DEFINE`, but provides buffers
125  * with alignment and granularity suitable for use by UDC driver.
126  *
127  * @see NET_BUF_POOL_DEFINE
128 
129  * @param pname      Name of the pool variable.
130  * @param count      Number of buffers in the pool.
131  * @param size       Maximum data payload per buffer.
132  * @param ud_size    User data space to reserve per buffer.
133  * @param fdestroy   Optional destroy callback when buffer is freed.
134  */
135 #define UDC_BUF_POOL_DEFINE(pname, count, size, ud_size, fdestroy)		\
136 	_NET_BUF_ARRAY_DEFINE(pname, count, ud_size);				\
137 	BUILD_ASSERT((UDC_BUF_GRANULARITY) % (UDC_BUF_ALIGN) == 0,		\
138 		     "Code assumes granurality is multiple of alignment");	\
139 	static uint8_t __nocache __aligned(UDC_BUF_ALIGN)			\
140 		net_buf_data_##pname[count][ROUND_UP(size, UDC_BUF_GRANULARITY)];\
141 	static const struct net_buf_pool_fixed net_buf_fixed_##pname = {	\
142 		.data_pool = (uint8_t *)net_buf_data_##pname,			\
143 	};									\
144 	static const struct net_buf_data_alloc net_buf_fixed_alloc_##pname = {	\
145 		.cb = &net_buf_fixed_cb,					\
146 		.alloc_data = (void *)&net_buf_fixed_##pname,			\
147 		.max_alloc_size = ROUND_UP(size, UDC_BUF_GRANULARITY),		\
148 	};									\
149 	static STRUCT_SECTION_ITERABLE(net_buf_pool, pname) =			\
150 		NET_BUF_POOL_INITIALIZER(pname, &net_buf_fixed_alloc_##pname,	\
151 					 _net_buf_##pname, count, ud_size,	\
152 					 fdestroy)
153 
154 /**
155  * @}
156  */
157 
158 #endif /* ZEPHYR_INCLUDE_UDC_BUF_H */
159