ram savings by using new bitfield-based rsc alloc

sipo
Ondřej Hruška 6 years ago
parent e82306c36f
commit 05a568a27c
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 107
      framework/resources.c
  2. 59
      framework/rsc_enum.h
  3. 3
      framework/unit.h
  4. 12
      framework/unit_registry.c
  5. 8
      framework/unit_registry.h
  6. 2
      gex.mk
  7. 8
      platform/pin_utils.c
  8. 32
      platform/platform.c
  9. 2
      utils/error.h

@ -6,18 +6,15 @@
#include "unit.h"
#include "resources.h"
#include "pin_utils.h"
#include "unit_registry.h"
static bool rsc_initialized = false;
// This takes quite a lot of space, we could use u8 and IDs instead if needed
struct resouce_slot {
const char *name;
Unit *owner;
} __attribute__((packed));
static ResourceMap global_rscmap;
static struct resouce_slot resources[R_RESOURCE_COUNT];
// here are the resource names for better debugging
// here are the resource names for better debugging (could also be removed if absolutely necessary)
// this list doesn't include GPIO names, they can be easily generated
const char *const rsc_names[] = {
#define X(res_name) #res_name,
XX_RESOURCES
@ -27,16 +24,28 @@ const char *const rsc_names[] = {
/** Get rsc name */
const char * rsc_get_name(Resource rsc)
{
assert_param(rsc < R_RESOURCE_COUNT);
assert_param(rsc < RESOURCE_COUNT);
static char gpionamebuf[4];
if (rsc >= R_PA0) {
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call.
uint8_t index = rsc - R_PA0;
SNPRINTF(gpionamebuf, 4, "%c%d", 'A'+(index/16), index%16);
return gpionamebuf;
}
return rsc_names[rsc];
}
/** Get rsc owner name */
const char * rsc_get_owner_name(Resource rsc)
{
assert_param(rsc < R_RESOURCE_COUNT);
if (resources[rsc].owner == NULL) return "NULL";
return resources[rsc].owner->name;
assert_param(rsc < RESOURCE_COUNT);
Unit *pUnit = ureg_get_rsc_owner(rsc);
if (pUnit == NULL) return "NULL";
return pUnit->name;
}
/**
@ -44,9 +53,10 @@ const char * rsc_get_owner_name(Resource rsc)
*/
void rsc_init_registry(void)
{
for (int i = 0; i < R_RESOURCE_COUNT; i++) {
resources[i].owner = &UNIT_PLATFORM;
for(uint32_t i = 0; i < RSCMAP_LEN; i++) {
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF;
}
rsc_initialized = true;
}
@ -60,22 +70,38 @@ void rsc_init_registry(void)
error_t rsc_claim(Unit *unit, Resource rsc)
{
assert_param(rsc_initialized);
assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT);
assert_param(rsc < RESOURCE_COUNT);
assert_param(unit != NULL);
if (resources[rsc].owner) {
//TODO properly report to user
if (RSC_IS_HELD(global_rscmap, rsc)) {
// this whole branch is just reporting the error
Unit *holder = ureg_get_rsc_owner(rsc);
if (holder == NULL) {
// It must be one of the dummy built-in units
if (RSC_IS_HELD(UNIT_SYSTEM.resources, rsc))
holder = &UNIT_SYSTEM;
else if (RSC_IS_HELD(UNIT_PLATFORM.resources, rsc))
holder = &UNIT_SYSTEM;
}
assert_param(holder != NULL);
dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!",
unit->name,
rsc_get_name(rsc),
rsc_get_owner_name(rsc));
holder->name);
unit->failed_rsc = rsc;
return E_RESOURCE_NOT_AVAILABLE;
}
resources[rsc].owner = unit;
// must claim both in global and in unit
RSC_CLAIM(global_rscmap, rsc);
RSC_CLAIM(unit->resources, rsc);
return E_SUCCESS;
}
@ -90,8 +116,9 @@ error_t rsc_claim(Unit *unit, Resource rsc)
error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1)
{
assert_param(rsc_initialized);
assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT);
assert_param(rsc1 > R_NONE && rsc1 < R_RESOURCE_COUNT);
assert_param(rsc0 < RESOURCE_COUNT);
assert_param(rsc1 < RESOURCE_COUNT);
assert_param(rsc0 <= rsc1);
assert_param(unit != NULL);
for (int i = rsc0; i <= rsc1; i++) {
@ -125,11 +152,29 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
void rsc_free(Unit *unit, Resource rsc)
{
assert_param(rsc_initialized);
assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT);
assert_param(rsc < RESOURCE_COUNT);
if (RSC_IS_FREE(global_rscmap, rsc)) return;
// free it in any unit that holds it
if (unit) {
if (RSC_IS_HELD(unit->resources, rsc)) {
RSC_FREE(unit->resources, rsc);
}
} else {
// Try to free it in any unit that may hold it
unit = ureg_get_rsc_owner(rsc);
if (unit == NULL) {
// try one of the built-in ones
if (RSC_IS_HELD(UNIT_SYSTEM.resources, rsc)) unit = &UNIT_SYSTEM;
else if (RSC_IS_HELD(UNIT_PLATFORM.resources, rsc)) unit = &UNIT_PLATFORM;
}
if (unit == NULL || resources[rsc].owner == unit) {
resources[rsc].owner = NULL;
if (unit != NULL) RSC_FREE(unit->resources, rsc);
}
// also free it in the global map
RSC_FREE(global_rscmap, rsc);
}
/**
@ -142,13 +187,12 @@ void rsc_free(Unit *unit, Resource rsc)
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1)
{
assert_param(rsc_initialized);
assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT);
assert_param(rsc1 > R_NONE && rsc1 < R_RESOURCE_COUNT);
assert_param(rsc0 < RESOURCE_COUNT);
assert_param(rsc1 < RESOURCE_COUNT);
assert_param(rsc0 <= rsc1);
for (int i = rsc0; i <= rsc1; i++) {
if (unit == NULL || resources[i].owner == unit) {
resources[i].owner = NULL;
}
rsc_free(unit, (Resource) i);
}
}
@ -162,9 +206,8 @@ void rsc_teardown(Unit *unit)
assert_param(rsc_initialized);
assert_param(unit != NULL);
for (int i = R_NONE+1; i < R_RESOURCE_COUNT; i++) {
if (resources[i].owner == unit) {
resources[i].owner = NULL;
}
for (uint32_t i = 0; i < RSCMAP_LEN; i++) {
global_rscmap[i] &= ~unit->resources[i];
unit->resources[i] = 0;
}
}

@ -7,7 +7,30 @@
// X macro: Resource name,
#define XX_RESOURCES \
X(NONE) \
X(SPI1) X(SPI2) X(SPI3) \
X(I2C1) X(I2C2) X(I2C3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(DAC1) X(DAC2) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
X(TIM15) X(TIM16) X(TIM17) \
X(DMA1) X(DMA2)
// Resources not used anywhere:
// X(I2S1) X(I2S2) X(I2S3)
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
// X(CAN1) X(CAN2)
// X(TSC)
// X(DCMI)
// X(ETH)
// X(FSMC)
// X(SDIO)
// X(RNG) X(LCD)
// X(HDMI_CEC)
// X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7)
#define XX_RESOURCES_GPIO \
X(PA0) X(PA1) X(PA2) X(PA3) X(PA4) X(PA5) X(PA6) X(PA7) \
X(PA8) X(PA9) X(PA10) X(PA11) X(PA12) X(PA13) X(PA14) X(PA15) \
X(PB0) X(PB1) X(PB2) X(PB3) X(PB4) X(PB5) X(PB6) X(PB7) \
@ -20,26 +43,6 @@
X(PE8) X(PE9) X(PE10) X(PE11) X(PE12) X(PE13) X(PE14) X(PE15) \
X(PF0) X(PF1) X(PF2) X(PF3) X(PF4) X(PF5) X(PF6) X(PF7) \
X(PF8) X(PF9) X(PF10) X(PF11) X(PF12) X(PF13) X(PF14) X(PF15) \
X(SPI1) X(SPI2) X(SPI3) \
X(I2C1) X(I2C2) X(I2C3) \
X(I2S1) X(I2S2) X(I2S3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) \
X(DAC1) X(DAC2) \
X(CAN1) X(CAN2) \
X(TSC) \
X(DCMI) \
X(ETH) \
X(FSMC) \
X(SDIO) \
X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7) \
X(HDMI_CEC) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
X(TIM15) X(TIM16) X(TIM17) \
X(DMA1) X(DMA2) \
X(RNG) X(LCD)
// GPIOs are allocated whenever the pin is needed
// (e.g. when used for SPI, the R_SPI resource as well as the corresponding R_GPIO resources must be claimed)
@ -70,8 +73,20 @@ typedef enum hw_resource Resource;
enum hw_resource {
#define X(res_name) R_##res_name,
XX_RESOURCES
XX_RESOURCES_GPIO
#undef X
R_RESOURCE_COUNT
R_NONE,
RESOURCE_COUNT = R_NONE,
};
#define RSCMAP_LEN ((RESOURCE_COUNT/8)+1)
typedef uint8_t ResourceMap[RSCMAP_LEN];
#define RSC_IS_FREE(rscmap, rsc) (0 == (rscmap[((rsc)>>3)&0xFF] & (1<<((rsc)&0x7))))
#define RSC_IS_HELD(rscmap, rsc) (!RSC_IS_FREE(rscmap, rsc))
#define RSC_CLAIM(rscmap, rsc) do { rscmap[((rsc)>>3)&0xFF] |= (1<<((rsc)&0x7)); } while(0)
#define RSC_FREE(rscmap, rsc) do { rscmap[((rsc)>>3)&0xFF] &= ~(1<<((rsc)&0x7)); } while(0)
#endif //GEX_F072_RSC_ENUM_H

@ -42,6 +42,9 @@ struct unit {
/** If RSC not avail. error is caught, the resource is stored here. */
Resource failed_rsc;
/** Bit-map of held resources */
ResourceMap resources;
};
/**

@ -530,3 +530,15 @@ void ureg_report_active_units(TF_ID frame_id)
}
free(buff);
}
Unit *ureg_get_rsc_owner(Resource resource)
{
UlistEntry *li = ulist_head;
while (li != NULL) {
if (RSC_IS_HELD(li->unit.resources, resource)) {
return &li->unit;
}
li = li->next;
}
return NULL;
}

@ -127,4 +127,12 @@ void ureg_deliver_unit_request(TF_Msg *msg);
*/
void ureg_report_active_units(TF_ID frame_id);
/**
* Get unit holding a resource, or NULL.
*
* @param resource
* @return unit
*/
Unit *ureg_get_rsc_owner(Resource resource);
#endif //GEX_UNIT_REGISTRY_H

