blob: 57b428b2b34a7a9b781d7d36d7efb3e049a65427 [file] [log] [blame]
/* 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)
}