summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/sys
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/intel/sys')
-rw-r--r--usr/src/uts/intel/sys/amdzen/smn.h90
-rw-r--r--usr/src/uts/intel/sys/amdzen/umc.h4
2 files changed, 83 insertions, 11 deletions
diff --git a/usr/src/uts/intel/sys/amdzen/smn.h b/usr/src/uts/intel/sys/amdzen/smn.h
index 3f8250a158..8187042b2f 100644
--- a/usr/src/uts/intel/sys/amdzen/smn.h
+++ b/usr/src/uts/intel/sys/amdzen/smn.h
@@ -17,6 +17,7 @@
#define _SYS_AMDZEN_SMN_H
#include <sys/debug.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
/*
@@ -351,11 +352,72 @@ extern "C" {
*/
typedef struct smn_reg {
uint32_t sr_addr;
+ uint8_t sr_size; /* Not size_t: can't ever be that big. */
} smn_reg_t;
-/*CSTYLED*/
-#define SMN_MAKE_REG(x) ((const smn_reg_t){ .sr_addr = (x) })
-#define SMN_REG_ADDR(x) ((x).sr_addr)
+/*
+ * These are intended to be macro-like (and indeed some used to be macros) but
+ * are implemented as inline functions so that we can use compound statements
+ * without extensions and don't have to worry about multiple evaluation. Hence
+ * their capitalised names.
+ */
+static inline smn_reg_t
+SMN_MAKE_REG_SIZED(const uint32_t addr, const uint8_t size)
+{
+ const uint8_t size_always = (size == 0) ? 4 : size;
+ const smn_reg_t rv = {
+ .sr_addr = addr,
+ .sr_size = size_always
+ };
+
+ return (rv);
+}
+
+#define SMN_MAKE_REG(x) SMN_MAKE_REG_SIZED(x, 4)
+#define SMN_REG_ADDR(x) ((x).sr_addr)
+#define SMN_REG_SIZE(x) ((x).sr_size)
+
+static inline boolean_t
+SMN_REG_SIZE_IS_VALID(const smn_reg_t reg)
+{
+ return (reg.sr_size == 1 || reg.sr_size == 2 || reg.sr_size == 4);
+}
+
+/* Is this register suitably aligned for access of <size> bytes? */
+#define SMN_REG_IS_ALIGNED(x, size) IS_P2ALIGNED(SMN_REG_ADDR(x), size)
+
+/* Is this register naturally aligned with respect to its own width? */
+static inline boolean_t
+SMN_REG_IS_NATURALLY_ALIGNED(const smn_reg_t reg)
+{
+ return (SMN_REG_IS_ALIGNED(reg, reg.sr_size));
+}
+
+/* Does <val> fit into SMN register <x>? */
+#define SMN_REG_VALUE_FITS(x, val) \
+ (((val) & ~(0xffffffffU >> ((4 - SMN_REG_SIZE(x)) << 3))) == 0)
+
+/*
+ * Retrieve the base address of the register. This is the address that will
+ * actually be set in the index register when performing a read or write of the
+ * underlying register via SMN. It must always be 32-bit aligned.
+ */
+static inline uint32_t
+SMN_REG_ADDR_BASE(const smn_reg_t reg)
+{
+ return (reg.sr_addr & ~3);
+}
+
+/*
+ * The offset address is the byte offset into the 32-bit-wide data register that
+ * will be returned by a read or set by a write, if the register is smaller than
+ * 32 bits wide. For registers that are 32 bits wide, this is always 0.
+ */
+static inline uint32_t
+SMN_REG_ADDR_OFF(const smn_reg_t reg)
+{
+ return (reg.sr_addr & 3);
+}
/*
* This exists so that address calculation functions can check that the register
@@ -396,10 +458,12 @@ typedef enum smn_unit {
* aperture described above or a smaller one if a unit has been broken down
* logically into smaller units). srd_nents is optional; if not set, all
* existing consumers assume a value of 0 is equivalent to 1: the register has
- * but a single instance in each unit. srd_stride is ignored if srd_nents is 0
- * or 1 and optional otherwise; it describes the number of bytes to be added to
- * the previous instance's address to obtain that of the next instance. If left
- * at 0 it is assumed to be 4 bytes.
+ * but a single instance in each unit. srd_size is the width of the register in
+ * bytes, which must be 0, 1, 2, or 4. If 0, the size is assumed to be 4 bytes.
+ * srd_stride is ignored if srd_nents is 0 or 1 and optional otherwise; it
+ * describes the number of bytes to be added to the previous instance's address
+ * to obtain that of the next instance. If left at 0 it is assumed to be equal
+ * to the width of the register.
*
* There are units in which registers have more complicated collections of
* instances that cannot be represented perfectly by this simple descriptor;
@@ -412,6 +476,7 @@ typedef struct smn_reg_def {
uint32_t srd_reg;
uint32_t srd_stride;
uint16_t srd_nents;
+ uint8_t srd_size;
} smn_reg_def_t;
/*
@@ -431,7 +496,12 @@ _fn(const uint8_t unitno, const smn_reg_def_t def, const uint16_t reginst) \
{ \
const uint32_t unit32 = (const uint32_t)unitno; \
const uint32_t reginst32 = (const uint32_t)reginst; \
- const uint32_t stride = (def.srd_stride == 0) ? 4 : def.srd_stride; \
+ const uint32_t size32 = (def.srd_size == 0) ? 4 : \
+ (const uint32_t)def.srd_size; \
+ ASSERT(size32 == 1 || size32 == 2 || size32 == 4); \
+ const uint32_t stride = (def.srd_stride == 0) ? size32 : \
+ def.srd_stride; \
+ ASSERT3U(stride, >=, size32); \
const uint32_t nents = (def.srd_nents == 0) ? 1 : \
(const uint32_t)def.srd_nents; \
\
@@ -449,9 +519,9 @@ _fn(const uint8_t unitno, const smn_reg_def_t def, const uint16_t reginst) \
ASSERT0(aperture & ~(_mask)); \
\
const uint32_t reg = def.srd_reg + reginst32 * stride; \
- ASSERT0(reg & (_mask)); \
+ ASSERT0(reg & (_mask)); \
\
- return (SMN_MAKE_REG(aperture + reg)); \
+ return (SMN_MAKE_REG_SIZED(aperture + reg, size32)); \
}
#ifdef __cplusplus
diff --git a/usr/src/uts/intel/sys/amdzen/umc.h b/usr/src/uts/intel/sys/amdzen/umc.h
index a06c2021eb..ca018c89af 100644
--- a/usr/src/uts/intel/sys/amdzen/umc.h
+++ b/usr/src/uts/intel/sys/amdzen/umc.h
@@ -76,7 +76,8 @@ extern "C" {
* UMC Channel registers. These are in SMN Space. DDR4 and DDR5 based UMCs share
* the same base address, somewhat surprisingly. This constructs the appropriate
* offset and ensures that a caller doesn't exceed the number of known instances
- * of the register. See smn.h for additional details on SMN addressing.
+ * of the register. See smn.h for additional details on SMN addressing. All
+ * UMC registers are 32 bits wide; we check for violations.
*/
static inline smn_reg_t
@@ -93,6 +94,7 @@ amdzen_umc_smn_reg(const uint8_t umcno, const smn_reg_def_t def,
const uint32_t nents = (def.srd_nents == 0) ? 1 :
(const uint32_t)def.srd_nents;
+ ASSERT0(def.srd_size);
ASSERT3S(def.srd_unit, ==, SMN_UNIT_UMC);
ASSERT0(def.srd_reg & APERTURE_MASK);
ASSERT3U(umc32, <, 12);