Skip to content

Commit

Permalink
device: store device pm busy status in the state structure
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
pabigot authored and nashif committed Feb 19, 2021
1 parent 65eee5c commit d1a0568
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 43 deletions.
10 changes: 9 additions & 1 deletion include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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
*
Expand Down
22 changes: 0 additions & 22 deletions include/linker/common-ram.ld
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,,)
Expand Down
37 changes: 17 additions & 20 deletions kernel/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -180,43 +174,46 @@ 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;
}

#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
}

0 comments on commit d1a0568

Please sign in to comment.