powerpc/85xx: implement hardware timebase sync
Do hardware timebase sync. Firstly, stop all timebases, and transfer the timebase value of the boot core to the other core. Finally, start all timebases. Only apply to dual-core chips, such as MPC8572, P2020, etc. Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
This commit is contained in:
parent
ae5cab4763
commit
bf34526374
@ -48,6 +48,8 @@ struct ccsr_guts {
|
||||
__be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
|
||||
u8 res06c[0x70 - 0x6c];
|
||||
__be32 devdisr; /* 0x.0070 - Device Disable Control */
|
||||
#define CCSR_GUTS_DEVDISR_TB1 0x00001000
|
||||
#define CCSR_GUTS_DEVDISR_TB0 0x00004000
|
||||
__be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
|
||||
u8 res078[0x7c - 0x78];
|
||||
__be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <asm/mpic.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/dbell.h>
|
||||
#include <asm/fsl_guts.h>
|
||||
|
||||
#include <sysdev/fsl_soc.h>
|
||||
#include <sysdev/mpic.h>
|
||||
@ -41,6 +42,64 @@ struct epapr_spin_table {
|
||||
u32 pir;
|
||||
};
|
||||
|
||||
static struct ccsr_guts __iomem *guts;
|
||||
static u64 timebase;
|
||||
static int tb_req;
|
||||
static int tb_valid;
|
||||
|
||||
static void mpc85xx_timebase_freeze(int freeze)
|
||||
{
|
||||
uint32_t mask;
|
||||
|
||||
mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
|
||||
if (freeze)
|
||||
setbits32(&guts->devdisr, mask);
|
||||
else
|
||||
clrbits32(&guts->devdisr, mask);
|
||||
|
||||
in_be32(&guts->devdisr);
|
||||
}
|
||||
|
||||
static void mpc85xx_give_timebase(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
while (!tb_req)
|
||||
barrier();
|
||||
tb_req = 0;
|
||||
|
||||
mpc85xx_timebase_freeze(1);
|
||||
timebase = get_tb();
|
||||
mb();
|
||||
tb_valid = 1;
|
||||
|
||||
while (tb_valid)
|
||||
barrier();
|
||||
|
||||
mpc85xx_timebase_freeze(0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void mpc85xx_take_timebase(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
tb_req = 1;
|
||||
while (!tb_valid)
|
||||
barrier();
|
||||
|
||||
set_tb(timebase >> 32, timebase & 0xffffffff);
|
||||
isync();
|
||||
tb_valid = 0;
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int __init
|
||||
smp_85xx_kick_cpu(int nr)
|
||||
{
|
||||
@ -228,6 +287,16 @@ smp_85xx_setup_cpu(int cpu_nr)
|
||||
doorbell_setup_this_cpu();
|
||||
}
|
||||
|
||||
static const struct of_device_id mpc85xx_smp_guts_ids[] = {
|
||||
{ .compatible = "fsl,mpc8572-guts", },
|
||||
{ .compatible = "fsl,p1020-guts", },
|
||||
{ .compatible = "fsl,p1021-guts", },
|
||||
{ .compatible = "fsl,p1022-guts", },
|
||||
{ .compatible = "fsl,p1023-guts", },
|
||||
{ .compatible = "fsl,p2020-guts", },
|
||||
{},
|
||||
};
|
||||
|
||||
void __init mpc85xx_smp_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
@ -249,6 +318,19 @@ void __init mpc85xx_smp_init(void)
|
||||
smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
|
||||
}
|
||||
|
||||
np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
|
||||
if (np) {
|
||||
guts = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
if (!guts) {
|
||||
pr_err("%s: Could not map guts node address\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
|
||||
smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
|
||||
}
|
||||
|
||||
smp_ops = &smp_85xx_ops;
|
||||
|
||||
#ifdef CONFIG_KEXEC
|
||||
|
Loading…
Reference in New Issue
Block a user