diff options
Diffstat (limited to 'usr/src/uts/intel/sys')
-rw-r--r-- | usr/src/uts/intel/sys/amdzen/smn.h | 90 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/amdzen/umc.h | 4 |
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); |