aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/include/cpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/include/cpu.h')
-rw-r--r--roms/skiboot/include/cpu.h334
1 files changed, 334 insertions, 0 deletions
diff --git a/roms/skiboot/include/cpu.h b/roms/skiboot/include/cpu.h
new file mode 100644
index 000000000..b0c78ce62
--- /dev/null
+++ b/roms/skiboot/include/cpu.h
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright 2013-2019 IBM Corp. */
+
+#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>
+#include <timer.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_fast_reboot_entry, /* Called back into OPAL, real mode */
+ 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;
+
+struct cpu_thread {
+ /*
+ * "stack_guard" must be at offset 0 to match the
+ * -mstack-protector-guard-offset=0 statement in the Makefile
+ */
+ uint64_t stack_guard;
+ uint32_t pir;
+ uint32_t server_no;
+ uint32_t chip_id;
+ bool is_secondary;
+ bool is_fused_core;
+ struct cpu_thread *primary;
+ struct cpu_thread *ec_primary;
+ enum cpu_thread_state state;
+ struct dt_node *node;
+ struct trace_info *trace;
+ uint64_t save_r1;
+ void *icp_regs;
+ uint32_t in_opal_call;
+ uint32_t quiesce_opal_call;
+ uint64_t entered_opal_call_at;
+ uint32_t con_suspend;
+ struct list_head locks_held;
+ 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];
+ struct bt_metadata stack_bot_bt_metadata;
+#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;
+ bool tb_invalid;
+ bool tb_resynced;
+
+ /* For use by XICS emulation on XIVE */
+ struct xive_cpu_state *xstate;
+
+ /*
+ * For direct controls scoms, including special wakeup.
+ */
+ struct lock dctl_lock; /* primary only */
+ bool dctl_stopped; /* per thread */
+ uint32_t special_wakeup_count; /* primary */
+
+ /*
+ * For reading DTS sensors async
+ */
+ struct lock dts_lock;
+ struct timer dts_timer;
+ __be64 *sensor_data;
+ u32 sensor_attr;
+ u32 token;
+ bool dts_read_in_progress;
+
+#ifdef DEBUG_LOCKS
+ /* The lock requested by this cpu, used for deadlock detection */
+ struct lock *requested_lock;
+#endif
+};
+
+/* 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;
+
+extern void __nomcount cpu_relax(void);
+
+/* Initialize CPUs */
+void pre_init_boot_cpu(void);
+void init_boot_cpu(void);
+void init_cpu_max_pir(void);
+void init_all_cpus(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);
+
+/* Used for lock internals to avoid re-entrancy */
+extern struct cpu_thread __nomcount *find_cpu_by_pir_nomcount(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);
+extern struct cpu_thread *first_ungarded_cpu(void);
+extern struct cpu_thread *next_ungarded_cpu(struct cpu_thread *cpu);
+extern struct cpu_thread *first_ungarded_primary(void);
+extern struct cpu_thread *next_ungarded_primary(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))
+
+#define for_each_ungarded_cpu(cpu) \
+ for (cpu = first_ungarded_cpu(); cpu; cpu = next_ungarded_cpu(cpu))
+
+#define for_each_ungarded_primary(cpu) \
+ for (cpu = first_ungarded_primary(); cpu; cpu = next_ungarded_primary(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) */
+#ifndef __TEST__
+register struct cpu_thread *__this_cpu asm("r16");
+#else
+struct cpu_thread *__this_cpu;
+#endif
+
+static inline __nomcount struct cpu_thread *this_cpu(void)
+{
+ return __this_cpu;
+}
+
+/*
+ * Note: On POWER9 fused core, cpu_get_thread_index() and cpu_get_core_index()
+ * return respectively the thread number within a fused core (0..7) and
+ * the fused core number. If you want the EC (small core) number, you have
+ * to use the low level pir_to_core_id() and pir_to_thread_id().
+ */
+/* 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_core_chiplet_primary(struct cpu_thread *cpu)
+{
+ return cpu->is_fused_core & (cpu_get_thread_index(cpu) == 1);
+}
+
+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);
+}
+
+extern struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+ const char *name,
+ void (*func)(void *data), void *data);
+
+
+/* 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);
+
+/* Set/clear HILE on all CPUs */
+void cpu_set_hile_mode(bool hile);
+
+/* OPAL sreset vector in place at 0x100 */
+void cpu_set_sreset_enable(bool sreset_enabled);
+
+/* IPI for PM modes is enabled */
+void cpu_set_ipi_enable(bool sreset_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 unsigned long __attrconst cpu_emergency_stack_top(unsigned int pir);
+
+extern void cpu_idle_job(void);
+extern void cpu_idle_delay(unsigned long delay);
+
+extern void cpu_fast_reboot_complete(void);
+
+int dctl_set_special_wakeup(struct cpu_thread *t);
+int dctl_clear_special_wakeup(struct cpu_thread *t);
+int dctl_core_is_gated(struct cpu_thread *t);
+
+extern void exit_uv_mode(int);
+void cpu_disable_pef(void);
+
+#endif /* __CPU_H */