intel-device-plugins-for-ku.../cmd/fpga_tool/fpga_tool.go
2020-06-23 12:04:35 +03:00

347 lines
9.1 KiB
Go

// Copyright 2019 Intel Corporation. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/intel/intel-device-plugins-for-kubernetes/pkg/fpga"
"github.com/intel/intel-device-plugins-for-kubernetes/pkg/fpga/bitstream"
)
const (
fpgaBitStreamDirectory = "/srv/intel.com/fpga"
)
func main() {
var err error
var bitstream, device string
var dryRun, force, quiet bool
flag.StringVar(&bitstream, "b", "", "Path to bitstream file (GBS or AOCX)")
flag.StringVar(&device, "d", "", "Path to device node (FME or Port)")
flag.BoolVar(&dryRun, "dry-run", false, "Don't write/program, just validate and log")
flag.BoolVar(&force, "force", false, "Force overwrite operation for installing bitstreams")
flag.BoolVar(&quiet, "q", false, "Quiet mode. Only errors will be reported")
flag.Parse()
if flag.NArg() < 1 {
log.Fatal("Please provide command: info, fpgainfo, install, list, fmeinfo, portinfo, list-fme, list-port, pr")
}
cmd := flag.Arg(0)
err = validateFlags(cmd, bitstream, device)
if err != nil {
log.Fatalf("Invalid arguments: %+v", err)
}
switch cmd {
case "info":
err = printBitstreamInfo(bitstream, quiet)
case "pr":
err = doPR(device, bitstream, dryRun, quiet)
case "fpgainfo":
err = fpgaInfo(device, quiet)
case "fmeinfo":
err = fmeInfo(device, quiet)
case "portinfo":
err = portInfo(device, quiet)
case "install":
err = installBitstream(bitstream, dryRun, force, quiet)
case "list":
err = listDevices(true, true, quiet)
case "list-fme":
err = listDevices(true, false, quiet)
case "list-port":
err = listDevices(false, true, quiet)
default:
err = errors.Errorf("unknown command %+v", flag.Args())
}
if err != nil {
log.Fatalf("%+v", err)
}
}
func validateFlags(cmd, bitstream, device string) error {
switch cmd {
case "info", "install":
// bitstream must not be empty
if bitstream == "" {
return errors.Errorf("bitstream filename is missing")
}
case "fpgainfo", "fmeinfo", "portinfo":
// device must not be empty
if device == "" {
return errors.Errorf("FPGA device name is missing")
}
case "pr":
// device and bitstream can't be empty
if bitstream == "" {
return errors.Errorf("bitstream filename is missing")
}
if device == "" {
return errors.Errorf("FPGA device name is missing")
}
}
return nil
}
func installBitstream(fname string, dryRun, force, quiet bool) (err error) {
info, err := bitstream.Open(fname)
if err != nil {
return
}
defer info.Close()
installPath := info.InstallPath(fpgaBitStreamDirectory)
if !quiet {
fmt.Printf("Installing bitstream %q as %q\n", fname, installPath)
if dryRun {
fmt.Println("Dry-run: no copying performed")
return
}
}
err = os.MkdirAll(filepath.Dir(installPath), 0755)
if err != nil {
return errors.Wrap(err, "unable to create destination directory")
}
src, err := os.Open(fname)
if err != nil {
return errors.Wrap(err, "can't open bitstream file")
}
defer src.Close()
flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
if !force {
flags = flags | os.O_EXCL
}
dst, err := os.OpenFile(installPath, flags, 0644)
if err != nil {
if os.IsExist(err) {
return fmt.Errorf("destination file %q already exist. Use --force to overwrite it", installPath)
}
return errors.Wrap(err, "can't create destination file")
}
defer dst.Close()
_, err = io.Copy(dst, src)
return err
}
func printBitstreamInfo(fname string, quiet bool) (err error) {
info, err := bitstream.Open(fname)
if err != nil {
return
}
defer info.Close()
fmt.Printf("Bitstream file : %q\n", fname)
fmt.Printf("Interface UUID : %q\n", info.InterfaceUUID())
fmt.Printf("Accelerator Type UUID : %q\n", info.AcceleratorTypeUUID())
fmt.Printf("Unique UUID : %q\n", info.UniqueUUID())
fmt.Printf("Installation Path : %q\n", info.InstallPath(fpgaBitStreamDirectory))
extra := info.ExtraMetadata()
if len(extra) > 0 && !quiet {
fmt.Println("Extra:")
for k, v := range extra {
fmt.Printf("\t%s : %q\n", k, v)
}
}
return
}
func fpgaInfo(fname string, quiet bool) error {
switch {
case fpga.IsFpgaFME(fname):
return fmeInfo(fname, quiet)
case fpga.IsFpgaPort(fname):
return portInfo(fname, quiet)
}
return errors.Errorf("unknown FPGA device file %s", fname)
}
func fmeInfo(fname string, quiet bool) error {
var f fpga.FME
var err error
f, err = fpga.NewFME(fname)
if err != nil {
return err
}
defer f.Close()
return printFpgaFME(f, quiet)
}
func printFpgaFME(f fpga.FME, quiet bool) (err error) {
fmt.Println("//****** FME ******//")
fmt.Printf("Name : %s\n", f.GetName())
fmt.Printf("Device Node : %s\n", f.GetDevPath())
fmt.Printf("SysFS Path : %s\n", f.GetSysFsPath())
pci, err := f.GetPCIDevice()
if err != nil {
return
}
printPCIeInfo(pci, quiet)
fmt.Printf("Interface UUID : %s\n", f.GetInterfaceUUID())
if !quiet {
if apiVer, err := f.GetAPIVersion(); err == nil {
fmt.Printf("Kernet API Version : %d\n", apiVer)
}
fmt.Printf("Ports Num : %d\n", f.GetPortsNum())
if id, err := f.GetSocketID(); err == nil {
fmt.Printf("Socket Id : %d\n", id)
}
fmt.Printf("Bitstream Id : %s\n", f.GetBitstreamID())
fmt.Printf("Bitstream Metadata : %s\n", f.GetBitstreamMetadata())
}
return
}
func portInfo(fname string, quiet bool) error {
var f fpga.Port
var err error
f, err = fpga.NewPort(fname)
if err != nil {
return err
}
defer f.Close()
return printFpgaPort(f, quiet)
}
func printFpgaPort(f fpga.Port, quiet bool) (err error) {
fmt.Println("//****** PORT ******//")
fmt.Printf("Name : %s\n", f.GetName())
fmt.Printf("Device Node : %s\n", f.GetDevPath())
fmt.Printf("SysFS Path : %s\n", f.GetSysFsPath())
pci, err := f.GetPCIDevice()
if err != nil {
return
}
printPCIeInfo(pci, quiet)
fme, err := f.GetFME()
if err != nil {
return
}
fmt.Printf("FME Name : %s\n", fme.GetName())
num, err := f.GetPortID()
if err != nil {
return
}
fmt.Printf("Port Id : %d\n", num)
fmt.Printf("Interface UUID : %s\n", f.GetInterfaceUUID())
fmt.Printf("Accelerator UUID : %s\n", f.GetAcceleratorTypeUUID())
if quiet {
return err
}
apiVer, err := f.GetAPIVersion()
if err != nil {
return err
}
fmt.Printf("Kernet API Version : %d\n", apiVer)
pi, err := f.PortGetInfo()
if err != nil {
return err
}
fmt.Printf("Port Regions : %d\n", pi.Regions)
for idx := uint32(0); idx < pi.Regions; idx++ {
ri, err := f.PortGetRegionInfo(idx)
if err != nil {
return err
}
fmt.Printf("Port Region (Index/Size/Offset) : %d / %d / %d\n", ri.Index, ri.Size, ri.Offset)
}
return nil
}
func printPCIeInfo(pci *fpga.PCIDevice, quiet bool) {
fmt.Printf("PCIe s:b:d:f : %s\n", pci.BDF)
if pci.PhysFn != nil && !quiet {
fmt.Printf("Physical Function PCIe s:b:d:f : %s\n", pci.PhysFn.BDF)
}
fmt.Printf("Device Id : %s:%s\n", pci.Vendor, pci.Device)
if !quiet {
fmt.Printf("Device Class : %s\n", pci.Class)
fmt.Printf("Local CPUs : %s\n", pci.CPUs)
fmt.Printf("NUMA : %s\n", pci.NUMA)
if pci.VFs != "" {
fmt.Printf("SR-IOV Virtual Functions : %s\n", pci.VFs)
}
if pci.TotalVFs != "" {
fmt.Printf("SR-IOV maximum Virtual Functions : %s\n", pci.TotalVFs)
}
}
}
func doPR(dev, fname string, dryRun, quiet bool) (err error) {
fp, err := fpga.NewPort(dev)
if err != nil {
return
}
defer fp.Close()
bs, err := bitstream.Open(fname)
if err != nil {
return
}
defer bs.Close()
if !quiet {
fmt.Printf("Before: Interface ID: %q AFU ID: %q\n", fp.GetInterfaceUUID(), fp.GetAcceleratorTypeUUID())
fmt.Printf("Programming %q to port %q: ", fname, dev)
}
err = fp.PR(bs, dryRun)
if !quiet {
if err != nil {
fmt.Println("FAILED")
} else {
fmt.Println("OK")
}
fmt.Printf("After : Interface ID: %q AFU ID: %q\n", fp.GetInterfaceUUID(), fp.GetAcceleratorTypeUUID())
}
return
}
func listDevices(listFMEs, listPorts, quiet bool) error {
fmes, ports := fpga.ListFpgaDevices()
if listFMEs {
if !quiet {
fmt.Printf("Detected FPGA FMEs: %d\n", len(fmes))
}
for _, v := range fmes {
fmt.Println(v)
}
}
if listPorts {
if !quiet {
fmt.Printf("Detected FPGA Ports: %d\n", len(ports))
}
for _, v := range ports {
fmt.Println(v)
}
}
return nil
}