1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2023 Oxide Computer Company 14 */ 15 16 #ifndef _LIBJEDEC_SPD_H 17 #define _LIBJEDEC_SPD_H 18 19 /* 20 * This header contains all the library-specific definitions for SPD parsing 21 * that are split up between different files. The protocol definitions are 22 * rooted in spd_common.h and spd_<spec>.h (e.g. spd_ddr4.h). 23 */ 24 25 #include <stdint.h> 26 #include <stdbool.h> 27 #include <libjedec.h> 28 #include <sys/ccompile.h> 29 #include "spd_common.h" 30 31 #ifdef __cplusplus 32 extern "C" { 33 #endif 34 35 typedef enum { 36 SPD_INFO_F_INCOMPLETE = 1 << 0 37 } spd_info_flags_t; 38 39 typedef struct { 40 const uint8_t *si_data; 41 size_t si_nbytes; 42 spd_dram_type_t si_dram; 43 spd_module_type_t si_type; 44 uint32_t si_max_bytes; 45 spd_error_t si_error; 46 spd_info_flags_t si_flags; 47 nvlist_t *si_nvl; 48 nvlist_t *si_errs; 49 } spd_info_t; 50 51 typedef struct { 52 /* 53 * Byte offset of this key we're going to parse. 54 */ 55 uint32_t sp_off; 56 /* 57 * Length of the field we're parsing. If this is left as zero, we assume 58 * it is one. This is mostly used for string parsing logic as opposed to 59 * integer related pieces. 60 */ 61 uint32_t sp_len; 62 /* 63 * An optional key-name. This is used when we're using a common parsing 64 * function ala manufacturing data as opposed to say parsing timing 65 * values that may look for multiple values. 66 */ 67 const char *sp_key; 68 void (*sp_parse)(spd_info_t *, uint32_t, uint32_t, const char *); 69 } spd_parse_t; 70 71 /* 72 * Many SPD keys map to a different enum of set of discrete values. The 73 * following structures are used to create pairs of these that we will process 74 * so that way we can have basic tables that are consumed and less switch 75 * statements. The svm_spd value tracks the value in the spec. The svm_use is 76 * the corresponding value that should be used in the system. Finally, the 77 * svm_skip, is a way to indicate that a value is valid, but undefined and 78 * therefore no entry should be created as opposed to being treated as an 79 * invalid value. 80 */ 81 typedef struct { 82 uint8_t svm_spd; 83 uint32_t svm_use; 84 bool svm_skip; 85 } spd_value_map_t; 86 87 typedef struct { 88 uint8_t svm_spd; 89 uint64_t svm_use; 90 bool svm_skip; 91 } spd_value_map64_t; 92 93 typedef struct { 94 uint8_t ssm_spd; 95 const char *ssm_str; 96 bool ssm_skip; 97 } spd_str_map_t; 98 99 typedef struct { 100 uint32_t svr_min; 101 uint32_t svr_max; 102 uint32_t svr_base; 103 uint32_t svr_mult; 104 } spd_value_range_t; 105 106 /* 107 * Common routines for parsing and nvlist work. 108 */ 109 extern void spd_parse(spd_info_t *, const spd_parse_t *, size_t); 110 extern void spd_nvl_err(spd_info_t *, const char *, spd_error_kind_t, 111 const char *, ...) __PRINTFLIKE(4); 112 extern void spd_nvl_insert_str(spd_info_t *, const char *, const char *); 113 extern void spd_nvl_insert_u32(spd_info_t *, const char *, uint32_t); 114 extern void spd_nvl_insert_u64(spd_info_t *, const char *, uint64_t); 115 extern void spd_nvl_insert_u32_array(spd_info_t *, const char *, 116 uint32_t *, uint_t); 117 extern void spd_nvl_insert_key(spd_info_t *, const char *); 118 119 extern void spd_insert_map(spd_info_t *, const char *, uint8_t, 120 const spd_value_map_t *, size_t); 121 extern void spd_insert_map64(spd_info_t *, const char *, uint8_t, 122 const spd_value_map64_t *, size_t); 123 extern void spd_insert_str_map(spd_info_t *, const char *, uint8_t, 124 const spd_str_map_t *, size_t); 125 extern void spd_insert_map_array(spd_info_t *, const char *, const uint8_t *, 126 size_t, const spd_value_map_t *, size_t); 127 extern void spd_insert_range(spd_info_t *, const char *, uint8_t, 128 const spd_value_range_t *); 129 extern void spd_upsert_flag(spd_info_t *, const char *, uint32_t); 130 131 extern void spd_parse_jedec_id(spd_info_t *, uint32_t, uint32_t, const char *); 132 extern void spd_parse_jedec_id_str(spd_info_t *, uint32_t, uint32_t, 133 const char *); 134 extern void spd_parse_string(spd_info_t *, uint32_t, uint32_t, const char *); 135 extern void spd_parse_hex_string(spd_info_t *, uint32_t, uint32_t, 136 const char *); 137 extern void spd_parse_hex_vers(spd_info_t *, uint32_t, uint32_t, const char *); 138 extern void spd_parse_raw_u8(spd_info_t *, uint32_t, uint32_t, const char *); 139 extern void spd_parse_dram_step(spd_info_t *, uint32_t, uint32_t, const char *); 140 extern void spd_parse_crc(spd_info_t *, uint32_t, uint32_t, const char *); 141 extern void spd_parse_rev(spd_info_t *, uint32_t, uint32_t, const char *); 142 extern void spd_parse_height(spd_info_t *, uint32_t, uint32_t, const char *); 143 extern void spd_parse_thickness(spd_info_t *, uint32_t, uint32_t, const char *); 144 145 /* 146 * Protocol-specific entry points. 147 */ 148 extern void spd_parse_ddr4(spd_info_t *); 149 extern void spd_parse_ddr5(spd_info_t *); 150 151 #ifdef __cplusplus 152 } 153 #endif 154 155 #endif /* _LIBJEDEC_SPD_H */ 156