From 75e7f5cb8018860a1c1227453e818d527dbff869 Mon Sep 17 00:00:00 2001 From: Kinsey Moore Date: Thu, 18 Sep 2025 17:16:46 -0500 Subject: [PATCH] cpukit/flashdev: Add unregister call and private data destructor This adds an API call allowing for unregistration to include destruction of private data that is not managed by the flashdev framework. This also updates the existing consumers of flashdev to use the new private data destructor callback. --- .../xilinx-zynq/dev/spi/zynq-qspi-flashdev.c | 14 +++---- .../include/dev/spi/zynq-qspi-flashdev.h | 19 +++------ bsps/include/dev/spi/xqspi_flash.h | 18 ++------ bsps/shared/dev/spi/xqspi_flash.c | 14 +++---- cpukit/dev/flash/flashdev.c | 31 +++++++++++--- cpukit/include/dev/flash/flashdev.h | 31 +++++++++++++- testsuites/libtests/flashdev01/init.c | 41 +++++++++++++++++++ .../libtests/flashdev01/test_flashdev.c | 9 ++++ 8 files changed, 129 insertions(+), 48 deletions(-) diff --git a/bsps/arm/xilinx-zynq/dev/spi/zynq-qspi-flashdev.c b/bsps/arm/xilinx-zynq/dev/spi/zynq-qspi-flashdev.c index 439ffa03cd..7fe42452b6 100644 --- a/bsps/arm/xilinx-zynq/dev/spi/zynq-qspi-flashdev.c +++ b/bsps/arm/xilinx-zynq/dev/spi/zynq-qspi-flashdev.c @@ -149,6 +149,12 @@ static int zqspi_sector_count( return 0; } +static void zqspi_priv_destroy(rtems_flashdev* flash) +{ + free(flash->region_table->regions); + free(flash->region_table); +} + rtems_flashdev* zqspi_flashdev_init(zqspiflash *bmdriver) { zqspi_flash_region_table *xtable = @@ -180,6 +186,7 @@ rtems_flashdev* zqspi_flashdev_init(zqspiflash *bmdriver) } flash->driver = bmdriver; + flash->priv_destroy = &zqspi_priv_destroy; flash->read = &zqspi_read_wrapper; flash->write = &zqspi_write_wrapper; flash->erase = &zqspi_erase_wrapper; @@ -195,10 +202,3 @@ rtems_flashdev* zqspi_flashdev_init(zqspiflash *bmdriver) return flash; } - -void zqspi_flashdev_destroy(rtems_flashdev* flash) -{ - free(flash->region_table->regions); - free(flash->region_table); - rtems_flashdev_destroy_and_free(flash); -} diff --git a/bsps/arm/xilinx-zynq/include/dev/spi/zynq-qspi-flashdev.h b/bsps/arm/xilinx-zynq/include/dev/spi/zynq-qspi-flashdev.h index 78d8f0ac22..b67de802d2 100644 --- a/bsps/arm/xilinx-zynq/include/dev/spi/zynq-qspi-flashdev.h +++ b/bsps/arm/xilinx-zynq/include/dev/spi/zynq-qspi-flashdev.h @@ -34,10 +34,11 @@ #define ZQSPI_FLASH_MAX_REGIONS ((size_t)32) /* - * @brief Initializes a flash device using zynq qspi flash - * driver. The flash device is not registered in this call. - * If an rtems_flashdev is created using zqspi_flash_init it must be - * destroyed using xqspi_flash_destroy. + * @brief Initializes a flash device using zynq qspi flash driver. + * + * The flash device is not registered in this call. If an rtems_flashdev is + * created using zqspi_flash_init and is not registered, it must be destroyed + * using rtems_flashdev_destroy. * * @param[in] zqspiflash A initialised zqspiflash device to wrap. * @@ -46,16 +47,6 @@ */ rtems_flashdev* zqspi_flashdev_init(zqspiflash *bmdriver); -/* - * @brief Destroys a rtems_flashdev initialised with zqspi_flash_init. - * If an rtems_flashdev is created using zqspi_flash_init it must be - * destroyed using zqspi_flash_destroy. The zqspiflash originally passed in - * is untouched. - * - * @param[in] flash The flashdev to destroy -*/ -void zqspi_flashdev_destroy(rtems_flashdev* flash); - /* * @brief Struct allocating memory space for flash regions. Used by * rtems_flashdev to store region allocations. diff --git a/bsps/include/dev/spi/xqspi_flash.h b/bsps/include/dev/spi/xqspi_flash.h index dbd1f913d3..92010eae7c 100644 --- a/bsps/include/dev/spi/xqspi_flash.h +++ b/bsps/include/dev/spi/xqspi_flash.h @@ -38,10 +38,10 @@ extern "C" { #define XQSPI_FLASH_MAX_REGIONS ((size_t)32) /* - * @brief Initializes a flash device using Xilinx's xqspi flash - * driver. The flash device is not registered in this call. - * If an rtems_flashdev is created using xqspi_flash_init it must be - * destroyed using xqspi_flash_destroy. + * @brief Initializes a flash device using Xilinx's xqspi flash driver. + * + * The flash device is not registered in this call. The returned object must be + * destroyed with rtems_flashdev_destroy_and_free if it has not been registered. * * @param[in] xQspiDev A configured XQspiPsu device to initialise. * @@ -50,16 +50,6 @@ extern "C" { */ rtems_flashdev* xqspi_flash_init(XQspiPsu *xQspiDev); -/* - * @brief Destroys a rtems_flashdev initialised with xqspi_flash_init. - * If an rtems_flashdev is created using xqspi_flash_init it must be - * destroyed using xqspi_flash_destroy. The XQspiPsu originally passed in - * is untouched. - * - * @param[in] flash The flashdev to destroy -*/ -void xqspi_flash_destroy(rtems_flashdev* flash); - /* * @brief Struct allocating memory space for flash regions. Used by * rtems_flashdev to store region allocations. diff --git a/bsps/shared/dev/spi/xqspi_flash.c b/bsps/shared/dev/spi/xqspi_flash.c index 299cfd37f9..e757e4f9bb 100644 --- a/bsps/shared/dev/spi/xqspi_flash.c +++ b/bsps/shared/dev/spi/xqspi_flash.c @@ -121,6 +121,12 @@ static int xqspi_erase_wrapper( return QspiPsu_NOR_Erase(flash_driver, (uint32_t)offset, (uint32_t)count); } +static void xqspi_flash_priv_destroy(rtems_flashdev* flash) +{ + free(flash->region_table->regions); + free(flash->region_table); +} + rtems_flashdev* xqspi_flash_init(XQspiPsu *xQspiDev) { xqspi_flash_region_table *xtable = @@ -152,6 +158,7 @@ rtems_flashdev* xqspi_flash_init(XQspiPsu *xQspiDev) } flash->driver = xQspiDev; + flash->priv_destroy = &xqspi_flash_priv_destroy; flash->read = &xqspi_read_wrapper; flash->write = &xqspi_write_wrapper; flash->erase = &xqspi_erase_wrapper; @@ -165,10 +172,3 @@ rtems_flashdev* xqspi_flash_init(XQspiPsu *xQspiDev) return flash; } - -void xqspi_flash_destroy(rtems_flashdev* flash) -{ - free(flash->region_table->regions); - free(flash->region_table); - rtems_flashdev_destroy_and_free(flash); -} diff --git a/cpukit/dev/flash/flashdev.c b/cpukit/dev/flash/flashdev.c index 482468cb67..852af49bb9 100644 --- a/cpukit/dev/flash/flashdev.c +++ b/cpukit/dev/flash/flashdev.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -503,6 +504,13 @@ int rtems_flashdev_register( return rv; } +int rtems_flashdev_unregister( + const char *flash_path +) +{ + return unlink(flash_path); +} + static int rtems_flashdev_do_init( rtems_flashdev *flash, void ( *destroy )( rtems_flashdev *flash ) @@ -517,25 +525,38 @@ static int rtems_flashdev_do_init( void rtems_flashdev_destroy( rtems_flashdev *flash ) { - rtems_recursive_mutex_destroy( &flash->mutex ); + ( *flash->destroy )( flash ); } void rtems_flashdev_destroy_and_free( rtems_flashdev *flash ) +{ + rtems_flashdev_destroy( flash ); +} + +static void flashdev_destroy_internal( rtems_flashdev *flash ) +{ + if (flash->priv_destroy != NULL) { + ( *flash->priv_destroy )( flash ); + } + + rtems_recursive_mutex_destroy( &flash->mutex ); +} + +static void flashdev_destroy_and_free_internal( rtems_flashdev *flash ) { if ( flash == NULL ) { return; } - rtems_recursive_mutex_destroy( &( flash->mutex ) ); + flashdev_destroy_internal( flash ); free( flash ); flash = NULL; - return; } int rtems_flashdev_init( rtems_flashdev *flash ) { memset( flash, 0, sizeof( *flash ) ); - return rtems_flashdev_do_init( flash, rtems_flashdev_destroy ); + return rtems_flashdev_do_init( flash, flashdev_destroy_internal ); } rtems_flashdev *rtems_flashdev_alloc_and_init( size_t size ) @@ -547,7 +568,7 @@ rtems_flashdev *rtems_flashdev_alloc_and_init( size_t size ) if ( flash != NULL ) { int rv; - rv = rtems_flashdev_do_init( flash, rtems_flashdev_destroy_and_free ); + rv = rtems_flashdev_do_init( flash, flashdev_destroy_and_free_internal ); if ( rv != 0 ) { rtems_recursive_mutex_destroy( &flash->mutex ); free( flash ); diff --git a/cpukit/include/dev/flash/flashdev.h b/cpukit/include/dev/flash/flashdev.h index 62bc5cf443..207b794c68 100644 --- a/cpukit/include/dev/flash/flashdev.h +++ b/cpukit/include/dev/flash/flashdev.h @@ -443,6 +443,16 @@ struct rtems_flashdev { rtems_flashdev *flashdev ); + /** + * @brief Callback to destroy private data not owned directly by the flashdev + * framework. + * + * @param[in] flash Pointer to flash device. + */ + void ( *priv_destroy )( + rtems_flashdev *flashdev + ); + /** * @brief Pointer to device driver. */ @@ -495,7 +505,8 @@ int rtems_flashdev_init( /** * @brief Register the flash device. * - * This function always claims ownership of the flash device. + * This function always claims ownership of the flash device passed to it. Once + * registered, the flash device can only be destroyed by unregistering it. * * After initialization and before registration read, write, erase, jedec_id * and flash_type functions need to be set in the flashdev. @@ -511,9 +522,24 @@ int rtems_flashdev_register( const char *flash_path ); +/** + * @brief Unregister the flash device. + * + * @param[in] flash The flash device. + * + * @retval 0 Successful operation. + * @retval non-zero Failed operation. + */ +int rtems_flashdev_unregister( + const char *flash_path +); + /** * @brief Destroys the flash device. * + * This function must only be used on rtems_flashdev instances that have not + * been registered. + * * @param[in] flash The flash device. */ void rtems_flashdev_destroy( @@ -523,6 +549,9 @@ void rtems_flashdev_destroy( /** * @brief Destroys the flash device and frees its memory. * + * This function must only be used on rtems_flashdev instances that have not + * been registered. + * * @param[in] flash The flash device. */ void rtems_flashdev_destroy_and_free( diff --git a/testsuites/libtests/flashdev01/init.c b/testsuites/libtests/flashdev01/init.c index 54b6290e01..8b348778ce 100644 --- a/testsuites/libtests/flashdev01/init.c +++ b/testsuites/libtests/flashdev01/init.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #define TEST_NAME_LENGTH 10 @@ -64,6 +65,32 @@ static void run_test(void) { int sector_count; int type; size_t wb_size; + rtems_resource_snapshot snapshot; + + /* Check resource usage on creation and deletion */ + rtems_resource_snapshot_take(&snapshot); + + flash = test_flashdev_init(); + rtems_test_assert(flash != NULL); + + rtems_flashdev_destroy(flash); + flash = NULL; + + rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); + + /* Check resource usage on registration */ + rtems_resource_snapshot_take(&snapshot); + + flash = test_flashdev_init(); + rtems_test_assert(flash != NULL); + + status = rtems_flashdev_register(flash, "dev/flashdev0"); + rtems_test_assert(!status); + + status = rtems_flashdev_unregister("dev/flashdev0"); + rtems_test_assert(!status); + + rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); /* Initalize the flash device driver and flashdev */ flash = test_flashdev_init(); @@ -78,6 +105,12 @@ static void run_test(void) { rtems_test_assert(file != NULL); fd = fileno(file); + /* Initial read to establish cached buffers */ + read_data = fgets(buff, TEST_DATA_SIZE, file); + rtems_test_assert(read_data != NULL); + + rtems_resource_snapshot_take(&snapshot); + /* Read data from flash */ read_data = fgets(buff, TEST_DATA_SIZE, file); rtems_test_assert(read_data != NULL); @@ -176,6 +209,14 @@ static void run_test(void) { fseek(file, 0x400, SEEK_SET); fgets(buff, 11, file); rtems_test_assert(strncmp(buff, "HELLO WORLD", 11)); + + rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); + + status = fclose(file); + rtems_test_assert(!status); + + status = rtems_flashdev_unregister("dev/flashdev0"); + rtems_test_assert(!status); } static void Init(rtems_task_argument arg) diff --git a/testsuites/libtests/flashdev01/test_flashdev.c b/testsuites/libtests/flashdev01/test_flashdev.c index 2fc0b3e83a..993cb9ae99 100644 --- a/testsuites/libtests/flashdev01/test_flashdev.c +++ b/testsuites/libtests/flashdev01/test_flashdev.c @@ -264,6 +264,14 @@ int test_flashdev_erase( return 0; } +static void test_flashdev_priv_destroy(rtems_flashdev *flash) +{ + test_flashdev* flash_driver = flash->driver; + free(flash_driver->data); + free(flash->driver); + free(flash->region_table); +} + /* Initialize Flashdev and underlying driver. */ rtems_flashdev* test_flashdev_init(void) { @@ -295,6 +303,7 @@ rtems_flashdev* test_flashdev_init(void) ftable->bit_allocator = flash_driver->bit_allocator; flash->driver = flash_driver; + flash->priv_destroy = &test_flashdev_priv_destroy; flash->read = &test_flashdev_read; flash->write = &test_flashdev_write; flash->erase = &test_flashdev_erase;