blob: 1e147aa861ab390dbc6a8f54985a38e40c162eb0 [file] [log] [blame]
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CPU_H
#define __CPU_H
#include <processor.h>
#include <ccan/list/list.h>
#include <lock.h>
#include <device.h>
#include <opal.h>
#include <stack.h>
/*
* cpu_thread is our internal structure representing each
* thread in the system
*/
enum cpu_thread_state {
cpu_state_no_cpu = 0, /* Nothing there */
cpu_state_unknown, /* In PACA, not called in yet */
cpu_state_unavailable, /* Not available */
cpu_state_present, /* Assumed to spin in asm entry */
cpu_state_active, /* Secondary called in */
cpu_state_os, /* Under OS control */
cpu_state_disabled, /* Disabled by us due to error */
cpu_state_rvwinkle, /* Doing an rvwinkle cycle */
};
struct cpu_job;
struct xive_cpu_state;
enum cpu_wake_cause {
cpu_wake_on_job,
cpu_wake_on_dec,
};
struct cpu_thread {
uint32_t pir;
uint32_t server_no;
uint32_t chip_id;
bool is_secondary;
bool current_hile;
struct cpu_thread *primary;
enum cpu_thread_state state;
struct dt_node *node;
struct trace_info *trace;
uint64_t save_r1;
void *icp_regs;
uint32_t lock_depth;
uint32_t con_suspend;
bool con_need_flush;
bool in_mcount;
bool in_poller;
bool in_reinit;
bool in_fast_sleep;
bool in_sleep;
bool in_idle;
uint32_t hbrt_spec_wakeup; /* primary only */
uint64_t save_l2_fir_action1;
uint64_t current_token;
#ifdef STACK_CHECK_ENABLED
int64_t stack_bot_mark;
uint64_t stack_bot_pc;
uint64_t stack_bot_tok;
#define CPU_BACKTRACE_SIZE 60
struct bt_entry stack_bot_bt[CPU_BACKTRACE_SIZE];
unsigned int stack_bot_bt_count;
#endif
struct lock job_lock;
struct list_head job_queue;
uint32_t job_count;
bool job_has_no_return;
/*
* Per-core mask tracking for threads in HMI handler and
* a cleanup done bit.
* [D][TTTTTTTT]
*
* The member 'core_hmi_state' is primary only.
* The 'core_hmi_state_ptr' member from all secondry cpus will point
* to 'core_hmi_state' member in primary cpu.
*/
uint32_t core_hmi_state; /* primary only */
uint32_t *core_hmi_state_ptr;
/* Mask to indicate thread id in core. */
uint8_t thread_mask;
bool tb_invalid;
/* For use by XICS emulation on XIVE */
struct xive_cpu_state *xstate;
};
/* This global is set to 1 to allow secondaries to callin,
* typically set after the primary has allocated the cpu_thread
* array and stacks
*/
extern unsigned long cpu_secondary_start;
/* Max PIR in the system */
extern unsigned int cpu_max_pir;
/* Max # of threads per core */
extern unsigned int cpu_thread_count;
/* Boot CPU. */
extern struct cpu_thread *boot_cpu;
static inline void __nomcount cpu_relax(void)
{
/* Relax a bit to give sibling threads some breathing space */
smt_low();
smt_very_low();
asm volatile("nop; nop; nop; nop;\n"
"nop; nop; nop; nop;\n"
"nop; nop; nop; nop;\n"
"nop; nop; nop; nop;\n");
smt_medium();
barrier();
}
/* Initialize CPUs */
void pre_init_boot_cpu(void);
void init_boot_cpu(void);
void init_all_cpus(void);
void init_hid(void);
/* This brings up our secondaries */
extern void cpu_bringup(void);
/* This is called by secondaries as they call in */
extern void cpu_callin(struct cpu_thread *cpu);
/* For cpus which fail to call in. */
extern void cpu_remove_node(const struct cpu_thread *t);
/* Find CPUs using different methods */
extern struct cpu_thread *find_cpu_by_chip_id(u32 chip_id);
extern struct cpu_thread *find_cpu_by_node(struct dt_node *cpu);
extern struct cpu_thread *find_cpu_by_server(u32 server_no);
extern struct cpu_thread *find_cpu_by_pir(u32 pir);
extern struct dt_node *get_cpu_node(u32 pir);
/* Iterator */
extern struct cpu_thread *first_cpu(void);
extern struct cpu_thread *next_cpu(struct cpu_thread *cpu);
/* WARNING: CPUs that have been picked up by the OS are no longer
* appearing as available and can not have jobs scheduled
* on them. Essentially that means that after the OS is
* fully started, all CPUs are seen as unavailable from
* this API standpoint.
*/
static inline bool cpu_is_present(struct cpu_thread *cpu)
{
return cpu->state >= cpu_state_present;
}
static inline bool cpu_is_available(struct cpu_thread *cpu)
{
return cpu->state == cpu_state_active ||
cpu->state == cpu_state_rvwinkle;
}
extern struct cpu_thread *first_available_cpu(void);
extern struct cpu_thread *next_available_cpu(struct cpu_thread *cpu);
extern struct cpu_thread *first_present_cpu(void);
extern struct cpu_thread *next_present_cpu(struct cpu_thread *cpu);
#define for_each_cpu(cpu) \
for (cpu = first_cpu(); cpu; cpu = next_cpu(cpu))
#define for_each_available_cpu(cpu) \
for (cpu = first_available_cpu(); cpu; cpu = next_available_cpu(cpu))
#define for_each_present_cpu(cpu) \
for (cpu = first_present_cpu(); cpu; cpu = next_present_cpu(cpu))
extern struct cpu_thread *first_available_core_in_chip(u32 chip_id);
extern struct cpu_thread *next_available_core_in_chip(struct cpu_thread *cpu, u32 chip_id);
extern u8 get_available_nr_cores_in_chip(u32 chip_id);
#define for_each_available_core_in_chip(core, chip_id) \
for (core = first_available_core_in_chip(chip_id); core; \
core = next_available_core_in_chip(core, chip_id))
/* Return the caller CPU (only after init_cpu_threads) */
register struct cpu_thread *__this_cpu asm("r13");
static inline __nomcount struct cpu_thread *this_cpu(void)
{
return __this_cpu;
}
/* Get the thread # of a cpu within the core */
static inline uint32_t cpu_get_thread_index(struct cpu_thread *cpu)
{
return cpu->pir - cpu->primary->pir;
}
/* Get the core # of a cpu within the core */
extern uint32_t cpu_get_core_index(struct cpu_thread *cpu);
/* Get the PIR of thread 0 of the same core */
static inline uint32_t cpu_get_thread0(struct cpu_thread *cpu)
{
return cpu->primary->pir;
}
static inline bool cpu_is_thread0(struct cpu_thread *cpu)
{
return cpu->primary == cpu;
}
static inline bool cpu_is_sibling(struct cpu_thread *cpu1,
struct cpu_thread *cpu2)
{
return cpu1->primary == cpu2->primary;
}
/* Called when some error condition requires disabling a core */
void cpu_disable_all_threads(struct cpu_thread *cpu);
/* Allocate & queue a job on target CPU */
extern struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
const char *name,
void (*func)(void *data), void *data,
bool no_return);
static inline struct cpu_job *cpu_queue_job(struct cpu_thread *cpu,
const char *name,
void (*func)(void *data),
void *data)
{
return __cpu_queue_job(cpu, name, func, data, false);
}
/* Poll job status, returns true if completed */
extern bool cpu_poll_job(struct cpu_job *job);
/* Synchronously wait for a job to complete, this will
* continue handling the FSP mailbox if called from the
* boot CPU. Set free_it to free it automatically.
*/
extern void cpu_wait_job(struct cpu_job *job, bool free_it);
/* Called by init to process jobs */
extern void cpu_process_jobs(void);
/* Fallback to running jobs synchronously for global jobs */
extern void cpu_process_local_jobs(void);
/* Check if there's any job pending */
bool cpu_check_jobs(struct cpu_thread *cpu);
/* Enable/disable PM */
void cpu_set_pm_enable(bool pm_enabled);
static inline void cpu_give_self_os(void)
{
__this_cpu->state = cpu_state_os;
}
extern unsigned long __attrconst cpu_stack_bottom(unsigned int pir);
extern unsigned long __attrconst cpu_stack_top(unsigned int pir);
extern void cpu_idle(enum cpu_wake_cause wake_on);
#endif /* __CPU_H */