Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions pkg/engines/busses.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ func (device Device) validateBus(extraFields []string) error {
return device.validatePci(extraFields)
case "usb":
return device.validateUsb(extraFields)
case "fastrpc":
return device.validateFastRpc(extraFields)
case "drpai":
return device.validateDrpAi(extraFields)
case "": // default to pci bus
return device.validatePci(extraFields)
default:
Expand Down Expand Up @@ -49,3 +53,61 @@ func (device Device) validatePci(extraFields []string) error {

return nil
}

func (device Device) validateFastRpc(extraFields []string) error {
if device.Type != "" && device.Type != "npu" {
return fmt.Errorf("fastrpc bus only supports npu devices")
}

validFields := []string{
"Type",
"Bus",
"NodeGlob",
"SnapConnections",
}
validFields = append(validFields, extraFields...)

t := reflect.TypeOf(device)
v := reflect.ValueOf(device)

for i := 0; i < t.NumField(); i++ {
fieldName := t.Field(i).Name
fieldValue := v.FieldByName(fieldName)
if fieldValue.IsValid() && !fieldValue.IsZero() {
if !slices.Contains(validFields, fieldName) {
return fmt.Errorf("fastrpc: invalid field: %s", fieldName)
}
}
}

return nil
}

func (device Device) validateDrpAi(extraFields []string) error {
if device.Type != "" && device.Type != "npu" {
return fmt.Errorf("drpai bus only supports npu devices")
}

validFields := []string{
"Type",
"Bus",
"NodeGlob",
"SnapConnections",
}
validFields = append(validFields, extraFields...)

t := reflect.TypeOf(device)
v := reflect.ValueOf(device)

for i := 0; i < t.NumField(); i++ {
fieldName := t.Field(i).Name
fieldValue := v.FieldByName(fieldName)
if fieldValue.IsValid() && !fieldValue.IsZero() {
if !slices.Contains(validFields, fieldName) {
return fmt.Errorf("drpai: invalid field: %s", fieldName)
}
}
}

return nil
}
18 changes: 18 additions & 0 deletions pkg/engines/busses_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,22 @@ func TestDeviceBus(t *testing.T) {
}
t.Log(err)
})

t.Run("FastRPC bus with non-NPU type", func(t *testing.T) {
device.Bus = "fastrpc"
err := device.validate()
if err == nil {
t.Fatal("FastRPC bus should be invalid for GPU type")
}
t.Log(err)
})

t.Run("DRP-AI bus with non-NPU type", func(t *testing.T) {
device.Bus = "drpai"
err := device.validate()
if err == nil {
t.Fatal("DRP-AI bus should be invalid for GPU type")
}
t.Log(err)
})
}
46 changes: 46 additions & 0 deletions pkg/engines/devices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,52 @@ func TestDeviceNpu(t *testing.T) {
}
t.Log(err)
})

t.Run("NPU fastrpc valid fields", func(t *testing.T) {
device = Device{Type: "npu", Bus: "fastrpc"}
nodeGlob := "/dev/fastrpc-cdsp*"
device.NodeGlob = &nodeGlob

err := device.validate()
if err != nil {
t.Fatalf("NPU fastrpc fields should be valid: %v", err)
}
})

t.Run("NPU fastrpc invalid fields", func(t *testing.T) {
device = Device{Type: "npu", Bus: "fastrpc"}
hexValue := types.HexInt(0xAA)
device.VendorId = &hexValue

err := device.validate()
if err == nil {
t.Fatal("NPU fastrpc fields should be invalid")
}
t.Log(err)
})

t.Run("NPU drpai valid fields", func(t *testing.T) {
device = Device{Type: "npu", Bus: "drpai"}
nodeGlob := "/dev/drpai*"
device.NodeGlob = &nodeGlob

err := device.validate()
if err != nil {
t.Fatalf("NPU drpai fields should be valid: %v", err)
}
})

t.Run("NPU drpai invalid fields", func(t *testing.T) {
device = Device{Type: "npu", Bus: "drpai"}
hexValue := types.HexInt(0xAA)
device.VendorId = &hexValue

err := device.validate()
if err == nil {
t.Fatal("NPU drpai fields should be invalid")
}
t.Log(err)
})
}

