util/intelp2m/parser: Add unit test

Also add an interface for printing macros to override this in the test
and not create a new gpio file for comparison.

Change-Id: I16c9b4451cd4418b49043a925cb879a982a56461
Signed-off-by: Maxim Polyakov <max.senia.poliak@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/67701
Reviewed-by: Maximilian Brune <maximilian.brune@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Maxim Polyakov 2022-09-17 13:47:11 +03:00 committed by Matt DeVillier
commit 7d1c33c9d1
4 changed files with 291 additions and 125 deletions

View file

@ -9,6 +9,20 @@ import (
"review.coreboot.org/coreboot.git/util/intelp2m/parser"
)
type Printer struct{}
func (Printer) Linef(lvl int, format string, args ...interface{}) {
if config.InfoLevelGet() >= lvl {
fmt.Fprintf(config.OutputGenFile, format, args...)
}
}
func (Printer) Line(lvl int, str string) {
if config.InfoLevelGet() >= lvl {
fmt.Fprint(config.OutputGenFile, str)
}
}
var (
// Version is injected into main during project build
Version string = "Unknown"
@ -19,28 +33,6 @@ func printVersion() {
fmt.Printf("[ intelp2m ] Version: %s\n", Version)
}
// generateOutputFile - generates include file
// parser : parser data structure
func generateOutputFile(parser *parser.ParserData) (err error) {
header := fmt.Sprintf(`/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef CFG_GPIO_H
#define CFG_GPIO_H
#include <gpio.h>
/* Pad configuration was generated automatically using intelp2m %s */
static const struct pad_config gpio_table[] = {`, Version)
config.OutputGenFile.WriteString(header + "\n")
// Add the pads map
parser.PadMapFprint()
config.OutputGenFile.WriteString(`};
#endif /* CFG_GPIO_H */
`)
return nil
}
// main
func main() {
// Command line arguments
@ -148,13 +140,31 @@ func main() {
config.OutputGenFile = outputGenFile
config.InputRegDumpFile = inputRegDumpFile
parser := parser.ParserData{}
parser.Parse()
prs := parser.ParserData{}
prs.Parse()
// gpio.h
err = generateOutputFile(&parser)
if err != nil {
fmt.Printf("Error! Can not create the file with GPIO configuration!\n")
generator := parser.Generator{
PrinterIf: Printer{},
Data: &prs,
}
header := fmt.Sprintf(`/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef CFG_GPIO_H
#define CFG_GPIO_H
#include <gpio.h>
/* Pad configuration was generated automatically using intelp2m %s */
static const struct pad_config gpio_table[] = {`, Version)
config.OutputGenFile.WriteString(header + "\n")
// Add the pads map
if err := generator.Run(); err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
config.OutputGenFile.WriteString(`};
#endif /* CFG_GPIO_H */
`)
}

View file

@ -2,21 +2,22 @@ package parser
import (
"bufio"
"errors"
"fmt"
"strings"
"strconv"
"strings"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/common"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/snr"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/lbg"
"review.coreboot.org/coreboot.git/util/intelp2m/config"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/adl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/apl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/cnl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/tgl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/adl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/jsl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/mtl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/common"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/ebg"
"review.coreboot.org/coreboot.git/util/intelp2m/config"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/jsl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/lbg"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/mtl"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/snr"
"review.coreboot.org/coreboot.git/util/intelp2m/platforms/tgl"
)
// PlatformSpecific - platform-specific interface
@ -42,57 +43,16 @@ type padInfo struct {
ownership uint8
}
// generate - wrapper for Fprintf(). Writes text to the file specified
// in config.OutputGenFile
func (info *padInfo) generate(lvl int, line string, a ...interface{}) {
if config.InfoLevelGet() >= lvl {
fmt.Fprintf(config.OutputGenFile, line, a...)
}
}
// titleFprint - print GPIO group title to file
// /* ------- GPIO Group GPP_L ------- */
func (info *padInfo) titleFprint() {
info.generate(0, "\n\t/* %s */\n", info.function)
}
// reservedFprint - print reserved GPIO to file as comment
// /* GPP_H17 - RESERVED */
func (info *padInfo) reservedFprint() {
info.generate(2, "\n")
// small comment about reserved port
info.generate(0, "\t/* %s - %s */\n", info.id, info.function)
}
// padInfoMacroFprint - print information about current pad to file using
// special macros:
// PAD_CFG_NF(GPP_F1, 20K_PU, PLTRST, NF1), /* SATAXPCIE4 */
// gpio : gpio.c file descriptor
// macro : string of the generated macro
func (info *padInfo) padInfoMacroFprint(macro string) {
info.generate(2,
"\n\t/* %s - %s */\n\t/* DW0: 0x%0.8x, DW1: 0x%0.8x */\n",
info.id,
info.function,
info.dw0,
info.dw1)
info.generate(0, "\t%s", macro)
if config.InfoLevelGet() == 1 {
info.generate(1, "\t/* %s */", info.function)
}
info.generate(0, "\n")
}
// ParserData - global data
// line : string from the configuration file
// padmap : pad info map
// RawFmt : flag for generating pads config file with DW0/1 reg raw values
// Template : structure template type of ConfigFile
type ParserData struct {
platform PlatformSpecific
line string
padmap []padInfo
ownership map[string]uint32
platform PlatformSpecific
line string
padmap []padInfo
ownership map[string]uint32
}
// hostOwnershipGet - get the host software ownership value for the corresponding
@ -118,14 +78,14 @@ func (parser *ParserData) padInfoExtract() int {
var dw0, dw1 uint32
var template = map[int]template{
config.TempInteltool: UseInteltoolLogTemplate,
config.TempGpioh : useGpioHTemplate,
config.TempSpec : useYourTemplate,
config.TempGpioh: useGpioHTemplate,
config.TempSpec: useYourTemplate,
}
if template[config.TemplateGet()](parser.line, &function, &id, &dw0, &dw1) == 0 {
pad := padInfo{id: id,
function: function,
dw0: dw0,
dw1: dw1,
function: function,
dw0: dw0,
dw1: dw1,
ownership: parser.hostOwnershipGet(id)}
parser.padmap = append(parser.padmap, pad)
return 0
@ -143,56 +103,46 @@ func (parser *ParserData) communityGroupExtract() {
// PlatformSpecificInterfaceSet - specific interface for the platform selected
// in the configuration
func (parser *ParserData) PlatformSpecificInterfaceSet() {
var platform = map[uint8]PlatformSpecific {
config.SunriseType : snr.PlatformSpecific{},
var platform = map[uint8]PlatformSpecific{
config.SunriseType: snr.PlatformSpecific{},
// See platforms/lbg/macro.go
config.LewisburgType : lbg.PlatformSpecific{
InheritanceTemplate : snr.PlatformSpecific{},
config.LewisburgType: lbg.PlatformSpecific{
InheritanceTemplate: snr.PlatformSpecific{},
},
config.ApolloType : apl.PlatformSpecific{},
config.CannonType : cnl.PlatformSpecific{
InheritanceTemplate : snr.PlatformSpecific{},
config.ApolloType: apl.PlatformSpecific{},
config.CannonType: cnl.PlatformSpecific{
InheritanceTemplate: snr.PlatformSpecific{},
},
config.TigerType : tgl.PlatformSpecific{},
config.AlderType : adl.PlatformSpecific{},
config.JasperType : jsl.PlatformSpecific{},
config.MeteorType : mtl.PlatformSpecific{},
config.TigerType: tgl.PlatformSpecific{},
config.AlderType: adl.PlatformSpecific{},
config.JasperType: jsl.PlatformSpecific{},
config.MeteorType: mtl.PlatformSpecific{},
// See platforms/ebg/macro.go
config.EmmitsburgType : ebg.PlatformSpecific{
InheritanceTemplate : cnl.PlatformSpecific{
InheritanceTemplate : snr.PlatformSpecific{},
config.EmmitsburgType: ebg.PlatformSpecific{
InheritanceTemplate: cnl.PlatformSpecific{
InheritanceTemplate: snr.PlatformSpecific{},
},
},
}
parser.platform = platform[config.PlatformGet()]
}
// PadMapFprint - print pad info map to file
func (parser *ParserData) PadMapFprint() {
for _, pad := range parser.padmap {
switch pad.dw0 {
case 0:
pad.titleFprint()
case 0xffffffff:
pad.reservedFprint()
default:
str := parser.platform.GenMacro(pad.id, pad.dw0, pad.dw1, pad.ownership)
pad.padInfoMacroFprint(str)
}
}
}
// Register - read specific platform registers (32 bits)
// line : string from file with pad config map
// nameTemplate : register name femplate to filter parsed lines
// return
// valid : true if the dump of the register in intertool.log is set in accordance
// with the template
// name : full register name
// offset : register offset relative to the base address
// value : register value
//
// valid : true if the dump of the register in intertool.log is set in accordance
// with the template
// name : full register name
// offset : register offset relative to the base address
// value : register value
func (parser *ParserData) Register(nameTemplate string) (
valid bool, name string, offset uint32, value uint32) {
valid bool,
name string,
offset uint32,
value uint32,
) {
if strings.Contains(parser.line, nameTemplate) &&
config.TemplateGet() == config.TempInteltool {
if registerInfoTemplate(parser.line, &name, &offset, &value) == 0 {
@ -204,7 +154,8 @@ func (parser *ParserData) Register(nameTemplate string) (
}
// padOwnershipExtract - extract Host Software Pad Ownership from inteltool dump
// return true if success
//
// return true if success
func (parser *ParserData) padOwnershipExtract() bool {
var group string
status, name, offset, value := parser.Register("HOSTSW_OWN_GPP_")
@ -212,13 +163,14 @@ func (parser *ParserData) padOwnershipExtract() bool {
_, group = parser.platform.GroupNameExtract(parser.line)
parser.ownership[group] = value
fmt.Printf("\n\t/* padOwnershipExtract: [offset 0x%x] %s = 0x%x */\n",
offset, name, parser.ownership[group])
offset, name, parser.ownership[group])
}
return status
}
// padConfigurationExtract - reads GPIO configuration registers and returns true if the
// information from the inteltool log was successfully parsed.
//
// information from the inteltool log was successfully parsed.
func (parser *ParserData) padConfigurationExtract() bool {
// Only for Sunrise or CannonLake, and only for inteltool.log file template
if config.TemplateGet() != config.TempInteltool || config.IsPlatformApollo() {
@ -242,7 +194,7 @@ func (parser *ParserData) Parse() {
scanner := bufio.NewScanner(config.InputRegDumpFile)
for scanner.Scan() {
parser.line = scanner.Text()
isIncluded, _ := common.KeywordsCheck(parser.line, "GPIO Community", "GPIO Group");
isIncluded, _ := common.KeywordsCheck(parser.line, "GPIO Community", "GPIO Group")
if isIncluded {
parser.communityGroupExtract()
} else if !parser.padConfigurationExtract() && parser.platform.KeywordCheck(parser.line) {
@ -253,3 +205,48 @@ func (parser *ParserData) Parse() {
}
fmt.Println("...done!")
}
type PrinterIf interface {
Linef(lvl int, format string, args ...interface{})
Line(lvl int, str string)
}
type Generator struct {
Data *ParserData // information from the parser
PrinterIf // interface for printing
}
// Run - generate a new gpio file based on the information from the parser
func (g Generator) Run() error {
if g.PrinterIf == nil && g.Data == nil {
return errors.New("Generator: Incorrect initialization")
}
for _, pad := range g.Data.padmap {
switch pad.dw0 {
case 0x00000000:
// titleFprint - print GPIO group title to file
// /* ------- GPIO Group GPP_L ------- */
g.Linef(0, "\n\t/* %s */\n", pad.function)
case 0xffffffff:
// reservedFprint - print reserved GPIO to file as comment
// /* GPP_H17 - RESERVED */
g.Line(2, "\n")
// small comment about reserved port
g.Linef(0, "\t/* %s - %s */\n", pad.id, pad.function)
default:
// padInfoMacroFprint - print information about current pad to file using
// special macros:
// PAD_CFG_NF(GPP_F1, 20K_PU, PLTRST, NF1), /* SATAXPCIE4 */
platform := g.Data.platform
macro := platform.GenMacro(pad.id, pad.dw0, pad.dw1, pad.ownership)
g.Linef(2, "\n\t/* %s - %s */\n\t/* DW0: 0x%0.8x, DW1: 0x%0.8x */\n",
pad.id, pad.function, pad.dw0, pad.dw1)
g.Linef(0, "\t%s", macro)
if config.InfoLevelGet() == 1 {
g.Linef(1, "\t/* %s */", pad.function)
}
g.Line(0, "\n")
}
}
return nil
}

View file

@ -0,0 +1,104 @@
package parser_test
import (
"fmt"
"os"
"testing"
"review.coreboot.org/coreboot.git/util/intelp2m/config"
"review.coreboot.org/coreboot.git/util/intelp2m/parser"
)
const testLogFilePath = "test/inteltool_test.log"
type Printer struct {
lines []string
}
func (p *Printer) Linef(lvl int, format string, args ...interface{}) {
if config.InfoLevelGet() >= lvl {
p.lines = append(p.lines, fmt.Sprintf(format, args...))
}
}
func (p *Printer) Line(lvl int, str string) {
if config.InfoLevelGet() >= lvl {
p.lines = append(p.lines, str)
}
}
func TestParser(t *testing.T) {
t.Run("PARSER/PARSE-INTELTOOL-FILE", func(t *testing.T) {
reference := []string{
"\n\t/* ------- GPIO Community 0 ------- */\n",
"\n\t/* ------- GPIO Group GPP_A ------- */\n",
"\tPAD_CFG_NF(GPP_A0, NONE, PLTRST, NF1),", "\t/* RCIN# */", "\n",
"\tPAD_CFG_NF(GPP_A1, UP_20K, PLTRST, NF1),", "\t/* LAD0 */", "\n",
"\tPAD_CFG_NF(GPP_A5, NONE, PLTRST, NF1),", "\t/* LFRAME# */", "\n",
"\tPAD_CFG_NF(GPP_A13, NONE, DEEP, NF1),", "\t/* SUSWARN#/SUSPWRDNACK */", "\n",
"\tPAD_CFG_GPI_TRIG_OWN(GPP_A23, NONE, PLTRST, OFF, ACPI),", "\t/* GPIO */", "\n",
"\n\t/* ------- GPIO Group GPP_B ------- */\n",
"\t/* GPP_C1 - RESERVED */\n",
"\tPAD_CFG_GPI_TRIG_OWN(GPP_B0, NONE, PLTRST, OFF, ACPI),", "\t/* GPIO */", "\n",
"\tPAD_CFG_NF(GPP_B23, DN_20K, PLTRST, NF2),", "\t/* PCHHOT# */", "\n",
"\n\t/* ------- GPIO Community 1 ------- */\n",
"\n\t/* ------- GPIO Group GPP_C ------- */\n",
"\tPAD_CFG_NF(GPP_C0, NONE, DEEP, NF1),", "\t/* SMBCLK */", "\n",
"\tPAD_CFG_GPI_TRIG_OWN(GPP_C5, NONE, PLTRST, OFF, ACPI),", "\t/* GPIO */", "\n",
"\t/* GPP_C6 - RESERVED */\n",
"\t/* GPP_C7 - RESERVED */\n",
"\tPAD_CFG_NF(GPP_C22, NONE, PLTRST, NF1),", "\t/* UART2_RTS# */", "\n",
"\n\t/* ------- GPIO Group GPP_D ------- */\n",
"\n\t/* ------- GPIO Group GPP_E ------- */\n",
"\tPAD_CFG_NF(GPP_E0, UP_20K, PLTRST, NF1),", "\t/* SATAXPCIE0 */", "\n",
"\n\t/* ------- GPIO Group GPP_G ------- */\n",
"\tPAD_CFG_NF(GPP_G19, NONE, PLTRST, NF1),", "\t/* SMI# */", "\n",
"\n\t/* ------- GPIO Community 2 ------- */\n",
"\n\t/* -------- GPIO Group GPD -------- */\n",
"\tPAD_CFG_NF(GPD9, NONE, PWROK, NF1),", "\t/* SLP_WLAN# */", "\n",
"\n\t/* ------- GPIO Community 3 ------- */\n",
"\n\t/* ------- GPIO Group GPP_I ------- */\n",
"\tPAD_CFG_NF(GPP_I0, NONE, PLTRST, NF1),", "\t/* DDPB_HPD0 */", "\n",
"\tPAD_CFG_NF(GPP_I1, NONE, PLTRST, NF1),", "\t/* DDPC_HPD1 */", "\n",
"\tPAD_CFG_NF(GPP_I2, NONE, PLTRST, NF1),", "\t/* DDPD_HPD2 */", "\n",
}
input, err := os.Open(testLogFilePath)
if err != nil {
t.Errorf("Something is wrong with the test file - %s!\n", testLogFilePath)
os.Exit(1)
}
defer input.Close()
config.InputRegDumpFile = input
config.FldStyleSet("none")
config.NonCheckingFlagSet(true)
config.InfoLevelSet(1)
prs := parser.ParserData{}
prs.Parse()
printer := Printer{lines: make([]string, 0)}
generator := parser.Generator{
PrinterIf: &printer,
Data: &prs,
}
if err := generator.Run(); err != nil {
t.Errorf("Generator: %v", err)
os.Exit(1)
}
if len(printer.lines) == len(reference) {
for i := range printer.lines {
if printer.lines[i] != reference[i] {
t.Errorf("\nExpects: '%s'\nActually: '%s'\n\n", reference[i], printer.lines[i])
return
}
}
} else {
t.Errorf("%d does not match the reference slice len - %d!",
len(reference), len(printer.lines))
}
})
}

View file

@ -0,0 +1,55 @@
CPU: ID 0x906e9, Processor Type 0x0, Family 0x6, Model 0x9e, Stepping 0x9
Northbridge: 8086:591f (unknown)
Southbridge: 8086:a143 (H110)
IGD: 8086:5912 (Intel(R) UHD Graphics 630)
Trying to reveal Primary to Sideband Bridge (P2SB),
let's hope the OS doesn't mind... done.
SBREG_BAR = 0xfd000000 (MEM)
Hiding Primary to Sideband Bridge (P2SB).
============= GPIOS =============
------- GPIO Community 0 -------
PCR Port ID: 0xaf0000
------- GPIO Group GPP_A -------
0x0400: 0x0000001884000502 GPP_A0 RCIN#
0x0408: 0x0000301984000402 GPP_A1 LAD0
0x0428: 0x0000001d84000600 GPP_A5 LFRAME#
0x0468: 0x0000002544000600 GPP_A13 SUSWARN#/SUSPWRDNACK
0x04b8: 0x0000002f84000102 GPP_A23 GPIO
------- GPIO Group GPP_B -------
0x0438: 0xffffffffffffffff GPP_C1 RESERVED
0x04c0: 0x0000003084000100 GPP_B0 GPIO
0x0578: 0x0000104784000a01 GPP_B23 PCHHOT#
------- GPIO Community 1 -------
PCR Port ID: 0xae0000
------- GPIO Group GPP_C -------
0x0400: 0x0000004844000502 GPP_C0 SMBCLK
0x0428: 0x0000004d84000100 GPP_C5 GPIO
0x0430: 0xffffffffffffffff GPP_C6 RESERVED
0x0438: 0xffffffffffffffff GPP_C7 RESERVED
0x04b0: 0x0000005e84000600 GPP_C22 UART2_RTS#
------- GPIO Group GPP_D -------
------- GPIO Group GPP_E -------
0x0580: 0x0000301884000502 GPP_E0 SATAXPCIE0
------- GPIO Group GPP_G -------
0x0740: 0x0000005084000500 GPP_G19 SMI#
------- GPIO Community 2 -------
PCR Port ID: 0xad0000
-------- GPIO Group GPD --------
0x0448: 0x0000002104000600 GPD9 SLP_WLAN#
------- GPIO Community 3 -------
PCR Port ID: 0xac0000
------- GPIO Group GPP_I -------
0x0400: 0x0000006d84000500 GPP_I0 DDPB_HPD0
0x0408: 0x0000006e84000502 GPP_I1 DDPC_HPD1
0x0410: 0x0000006f84000502 GPP_I2 DDPD_HPD2