ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_io_blockdev_cache.c
Go to the documentation of this file.
1
17
19
20#include <stddef.h>
21#include <stdint.h>
22#include <string.h>
23
24#include "ra8_attributes.h"
25#include "ra8_check.h"
26#include "ra8_err.h"
27#include "ra8_io_blockdev.h"
29
31static const char* const s_tag = "ra8_io_blockdev_cache";
32
56 uint32_t lba)
57{
58 for (uint32_t i = 0; i < st->n_slots; ++i) {
59 if (!st->slots[i].valid) {
60 continue;
61 }
62 if (st->slots[i].lba == lba) {
63 return i;
64 }
65 }
66 return st->n_slots;
67}
68
91{
92 uint32_t best = 0;
93 for (uint32_t i = 0; i < st->n_slots; ++i) {
94 if (!st->slots[i].valid) {
95 return i;
96 }
97 if (st->slots[i].last_use < st->slots[best].last_use) {
98 best = i;
99 }
100 }
101 return best;
102}
103
131{
132 st->clock++;
133 const uint32_t hit = internal_cache_find(st, lba);
134 const size_t span = (size_t)k_ra8_io_block_size_bytes;
135 if (hit != st->n_slots) {
136 st->hits++;
137 (void)memcpy(dst, &st->data[(size_t)hit * span], span);
138 st->slots[hit].last_use = st->clock;
139 return k_ra8_ok;
140 }
141 st->misses++;
142 const uint32_t v = internal_cache_pick_victim(st);
143 RA8_RETURN_ON_ERROR(ra8_io_blockdev_read(st->under, lba, 1, &st->data[(size_t)v * span]),
144 s_tag,
145 "backend read");
146 st->slots[v].lba = lba;
147 st->slots[v].valid = true;
148 st->slots[v].last_use = st->clock;
149 (void)memcpy(dst, &st->data[(size_t)v * span], span);
150 return k_ra8_ok;
151}
152
178internal_cache_write_block(ra8_io_blockdev_cache_state_t* st, uint32_t lba, const uint8_t* src)
179{
180 RA8_RETURN_ON_ERROR(ra8_io_blockdev_write(st->under, lba, 1, src), s_tag, "backend write");
181 st->clock++;
182 const size_t span = (size_t)k_ra8_io_block_size_bytes;
183 uint32_t idx = internal_cache_find(st, lba);
184 if (idx == st->n_slots) {
186 }
187 (void)memcpy(&st->data[(size_t)idx * span], src, span);
188 st->slots[idx].lba = lba;
189 st->slots[idx].valid = true;
190 st->slots[idx].last_use = st->clock;
191 return k_ra8_ok;
192}
193
220internal_cache_read(void* ctx, uint32_t lba, uint32_t count, uint8_t* buf)
221{
222 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
223 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
225 const size_t span = (size_t)k_ra8_io_block_size_bytes;
226 for (uint32_t i = 0; i < count; ++i) {
227 RA8_RETURN_ON_ERROR(internal_cache_read_block(st, lba + i, &buf[(size_t)i * span]),
228 s_tag,
229 "read block");
230 }
231 return k_ra8_ok;
232}
233
260internal_cache_write(void* ctx, uint32_t lba, uint32_t count, const uint8_t* buf)
261{
262 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
263 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
265 const size_t span = (size_t)k_ra8_io_block_size_bytes;
266 for (uint32_t i = 0; i < count; ++i) {
267 RA8_RETURN_ON_ERROR(internal_cache_write_block(st, lba + i, &buf[(size_t)i * span]),
268 s_tag,
269 "write block");
270 }
271 return k_ra8_ok;
272}
273
299RA8_INTERNAL static ra8_err_t internal_cache_erase(void* ctx, uint32_t lba, uint32_t count)
300{
301 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
303 RA8_RETURN_ON_ERROR(ra8_io_blockdev_erase(st->under, lba, count), s_tag, "backend erase");
304 const uint32_t end = lba + count;
305 for (uint32_t i = 0; i < st->n_slots; ++i) {
306 if (!st->slots[i].valid) {
307 continue;
308 }
309 if (st->slots[i].lba < lba) {
310 continue;
311 }
312 if (st->slots[i].lba >= end) {
313 continue;
314 }
315 st->slots[i].valid = false;
316 }
317 return k_ra8_ok;
318}
319
344{
345 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
346 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
348 return ra8_io_blockdev_get_caps(st->under, out);
349}
350
375{
376 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
378 return ra8_io_blockdev_sync(st->under);
379}
380
383 .read = internal_cache_read,
384 .write = internal_cache_write,
385 .erase = internal_cache_erase,
386 .get_caps = internal_cache_get_caps,
387 .sync = internal_cache_sync,
388};
389
416 const ra8_io_blockdev_t* under,
417 uint8_t* data,
419 uint32_t n_slots)
420{
421 state->under = under;
422 state->data = data;
423 state->slots = slots;
424 state->n_slots = n_slots;
425 state->clock = 0;
426 state->hits = 0;
427 state->misses = 0;
428}
429
452 uint32_t n_slots)
453{
454 for (uint32_t i = 0; i < n_slots; ++i) {
455 slots[i].valid = false;
456 slots[i].lba = 0;
457 slots[i].last_use = 0;
458 }
459}
460
463 const ra8_io_blockdev_t* under,
464 uint8_t* data,
466 uint32_t n_slots)
467{
468 RA8_CHECK_NULL_PTR(bd, s_tag, "bd must not be nullptr");
469 RA8_CHECK_NULL_PTR(state, s_tag, "state must not be nullptr");
470 RA8_CHECK_NULL_PTR(under, s_tag, "under must not be nullptr");
471 RA8_CHECK_NULL_PTR(data, s_tag, "data must not be nullptr");
472 RA8_CHECK_NULL_PTR(slots, s_tag, "slots must not be nullptr");
473 if (n_slots == 0U) {
475 }
476 internal_cache_state_init(state, under, data, slots, n_slots);
477 internal_cache_reset_slots(slots, n_slots);
478 bd->iface = &s_cache_iface;
479 bd->ctx = state;
480 return k_ra8_ok;
481}
482
484 uint32_t* out_hits,
485 uint32_t* out_misses)
486{
487 RA8_CHECK_NULL_PTR(state, s_tag, "state must not be nullptr");
488 if (out_hits != nullptr) {
489 *out_hits = state->hits;
490 }
491 if (out_misses != nullptr) {
492 *out_misses = state->misses;
493 }
494 return k_ra8_ok;
495}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
ra8_io block-device fabric – one LBA vtable across every storage medium.
ra8_err_t ra8_io_blockdev_sync(const ra8_io_blockdev_t *bd)
Flush any backend write buffering to the medium.
ra8_err_t ra8_io_blockdev_read(const ra8_io_blockdev_t *bd, uint32_t lba, uint32_t count, uint8_t *buf)
Read count logical blocks starting at lba into buf.
struct ra8_io_blockdev_iface ra8_io_blockdev_iface_t
@ k_ra8_io_block_size_bytes
Bytes per logical block (the only size).
ra8_err_t ra8_io_blockdev_write(const ra8_io_blockdev_t *bd, uint32_t lba, uint32_t count, const uint8_t *buf)
Write count logical blocks from buf starting at lba.
ra8_err_t ra8_io_blockdev_get_caps(const ra8_io_blockdev_t *bd, ra8_io_blockdev_caps_t *out)
Report the bound backend's medium capabilities.
ra8_err_t ra8_io_blockdev_erase(const ra8_io_blockdev_t *bd, uint32_t lba, uint32_t count)
Erase count blocks starting at lba to the medium's erase value.
Backend implementation contract for the ra8_io block-device fabric.
static uint32_t internal_cache_find(const ra8_io_blockdev_cache_state_t *st, uint32_t lba)
Find the cache slot holding lba.
ra8_err_t ra8_io_blockdev_cache_init(ra8_io_blockdev_t *bd, ra8_io_blockdev_cache_state_t *state, const ra8_io_blockdev_t *under, uint8_t *data, ra8_io_blockdev_cache_slot_t *slots, uint32_t n_slots)
Bind a caching block device over an existing backend.
static uint32_t internal_cache_pick_victim(const ra8_io_blockdev_cache_state_t *st)
Pick a slot to (re)use: the first free slot, else least-recently-used.
static void internal_cache_reset_slots(ra8_io_blockdev_cache_slot_t *slots, uint32_t n_slots)
Reset a slot array to the empty (no sectors cached) state.
static ra8_err_t internal_cache_sync(void *ctx)
Cache vtable: flush the wrapped backend.
static ra8_err_t internal_cache_write_block(ra8_io_blockdev_cache_state_t *st, uint32_t lba, const uint8_t *src)
Write one block through to the backend and update the cache.
static ra8_err_t internal_cache_get_caps(const void *ctx, ra8_io_blockdev_caps_t *out)
Cache vtable: report the wrapped backend's capabilities.
static ra8_err_t internal_cache_erase(void *ctx, uint32_t lba, uint32_t count)
Cache vtable: erase through to the backend and drop stale slots.
static void internal_cache_state_init(ra8_io_blockdev_cache_state_t *state, const ra8_io_blockdev_t *under, uint8_t *data, ra8_io_blockdev_cache_slot_t *slots, uint32_t n_slots)
Populate the scalar fields of a fresh cache state.
ra8_err_t ra8_io_blockdev_cache_stats(const ra8_io_blockdev_cache_state_t *state, uint32_t *out_hits, uint32_t *out_misses)
Report the cache hit/miss counters.
static ra8_err_t internal_cache_read(void *ctx, uint32_t lba, uint32_t count, uint8_t *buf)
Cache vtable: read count blocks at lba into buf.
static ra8_err_t internal_cache_read_block(ra8_io_blockdev_cache_state_t *st, uint32_t lba, uint8_t *dst)
Read one block through the cache (hit) or fill it (miss).
static const ra8_io_blockdev_iface_t s_cache_iface
Caching block-device vtable.
static ra8_err_t internal_cache_write(void *ctx, uint32_t lba, uint32_t count, const uint8_t *buf)
Cache vtable: write count blocks from buf at lba.
ra8_io caching block device – an LRU sector cache over any backend.
Per-sector cache metadata (one caller-owned array entry per slot).
uint32_t lba
Cached logical block address (valid only if in use).
bool valid
true => this slot holds a cached sector.
uint32_t last_use
LRU stamp; larger == more recently used.
Caller-owned private state for a caching block device.
uint8_t * data
n_slots * 512 cache bytes.
uint32_t misses
Read cache misses so far.
const ra8_io_blockdev_t * under
Wrapped backend (private).
uint32_t clock
Monotonic LRU access counter.
uint32_t hits
Read cache hits so far.
uint32_t n_slots
Number of cached sectors.
ra8_io_blockdev_cache_slot_t * slots
n_slots metadata entries.
Static properties a backend reports about its medium.
Caller-allocated block-device handle binding a backend to its context.
const ra8_io_blockdev_iface_t * iface
Bound backend vtable (private).
void * ctx
Backend-private context (private).