func TestDeviceTypeless(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/engines/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type Devices struct {
type Device struct {
// General
Type string `yaml:"type,omitempty" json:"type,omitempty"` // cpu, gpu, npu or nil
Bus string `yaml:"bus,omitempty" json:"bus,omitempty"` // pci, usb or nil
Bus string `yaml:"bus,omitempty" json:"bus,omitempty"` // pci, usb, fastrpc or nil

// CPUs
Architecture *string `yaml:"architecture,omitempty" json:"architecture,omitempty"`
Expand All @@ -69,7 +69,7 @@ type Device struct {
ComputeCapability *string `yaml:"compute-capability,omitempty" json:"compute-capability,omitempty"`

// NPU
// no additional properties for now
NodeGlob *string `yaml:"node-glob,omitempty" json:"node-glob,omitempty"`

// Drivers
SnapConnections []string `yaml:"snap-connections,omitempty" json:"snap-connections,omitempty"`
Expand Down
9 changes: 9 additions & 0 deletions pkg/hardware_info/disk/disk_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package disk

import (
"fmt"
"os"

"github.com/canonical/inference-snaps-cli/pkg/constants"
"github.com/canonical/inference-snaps-cli/pkg/types"
Expand All @@ -16,6 +17,14 @@ func Info() (map[string]types.DirStats, error) {
var info = make(map[string]types.DirStats)

for _, dir := range directories {
// Skip directories that don't exist
if _, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) {
continue
}
return nil, fmt.Errorf("checking directory %s: %v", dir, err)
}

dirInfo, err := statFs(dir)
if err != nil {
return nil, fmt.Errorf("getting directory info for %s: %v", dir, err)
Expand Down
63 changes: 63 additions & 0 deletions pkg/hardware_info/hardware-info.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import (
"encoding/json"
"fmt"
"os"
"strings"
"testing"

"github.com/canonical/inference-snaps-cli/pkg/hardware_info/cpu"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/disk"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/mediatek"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/memory"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/pci"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/qualcomm"
"github.com/canonical/inference-snaps-cli/pkg/hardware_info/renesas"
"github.com/canonical/inference-snaps-cli/pkg/types"
)

Expand Down Expand Up @@ -40,6 +44,24 @@ func Get(friendlyNames bool) (*types.HwInfo, []string, error) {
}
hwInfo.PciDevices = pciDevices

qualcommDevices, err := qualcomm.Info()
if err != nil {
return nil, nil, fmt.Errorf("getting qualcomm devices: %v", err)
}
hwInfo.Devices = append(hwInfo.Devices, qualcommDevices...)

mediatekDevices, err := mediatek.Info()
if err != nil {
return nil, nil, fmt.Errorf("getting mediatek devices: %v", err)
}
hwInfo.Devices = append(hwInfo.Devices, mediatekDevices...)

renesasDevices, err := renesas.Info()
if err != nil {
return nil, nil, fmt.Errorf("getting renesas devices: %v", err)
}
hwInfo.Devices = append(hwInfo.Devices, renesasDevices...)

return &hwInfo, warnings, nil
}

Expand Down Expand Up @@ -100,6 +122,47 @@ func GetFromRawData(t *testing.T, device string, friendlyNames bool, testDir str
}
hwInfo.PciDevices = pciDevices

fastrpcNodesFile := devicePath + "fastrpc-nodes.txt"
if _, err := os.Stat(fastrpcNodesFile); err == nil {
nodesData, err := os.ReadFile(fastrpcNodesFile)
if err != nil {
t.Fatal(err)
}

nodes := strings.Fields(string(nodesData))
devices := qualcomm.DetectFromNodes(nodes)
hwInfo.Devices = devices
} else if !os.IsNotExist(err) {
t.Fatalf("error checking file '%s': %v\n", fastrpcNodesFile, err)
}

mediatekCompatiblesFile := devicePath + "mediatek-compatible.txt"
if _, err := os.Stat(mediatekCompatiblesFile); err == nil {
compatiblesData, err := os.ReadFile(mediatekCompatiblesFile)
if err != nil {
t.Fatal(err)
}

devices := mediatek.DetectFromCompatibles(strings.Fields(string(compatiblesData)))
hwInfo.Devices = append(hwInfo.Devices, devices...)
} else if !os.IsNotExist(err) {
t.Fatalf("error checking file '%s': %v\n", mediatekCompatiblesFile, err)
}

drpAiNodesFile := devicePath + "drpai-nodes.txt"
if _, err := os.Stat(drpAiNodesFile); err == nil {
nodesData, err := os.ReadFile(drpAiNodesFile)
if err != nil {
t.Fatal(err)
}

nodes := strings.Fields(string(nodesData))
devices := renesas.DetectFromNodes(nodes)
hwInfo.Devices = append(hwInfo.Devices, devices...)
} else if !os.IsNotExist(err) {
t.Fatalf("error checking file '%s': %v\n", drpAiNodesFile, err)
}

// Additional properties - we append these directly from a file, as we can not run the vendor specific tools on the machine
addPropsFile := devicePath + "additional-properties.json"
_, err = os.Stat(addPropsFile)
Expand Down
Loading
Loading