From 714114c8a7368192f679429f64cc3eeed8892f4c Mon Sep 17 00:00:00 2001 From: Peter Bigot Date: Tue, 2 Feb 2021 10:37:30 -0600 Subject: [PATCH] device: store device pm busy status in the state structure Move the busy status from a global atomic bit sequence to atomic flags in the device PM state. While this temporarily adds 4 bytes to each PM structure the whole device PM infrastructure will be refactored and it's likely the extra memory can be recovered. Signed-off-by: Peter Bigot --- include/device.h | 10 +++++++++- include/linker/common-ram.ld | 22 --------------------- kernel/device.c | 37 +++++++++++++++++------------------- 3 files changed, 26 insertions(+), 43 deletions(-) diff --git a/include/device.h b/include/device.h index 51ee8b3dcb62d4..3eba62d4c706a2 100644 --- a/include/device.h +++ b/include/device.h @@ -270,8 +270,11 @@ struct device_pm { const struct device *dev; /** Lock to synchronize the get/put operations */ struct k_sem lock; + /* Following are packed fields protected by #lock. */ /** Device pm enable flag */ - bool enable; + bool enable : 1; + /* Following are packed fields accessed with atomic bit operations. */ + atomic_t atomic_flags; /** Device usage count */ atomic_t usage; /** Device idle internal power state */ @@ -284,6 +287,11 @@ struct device_pm { struct k_poll_signal signal; }; +/** Bit position in device_pm::atomic_flags that records whether the + * device is busy. + */ +#define DEVICE_PM_ATOMIC_FLAGS_BUSY_BIT 0 + /** * @brief Runtime device dynamic structure (in RAM) per driver instance * diff --git a/include/linker/common-ram.ld b/include/linker/common-ram.ld index c6838af3d81a75..64285bd3b759f8 100644 --- a/include/linker/common-ram.ld +++ b/include/linker/common-ram.ld @@ -13,27 +13,6 @@ } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif -/* - * Space for storing per device init status and busy bitmap in case PM is - * enabled. Since we do not know beforehand the number of devices, - * we go through the below mechanism to allocate the required space. - * Both are made of 1 bit per-device instance, so we compute the size of - * of an entire bitfield, aligned on 32bits. - */ -#define DEVICE_COUNT \ - ((__device_end - __device_start) / _DEVICE_STRUCT_SIZEOF) -#define DEVICE_BITFIELD_SIZE (((DEVICE_COUNT + 31) / 32) * 4) - -#ifdef CONFIG_PM_DEVICE -#define DEVICE_BUSY_BITFIELD() \ - FILL(0x00); \ - __device_busy_start = .; \ - . = . + DEVICE_BITFIELD_SIZE; \ - __device_busy_end = .; -#else -#define DEVICE_BUSY_BITFIELD() -#endif - SECTION_DATA_PROLOGUE(devices,,) { /* link in devices objects, which are tied to the init ones; @@ -47,7 +26,6 @@ CREATE_OBJ_LEVEL(device, APPLICATION) CREATE_OBJ_LEVEL(device, SMP) __device_end = .; - DEVICE_BUSY_BITFIELD() } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) SECTION_DATA_PROLOGUE(initshell,,) diff --git a/kernel/device.c b/kernel/device.c index 5e6556020b2655..b561b9745c1871 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -25,12 +25,6 @@ extern const struct device __device_end[]; extern uint32_t __device_init_status_start[]; -#ifdef CONFIG_PM_DEVICE -extern uint32_t __device_busy_start[]; -extern uint32_t __device_busy_end[]; -#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start) -#endif - static inline void device_pm_state_init(const struct device *dev) { #ifdef CONFIG_PM_DEVICE @@ -180,20 +174,23 @@ int device_pm_control_nop(const struct device *unused_device, int device_any_busy_check(void) { - int i = 0; + const struct device *dev = __device_start; - for (i = 0; i < DEVICE_BUSY_SIZE; i++) { - if (__device_busy_start[i] != 0U) { + while (dev < __device_end) { + if (atomic_test_bit(&dev->pm->atomic_flags, + DEVICE_PM_ATOMIC_FLAGS_BUSY_BIT)) { return -EBUSY; } + ++dev; } + return 0; } -int device_busy_check(const struct device *chk_dev) +int device_busy_check(const struct device *dev) { - if (atomic_test_bit((const atomic_t *)__device_busy_start, - (chk_dev - __device_start))) { + if (atomic_test_bit(&dev->pm->atomic_flags, + DEVICE_PM_ATOMIC_FLAGS_BUSY_BIT)) { return -EBUSY; } return 0; @@ -201,22 +198,22 @@ int device_busy_check(const struct device *chk_dev) #endif -void device_busy_set(const struct device *busy_dev) +void device_busy_set(const struct device *dev) { #ifdef CONFIG_PM_DEVICE - atomic_set_bit((atomic_t *) __device_busy_start, - (busy_dev - __device_start)); + atomic_set_bit(&dev->pm->atomic_flags, + DEVICE_PM_ATOMIC_FLAGS_BUSY_BIT); #else - ARG_UNUSED(busy_dev); + ARG_UNUSED(dev); #endif } -void device_busy_clear(const struct device *busy_dev) +void device_busy_clear(const struct device *dev) { #ifdef CONFIG_PM_DEVICE - atomic_clear_bit((atomic_t *) __device_busy_start, - (busy_dev - __device_start)); + atomic_clear_bit(&dev->pm->atomic_flags, + DEVICE_PM_ATOMIC_FLAGS_BUSY_BIT); #else - ARG_UNUSED(busy_dev); + ARG_UNUSED(dev); #endif }