util/spd_tools: Add support for exclusive IDs

Currently memory parts that use the same SPD are assigned the same ID by
spd_tools. This commit adds support for exclusive IDs. When given an
exclusive ID a memory part will not share its ID with other parts unless
they also have the same exclusive ID.

BUG=b:225161910
TEST=Ran part_id_gen and checked that exclusive IDs work correctly and
that the current behavior still works in their abscence.

Signed-off-by: Robert Zieba <robertzieba@google.com>
Change-Id: Ife5afe32337f69bc06451ce16238c7a83bc983c8
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62905
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
This commit is contained in:
Robert Zieba 2022-03-17 13:14:12 -06:00 committed by Karthik Ramasubramanian
parent 5d3b1bbce4
commit a6425f170c
2 changed files with 62 additions and 17 deletions

View File

@ -459,10 +459,14 @@ This program takes the following inputs:
* The memory technology used by the board, e.g. lp4x. * The memory technology used by the board, e.g. lp4x.
* The path to the directory where the generated Makefile.inc should be placed. * The path to the directory where the generated Makefile.inc should be placed.
* A CSV file containing a list of the memory parts used by the board, with an * A CSV file containing a list of the memory parts used by the board, with an
optional fixed ID for each part. NOTE: Only assign a fixed ID if required * optional fixed or exclusive ID for each part. A fixed ID is simply an integer
for legacy reasons. * and it ensure that part (and any that share the same SPD) will be assigned
* that ID. An exclusive ID is prefixed with `*` and ensures that only parts with
* the same exclusive ID will be assigned that ID, even if they would otherwise
* share the same ID.
* NOTE: Only assign a fixed/exclusive ID if required for legacy reasons.
Example of a CSV file using fixed IDs: Example of a CSV file using fixed and exclusive IDs:
``` ```
K4AAG165WA-BCWE,1 K4AAG165WA-BCWE,1
@ -470,13 +474,15 @@ MT40A512M16TB-062E:J
MT40A1G16KD-062E:E MT40A1G16KD-062E:E
K4A8G165WC-BCWE K4A8G165WC-BCWE
H5AN8G6NDJR-XNC,8 H5AN8G6NDJR-XNC,8
H5ANAG6NCMR-XNC H5ANAG6NCMR-XNC,*9
``` ```
Explanation: This will ensure that the SPDs for K4AAG165WA-BCWE and Explanation: This will ensure that the SPDs for K4AAG165WA-BCWE and
H5AN8G6NDJR-XNC are assigned to IDs 1 and 8 respectively. The SPDs for all other H5AN8G6NDJR-XNC are assigned to IDs 1 and 8 respectively. H5ANAG6NCMR-XNC
memory parts will be assigned to the first compatible ID. Assigning fixed IDs will be assigned ID 9 and no other part will be assigned ID 9 even if it
may result in duplicate SPD entries or gaps in the ID mapping. shares the same SPD. The SPDs for all other memory parts will be assigned to
the first compatible ID. Assigning fixed/exclusive IDs may result in duplicate
SPD entries or gaps in the ID mapping.
### Output ### Output

View File

