1ba215efeSKeith M Wesolowski /*
2ba215efeSKeith M Wesolowski * This file and its contents are supplied under the terms of the
3ba215efeSKeith M Wesolowski * Common Development and Distribution License ("CDDL"), version 1.0.
4ba215efeSKeith M Wesolowski * You may only use this file in accordance with the terms of version
5ba215efeSKeith M Wesolowski * 1.0 of the CDDL.
6ba215efeSKeith M Wesolowski *
7ba215efeSKeith M Wesolowski * A full copy of the text of the CDDL should have accompanied this
8ba215efeSKeith M Wesolowski * source. A copy of the CDDL is also available via the Internet at
9ba215efeSKeith M Wesolowski * http://www.illumos.org/license/CDDL.
10ba215efeSKeith M Wesolowski */
11ba215efeSKeith M Wesolowski
12ba215efeSKeith M Wesolowski /*
13019df03dSRobert Mustacchi * Copyright 2024 Oxide Computer Co.
14ba215efeSKeith M Wesolowski */
15ba215efeSKeith M Wesolowski
16ba215efeSKeith M Wesolowski #ifndef _SYS_AMDZEN_SMN_H
17ba215efeSKeith M Wesolowski #define _SYS_AMDZEN_SMN_H
18ba215efeSKeith M Wesolowski
19ba215efeSKeith M Wesolowski #include <sys/debug.h>
204adf43b0SKeith M Wesolowski #include <sys/sysmacros.h>
21ba215efeSKeith M Wesolowski #include <sys/types.h>
22ba215efeSKeith M Wesolowski
23ba215efeSKeith M Wesolowski /*
24ba215efeSKeith M Wesolowski * Generic definitions for the system management network (SMN) in Milan and many
25ba215efeSKeith M Wesolowski * other AMD Zen processors. These are shared between the amdzen nexus and its
26ba215efeSKeith M Wesolowski * client drivers and kernel code that may require SMN access to resources.
27ba215efeSKeith M Wesolowski *
28ba215efeSKeith M Wesolowski * ------------------------
29ba215efeSKeith M Wesolowski * Endpoints and Addressing
30ba215efeSKeith M Wesolowski * ------------------------
31ba215efeSKeith M Wesolowski *
32ba215efeSKeith M Wesolowski * SMN addresses are 36 bits long but in practice we can use only 32. Bits
33ba215efeSKeith M Wesolowski * [35:32] identify a destination node, but all consumers instead direct SMN
34ba215efeSKeith M Wesolowski * transactions to a specific node by selecting the address/data register pair
35ba215efeSKeith M Wesolowski * in the NBIO PCI config space corresponding to the destination. Additional
36ba215efeSKeith M Wesolowski * information about nodes and the organisation of devices in the Zen
37ba215efeSKeith M Wesolowski * architecture may be found in the block comments in amdzen.c and cpuid.c.
38ba215efeSKeith M Wesolowski *
39ba215efeSKeith M Wesolowski * The SMN provides access to instances of various functional units present on
40ba215efeSKeith M Wesolowski * or accessed via each node. Some functional units have only a single instance
41ba215efeSKeith M Wesolowski * per node while others may have many. Each functional unit instance has one
42ba215efeSKeith M Wesolowski * or more apertures in which it decodes addresses. The aperture portion of the
43ba215efeSKeith M Wesolowski * address consists of bits [31:20] and the remainder of the address is used to
44ba215efeSKeith M Wesolowski * specify a register instance within that functional unit. To complicate
45ba215efeSKeith M Wesolowski * matters, some functional units have multiple smaller sub-units that decode
46ba215efeSKeith M Wesolowski * smaller regions within its parent's aperture; in some cases, the bits in a
47ba215efeSKeith M Wesolowski * mask describing the sub-unit's registers may not be contiguous. To keep
48ba215efeSKeith M Wesolowski * software relatively simple, we generally treat sub-units and parent units the
49ba215efeSKeith M Wesolowski * same and try to choose collections of registers whose addresses can all be
50ba215efeSKeith M Wesolowski * computed in the same manner to form what we will describe as a unit.
51ba215efeSKeith M Wesolowski *
52ba215efeSKeith M Wesolowski * Each functional unit should typically have its own header containing register
53ba215efeSKeith M Wesolowski * definitions, accessors, and address calculation routines; some functional
54ba215efeSKeith M Wesolowski * units are small and straightforward while others may have numerous complex
55ba215efeSKeith M Wesolowski * sub-units, registers with many instances whose locations are computed in
56ba215efeSKeith M Wesolowski * unusual and nonstandard ways, and other features that need to be declared for
57ba215efeSKeith M Wesolowski * consumers. Those functional units that are present across many processors
58ba215efeSKeith M Wesolowski * and have similar or identical contents across them should live in this
59ba215efeSKeith M Wesolowski * directory; umc.h is such an example. Others may be specific to a particular
60ba215efeSKeith M Wesolowski * processor family (see cpuid.c) or other collection and may require their own
61ba215efeSKeith M Wesolowski * subdirectories, symbol prefixes, and so on. Unlike the DF, the existence,
62ba215efeSKeith M Wesolowski * location, and format of registers accessible over SMN are not versioned nor
63ba215efeSKeith M Wesolowski * are they generally self-discoverable. Each functional unit may be present or
64ba215efeSKeith M Wesolowski * absent, in varying numbers and with varying functionality, across the entire
65ba215efeSKeith M Wesolowski * Zen product range. Therefore, at this time most per-unit headers are
66ba215efeSKeith M Wesolowski * intended for use only by code that will execute on a specific processor
67ba215efeSKeith M Wesolowski * family. Unifying them over time is considered desirable to the extent the
68ba215efeSKeith M Wesolowski * hardware allows it.
69ba215efeSKeith M Wesolowski *
70ba215efeSKeith M Wesolowski * -----
71ba215efeSKeith M Wesolowski * Types
72ba215efeSKeith M Wesolowski * -----
73ba215efeSKeith M Wesolowski *
74ba215efeSKeith M Wesolowski * Practically every last one of us has screwed up the order of arguments to
75ba215efeSKeith M Wesolowski * functions like amdzen_smn_write32() when they take an address and a value of
76ba215efeSKeith M Wesolowski * the same type. Repeatedly. Often. To safety this particularly annoying
77ba215efeSKeith M Wesolowski * footgun, we pass SMN register addresses around in a dedicated struct type
78ba215efeSKeith M Wesolowski * smn_reg_t, intended to be instantiated only by the amdzen_xx_smn_reg() and
79ba215efeSKeith M Wesolowski * analogous kernel functions and the macros that expand to them or, for the
80ba215efeSKeith M Wesolowski * YOLO crew, SMN_MAKE_REG(). Since the struct type and uint32_t are not
81ba215efeSKeith M Wesolowski * compatible, the compiler will always squawk if the register and value
82ba215efeSKeith M Wesolowski * arguments are reversed, leaving us far fewer baffling failures to debug at
83ba215efeSKeith M Wesolowski * runtime. Typical callers don't require any awareness of this at all, but
84ba215efeSKeith M Wesolowski * those that want to pass the address around to e.g. log warnings can obtain
85ba215efeSKeith M Wesolowski * the uint32_t address via SMN_REG_ADDR().
86ba215efeSKeith M Wesolowski *
87ba215efeSKeith M Wesolowski * Register definitions within functional units are provided by objects of type
88ba215efeSKeith M Wesolowski * `const smn_reg_def_t`, the usage of which is described in detail in the next
89ba215efeSKeith M Wesolowski * section. For now these are produced on demand by macros; see additional
90ba215efeSKeith M Wesolowski * notes on conventions below. In time, this mechanism may be extended to
91ba215efeSKeith M Wesolowski * incorporate version information in a manner similar to that used in df.h. An
92ba215efeSKeith M Wesolowski * automated mechanism for creating a single collection of register and field
93ba215efeSKeith M Wesolowski * definitions for C, in CTF, and/or for other language consumers as well as
94ba215efeSKeith M Wesolowski * automated register value decoding remains an open area for future work.
95ba215efeSKeith M Wesolowski *
96ba215efeSKeith M Wesolowski * -----------------------
97ba215efeSKeith M Wesolowski * Instances and Iterators
98ba215efeSKeith M Wesolowski * -----------------------
99ba215efeSKeith M Wesolowski *
100ba215efeSKeith M Wesolowski * Not only do some functional units have many instances, so too do many
101ba215efeSKeith M Wesolowski * registers. AMD documentation describes registers in terms of a series of
102ba215efeSKeith M Wesolowski * iterators over various functional units, subunits, and other entities and
103ba215efeSKeith M Wesolowski * attributes that each multiply the number of register instances. A concrete
104ba215efeSKeith M Wesolowski * example from the publicly-available Naples PPR (publication 54945 rev. 1.14)
105ba215efeSKeith M Wesolowski * may make this simpler to understand. Unfortunately, SMN is not described by
106ba215efeSKeith M Wesolowski * this document, but the register instance syntax used is the same and is
107ba215efeSKeith M Wesolowski * described in additional detail in sections 1.3.3-4. For our example, let us
108ba215efeSKeith M Wesolowski * consider the same MSR that AMD uses in their own example,
109ba215efeSKeith M Wesolowski * Core::X86::MSR::TSC. We are given that this register has the following
110ba215efeSKeith M Wesolowski * instances: lthree[1:0]_core[3:0]_thread[1:0]. We therefore have three
111ba215efeSKeith M Wesolowski * iterators: one for 'lthree's, one for 'core's for each 'lthree', and one for
112ba215efeSKeith M Wesolowski * 'thread's for each 'core'. We can also see that there are 16 total
113ba215efeSKeith M Wesolowski * instances; in fact, there are actually 16 per core-complex die (CCD), which
114ba215efeSKeith M Wesolowski * documents for more recent processors would expose as a fourth iterator. To
115ba215efeSKeith M Wesolowski * keep things relatively simple, we will assume that there are only 16 per
116ba215efeSKeith M Wesolowski * processor. If it were possible to access all of these instances via MMIO,
117ba215efeSKeith M Wesolowski * SMN, or some other flat address space (it isn't, as far as we can tell), a
118ba215efeSKeith M Wesolowski * function for computing the address of each instance would require three
119ba215efeSKeith M Wesolowski * parameters. Let us suppose that this register really were accessible via
120ba215efeSKeith M Wesolowski * SMN; in that case, we would also be provided with a list of instance alias
121ba215efeSKeith M Wesolowski * such as
122ba215efeSKeith M Wesolowski *
123ba215efeSKeith M Wesolowski * _thread[1:0]_core[7:0]_lthree[1:0]_alias_SMN: THREADREGS[1:0]x0000_0010;
124ba215efeSKeith M Wesolowski * THREADREGS[1:0]=COREREGS[7:0]x0000_[4,0]000;
125ba215efeSKeith M Wesolowski * COREREGS[7:0]=L3REGS[1:0]x000[7:0]_5000; L3REGS[1:0]=57[A,6]0_0000
126ba215efeSKeith M Wesolowski *
127ba215efeSKeith M Wesolowski * To compute the address of an instance of this hypothetical register, we would
128ba215efeSKeith M Wesolowski * begin by determining that its top-level functional unit is L3REGS with a base
129ba215efeSKeith M Wesolowski * aperture at 0x5760_0000. There are two instances of this functional unit (01
130ba215efeSKeith M Wesolowski * and 1) and each subsequent instance is offset 0x40_0000 from the previous.
131ba215efeSKeith M Wesolowski * This allows us to compute the base address of each L3REGS block; a similar
132ba215efeSKeith M Wesolowski * process is then used to compute the base address of each COREREGS block, and
133ba215efeSKeith M Wesolowski * finally the address of each THREADREGS block that contains the register
134ba215efeSKeith M Wesolowski * instance. In practice, we might choose instead to consider the COREREGS as
135ba215efeSKeith M Wesolowski * our functional unit, with instances at 0x5760_5000, 0x5761_5000, 0x57A0_5000,
136ba215efeSKeith M Wesolowski * and 0x57A1_5000; whether it is useful to do this depends on whether we need
137ba215efeSKeith M Wesolowski * to consider other registers in the L3REGS unit that may not have per-core
138ba215efeSKeith M Wesolowski * blocks or instances but would otherwise be interleaved with these. This ends
139ba215efeSKeith M Wesolowski * up being something of a judgment call. Let's suppose we want to consider the
140ba215efeSKeith M Wesolowski * entire L3REGS functional unit and write a function to compute the address of
141ba215efeSKeith M Wesolowski * any register (including our hypothetical TSC) in the subordinate THREADREGS
142ba215efeSKeith M Wesolowski * blocks. We'll start by adding the new unit to the smn_unit_t enumeration;
143ba215efeSKeith M Wesolowski * let's call it SMN_UNIT_L3REGS_COREREGS since that's the sub-unit level at
144ba215efeSKeith M Wesolowski * which we can uniformly compute register instance addresses. We have already
145ba215efeSKeith M Wesolowski * determined our base aperture and we know that we have 3 iterators and
146ba215efeSKeith M Wesolowski * therefore three parameters; all SMN address calculators return an smn_reg_t
147ba215efeSKeith M Wesolowski * and must accept an smn_reg_def_t. Therefore our function's signature is:
148ba215efeSKeith M Wesolowski *
149ba215efeSKeith M Wesolowski * smn_reg_t amdzen_smn_l3regs_coreregs_reg(uint8_t l3no,
150ba215efeSKeith M Wesolowski * const smn_reg_def_t def, uint16_t coreinst, uint16_t threadinst);
151ba215efeSKeith M Wesolowski *
152ba215efeSKeith M Wesolowski * We have chosen to use a base aperture of 0x5760_0000 and unit offset
153ba215efeSKeith M Wesolowski * 0x40_0000, so we can begin by computing a COREREGS aperture:
154ba215efeSKeith M Wesolowski *
155ba215efeSKeith M Wesolowski * const uint32_t aperture_base = 0x57600000;
156ba215efeSKeith M Wesolowski * const uint32_t aperture_off = l3no * 0x400000;
157ba215efeSKeith M Wesolowski * const uint32_t coreregs_aperture_base = 0x5000;
158ba215efeSKeith M Wesolowski * const uint32_t coreregs_aperture_off = coreinst * 0x10000;
159ba215efeSKeith M Wesolowski *
160ba215efeSKeith M Wesolowski * We can now consider the smn_reg_def_t our function will be given, which
161ba215efeSKeith M Wesolowski * describes THREADREGS::TSC. Within the COREREGS functional sub-unit, each
162ba215efeSKeith M Wesolowski * thread register has 2 instances present at a stride of 0x4000 bytes (from our
163ba215efeSKeith M Wesolowski * hypothetical register definition), so the register would be defined as
164ba215efeSKeith M Wesolowski * follows:
165ba215efeSKeith M Wesolowski *
166ba215efeSKeith M Wesolowski * #define D_L3REGS_COREREGS_THREAD_TSC (const smn_reg_def_t){ \
167ba215efeSKeith M Wesolowski * .srd_unit = SMN_UNIT_L3REGS_COREREGS, \
168ba215efeSKeith M Wesolowski * .srd_reg = 0x10, \
169ba215efeSKeith M Wesolowski * .srd_nents = 2, \
170ba215efeSKeith M Wesolowski * .srd_stride = 0x4000 \
171ba215efeSKeith M Wesolowski * }
172ba215efeSKeith M Wesolowski *
173ba215efeSKeith M Wesolowski * Note that describing the number of entries and their stride in the register
174ba215efeSKeith M Wesolowski * definition allows us to collapse the last functional sub-unit in our
175ba215efeSKeith M Wesolowski * calculation process: we need not compute the base aperture address of the
176ba215efeSKeith M Wesolowski * THREADREGS sub-unit. Instead, we can follow our previous code with:
177ba215efeSKeith M Wesolowski *
178ba215efeSKeith M Wesolowski * const uint32_t aperture = aperture_base +
179ba215efeSKeith M Wesolowski * coreregs_aperture_base + coreregs_aperture_off;
180ba215efeSKeith M Wesolowski * const uint32_t reg = def.srd_reg + threadinst * def.srd_stride;
181ba215efeSKeith M Wesolowski *
182ba215efeSKeith M Wesolowski * Finally, we convert the aperture address and register offset into the
183ba215efeSKeith M Wesolowski * appropriate type and return it:
184ba215efeSKeith M Wesolowski *
185ba215efeSKeith M Wesolowski * return (SMN_MAKE_REG(aperture + reg));
186ba215efeSKeith M Wesolowski *
187ba215efeSKeith M Wesolowski * As you can see, other registers in THREADREGS would be defined with the same
188ba215efeSKeith M Wesolowski * number entries and stride but a different offset (srd_reg member), while
189ba215efeSKeith M Wesolowski * other registers in the COREREGS block would have a different offset and
190ba215efeSKeith M Wesolowski * stride. For example, if a block of per-core (not per-thread) registers were
191ba215efeSKeith M Wesolowski * located at COREREGS[7:0]x0000_1000, a register called "COREREGS::FrobberCntl"
192ba215efeSKeith M Wesolowski * in that block with a single instance at offset 0x48 might be defined as
193ba215efeSKeith M Wesolowski *
194ba215efeSKeith M Wesolowski * #define D_L3REGS_COREREGS_FROB_CTL (const smn_reg_def_t){ \
195ba215efeSKeith M Wesolowski * .srd_unit = SMN_UNIT_L3REGS_COREREGS, \
196ba215efeSKeith M Wesolowski * .srd_reg = 0x1048, \
197ba215efeSKeith M Wesolowski * .srd_nents = 1 \
198ba215efeSKeith M Wesolowski * }
199ba215efeSKeith M Wesolowski *
200ba215efeSKeith M Wesolowski * You can satisfy yourself that the same calculation function we wrote above
201ba215efeSKeith M Wesolowski * will correctly compute the address of the sole instance (0) of this register.
202ba215efeSKeith M Wesolowski * To further simplify register definitions and callers, the actual address
203ba215efeSKeith M Wesolowski * calculation functions are written to treat srd_nents == 0 to mean a register
204ba215efeSKeith M Wesolowski * with a single instance, and to treat srd_stride == 0 as if it were 4 (the
205ba215efeSKeith M Wesolowski * space occupied by registers accessed by SMN is -- so far as we can tell,
206ba215efeSKeith M Wesolowski * practically always -- 4 bytes in size, even if the register itself is
207ba215efeSKeith M Wesolowski * smaller). Additionally, a large number of assertions should be present in
208ba215efeSKeith M Wesolowski * such functions to guard against foreign unit register definitions,
209ba215efeSKeith M Wesolowski * out-of-bounds unit and register instance parameters, address overflow, and
210ba215efeSKeith M Wesolowski * register instance offsets that overflow improperly into an aperture base
211ba215efeSKeith M Wesolowski * address. All of these conditions indicate either an incorrect register
212ba215efeSKeith M Wesolowski * definition or a bug in the caller. See the template macro at the bottom of
213ba215efeSKeith M Wesolowski * this file and umc.h for additional examples of calculating and checking
214ba215efeSKeith M Wesolowski * register addresses.
215ba215efeSKeith M Wesolowski *
216ba215efeSKeith M Wesolowski * With address computation out of the way, we can then provide an accessor for
217ba215efeSKeith M Wesolowski * each instance this register:
218ba215efeSKeith M Wesolowski *
219ba215efeSKeith M Wesolowski * #define L3REGS_COREREGS_THREAD_TSC(l3, core, thread) \
220ba215efeSKeith M Wesolowski * amdzen_l3regs_coreregs_reg(l3, D_L3REGS_COREREGS_THREAD_TSC, \
221ba215efeSKeith M Wesolowski * core, thread)
222ba215efeSKeith M Wesolowski *
223ba215efeSKeith M Wesolowski * Our other per-core register's accessor would look like:
224ba215efeSKeith M Wesolowski *
225ba215efeSKeith M Wesolowski * #define L3REGS_COREREGS_FROB_CTL(l3, core) \
226ba215efeSKeith M Wesolowski * amdzen_l3regs_coreregs_reg(l3, D_L3REGS_COREREGS_FROB_CTL, core, 0)
227ba215efeSKeith M Wesolowski *
228ba215efeSKeith M Wesolowski * The next section describes these conventions in greater detail.
229ba215efeSKeith M Wesolowski *
230ba215efeSKeith M Wesolowski * -----------
231ba215efeSKeith M Wesolowski * Conventions
232ba215efeSKeith M Wesolowski * -----------
233ba215efeSKeith M Wesolowski *
234ba215efeSKeith M Wesolowski * First, let's consider the names of the register definition and the
235ba215efeSKeith M Wesolowski * convenience macro supplied to obtain an instance of that register: we've
236ba215efeSKeith M Wesolowski * prefixed the global definition of the registers with D_ and the convenience
237ba215efeSKeith M Wesolowski * macros to return a specific instance are simply named for the register
238ba215efeSKeith M Wesolowski * itself. Additionally, the two macros expand to objects of incompatible
239ba215efeSKeith M Wesolowski * types, so that using the wrong one will always be detected at compile time.
240ba215efeSKeith M Wesolowski * Why do we expose both of these? The instance macro is useful for callers who
241ba215efeSKeith M Wesolowski * know at compile-time the name of the register of which they want instances;
242ba215efeSKeith M Wesolowski * this makes it unnecessary to remember the names of functions used to compute
243ba215efeSKeith M Wesolowski * register instance addresses. The definition itself is useful to callers that
244ba215efeSKeith M Wesolowski * accept const smn_reg_def_t arguments referring to registers of which the
245ba215efeSKeith M Wesolowski * immediate caller does not know the names at compile time.
246ba215efeSKeith M Wesolowski *
247ba215efeSKeith M Wesolowski * You may wonder why we don't declare named constants for the definitions.
248ba215efeSKeith M Wesolowski * There are two ways we could do that and both are unfortunate: one would be to
249ba215efeSKeith M Wesolowski * declare them static in the header, the other to separate declarations in the
250ba215efeSKeith M Wesolowski * header from initialisation in a separate source file. Measurements revealed
251ba215efeSKeith M Wesolowski * that the former causes a very substantial increase in data size, which will
252ba215efeSKeith M Wesolowski * be multiplied by the number of registers defined and the number of source
253ba215efeSKeith M Wesolowski * files including the header. As convenient as it is to have these symbolic
254ba215efeSKeith M Wesolowski * constants available to debuggers and other tools at runtime, they're just too
255ba215efeSKeith M Wesolowski * big. However, it is possible to generate code to be compiled into loadable
256ba215efeSKeith M Wesolowski * modules that would contain a single copy of the constants for this purpose as
257ba215efeSKeith M Wesolowski * well as for providing CTF to foreign-language binding generators. The other
258ba215efeSKeith M Wesolowski * option considered here, putting the constants in separate source files, makes
259ba215efeSKeith M Wesolowski * maintenance significantly more challenging and makes it likely not only that
260ba215efeSKeith M Wesolowski * new registers may not be added properly but also that definitions, macros, or
261ba215efeSKeith M Wesolowski * both may be incorrect. Neither of these options is terrible but for now
262ba215efeSKeith M Wesolowski * we've optimised for simplicity of maintenance and minimal data size at the
263ba215efeSKeith M Wesolowski * immediate but not necessarily permanent expense of some debugging
264ba215efeSKeith M Wesolowski * convenience.
265ba215efeSKeith M Wesolowski *
266ba215efeSKeith M Wesolowski * We wish to standardise as much as possible on conventions across all
267ba215efeSKeith M Wesolowski * Zen-related functional units and blocks (including those accessed by SMN,
268ba215efeSKeith M Wesolowski * through the DF directly, and by other means). In general, some register and
269ba215efeSKeith M Wesolowski * field names are shortened from their official names for clarity and brevity;
270ba215efeSKeith M Wesolowski * the official names are always given in the comment above the definition.
271ba215efeSKeith M Wesolowski * AMD's functional units come from many internal teams and presumably several
272ba215efeSKeith M Wesolowski * outside vendors as well; as a result, there is no single convention to be
273ba215efeSKeith M Wesolowski * found throughout the PPRs and other documentation. For example, different
274ba215efeSKeith M Wesolowski * units may have registers containing "CTL", "CNTL", "CTRL", "CNTRL", and
275ba215efeSKeith M Wesolowski * "CONTROL", as well as "FOO_CNTL", "FooCntl", and "Foo_Cntl". Reflecting
276ba215efeSKeith M Wesolowski * longstanding illumos conventions, we collapse all such register names
277ba215efeSKeith M Wesolowski * regardless of case as follows:
278ba215efeSKeith M Wesolowski *
279ba215efeSKeith M Wesolowski * CTL/CTRL/CNTL/CNTRL/CONTROL => CTL
280ba215efeSKeith M Wesolowski * CFG/CONF/CONFIG/CONFIGURATION => CFG
281ba215efeSKeith M Wesolowski * EN/ENAB/ENABLE/ENABLED => EN
282ba215efeSKeith M Wesolowski * DIS/DISAB/DISABLE/DISABLED => DIS
283ba215efeSKeith M Wesolowski *
284ba215efeSKeith M Wesolowski * Note that if collapsing these would result in ambiguity, more of the official
285ba215efeSKeith M Wesolowski * names will be preserved. In addition to collapsing register and field names
286ba215efeSKeith M Wesolowski * in this case-insensitive manner, we also follow standard code style practice
287ba215efeSKeith M Wesolowski * and name macros and constants in SCREAMING_SNAKE_CASE regardless of AMD's
288ba215efeSKeith M Wesolowski * official name. It is similarly reasonable to truncate or abbreviate other
289ba215efeSKeith M Wesolowski * common terms in a consistent manner where doing so preserves uniqueness and
290ba215efeSKeith M Wesolowski * at least some semantic value; without doing so, some official register names
291ba215efeSKeith M Wesolowski * will be excessively unwieldy and may not even fit into 80 columns. Please
292ba215efeSKeith M Wesolowski * maintain these practices and strive for consistency with existing examples
293ba215efeSKeith M Wesolowski * when abbreviation is required.
294ba215efeSKeith M Wesolowski *
295ba215efeSKeith M Wesolowski * As we have done elsewhere throughout the amdzen body of work, register fields
296ba215efeSKeith M Wesolowski * should always be given in order starting with the most significant bits and
297ba215efeSKeith M Wesolowski * working down toward 0; this matches AMD's documentation and makes it easier
298ba215efeSKeith M Wesolowski * for reviewers and other readers to follow. The routines in bitext.h should
299ba215efeSKeith M Wesolowski * be used to extract and set bitfields unless there is a compelling reason to
300ba215efeSKeith M Wesolowski * do otherwise (e.g., assembly consumers). Accessors should be named
301ba215efeSKeith M Wesolowski * UNIT_REG_GET_FIELD and UNIT_REG_SET_FIELD respectively, unless the register
302ba215efeSKeith M Wesolowski * has a single field that has no meaningful name (i.e., the field's name is the
303ba215efeSKeith M Wesolowski * same as the register's or it's otherwise obvious from the context what its
304ba215efeSKeith M Wesolowski * purpose is), in which case UNIT_REG_GET and UNIT_REG_SET are appropriate.
305ba215efeSKeith M Wesolowski * Additional getters and setters that select a particular bit from a register
306ba215efeSKeith M Wesolowski * or field consisting entirely of individual bits describing or controlling the
307ba215efeSKeith M Wesolowski * state of some entity may also be useful. As with register names, be as brief
308ba215efeSKeith M Wesolowski * as possible without sacrificing too much information.
309ba215efeSKeith M Wesolowski *
310ba215efeSKeith M Wesolowski * Constant values associated with a field should be declared immediately
311ba215efeSKeith M Wesolowski * following that field. If a constant or collection of constants is used in
312ba215efeSKeith M Wesolowski * multiple fields of the same register, the definitions should follow the last
313ba215efeSKeith M Wesolowski * such field; similarly, constants used in multiple registers should follow the
314ba215efeSKeith M Wesolowski * last such register, and a comment explaining the scope of their validity is
315ba215efeSKeith M Wesolowski * recommended. Such constants should be named for the common elements of the
316ba215efeSKeith M Wesolowski * fields or registers in which they are valid.
317ba215efeSKeith M Wesolowski *
318ba215efeSKeith M Wesolowski * As noted above, SMN register definitions should omit the srd_nents and
319ba215efeSKeith M Wesolowski * srd_stride members when there is a single instance of the register within the
320ba215efeSKeith M Wesolowski * unit. The srd_stride member should also be elided when the register
321ba215efeSKeith M Wesolowski * instances are contiguous. All address calculation routines should be written
322ba215efeSKeith M Wesolowski * to support these conventions. Each register should have an accessor macro or
323ba215efeSKeith M Wesolowski * function, and should accept instance numbers in order from superior to
324ba215efeSKeith M Wesolowski * inferior (e.g., from the largest functional unit to the smallest, ending with
325ba215efeSKeith M Wesolowski * the register instance itself). This convention is similar to that used in
326ba215efeSKeith M Wesolowski * generic PCIe code in which a register is specified by bus, device, and
327ba215efeSKeith M Wesolowski * function numbers in that order. Register accessor macros or inline functions
328ba215efeSKeith M Wesolowski * should not expose inapplicable taxons to callers; in our example above,
329ba215efeSKeith M Wesolowski * COREREGS_FROB_CTL has an instance for each core but is not associated with a
330ba215efeSKeith M Wesolowski * thread; therefore its accessor should not accept a thread instance argument
331ba215efeSKeith M Wesolowski * even though the address calculation function it uses does.
332ba215efeSKeith M Wesolowski *
333ba215efeSKeith M Wesolowski * Most of these conventions are not specific to registers accessed via SMN;
334ba215efeSKeith M Wesolowski * note also that some registers may be accessed in multiple ways (e.g., SMN and
335ba215efeSKeith M Wesolowski * MMIO, or SMN and the MSR instructions). While the code here is generally
336ba215efeSKeith M Wesolowski * unaware of such aliased access methods, following these conventions will
337ba215efeSKeith M Wesolowski * simplify naming and usage if such a register needs to be accessed in multiple
338ba215efeSKeith M Wesolowski * ways. Sensible additions to macro and symbol names such as the access method
339ba215efeSKeith M Wesolowski * to be used will generally be sufficient to disambiguate while allowing reuse
340ba215efeSKeith M Wesolowski * of associated field accessors, constants, and in some cases even register
341ba215efeSKeith M Wesolowski * offset, instance count, and stride.
342ba215efeSKeith M Wesolowski */
343ba215efeSKeith M Wesolowski
344ba215efeSKeith M Wesolowski #ifdef __cplusplus
345ba215efeSKeith M Wesolowski extern "C" {
346ba215efeSKeith M Wesolowski #endif
347ba215efeSKeith M Wesolowski
348ba215efeSKeith M Wesolowski #define SMN_APERTURE_MASK 0xfff00000
349ba215efeSKeith M Wesolowski
350ba215efeSKeith M Wesolowski /*
351ba215efeSKeith M Wesolowski * An instance of an SMN-accessible register.
352ba215efeSKeith M Wesolowski */
353ba215efeSKeith M Wesolowski typedef struct smn_reg {
354ba215efeSKeith M Wesolowski uint32_t sr_addr;
3554adf43b0SKeith M Wesolowski uint8_t sr_size; /* Not size_t: can't ever be that big. */
356ba215efeSKeith M Wesolowski } smn_reg_t;
357ba215efeSKeith M Wesolowski
3584adf43b0SKeith M Wesolowski /*
3594adf43b0SKeith M Wesolowski * These are intended to be macro-like (and indeed some used to be macros) but
3604adf43b0SKeith M Wesolowski * are implemented as inline functions so that we can use compound statements
3614adf43b0SKeith M Wesolowski * without extensions and don't have to worry about multiple evaluation. Hence
3624adf43b0SKeith M Wesolowski * their capitalised names.
3634adf43b0SKeith M Wesolowski */
3644adf43b0SKeith M Wesolowski static inline smn_reg_t
SMN_MAKE_REG_SIZED(const uint32_t addr,const uint8_t size)3654adf43b0SKeith M Wesolowski SMN_MAKE_REG_SIZED(const uint32_t addr, const uint8_t size)
3664adf43b0SKeith M Wesolowski {
3674adf43b0SKeith M Wesolowski const uint8_t size_always = (size == 0) ? 4 : size;
3684adf43b0SKeith M Wesolowski const smn_reg_t rv = {
3694adf43b0SKeith M Wesolowski .sr_addr = addr,
3704adf43b0SKeith M Wesolowski .sr_size = size_always
3714adf43b0SKeith M Wesolowski };
3724adf43b0SKeith M Wesolowski
3734adf43b0SKeith M Wesolowski return (rv);
3744adf43b0SKeith M Wesolowski }
3754adf43b0SKeith M Wesolowski
3764adf43b0SKeith M Wesolowski #define SMN_MAKE_REG(x) SMN_MAKE_REG_SIZED(x, 4)
377ba215efeSKeith M Wesolowski #define SMN_REG_ADDR(x) ((x).sr_addr)
3784adf43b0SKeith M Wesolowski #define SMN_REG_SIZE(x) ((x).sr_size)
3794adf43b0SKeith M Wesolowski
3804adf43b0SKeith M Wesolowski static inline boolean_t
SMN_REG_SIZE_IS_VALID(const smn_reg_t reg)3814adf43b0SKeith M Wesolowski SMN_REG_SIZE_IS_VALID(const smn_reg_t reg)
3824adf43b0SKeith M Wesolowski {
3834adf43b0SKeith M Wesolowski return (reg.sr_size == 1 || reg.sr_size == 2 || reg.sr_size == 4);
3844adf43b0SKeith M Wesolowski }
3854adf43b0SKeith M Wesolowski
3864adf43b0SKeith M Wesolowski /* Is this register suitably aligned for access of <size> bytes? */
3874adf43b0SKeith M Wesolowski #define SMN_REG_IS_ALIGNED(x, size) IS_P2ALIGNED(SMN_REG_ADDR(x), size)
3884adf43b0SKeith M Wesolowski
3894adf43b0SKeith M Wesolowski /* Is this register naturally aligned with respect to its own width? */
3904adf43b0SKeith M Wesolowski static inline boolean_t
SMN_REG_IS_NATURALLY_ALIGNED(const smn_reg_t reg)3914adf43b0SKeith M Wesolowski SMN_REG_IS_NATURALLY_ALIGNED(const smn_reg_t reg)
3924adf43b0SKeith M Wesolowski {
3934adf43b0SKeith M Wesolowski return (SMN_REG_IS_ALIGNED(reg, reg.sr_size));
3944adf43b0SKeith M Wesolowski }
3954adf43b0SKeith M Wesolowski
3964adf43b0SKeith M Wesolowski /* Does <val> fit into SMN register <x>? */
3974adf43b0SKeith M Wesolowski #define SMN_REG_VALUE_FITS(x, val) \
3984adf43b0SKeith M Wesolowski (((val) & ~(0xffffffffU >> ((4 - SMN_REG_SIZE(x)) << 3))) == 0)
3994adf43b0SKeith M Wesolowski
4004adf43b0SKeith M Wesolowski /*
4014adf43b0SKeith M Wesolowski * Retrieve the base address of the register. This is the address that will
4024adf43b0SKeith M Wesolowski * actually be set in the index register when performing a read or write of the
4034adf43b0SKeith M Wesolowski * underlying register via SMN. It must always be 32-bit aligned.
4044adf43b0SKeith M Wesolowski */
4054adf43b0SKeith M Wesolowski static inline uint32_t
SMN_REG_ADDR_BASE(const smn_reg_t reg)4064adf43b0SKeith M Wesolowski SMN_REG_ADDR_BASE(const smn_reg_t reg)
4074adf43b0SKeith M Wesolowski {
4084adf43b0SKeith M Wesolowski return (reg.sr_addr & ~3);
4094adf43b0SKeith M Wesolowski }
4104adf43b0SKeith M Wesolowski
4114adf43b0SKeith M Wesolowski /*
4124adf43b0SKeith M Wesolowski * The offset address is the byte offset into the 32-bit-wide data register that
4134adf43b0SKeith M Wesolowski * will be returned by a read or set by a write, if the register is smaller than
4144adf43b0SKeith M Wesolowski * 32 bits wide. For registers that are 32 bits wide, this is always 0.
4154adf43b0SKeith M Wesolowski */
4164adf43b0SKeith M Wesolowski static inline uint32_t
SMN_REG_ADDR_OFF(const smn_reg_t reg)4174adf43b0SKeith M Wesolowski SMN_REG_ADDR_OFF(const smn_reg_t reg)
4184adf43b0SKeith M Wesolowski {
4194adf43b0SKeith M Wesolowski return (reg.sr_addr & 3);
4204adf43b0SKeith M Wesolowski }
421ba215efeSKeith M Wesolowski
422ba215efeSKeith M Wesolowski /*
423ba215efeSKeith M Wesolowski * This exists so that address calculation functions can check that the register
424ba215efeSKeith M Wesolowski * definitions they're passed are something they understand how to use. While
425ba215efeSKeith M Wesolowski * many address calculation functions are similar, some functional units define
426ba215efeSKeith M Wesolowski * registers with multiple iterators, have differently-sized apertures, or both;
427ba215efeSKeith M Wesolowski * it's important that we reject foreign register definitions in these
428ba215efeSKeith M Wesolowski * functions. In principle this could be done at compile time, but the
429ba215efeSKeith M Wesolowski * preprocessor gymnastics required to do so are excessively vile and we are
430ba215efeSKeith M Wesolowski * really already hanging it pretty far over the edge in terms of what the C
431ba215efeSKeith M Wesolowski * preprocessor can do for us.
432ba215efeSKeith M Wesolowski */
433ba215efeSKeith M Wesolowski typedef enum smn_unit {
434ba215efeSKeith M Wesolowski SMN_UNIT_UNKNOWN,
435ba215efeSKeith M Wesolowski SMN_UNIT_IOAPIC,
436ba215efeSKeith M Wesolowski SMN_UNIT_IOHC,
437ba215efeSKeith M Wesolowski SMN_UNIT_IOHCDEV_PCIE,
438ba215efeSKeith M Wesolowski SMN_UNIT_IOHCDEV_NBIF,
439ba215efeSKeith M Wesolowski SMN_UNIT_IOHCDEV_SB,
440ba215efeSKeith M Wesolowski SMN_UNIT_IOAGR,
441ba215efeSKeith M Wesolowski SMN_UNIT_SDPMUX,
442ba215efeSKeith M Wesolowski SMN_UNIT_UMC,
443ba215efeSKeith M Wesolowski SMN_UNIT_PCIE_CORE,
444ba215efeSKeith M Wesolowski SMN_UNIT_PCIE_PORT,
445ba215efeSKeith M Wesolowski SMN_UNIT_PCIE_RSMU,
446ba215efeSKeith M Wesolowski SMN_UNIT_SCFCTP,
447019df03dSRobert Mustacchi SMN_UNIT_L3SOC,
448ba215efeSKeith M Wesolowski SMN_UNIT_SMUPWR,
449ba215efeSKeith M Wesolowski SMN_UNIT_IOMMUL1,
450ba215efeSKeith M Wesolowski SMN_UNIT_IOMMUL2,
451ba215efeSKeith M Wesolowski SMN_UNIT_NBIF,
452ba215efeSKeith M Wesolowski SMN_UNIT_NBIF_ALT,
453*71536d92SRobert Mustacchi SMN_UNIT_NBIF_FUNC,
454*71536d92SRobert Mustacchi SMN_UNIT_SMU_THM
455ba215efeSKeith M Wesolowski } smn_unit_t;
456ba215efeSKeith M Wesolowski
457ba215efeSKeith M Wesolowski /*
458ba215efeSKeith M Wesolowski * srd_unit and srd_reg are required; they describe the functional unit and the
459ba215efeSKeith M Wesolowski * register's address within that unit's aperture (which may be the SDP-defined
460ba215efeSKeith M Wesolowski * aperture described above or a smaller one if a unit has been broken down
461ba215efeSKeith M Wesolowski * logically into smaller units). srd_nents is optional; if not set, all
462ba215efeSKeith M Wesolowski * existing consumers assume a value of 0 is equivalent to 1: the register has
4634adf43b0SKeith M Wesolowski * but a single instance in each unit. srd_size is the width of the register in
4644adf43b0SKeith M Wesolowski * bytes, which must be 0, 1, 2, or 4. If 0, the size is assumed to be 4 bytes.
4654adf43b0SKeith M Wesolowski * srd_stride is ignored if srd_nents is 0 or 1 and optional otherwise; it
4664adf43b0SKeith M Wesolowski * describes the number of bytes to be added to the previous instance's address
4674adf43b0SKeith M Wesolowski * to obtain that of the next instance. If left at 0 it is assumed to be equal
4684adf43b0SKeith M Wesolowski * to the width of the register.
469ba215efeSKeith M Wesolowski *
470ba215efeSKeith M Wesolowski * There are units in which registers have more complicated collections of
471ba215efeSKeith M Wesolowski * instances that cannot be represented perfectly by this simple descriptor;
472ba215efeSKeith M Wesolowski * they require custom address calculation macros and functions that may take
473ba215efeSKeith M Wesolowski * additional arguments, and they may not be able to check their arguments or
474ba215efeSKeith M Wesolowski * the computed addresses as carefully as would be ideal.
475ba215efeSKeith M Wesolowski */
476ba215efeSKeith M Wesolowski typedef struct smn_reg_def {
477ba215efeSKeith M Wesolowski smn_unit_t srd_unit;
478ba215efeSKeith M Wesolowski uint32_t srd_reg;
479ba215efeSKeith M Wesolowski uint32_t srd_stride;
480ba215efeSKeith M Wesolowski uint16_t srd_nents;
4814adf43b0SKeith M Wesolowski uint8_t srd_size;
482ba215efeSKeith M Wesolowski } smn_reg_def_t;
483ba215efeSKeith M Wesolowski
484ba215efeSKeith M Wesolowski /*
485ba215efeSKeith M Wesolowski * This macro may be used by per-functional-unit code to construct an address
486ba215efeSKeith M Wesolowski * calculation function. It is usable by some, BUT NOT ALL, functional units;
487ba215efeSKeith M Wesolowski * see the block comment above for an example that cannot be accommodated. Here
488ba215efeSKeith M Wesolowski * we assume that there are at most 2 iterators in any register's definition.
489ba215efeSKeith M Wesolowski * Use this when possible, as it provides a large number of useful checks on
490ba215efeSKeith M Wesolowski * DEBUG bits. Similar checks should be incorporated into implementations for
491ba215efeSKeith M Wesolowski * nonstandard functional units to the extent possible.
492ba215efeSKeith M Wesolowski */
493ba215efeSKeith M Wesolowski
494ba215efeSKeith M Wesolowski #define AMDZEN_MAKE_SMN_REG_FN(_fn, _unit, _base, _mask, _nunits, _unitshift) \
495ba215efeSKeith M Wesolowski CTASSERT(((_base) & ~(_mask)) == 0); \
496ba215efeSKeith M Wesolowski static inline smn_reg_t \
497ba215efeSKeith M Wesolowski _fn(const uint8_t unitno, const smn_reg_def_t def, const uint16_t reginst) \
498ba215efeSKeith M Wesolowski { \
499ba215efeSKeith M Wesolowski const uint32_t unit32 = (const uint32_t)unitno; \
500ba215efeSKeith M Wesolowski const uint32_t reginst32 = (const uint32_t)reginst; \
5014adf43b0SKeith M Wesolowski const uint32_t size32 = (def.srd_size == 0) ? 4 : \
5024adf43b0SKeith M Wesolowski (const uint32_t)def.srd_size; \
5034adf43b0SKeith M Wesolowski ASSERT(size32 == 1 || size32 == 2 || size32 == 4); \
5044adf43b0SKeith M Wesolowski const uint32_t stride = (def.srd_stride == 0) ? size32 : \
5054adf43b0SKeith M Wesolowski def.srd_stride; \
5064adf43b0SKeith M Wesolowski ASSERT3U(stride, >=, size32); \
507ba215efeSKeith M Wesolowski const uint32_t nents = (def.srd_nents == 0) ? 1 : \
508ba215efeSKeith M Wesolowski (const uint32_t)def.srd_nents; \
509ba215efeSKeith M Wesolowski \
510ba215efeSKeith M Wesolowski ASSERT3S(def.srd_unit, ==, SMN_UNIT_ ## _unit); \
511ba215efeSKeith M Wesolowski ASSERT3U(unit32, <, (_nunits)); \
512ba215efeSKeith M Wesolowski ASSERT3U(nents, >, reginst32); \
513ba215efeSKeith M Wesolowski ASSERT0(def.srd_reg & (_mask)); \
514ba215efeSKeith M Wesolowski \
515ba215efeSKeith M Wesolowski const uint32_t aperture_base = (_base); \
516ba215efeSKeith M Wesolowski \
517ba215efeSKeith M Wesolowski const uint32_t aperture_off = (unit32 << (_unitshift)); \
518ba215efeSKeith M Wesolowski ASSERT3U(aperture_off, <=, UINT32_MAX - aperture_base); \
519ba215efeSKeith M Wesolowski \
520ba215efeSKeith M Wesolowski const uint32_t aperture = aperture_base + aperture_off; \
521ba215efeSKeith M Wesolowski ASSERT0(aperture & ~(_mask)); \
522ba215efeSKeith M Wesolowski \
523ba215efeSKeith M Wesolowski const uint32_t reg = def.srd_reg + reginst32 * stride; \
524ba215efeSKeith M Wesolowski ASSERT0(reg & (_mask)); \
525ba215efeSKeith M Wesolowski \
5264adf43b0SKeith M Wesolowski return (SMN_MAKE_REG_SIZED(aperture + reg, size32)); \
527ba215efeSKeith M Wesolowski }
528ba215efeSKeith M Wesolowski
529dd23d762SRobert Mustacchi /*
530dd23d762SRobert Mustacchi * An invalid SMN read will return all 1s similar to PCI.
531dd23d762SRobert Mustacchi */
532dd23d762SRobert Mustacchi #define SMN_EINVAL32 0xffffffff
533dd23d762SRobert Mustacchi
534ba215efeSKeith M Wesolowski #ifdef __cplusplus
535ba215efeSKeith M Wesolowski }
536ba215efeSKeith M Wesolowski #endif
537ba215efeSKeith M Wesolowski
538ba215efeSKeith M Wesolowski #endif /* _SYS_AMDZEN_SMN_H */
539