pm/loapic: suspend/resume support for LOAPIC

Provide functions of saving and restoring LOAPIC
states to support deep sleep.

Jira: ZEP-223
Change-Id: I1fb427989b021ec8e3a4f6dd0f4766a214360621
Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
This commit is contained in:
Jithu Joseph 2016-05-06 21:55:51 -07:00 committed by Anas Nashif
parent b1625df534
commit 09a0c2f619

View file

@ -90,12 +90,14 @@
#include <nanokernel.h>
#include <arch/cpu.h>
#include <stdint.h>
#include <string.h>
#include "board.h"
#include <toolchain.h>
#include <sections.h>
#include <drivers/loapic.h> /* public API declarations */
#include <init.h>
#include <drivers/sysapic.h>
/* IA32_APIC_BASE MSR Bits */
@ -187,6 +189,14 @@
#define LOAPIC_SPURIOUS_VECTOR_ID CONFIG_LOAPIC_SPURIOUS_VECTOR_ID
#endif
#define LOPIC_SSPND_BITS_PER_IRQ 1 /* Just the one for enable disable*/
#define LOPIC_SUSPEND_BITS_REQD (ROUND_UP((LOAPIC_IRQ_COUNT * LOPIC_SSPND_BITS_PER_IRQ), 32))
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
#include <power.h>
uint32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0};
#endif
/**
*
* @brief Initialize the Local APIC or xAPIC
@ -444,7 +454,82 @@ int _loapic_isr_vector_get(void)
return 0;
}
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
static int loapic_suspend(struct device *port, int pm_policy)
{
volatile int *pLvt; /* pointer to local vector table */
int loapic_irq;
ARG_UNUSED(port);
if (pm_policy != SYS_PM_DEEP_SLEEP) {
return 0;
}
memset(loapic_suspend_buf, 0, (LOPIC_SUSPEND_BITS_REQD >> 3));
for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
if (_irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]) {
/* Since vector numbers are already present in RAM/ROM,
* We save only the mask bits here.
*/
pLvt = (volatile int *)
(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_TIMER +
(loapic_irq * 0x10));
if ((*pLvt & LOAPIC_LVT_MASKED) == 0) {
sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf,
loapic_irq);
}
}
}
return 0;
}
int loapic_resume(struct device *port, int pm_policy)
{
int loapic_irq;
ARG_UNUSED(port);
if (pm_policy != SYS_PM_DEEP_SLEEP) {
return 0;
}
/* Assuming all loapic device registers lose their state, the call to
* _loapic_init(), should bring all the registers to a sane state.
*/
_loapic_init(NULL);
for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
if (_irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]) {
/* Configure vector and enable the required ones*/
_loapic_int_vec_set(loapic_irq,
_irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]);
if (sys_bitfield_test_bit((mem_addr_t) loapic_suspend_buf,
loapic_irq)) {
_loapic_irq_enable(loapic_irq);
}
}
}
return 0;
}
struct device_pm_ops loapic_pm_ops = {
.suspend = loapic_suspend,
.resume = loapic_resume
};
SYS_INIT_PM("loapic", _loapic_init, &loapic_pm_ops, PRIMARY,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#else
SYS_INIT(_loapic_init, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif /* CONFIG_DEVICE_POWER_MANAGEMENT */
#if CONFIG_LOAPIC_SPURIOUS_VECTOR
extern void _loapic_spurious_handler(void);