@ -83,7 +83,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \
-DVERBOSE_ASSERT=1 \
-DDEBUG_VFS=0 \
-DDEBUG_FLASH_WRITE=0 \
-DVERBOSE_HARDFAULT=1 \
-DVERBOSE_HARDFAULT=0 \
-DUSE_STACK_MONITOR=0 \
-DUSE_DEBUG_UART=1

@ -208,17 +208,17 @@ char * str_pinmask(uint16_t pins, char *buffer)
} else {
if (on) {
if (!first) {
b += sprintf(b, ",");
b += SPRINTF(b, ",");
}
if (start == (uint32_t)(i+1)) {
b += sprintf(b, "%"PRIu32, start);
b += SPRINTF(b, "%"PRIu32, start);
}
else if (start == (uint32_t)(i+2)) {
// exception for 2-long ranges - don't show as range
b += sprintf(b, "%"PRIu32",%"PRIu32, start, i + 1);
b += SPRINTF(b, "%"PRIu32",%"PRIu32, start, i + 1);
}
else {
b += sprintf(b, "%"PRIu32"-%"PRIu32, start, i + 1);
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;

@ -83,13 +83,13 @@ void plat_init_resources(void)
// Free all present resources
{
rsc_free(NULL, R_ADC1);
rsc_free(NULL, R_CAN1);
rsc_free_range(NULL, R_COMP1, R_COMP2);
// rsc_free(NULL, R_CAN1);
// rsc_free_range(NULL, R_COMP1, R_COMP2);
rsc_free(NULL, R_DAC1);
rsc_free(NULL, R_HDMI_CEC);
rsc_free(NULL, R_TSC);
// rsc_free(NULL, R_HDMI_CEC);
// rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_I2C1, R_I2C2);
rsc_free_range(NULL, R_I2S1, R_I2S2);
// rsc_free_range(NULL, R_I2S1, R_I2S2);
rsc_free_range(NULL, R_SPI1, R_SPI2);
rsc_free_range(NULL, R_TIM1, R_TIM3);
rsc_free_range(NULL, R_TIM6, R_TIM7);
@ -131,18 +131,18 @@ void plat_init_resources(void)
// Free all present resources
{
rsc_free_range(NULL, R_ADC1, R_ADC4);
rsc_free(NULL, R_CAN1);
rsc_free_range(NULL, R_COMP1, R_COMP7);
rsc_free(NULL, R_HDMI_CEC);
// rsc_free(NULL, R_CAN1);
// rsc_free_range(NULL, R_COMP1, R_COMP7);
// rsc_free(NULL, R_HDMI_CEC);
rsc_free(NULL, R_DAC1);
rsc_free_range(NULL, R_I2C1, R_I2C2);
rsc_free_range(NULL, R_I2S2, R_I2S3);
rsc_free_range(NULL, R_OPAMP1, R_OPAMP4);
// rsc_free_range(NULL, R_OPAMP1, R_OPAMP4);
rsc_free_range(NULL, R_SPI1, R_SPI3);
rsc_free_range(NULL, R_TIM1, R_TIM4);
rsc_free_range(NULL, R_TIM6, R_TIM8);
rsc_free_range(NULL, R_TIM15, R_TIM17);
rsc_free(NULL, R_TSC);
// rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_USART1, R_USART5);
rsc_free_range(NULL, R_PA0, R_PA15);
@ -184,15 +184,15 @@ void plat_init_resources(void)
// Free all present resources
{
rsc_free_range(NULL, R_ADC1, R_ADC3);
rsc_free_range(NULL, R_CAN1, R_CAN2);
rsc_free_range(NULL, R_COMP1, R_COMP7);
// rsc_free_range(NULL, R_CAN1, R_CAN2);
// rsc_free_range(NULL, R_COMP1, R_COMP7);
rsc_free(NULL, R_DAC1);
rsc_free(NULL, R_DCMI);
rsc_free(NULL, R_ETH);
rsc_free(NULL, R_FSMC);
// rsc_free(NULL, R_DCMI);
// rsc_free(NULL, R_ETH);
// rsc_free(NULL, R_FSMC);
rsc_free_range(NULL, R_I2C1, R_I2C3);
rsc_free_range(NULL, R_I2S2, R_I2S3);
rsc_free(NULL, R_SDIO);
// rsc_free(NULL, R_SDIO);
rsc_free_range(NULL, R_SPI1, R_SPI3);
rsc_free_range(NULL, R_TIM1, R_TIM14);
rsc_free_range(NULL, R_USART1, R_USART3);

@ -58,7 +58,7 @@
X(BAD_KEY, "Unexpected config key") \
X(BAD_VALUE, "Bad config value") \
X(OUT_OF_MEM, "Not enough RAM") \
X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available")
X(RESOURCE_NOT_AVAILABLE, NULL)
// Keep in sync with the list error_message
typedef enum {

Loading…
Cancel
Save