@ -93,9 +93,18 @@ func checkArgs(platform string, memTech string, makefileDir string, memPartsUsed
return nil return nil
} }
type mappingType int
const (
Auto mappingType = iota
Fixed
Exclusive
)
type usedPart struct { type usedPart struct {
partName string partName string
index int index int
mapping mappingType
} }
func readPlatformsManifest(memTech string) (map[string]string, error) { func readPlatformsManifest(memTech string) (map[string]string, error) {
@ -174,16 +183,28 @@ func readParts(memPartsUsedFileName string) ([]usedPart, error) {
} }
if len(fields) == 1 { if len(fields) == 1 {
parts = append(parts, usedPart{fields[0], -1}) parts = append(parts, usedPart{fields[0], -1, Auto})
} else if len(fields) == 2 { } else if len(fields) == 2 {
assignedId, err := strconv.Atoi(fields[1]) var mapping = Auto
var assignedId = -1
var err error = nil
if len(fields[1]) >= 2 && fields[1][0] == '*' {
// Exclusive mapping
mapping = Exclusive
assignedId, err = strconv.Atoi(fields[1][1:])
} else {
mapping = Fixed
assignedId, err = strconv.Atoi(fields[1])
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
if assignedId > MaxMemoryId || assignedId < 0 { if assignedId > MaxMemoryId || assignedId < 0 {
return nil, fmt.Errorf("Out of bounds assigned id %d for part %s", assignedId, fields[0]) return nil, fmt.Errorf("Out of bounds assigned id %d for part %s", assignedId, fields[0])
} }
parts = append(parts, usedPart{fields[0], assignedId}) parts = append(parts, usedPart{fields[0], assignedId, mapping})
} else { } else {
return nil, fmt.Errorf("mem_parts_used_file file is incorrectly formatted") return nil, fmt.Errorf("mem_parts_used_file file is incorrectly formatted")
} }
@ -245,7 +266,7 @@ type partIds struct {
} }
func getFileHeader() string { func getFileHeader() string {
return `# SPDX-License-Identifier: GPL-2.0-or-later return `# SPDX-License-Identifier: GPL-2.0-or-later
# This is an auto-generated file. Do not edit!! # This is an auto-generated file. Do not edit!!
# Generated by: # Generated by:
` + fmt.Sprintf("# %s\n\n", strings.Join(os.Args[0:], " ")) ` + fmt.Sprintf("# %s\n\n", strings.Join(os.Args[0:], " "))
@ -262,6 +283,7 @@ func getFileHeader() string {
*/ */
func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) { func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) {
partIdList := []partIds{} partIdList := []partIds{}
assignedMapping := []mappingType{}
var s string var s string
// Assign parts with fixed ids first // Assign parts with fixed ids first
@ -280,19 +302,34 @@ func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexM
return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest") return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest")
} }
// Extend partIdList with empty entries if needed // Extend partIdList and assignedMapping with empty entries if needed
for i := len(partIdList) - 1; i < p.index; i++ { for i := len(partIdList) - 1; i < p.index; i++ {
partIdList = append(partIdList, partIds{}) partIdList = append(partIdList, partIds{})
assignedMapping = append(assignedMapping, Auto)
} }
if partIdList[p.index].SPDFileName != "" { // Only allow parts with the same index if they share the same SPD
return nil, fmt.Errorf("Part ", p.partName, " is assigned to an already assigned ID ", p.index) assignedSPD := partIdList[p.index].SPDFileName
if assignedSPD != "" && assignedSPD != partToSPDMap[p.partName] {
return nil, fmt.Errorf("ID %d is already assigned to %s, conflicting with %s(%s)", p.index, assignedSPD, p.partName, SPDFileName)
} }
partIdList[p.index] = partIds{SPDFileName: SPDFileName, memParts: p.partName} mapping := assignedMapping[p.index]
if (mapping == Fixed && p.mapping == Exclusive) || (mapping == Exclusive && p.mapping == Fixed) {
return nil, fmt.Errorf("Exclusive/non-exclusive conflict in assigning %s to ID %d", p.partName, p.index)
} else {
assignedMapping[p.index] = p.mapping
}
if partIdList[p.index].memParts == "" {
partIdList[p.index] = partIds{SPDFileName: SPDFileName, memParts: p.partName}
} else {
partIdList[p.index].memParts += ", " + p.partName
}
// SPDToIndexMap should point to first assigned index in the used part list // SPDToIndexMap should point to first assigned index in the used part list
if SPDToIndexMap[SPDFileName] < 0 { // Exclusive entries don't update the map because they're not valid for auto assigning
if SPDToIndexMap[SPDFileName] < 0 && p.mapping != Exclusive {
SPDToIndexMap[SPDFileName] = p.index SPDToIndexMap[SPDFileName] = p.index
} }
} }
@ -317,7 +354,8 @@ func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexM
} }
index := SPDToIndexMap[SPDFileName] index := SPDToIndexMap[SPDFileName]
if index != -1 { // Only Exclusive mappings don't allow automatic assigning of parts
if index != -1 && assignedMapping[index] != Exclusive {
partIdList[index].memParts += ", " + p.partName partIdList[index].memParts += ", " + p.partName
appendPartIdInfo(&s, p.partName, index) appendPartIdInfo(&s, p.partName, index)
continue continue
@ -338,6 +376,7 @@ func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexM
return nil, fmt.Errorf("Maximum part ID %d exceeded.", MaxMemoryId) return nil, fmt.Errorf("Maximum part ID %d exceeded.", MaxMemoryId)
} }
partIdList = append(partIdList, partIds{}) partIdList = append(partIdList, partIds{})
assignedMapping = append(assignedMapping, Auto)
} }
SPDToIndexMap[SPDFileName] = index SPDToIndexMap[SPDFileName] = index