1111#include <suit_ipuc.h>
1212#include <suit_plat_decode_util.h>
1313#include <zephyr/logging/log.h>
14+ #include <zephyr/cache.h>
1415
15- LOG_MODULE_REGISTER (flash_ipuc , CONFIG_FLASH_IPUC_LOG_LEVEL );
16+ /* __ALIGNED macro is not defined on NATIVE POSIX. This platform uses __aligned macro. */
17+ #ifndef __ALIGNED
18+ #ifdef __aligned
19+ #define __ALIGNED __aligned
20+ #endif
21+ #endif
22+
23+ #ifdef CONFIG_DCACHE_LINE_SIZE
24+ #define CACHE_ALIGNMENT CONFIG_DCACHE_LINE_SIZE
25+ #else
26+ #define CACHE_ALIGNMENT 4
27+ #endif
1628
1729#define FLASH_WRITE_BLOCK_SIZE DT_PROP(DT_CHOSEN(zephyr_flash), write_block_size)
1830#define WRITE_BLOCK_SIZE FLASH_WRITE_BLOCK_SIZE
@@ -45,6 +57,8 @@ struct ipuc_context {
4557
4658#define DEFINE_NRF_IPUC_REF (x , _ ) &__device_flash_nrf_ipuc_##x
4759
60+ LOG_MODULE_REGISTER (flash_ipuc , CONFIG_FLASH_IPUC_LOG_LEVEL );
61+
4862static int nrf_ipuc_read (const struct device * dev , off_t offset , void * data , size_t len )
4963{
5064 struct ipuc_context * ctx = NULL ;
@@ -75,8 +89,11 @@ static int nrf_ipuc_read(const struct device *dev, off_t offset, void *data, siz
7589
7690static int nrf_ipuc_write (const struct device * dev , off_t offset , const void * data , size_t len )
7791{
92+ uint8_t unaligned_data_buf [CACHE_ALIGNMENT ] __ALIGNED (CACHE_ALIGNMENT ) = {0 };
93+ size_t unaligned_len = MIN (CACHE_ALIGNMENT - (((uintptr_t )data ) % CACHE_ALIGNMENT ), len );
94+ suit_plat_err_t plat_ret = SUIT_PLAT_SUCCESS ;
7895 struct ipuc_context * ctx = NULL ;
79- bool last_chunk = false ;
96+ int ret = 0 ;
8097
8198 if (dev == NULL ) {
8299 return - EINVAL ;
@@ -88,20 +105,75 @@ static int nrf_ipuc_write(const struct device *dev, off_t offset, const void *da
88105 return - EBADF ;
89106 }
90107
108+ if (offset + len > ctx -> size ) {
109+ return - ENOMEM ;
110+ }
111+
91112 LOG_DBG ("write: %p:%zu" , (void * )offset , len );
92113
93114 if (len == 0 ) {
94- last_chunk = true;
115+ plat_ret = suit_ipuc_write (& ctx -> component_id , offset , 0 , 0 , true);
116+ if (plat_ret != SUIT_PLAT_SUCCESS ) {
117+ LOG_ERR ("Last write (flush) error: %d" , plat_ret );
118+ return - EIO ;
119+ }
120+
121+ return 0 ;
95122 }
96123
97- if (offset + len > ctx -> size ) {
98- return - ENOMEM ;
124+ /* Optimize: Use a single write call if all bytes can be transferred using stack-based
125+ * aligned buffer.
126+ */
127+ if (len <= ARRAY_SIZE (unaligned_data_buf )) {
128+ unaligned_len = len ;
99129 }
100130
101- suit_plat_err_t plat_ret =
102- suit_ipuc_write (& ctx -> component_id , offset , (uintptr_t )data , len , last_chunk );
131+ /* If the data buffer is not aligned to the cache lines:
132+ * - copy the unaligned part into stack-based aligned buffer
133+ * - write the internal buffer
134+ * - skip the unaligned bytes of the input buffer
135+ */
136+ if (unaligned_len != CACHE_ALIGNMENT ) {
137+ memcpy (unaligned_data_buf , data , unaligned_len );
103138
139+ LOG_DBG ("align: %p:%zu" , (void * )data , unaligned_len );
140+
141+ ret = sys_cache_data_flush_range ((void * )unaligned_data_buf ,
142+ sizeof (unaligned_data_buf ));
143+ if (ret != 0 && ret != - EAGAIN && ret != - ENOTSUP ) {
144+ LOG_ERR ("Failed to flush cache buffer range (%p, 0x%x): %d" ,
145+ (void * )unaligned_data_buf , sizeof (unaligned_data_buf ), ret );
146+ return - EIO ;
147+ }
148+
149+ plat_ret = suit_ipuc_write (& ctx -> component_id , offset ,
150+ (uintptr_t )unaligned_data_buf , unaligned_len , false);
151+ if (plat_ret != SUIT_PLAT_SUCCESS ) {
152+ LOG_ERR ("Unaligned data write (%p, 0x%x) error: %d" ,
153+ (void * )unaligned_data_buf , unaligned_len , plat_ret );
154+ return - EIO ;
155+ }
156+
157+ offset += unaligned_len ;
158+ len -= unaligned_len ;
159+ data = (void * )((uintptr_t )data + unaligned_len );
160+ }
161+
162+ /* If no more (aligned) bytes left - return. */
163+ if (len == 0 ) {
164+ return 0 ;
165+ }
166+
167+ /* Write (now aligned) data buffer. */
168+ ret = sys_cache_data_flush_range ((void * )data , len );
169+ if (ret != 0 && ret != - EAGAIN && ret != - ENOTSUP ) {
170+ LOG_ERR ("Failed to flush cache memory range (%p, 0x%x): %d" , data , len , ret );
171+ return - EIO ;
172+ }
173+
174+ plat_ret = suit_ipuc_write (& ctx -> component_id , offset , (uintptr_t )data , len , false);
104175 if (plat_ret != SUIT_PLAT_SUCCESS ) {
176+ LOG_ERR ("Aligned data write (%p, 0x%x) error: %d" , data , len , plat_ret );
105177 return - EIO ;
106178 }
107179
@@ -110,7 +182,8 @@ static int nrf_ipuc_write(const struct device *dev, off_t offset, const void *da
110182
111183static int nrf_ipuc_erase (const struct device * dev , off_t offset , size_t size )
112184{
113- static uint8_t erase_block [WRITE_BLOCK_SIZE ] = {ERASE_VALUE };
185+ static const uint8_t erase_block [WRITE_BLOCK_SIZE ] __ALIGNED (CACHE_ALIGNMENT ) = {
186+ ERASE_VALUE };
114187 suit_plat_err_t plat_ret = SUIT_PLAT_SUCCESS ;
115188 struct ipuc_context * ctx = NULL ;
116189
@@ -128,18 +201,27 @@ static int nrf_ipuc_erase(const struct device *dev, off_t offset, size_t size)
128201 return - ENOMEM ;
129202 }
130203
204+ int ret = sys_cache_data_flush_range ((void * )erase_block , sizeof (erase_block ));
205+
206+ if (ret != 0 && ret != - EAGAIN && ret != - ENOTSUP ) {
207+ LOG_ERR ("Failed to flush cache range (%p, 0x%x): %d" , erase_block ,
208+ sizeof (erase_block ), ret );
209+ return - EIO ;
210+ }
211+
131212 LOG_DBG ("erase: %p:%zu" , (void * )offset , size );
213+
132214 while (size > 0 ) {
133215 plat_ret = suit_ipuc_write (& ctx -> component_id , offset , (uintptr_t )erase_block ,
134216 sizeof (erase_block ), false);
217+ if (plat_ret != SUIT_PLAT_SUCCESS ) {
218+ return - EIO ;
219+ }
220+
135221 offset += sizeof (erase_block );
136222 size -= sizeof (erase_block );
137223 }
138224
139- if (plat_ret != SUIT_PLAT_SUCCESS ) {
140- return - EIO ;
141- }
142-
143225 return 0 ;
144226}
145227
0 commit comments