| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| package main |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "io/ioutil" |
| "log" |
| "os" |
| "path/filepath" |
| "reflect" |
| "regexp" |
| "sort" |
| "strings" |
| ) |
| |
| /* ------------------------------------------------------------------------------------------ */ |
| /* Program-defined types */ |
| /* ------------------------------------------------------------------------------------------ */ |
| type memParts struct { |
| MemParts []memPart `json:"parts"` |
| } |
| |
| type memPart struct { |
| Name string |
| Attribs interface{} |
| SPDId int |
| } |
| |
| type memTech interface { |
| getSetMap() map[int][]int |
| addNewPart(string, interface{}) error |
| getSPDAttribs(string, int) (interface{}, error) |
| getSPDLen() int |
| getSPDByte(int, interface{}) byte |
| } |
| |
| /* ------------------------------------------------------------------------------------------ */ |
| /* Constants */ |
| /* ------------------------------------------------------------------------------------------ */ |
| |
| const ( |
| PlatformTGL = iota |
| PlatformADL |
| PlatformJSL |
| PlatformPCO |
| PlatformCZN |
| PlatformMax |
| ) |
| |
| const ( |
| SPDManifestFileName = "parts_spd_manifest.generated.txt" |
| PlatformManifestFileName = "platforms_manifest.generated.txt" |
| ) |
| |
| /* ------------------------------------------------------------------------------------------ */ |
| /* Global variables */ |
| /* ------------------------------------------------------------------------------------------ */ |
| |
| var platformNames = map[int]string{ |
| PlatformTGL: "TGL", |
| PlatformADL: "ADL", |
| PlatformJSL: "JSL", |
| PlatformPCO: "PCO", |
| PlatformCZN: "CZN", |
| } |
| |
| /* ------------------------------------------------------------------------------------------ */ |
| /* Conversion Helper Functions */ |
| /* ------------------------------------------------------------------------------------------ */ |
| |
| func convNsToPs(timeNs int) int { |
| return timeNs * 1000 |
| } |
| |
| func convMtbToPs(mtb int) int { |
| return mtb * 125 |
| } |
| |
| func convPsToMtb(timePs int) int { |
| return divRoundUp(timePs, 125) |
| } |
| |
| func convPsToMtbByte(timePs int) byte { |
| return byte(convPsToMtb(timePs) & 0xff) |
| } |
| |
| func convPsToFtbByte(timePs int) byte { |
| mtb := convPsToMtb(timePs) |
| ftb := timePs - convMtbToPs(mtb) |
| |
| return byte(ftb) |
| } |
| |
| func convNsToMtb(timeNs int) int { |
| return convPsToMtb(convNsToPs(timeNs)) |
| } |
| |
| func convNsToMtbByte(timeNs int) byte { |
| return convPsToMtbByte(convNsToPs(timeNs)) |
| } |
| |
| func convNsToFtbByte(timeNs int) byte { |
| return convPsToFtbByte(convNsToPs(timeNs)) |
| } |
| |
| func divRoundUp(dividend int, divisor int) int { |
| return (dividend + divisor - 1) / divisor |
| } |
| |
| /* ------------------------------------------------------------------------------------------ */ |
| /* Functions */ |
| /* ------------------------------------------------------------------------------------------ */ |
| |
| func findIndex(dedupedAttribs []interface{}, newSPDAttribs interface{}) int { |
| for i := 0; i < len(dedupedAttribs); i++ { |
| if reflect.DeepEqual(dedupedAttribs[i], newSPDAttribs) { |
| return i |
| } |
| } |
| |
| return -1 |
| } |
| |
| func readMemParts(memPartsFilePath string) (memParts, error) { |
| var memParts memParts |
| |
| dataBytes, err := ioutil.ReadFile(memPartsFilePath) |
| if err != nil { |
| return memParts, err |
| } |
| |
| // Strip comments from json file |
| re := regexp.MustCompile(`(?m)^\s*//.*`) |
| dataBytes = re.ReplaceAll(dataBytes, []byte("")) |
| |
| if err := json.Unmarshal(dataBytes, &memParts); err != nil { |
| return memParts, err |
| } |
| |
| return memParts, nil |
| } |
| |
| func createSPD(memAttribs interface{}, t memTech) string { |
| var s string |
| |
| for i := 0; i < t.getSPDLen(); i++ { |
| var b byte = 0 |
| if memAttribs != nil { |
| b = t.getSPDByte(i, memAttribs) |
| } |
| |
| if (i+1)%16 == 0 { |
| s += fmt.Sprintf("%02X\n", b) |
| } else { |
| s += fmt.Sprintf("%02X ", b) |
| } |
| } |
| |
| return s |
| } |
| |
| func writeSPD(memAttribs interface{}, SPDId int, SPDSetDirName string, t memTech) { |
| s := createSPD(memAttribs, t) |
| SPDFileName := fmt.Sprintf("spd-%d.hex", SPDId) |
| ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644) |
| } |
| |
| func writeEmptySPD(SPDSetDirName string, t memTech) { |
| s := createSPD(nil, t) |
| SPDFileName := "spd-empty.hex" |
| ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644) |
| } |
| |
| func getGeneratedString() string { |
| return fmt.Sprintf("# Generated by:\n# %s\n\n", strings.Join(os.Args[0:], " ")) |
| } |
| |
| func writeSPDManifest(memPartArray []memPart, SPDSetDirName string) { |
| var s string |
| |
| s += getGeneratedString() |
| for i := 0; i < len(memPartArray); i++ { |
| s += fmt.Sprintf("%s,spd-%d.hex\n", memPartArray[i].Name, memPartArray[i].SPDId) |
| } |
| |
| ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDManifestFileName), []byte(s), 0644) |
| } |
| |
| func writeSetMap(setMap map[int][]int, SPDDirName string) { |
| var s string |
| |
| s += getGeneratedString() |
| |
| var setNumbers []int |
| for k, _ := range setMap { |
| setNumbers = append(setNumbers, k) |
| } |
| sort.Ints(setNumbers) |
| |
| for _, num := range setNumbers { |
| for _, item := range setMap[num] { |
| s += fmt.Sprintf("%s,set-%d\n", platformNames[item], num) |
| } |
| } |
| |
| ioutil.WriteFile(filepath.Join(SPDDirName, PlatformManifestFileName), []byte(s), 0644) |
| } |
| |
| func usage() { |
| fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0]) |
| fmt.Printf(" where,\n") |
| fmt.Printf(" mem_parts_list_json = JSON File containing list of memory parts and attributes\n") |
| fmt.Printf(" mem_technology = Memory technology -- one of lp4x, ddr4\n\n\n") |
| } |
| |
| func main() { |
| if len(os.Args) != 3 { |
| usage() |
| log.Fatal("Incorrect number of arguments") |
| } |
| |
| var t memTech |
| memPartsFilePath, memTechnology := os.Args[1], os.Args[2] |
| |
| if strings.ToUpper(memTechnology) == "LP4X" { |
| t = lp4x{} |
| } else if strings.ToUpper(memTechnology) == "DDR4" { |
| t = ddr4{} |
| } else { |
| log.Fatal("Unsupported memory technology ", memTechnology) |
| } |
| |
| SPDDir, err := filepath.Abs(filepath.Dir(memPartsFilePath)) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| memParts, err := readMemParts(memPartsFilePath) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| memPartExists := make(map[string]bool) |
| for i := 0; i < len(memParts.MemParts); i++ { |
| if memPartExists[memParts.MemParts[i].Name] { |
| log.Fatalf("%s is duplicated in mem_parts_list_json", memParts.MemParts[i].Name) |
| } |
| memPartExists[memParts.MemParts[i].Name] = true |
| |
| if err := t.addNewPart(memParts.MemParts[i].Name, memParts.MemParts[i].Attribs); err != nil { |
| log.Fatal(err) |
| } |
| } |
| |
| setMap := t.getSetMap() |
| |
| for i := 0; i < len(setMap); i++ { |
| var dedupedAttribs []interface{} |
| |
| for j := 0; j < len(memParts.MemParts); j++ { |
| spdAttribs, _ := t.getSPDAttribs(memParts.MemParts[j].Name, i) |
| index := -1 |
| |
| if index = findIndex(dedupedAttribs, spdAttribs); index == -1 { |
| dedupedAttribs = append(dedupedAttribs, spdAttribs) |
| index = len(dedupedAttribs) - 1 |
| } |
| |
| memParts.MemParts[j].SPDId = index + 1 |
| } |
| |
| SPDSetDir := fmt.Sprintf("%s/set-%d", SPDDir, i) |
| os.MkdirAll(SPDSetDir, os.ModePerm) |
| |
| for j := 0; j < len(dedupedAttribs); j++ { |
| writeSPD(dedupedAttribs[j], j+1, SPDSetDir, t) |
| } |
| |
| writeEmptySPD(SPDSetDir, t) |
| |
| writeSPDManifest(memParts.MemParts, SPDSetDir) |
| } |
| |
| writeSetMap(setMap, SPDDir) |
| } |