1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2package main 3 4import ( 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "os" 10 "path/filepath" 11 "reflect" 12 "regexp" 13 "sort" 14 "strings" 15) 16 17/* ------------------------------------------------------------------------------------------ */ 18/* Program-defined types */ 19/* ------------------------------------------------------------------------------------------ */ 20type memParts struct { 21 MemParts []memPart `json:"parts"` 22} 23 24type memPart struct { 25 Name string 26 Attribs interface{} 27 SPDId int 28} 29 30type memTech interface { 31 /* 32 * Returns the set -> platform mapping for the memory technology. Platforms with the 33 * same SPD requirements should be grouped together into a single set. 34 */ 35 getSetMap() map[int][]int 36 37 /* 38 * Takes the name and attributes of a part, as read from the memory_parts JSON file. 39 * Validates the attributes, returning an error if any attribute has an invalid value. 40 * Stores the name and attributes internally to be used later. 41 */ 42 addNewPart(string, interface{}) error 43 44 /* 45 * Takes the name of a part and a set number. 46 * Retrieves the part's attributes which were stored by addNewPart(). Updates them by 47 * setting any optional attributes which weren't specified in the JSON file to their 48 * default values. 49 * Returns these updated attributes. 50 */ 51 getSPDAttribs(string, int) (interface{}, error) 52 53 /* 54 * Returns the size of an SPD file for this memory technology. 55 */ 56 getSPDLen() int 57 58 /* 59 * Takes an SPD byte index and the attributes of a part. 60 * Returns the value which that SPD byte should be set to based on the attributes. 61 */ 62 getSPDByte(int, interface{}) byte 63} 64 65/* ------------------------------------------------------------------------------------------ */ 66/* Constants */ 67/* ------------------------------------------------------------------------------------------ */ 68 69const ( 70 PlatformTGL = iota 71 PlatformADL 72 PlatformJSL 73 PlatformPCO 74 PlatformCZN 75 PlatformMDN 76 PlatformMTL 77 PlatformPHX 78 PlatformMax 79) 80 81const ( 82 SPDManifestFileName = "parts_spd_manifest.generated.txt" 83 PlatformManifestFileName = "platforms_manifest.generated.txt" 84) 85 86/* ------------------------------------------------------------------------------------------ */ 87/* Global variables */ 88/* ------------------------------------------------------------------------------------------ */ 89 90var platformNames = map[int]string{ 91 PlatformTGL: "TGL", 92 PlatformADL: "ADL", 93 PlatformJSL: "JSL", 94 PlatformPCO: "PCO", 95 PlatformCZN: "CZN", 96 PlatformMDN: "MDN", 97 PlatformMTL: "MTL", 98 PlatformPHX: "PHX", 99} 100 101var memTechMap = map[string]memTech{ 102 "lp4x": lp4x{}, 103 "ddr4": ddr4{}, 104 "lp5": lp5{}, 105} 106 107/* ------------------------------------------------------------------------------------------ */ 108/* Conversion Helper Functions */ 109/* ------------------------------------------------------------------------------------------ */ 110 111func convNsToPs(timeNs int) int { 112 return timeNs * 1000 113} 114 115func convMtbToPs(mtb int) int { 116 return mtb * 125 117} 118 119func convPsToMtb(timePs int) int { 120 return divRoundUp(timePs, 125) 121} 122 123func convPsToMtbByte(timePs int) byte { 124 return byte(convPsToMtb(timePs) & 0xff) 125} 126 127func convPsToFtbByte(timePs int) byte { 128 mtb := convPsToMtb(timePs) 129 ftb := timePs - convMtbToPs(mtb) 130 131 return byte(ftb) 132} 133 134func convNsToMtb(timeNs int) int { 135 return convPsToMtb(convNsToPs(timeNs)) 136} 137 138func convNsToMtbByte(timeNs int) byte { 139 return convPsToMtbByte(convNsToPs(timeNs)) 140} 141 142func convNsToFtbByte(timeNs int) byte { 143 return convPsToFtbByte(convNsToPs(timeNs)) 144} 145 146func divRoundUp(dividend int, divisor int) int { 147 return (dividend + divisor - 1) / divisor 148} 149 150/* ------------------------------------------------------------------------------------------ */ 151/* Functions */ 152/* ------------------------------------------------------------------------------------------ */ 153 154func findIndex(dedupedAttribs []interface{}, newSPDAttribs interface{}) int { 155 for i := 0; i < len(dedupedAttribs); i++ { 156 if reflect.DeepEqual(dedupedAttribs[i], newSPDAttribs) { 157 return i 158 } 159 } 160 161 return -1 162} 163 164func readMemParts(memPartsFilePath string) (memParts, error) { 165 var memParts memParts 166 167 dataBytes, err := ioutil.ReadFile(memPartsFilePath) 168 if err != nil { 169 return memParts, err 170 } 171 172 // Strip comments from json file 173 re := regexp.MustCompile(`(?m)^\s*//.*`) 174 dataBytes = re.ReplaceAll(dataBytes, []byte("")) 175 176 if err := json.Unmarshal(dataBytes, &memParts); err != nil { 177 return memParts, err 178 } 179 180 return memParts, nil 181} 182 183func createSPD(memAttribs interface{}, t memTech) string { 184 var s string 185 186 for i := 0; i < t.getSPDLen(); i++ { 187 var b byte = 0 188 if memAttribs != nil { 189 b = t.getSPDByte(i, memAttribs) 190 } 191 192 if (i+1)%16 == 0 { 193 s += fmt.Sprintf("%02X\n", b) 194 } else { 195 s += fmt.Sprintf("%02X ", b) 196 } 197 } 198 199 return s 200} 201 202func writeSPD(memAttribs interface{}, SPDId int, SPDSetDirName string, t memTech) { 203 s := createSPD(memAttribs, t) 204 SPDFileName := fmt.Sprintf("spd-%d.hex", SPDId) 205 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644) 206} 207 208func writeEmptySPD(SPDSetDirName string, t memTech) { 209 s := createSPD(nil, t) 210 SPDFileName := "spd-empty.hex" 211 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644) 212} 213 214func getGeneratedString() string { 215 return fmt.Sprintf("# Generated by:\n# %s\n\n", strings.Join(os.Args[0:], " ")) 216} 217 218func writeSPDManifest(memPartArray []memPart, SPDSetDirName string) { 219 var s string 220 221 s += getGeneratedString() 222 for i := 0; i < len(memPartArray); i++ { 223 s += fmt.Sprintf("%s,spd-%d.hex\n", memPartArray[i].Name, memPartArray[i].SPDId) 224 } 225 226 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDManifestFileName), []byte(s), 0644) 227} 228 229func writeSetMap(setMap map[int][]int, SPDDirName string) { 230 var s string 231 232 s += getGeneratedString() 233 234 var setNumbers []int 235 for k, _ := range setMap { 236 setNumbers = append(setNumbers, k) 237 } 238 sort.Ints(setNumbers) 239 240 for _, num := range setNumbers { 241 for _, item := range setMap[num] { 242 s += fmt.Sprintf("%s,set-%d\n", platformNames[item], num) 243 } 244 } 245 246 ioutil.WriteFile(filepath.Join(SPDDirName, PlatformManifestFileName), []byte(s), 0644) 247} 248 249func usage() { 250 fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0]) 251 fmt.Printf(" where,\n") 252 fmt.Printf(" mem_parts_list_json = JSON File containing list of memory parts and attributes\n") 253 fmt.Printf(" mem_technology = Memory technology for which to generate SPDs\n") 254 fmt.Printf(" supported technologies: %v\n\n\n", 255 reflect.ValueOf(memTechMap).MapKeys()) 256} 257 258func main() { 259 if len(os.Args) != 3 { 260 usage() 261 log.Fatal("Incorrect number of arguments") 262 } 263 264 var t memTech 265 memPartsFilePath, memTechnology := os.Args[1], os.Args[2] 266 267 t, ok := memTechMap[strings.ToLower(memTechnology)] 268 if !ok { 269 log.Fatal("Unsupported memory technology ", memTechnology) 270 } 271 272 SPDDir, err := filepath.Abs(filepath.Dir(memPartsFilePath)) 273 if err != nil { 274 log.Fatal(err) 275 } 276 277 memParts, err := readMemParts(memPartsFilePath) 278 if err != nil { 279 log.Fatal(err) 280 } 281 282 memPartExists := make(map[string]bool) 283 for i := 0; i < len(memParts.MemParts); i++ { 284 if memPartExists[memParts.MemParts[i].Name] { 285 log.Fatalf("%s is duplicated in mem_parts_list_json", memParts.MemParts[i].Name) 286 } 287 memPartExists[memParts.MemParts[i].Name] = true 288 289 if err := t.addNewPart(memParts.MemParts[i].Name, memParts.MemParts[i].Attribs); err != nil { 290 log.Fatal(err) 291 } 292 } 293 294 setMap := t.getSetMap() 295 296 for i := 0; i < len(setMap); i++ { 297 var dedupedAttribs []interface{} 298 299 for j := 0; j < len(memParts.MemParts); j++ { 300 spdAttribs, _ := t.getSPDAttribs(memParts.MemParts[j].Name, i) 301 index := -1 302 303 if index = findIndex(dedupedAttribs, spdAttribs); index == -1 { 304 dedupedAttribs = append(dedupedAttribs, spdAttribs) 305 index = len(dedupedAttribs) - 1 306 } 307 308 memParts.MemParts[j].SPDId = index + 1 309 } 310 311 SPDSetDir := fmt.Sprintf("%s/set-%d", SPDDir, i) 312 os.MkdirAll(SPDSetDir, os.ModePerm) 313 314 for j := 0; j < len(dedupedAttribs); j++ { 315 writeSPD(dedupedAttribs[j], j+1, SPDSetDir, t) 316 } 317 318 writeEmptySPD(SPDSetDir, t) 319 320 writeSPDManifest(memParts.MemParts, SPDSetDir) 321 } 322 323 writeSetMap(setMap, SPDDir) 324} 325