mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
cpuidle: Enable hpet broadcast by default
And stop legacy hpet broadcast and limit max C-state to shallower state if RTC interrupts are enabled. Signed-off-by: Wei Gang <gang.wei@intel.com> Signed-off-by: Tian Kevin <kevin.tian@intel.com>
This commit is contained in:
1 parent
9c854741d6
commit
d09486dba3
4 files changed
+91
-6
No files matched your search
@@ -221,8 +221,8 @@ static void acpi_processor_idle(void)
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = power ? cpuidle_current_governor->select(power) : -1;
|
||||
if ( next_state > 0 )
|
||||
if ( max_cstate > 0 && power &&
|
||||
(next_state = cpuidle_current_governor->select(power)) > 0 )
|
||||
{
|
||||
cx = &power->states[next_state];
|
||||
if ( power->flags.bm_check && acpi_idle_bm_check()
|
||||
@@ -853,3 +853,18 @@ int pmstat_reset_cx_stat(uint32_t cpuid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpuidle_disable_deep_cstate(void)
|
||||
{
|
||||
if ( max_cstate > 1 )
|
||||
{
|
||||
if ( local_apic_timer_c2_ok )
|
||||
max_cstate = 2;
|
||||
else
|
||||
max_cstate = 1;
|
||||
}
|
||||
|
||||
mb();
|
||||
|
||||
hpet_disable_legacy_broadcast();
|
||||
}
|
||||
|
||||
+67
-4
@@ -22,8 +22,10 @@
|
||||
|
||||
#define MAX_HPET_NUM 32
|
||||
|
||||
#define HPET_EVT_USED_BIT 2
|
||||
#define HPET_EVT_USED_BIT 0
|
||||
#define HPET_EVT_USED (1 << HPET_EVT_USED_BIT)
|
||||
#define HPET_EVT_DISABLE_BIT 1
|
||||
#define HPET_EVT_DISALBE (1 << HPET_EVT_DISABLE_BIT)
|
||||
|
||||
struct hpet_event_channel
|
||||
{
|
||||
@@ -53,8 +55,11 @@ unsigned long hpet_address;
|
||||
|
||||
void msi_compose_msg(struct pci_dev *pdev, int vector, struct msi_msg *msg);
|
||||
|
||||
/* force_hpet_broadcast: if true, force using hpet_broadcast to fix lapic stop
|
||||
issue for deep C state with pit disabled */
|
||||
/*
|
||||
* force_hpet_broadcast: by default legacy hpet broadcast will be stopped
|
||||
* if RTC interrupts are enabled. Enable this option if want to always enable
|
||||
* legacy hpet broadcast for deep C state
|
||||
*/
|
||||
int force_hpet_broadcast;
|
||||
boolean_param("hpetbroadcast", force_hpet_broadcast);
|
||||
|
||||
@@ -114,6 +119,9 @@ static int reprogram_hpet_evt_channel(
|
||||
int64_t delta;
|
||||
int ret;
|
||||
|
||||
if ( ch->flags & HPET_EVT_DISALBE )
|
||||
return 0;
|
||||
|
||||
if ( unlikely(expire < 0) )
|
||||
{
|
||||
printk(KERN_DEBUG "reprogram: expire < 0\n");
|
||||
@@ -483,6 +491,32 @@ static void hpet_detach_channel_share(int cpu)
|
||||
static void (*hpet_attach_channel)(int cpu, struct hpet_event_channel *ch);
|
||||
static void (*hpet_detach_channel)(int cpu);
|
||||
|
||||
#include <asm/mc146818rtc.h>
|
||||
void cpuidle_disable_deep_cstate(void);
|
||||
|
||||
void (*pv_rtc_handler)(unsigned int port, uint8_t value);
|
||||
|
||||
static void handle_rtc_once(unsigned int port, uint8_t value)
|
||||
{
|
||||
static int index;
|
||||
|
||||
if ( port == 0x70 )
|
||||
{
|
||||
index = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( index != RTC_REG_B )
|
||||
return;
|
||||
|
||||
/* RTC Reg B, contain PIE/AIE/UIE */
|
||||
if ( value & (RTC_PIE | RTC_AIE | RTC_UIE ) )
|
||||
{
|
||||
cpuidle_disable_deep_cstate();
|
||||
pv_rtc_handler = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void hpet_broadcast_init(void)
|
||||
{
|
||||
u64 hpet_rate;
|
||||
@@ -526,8 +560,11 @@ void hpet_broadcast_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if ( legacy_hpet_event.flags & HPET_EVT_DISALBE )
|
||||
return;
|
||||
|
||||
hpet_id = hpet_read32(HPET_ID);
|
||||
if ( !(hpet_id & HPET_ID_LEGSUP) || !force_hpet_broadcast )
|
||||
if ( !(hpet_id & HPET_ID_LEGSUP) )
|
||||
return;
|
||||
|
||||
/* Start HPET legacy interrupts */
|
||||
@@ -555,6 +592,32 @@ void hpet_broadcast_init(void)
|
||||
|
||||
for_each_cpu(i)
|
||||
per_cpu(cpu_bc_channel, i) = &legacy_hpet_event;
|
||||
|
||||
if ( !force_hpet_broadcast )
|
||||
pv_rtc_handler = handle_rtc_once;
|
||||
}
|
||||
|
||||
void hpet_disable_legacy_broadcast(void)
|
||||
{
|
||||
u32 cfg;
|
||||
|
||||
spin_lock_irq(&legacy_hpet_event.lock);
|
||||
|
||||
legacy_hpet_event.flags |= HPET_EVT_DISALBE;
|
||||
|
||||
/* disable HPET T0 */
|
||||
cfg = hpet_read32(HPET_T0_CFG);
|
||||
cfg &= ~HPET_TN_ENABLE;
|
||||
hpet_write32(cfg, HPET_T0_CFG);
|
||||
|
||||
/* Stop HPET legacy interrupts */
|
||||
cfg = hpet_read32(HPET_CFG);
|
||||
cfg &= ~HPET_CFG_LEGACY;
|
||||
hpet_write32(cfg, HPET_CFG);
|
||||
|
||||
spin_unlock_irq(&legacy_hpet_event.lock);
|
||||
|
||||
smp_send_event_check_mask(cpu_online_map);
|
||||
}
|
||||
|
||||
void hpet_broadcast_enter(void)
|
||||
|
||||
@@ -1551,6 +1551,8 @@ static uint32_t guest_io_read(
|
||||
return data;
|
||||
}
|
||||
|
||||
extern void (*pv_rtc_handler)(unsigned int port, uint8_t value);
|
||||
|
||||
static void guest_io_write(
|
||||
unsigned int port, unsigned int bytes, uint32_t data,
|
||||
struct vcpu *v, struct cpu_user_regs *regs)
|
||||
@@ -1565,6 +1567,8 @@ static void guest_io_write(
|
||||
outb((uint8_t)data, port);
|
||||
if ( pv_post_outb_hook )
|
||||
pv_post_outb_hook(port, (uint8_t)data);
|
||||
if ( ((port == 0x71) || (port == 0x70)) && pv_rtc_handler )
|
||||
pv_rtc_handler(port, (uint8_t)data);
|
||||
break;
|
||||
case 2:
|
||||
outw((uint16_t)data, port);
|
||||
@@ -1936,6 +1940,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
|
||||
io_emul(regs);
|
||||
if ( (op_bytes == 1) && pv_post_outb_hook )
|
||||
pv_post_outb_hook(port, regs->eax);
|
||||
if ( ((port == 0x71) || (port == 0x70)) && pv_rtc_handler )
|
||||
pv_rtc_handler(port, regs->eax);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -78,5 +78,6 @@ void hpet_broadcast_init(void);
|
||||
void hpet_broadcast_enter(void);
|
||||
void hpet_broadcast_exit(void);
|
||||
int hpet_broadcast_is_available(void);
|
||||
void hpet_disable_legacy_broadcast(void);
|
||||
|
||||
#endif /* __X86_HPET_H__ */
|
||||