x86/apic: Migrate apic timer to new set_state interface

Migrate apic driver to the new 'set-state' interface provided by
clockevents core, the earlier 'set-mode' interface is marked obsolete
now.

This also enables us to implement callbacks for new states of clockevent
devices, for example: ONESHOT_STOPPED.

We weren't doing anything while switching to resume mode and so that
callback isn't implemented.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Cc: linaro-kernel@lists.linaro.org
Cc: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Rientjes <rientjes@google.com>
Cc: Bandan Das <bsd@redhat.com>
Link: http://lkml.kernel.org/r/1896ac5989d27f2ac37f4786af9bd537e1921b83.1437042675.git.viresh.kumar@linaro.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Viresh Kumar 2015-07-16 16:28:44 +05:30 коммит произвёл Thomas Gleixner
Родитель c149e4cd08
Коммит b23d8e5278
1 изменённых файлов: 51 добавлений и 35 удалений

Просмотреть файл

@ -462,40 +462,53 @@ static int lapic_next_deadline(unsigned long delta,
return 0; return 0;
} }
/* static int lapic_timer_shutdown(struct clock_event_device *evt)
* Setup the lapic timer in periodic or oneshot mode
*/
static void lapic_timer_setup(enum clock_event_mode mode,
struct clock_event_device *evt)
{ {
unsigned long flags; unsigned long flags;
unsigned int v; unsigned int v;
/* Lapic used as dummy for broadcast ? */ /* Lapic used as dummy for broadcast ? */
if (evt->features & CLOCK_EVT_FEAT_DUMMY) if (evt->features & CLOCK_EVT_FEAT_DUMMY)
return; return 0;
local_irq_save(flags); local_irq_save(flags);
switch (mode) { v = apic_read(APIC_LVTT);
case CLOCK_EVT_MODE_PERIODIC: v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
case CLOCK_EVT_MODE_ONESHOT: apic_write(APIC_LVTT, v);
__setup_APIC_LVTT(lapic_timer_frequency, apic_write(APIC_TMICT, 0);
mode != CLOCK_EVT_MODE_PERIODIC, 1);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
v = apic_read(APIC_LVTT);
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write(APIC_LVTT, v);
apic_write(APIC_TMICT, 0);
break;
case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
break;
}
local_irq_restore(flags); local_irq_restore(flags);
return 0;
}
static inline int
lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot)
{
unsigned long flags;
/* Lapic used as dummy for broadcast ? */
if (evt->features & CLOCK_EVT_FEAT_DUMMY)
return 0;
local_irq_save(flags);
__setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1);
local_irq_restore(flags);
return 0;
}
static int lapic_timer_set_periodic(struct clock_event_device *evt)
{
return lapic_timer_set_periodic_oneshot(evt, false);
}
static int lapic_timer_set_oneshot(struct clock_event_device *evt)
{
return lapic_timer_set_periodic_oneshot(evt, true);
} }
/* /*
@ -513,15 +526,18 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
* The local apic timer can be used for any function which is CPU local. * The local apic timer can be used for any function which is CPU local.
*/ */
static struct clock_event_device lapic_clockevent = { static struct clock_event_device lapic_clockevent = {
.name = "lapic", .name = "lapic",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT .features = CLOCK_EVT_FEAT_PERIODIC |
| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP
.shift = 32, | CLOCK_EVT_FEAT_DUMMY,
.set_mode = lapic_timer_setup, .shift = 32,
.set_next_event = lapic_next_event, .set_state_shutdown = lapic_timer_shutdown,
.broadcast = lapic_timer_broadcast, .set_state_periodic = lapic_timer_set_periodic,
.rating = 100, .set_state_oneshot = lapic_timer_set_oneshot,
.irq = -1, .set_next_event = lapic_next_event,
.broadcast = lapic_timer_broadcast,
.rating = 100,
.irq = -1,
}; };
static DEFINE_PER_CPU(struct clock_event_device, lapic_events); static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
@ -778,7 +794,7 @@ static int __init calibrate_APIC_clock(void)
* Setup the apic timer manually * Setup the apic timer manually
*/ */
levt->event_handler = lapic_cal_handler; levt->event_handler = lapic_cal_handler;
lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt); lapic_timer_set_periodic(levt);
lapic_cal_loops = -1; lapic_cal_loops = -1;
/* Let the interrupts run */ /* Let the interrupts run */
@ -788,7 +804,7 @@ static int __init calibrate_APIC_clock(void)
cpu_relax(); cpu_relax();
/* Stop the lapic timer */ /* Stop the lapic timer */
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); lapic_timer_shutdown(levt);
/* Jiffies delta */ /* Jiffies delta */
deltaj = lapic_cal_j2 - lapic_cal_j1; deltaj = lapic_cal_j2 - lapic_cal_j1;
@ -878,7 +894,7 @@ static void local_apic_timer_interrupt(void)
if (!evt->event_handler) { if (!evt->event_handler) {
pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu); pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu);
/* Switch it off */ /* Switch it off */
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); lapic_timer_shutdown(evt);
return; return;
} }