ZXFoundation™ 26h2
Loading...
Searching...
No Matches
percpu.cxxm
1/// SPDX-License-Identifier: Apache-2.0
2/// @file arch/s390x/cpu/percpu_types.cxxm
3/// @brief s390x per-CPU data block.
4
5export module arch.s390x.cpu.percpu;
6import arch.s390x.cpu.types;
7import zxfoundation.base.types;
8import zxfoundation.sync.qspinlock.mcs;
9import zxfoundation.memory.pmm.types;
10import lib.stl;
11
12export {
13
14namespace arch::s390x::cpu::percpu {
15
16 using zxfoundation::memory::pmm::pcp_pool;
17
18 /// @brief Explicit interrupt context classification.
19 enum class irq_class : u8 {
20 none = 0, ///< Not in any interrupt handler.
21 ext = 1, ///< External interrupt (SAVE_FRAME from LC_EXT_OLD_PSW).
22 io = 2, ///< I/O interrupt (SAVE_FRAME from LC_IO_OLD_PSW).
23 pgm = 3, ///< Program check (SAVE_FRAME from LC_PGM_OLD_PSW).
24 svc = 4, ///< Supervisor call (SAVE_NUCLEUS_FRAME from LC_SVC_OLD_PSW).
25 mcck = 5, ///< Machine check (SAVE_FRAME from LC_MCCK_OLD_PSW).
26 nucleus = 6, ///< Program-call (PC) gate entry.
27 };
28
29 /// @brief s390x per-CPU data block. See file-level comment for placement rationale.
30 struct alignas(processor::CACHE_LINE_SIZE) percpu_data {
31 u64 self_phys{}; ///< Physical address of this percpu_data instance (used for cross-CPU MCS node addressing by qspinlock; NOT the lowcore's physical address).
32
33 u16 cpu_id{}; ///< Logical CPU ID (0 = BSP, dense, 0-based).
34 u16 cpu_addr{}; ///< Hardware CPU address (from STAP instruction).
35 u32 _pad0{}; ///< Explicit padding to align next u64.
36
37 u64 current_domain{}; ///< Virtual address of the current domain struct.
38 u64 current_strand{}; ///< Virtual address of the currently executing strand.
39 u64 kernel_stack{}; ///< Top of this CPU's kernel stack (virtual).
40 u64 user_asce{}; ///< User ASCE (CR1 value for user address space).
41
42 i32 preempt_count{}; ///< Preemption depth. >0 means non-preemptible. Raw entry.S access via PCP_PREEMPT_COUNT.
43 u32 irq_nesting{}; ///< Hardware IRQ/MCCK nesting depth (0 = not in IRQ handler). Raw entry.S access via PCP_IRQ_NESTING.
44 u32 nucleus_nesting{}; ///< Synchronous SVC/PC nucleus-call nesting depth. Raw entry.S access via PCP_NUCLEUS_NESTING.
45 u32 lock_depth{}; ///< Current qspinlock MCS node allocation depth.
46 irq_class current_irq_class{}; ///< Explicit interrupt class being serviced (set by entry.S). Raw entry.S access via PCP_IRQ_CLASS.
47 u8 _pad_irq_class[3]{}; ///< Pad to u32 alignment.
48 std::atomic<u64> ec_bits{};
49
50 zxfoundation::sync::qspinlock::mcs_node qnodes[zxfoundation::sync::qspinlock::MCS_MAX_LOCK_DEPTH]{};
51
52 u64 rcu_gp_seq{}; ///< Last observed RCU grace-period sequence number.
53 u64 rcu_qs_seq{}; ///< Last quiescent-state sequence number.
54 u8 in_rcu_read_side{}; ///< Non-zero if inside read_unlock().
55 u8 _pad1[7]{}; ///< Pad to u64 alignment.
56
57 void* rcu_pending_cbs{nullptr}; ///< Head of pending rcu_head list (rcu_head*).
58 u64 rcu_pending_gp{0}; ///< Grace period at which pending_cbs mature.
59 u32 rcu_pending_count{0}; ///< Number of callbacks pending.
60 u32 _pad_rcu{};
61
62 u32 ipi_pending_count{}; ///< Counter of pending IPI completion events.
63 u32 _pad2{};
64
65 u64 ap_stack_phys{}; ///< Physical address of AP's initial stack top.
66
67 pcp_pool pcp{};
68
69 u8 drawer_id{0};
70 u8 cpu_type{0}; ///< ZXFL_CPU_TYPE_* for this CPU (CP, IFL, zIIP, etc.)
71 u8 core_id{0}; ///< Scheduler core-group ID from ZXFL/STSI or degraded fallback.
72 u8 smt_id{0}; ///< SMT sibling ID inside core-group, zero when unproven.
73 u8 topology_evidence{0}; ///< ZXFL_CPU_EVIDENCE_* provenance flags.
74 u8 capacity{100}; ///< Scheduler capacity percentage, 100 when unknown.
75 u8 _pad_drawer[2]{};
76
77 u64 attached_asce{0}; ///< ASCE currently attached to CR1 for DGP tracking.
78 u32 attached_domain_id{0}; ///< Domain ID owning attached_asce, or nucleus for idle/kernel.
79 u8 attached_dgp_state{0}; ///< DGP isolation_state snapshot admitted by the scheduler.
80 u8 _pad_asce[3]{};
81
82 u64 watchdog_heartbeat{0}; ///< Monotonic counter bumped by scheduler_tick().
83
84 u32 pgm_fixup_applied{0}; ///< Non-zero if last PGM applied a fixup (set by pgm handler).
85 u64 pgm_fixup_addr{0}; ///< Fixup recovery label address set by try_applying_fixup.
86
87 u32 ipd_count{0}; ///< Nullifying IPD event counter within sliding window.
88 u64 ipd_window_deadline{0}; ///< Absolute TOD deadline resetting the IPD window.
89
90 /// @brief Deferred-interrupt work bitmap
91 std::atomic<u32> deferred_pending{};
92
93 u8 _pad_fixup[2]{};
94 };
95
96 /// @brief self_phys must be first — qspinlock and early bringup code rely
97 /// on this being readable without walking past other fields.
98 static_assert(__builtin_offsetof(percpu_data, self_phys) == 0,
99 "self_phys must be at offset 0 within percpu_data");
100 static_assert(__builtin_offsetof(percpu_data, cpu_id) == 8,
101 "cpu_id must be at offset 8 within percpu_data");
102 static_assert(__builtin_offsetof(percpu_data, preempt_count) == 48,
103 "preempt_count offset must match PCP_PREEMPT_COUNT in lowcore.h");
104 static_assert(__builtin_offsetof(percpu_data, irq_nesting) == 52,
105 "irq_nesting offset must match PCP_IRQ_NESTING in lowcore.h");
106 static_assert(__builtin_offsetof(percpu_data, nucleus_nesting) == 56,
107 "nucleus_nesting offset must match PCP_NUCLEUS_NESTING in lowcore.h");
108 static_assert(__builtin_offsetof(percpu_data, current_irq_class) == 64,
109 "current_irq_class offset must match PCP_IRQ_CLASS in lowcore.h");
110
111 /// @brief Finish BSP per-CPU initialization.
112 auto init_bsp() noexcept -> void;
113
114 /// @brief Finish AP per-CPU initialization.
115 /// @param pcp Reference to the AP's percpu_data slot (percpu::at(cpu_id)).
116 auto init_ap(percpu_data& pcp) noexcept -> void;
117
118 /// @brief Return a reference to the current CPU's per-CPU block.
119 [[nodiscard]] auto this_cpu() noexcept -> percpu_data&;
120
121 /// @brief Direct, unconditional access to a logical CPU's percpu_data slot.
122 /// @param[in] cpu_id Logical CPU ID.
123 [[nodiscard]] auto at(u16 cpu_id) noexcept -> percpu_data&;
124
125 /// @brief Get other CPU's percpu
126 [[nodiscard]] auto cpu_percpu(u16 cpu_id) noexcept -> percpu::percpu_data*;
127
128 /// @brief get current cpu id
129 [[nodiscard]] auto cpu_id() noexcept -> u16;
130
131 /// @brief get current cpu's ZXFL_CPU_TYPE_* value
132 [[nodiscard]] auto cpu_type() noexcept -> u8;
133
134 /// @brief Return the lowercase short prefix for the current CPU type.
135 [[nodiscard]] auto cpu_type_prefix() noexcept -> std::string_view;
136
137} // namespace arch::s390x::cpu::percpu
138
139} // end export