Skip to content

Commit 2430e20

Browse files
committed
fpga_tool: UX improvements
- user readable output for fpgainfo/fmeinfo/portinfo commands - new commands: list, list-fme, list-port - new -q flag to suppres headers, progress and too verbose messages - install command will now fail if destination file already exist - new --force flag: allows overwrite files in install command - removed development and debug output
1 parent 6fd729f commit 2430e20

File tree

5 files changed

+218
-94
lines changed

5 files changed

+218
-94
lines changed

cmd/fpga_tool/fpga_tool.go

Lines changed: 171 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,18 @@ const (
3434

3535
func main() {
3636
var err error
37-
var bitstream string
38-
var device string
39-
var dryRun bool
37+
var bitstream, device string
38+
var dryRun, force, quiet bool
4039
flag.StringVar(&bitstream, "b", "", "Path to bitstream file (GBS or AOCX)")
4140
flag.StringVar(&device, "d", "", "Path to device node (FME or Port)")
4241
flag.BoolVar(&dryRun, "dry-run", false, "Don't write/program, just validate and log")
42+
flag.BoolVar(&force, "force", false, "Force overwrite operation for installing bitstreams")
43+
flag.BoolVar(&quiet, "q", false, "Quiet mode. Only errors will be reported")
4344

4445
flag.Parse()
4546

4647
if flag.NArg() < 1 {
47-
log.Fatal("Please provide command: info, fpgainfo, fmeinfo, portinfo, install, pr")
48+
log.Fatal("Please provide command: info, fpgainfo, install, list, fmeinfo, portinfo, list-fme, list-port, pr")
4849
}
4950

5051
cmd := flag.Arg(0)
@@ -53,25 +54,27 @@ func main() {
5354
log.Fatalf("Invalid arguments: %+v", err)
5455
}
5556

56-
// fmt.Printf("Cmd: %q\nBitstream: %q\nDevice: %q\n", cmd, bitstream, device)
5757
switch cmd {
5858
case "info":
59-
err = printBitstreamInfo(bitstream)
59+
err = printBitstreamInfo(bitstream, quiet)
6060
case "pr":
61-
err = doPR(device, bitstream, dryRun)
61+
err = doPR(device, bitstream, dryRun, quiet)
6262
case "fpgainfo":
63-
err = fpgaInfo(device)
63+
err = fpgaInfo(device, quiet)
6464
case "fmeinfo":
65-
err = fmeInfo(device)
65+
err = fmeInfo(device, quiet)
6666
case "portinfo":
67-
err = portInfo(device)
67+
err = portInfo(device, quiet)
6868
case "install":
69-
err = installBitstream(bitstream, dryRun)
70-
case "magic":
71-
err = magic(device)
69+
err = installBitstream(bitstream, dryRun, force, quiet)
70+
case "list":
71+
err = listDevices(true, true, quiet)
72+
case "list-fme":
73+
err = listDevices(true, false, quiet)
74+
case "list-port":
75+
err = listDevices(false, true, quiet)
7276
default:
7377
err = errors.Errorf("unknown command %+v", flag.Args())
74-
7578
}
7679
if err != nil {
7780
log.Fatalf("%+v", err)
@@ -85,7 +88,7 @@ func validateFlags(cmd, bitstream, device string) error {
8588
if bitstream == "" {
8689
return errors.Errorf("bitstream filename is missing")
8790
}
88-
case "fpgainfo", "fmeinfo", "portinfo", "magic":
91+
case "fpgainfo", "fmeinfo", "portinfo":
8992
// device must not be empty
9093
if device == "" {
9194
return errors.Errorf("FPGA device name is missing")
@@ -102,13 +105,7 @@ func validateFlags(cmd, bitstream, device string) error {
102105
return nil
103106
}
104107

105-
// WIP testing command
106-
func magic(dev string) (err error) {
107-
fmt.Println(fpga.ListFpgaDevices())
108-
return
109-
}
110-
111-
func installBitstream(fname string, dryRun bool) (err error) {
108+
func installBitstream(fname string, dryRun, force, quiet bool) (err error) {
112109
info, err := bitstream.Open(fname)
113110
if err != nil {
114111
return
@@ -117,10 +114,12 @@ func installBitstream(fname string, dryRun bool) (err error) {
117114

118115
installPath := info.InstallPath(fpgaBitStreamDirectory)
119116

120-
fmt.Printf("Installing bitstream %q as %q\n", fname, installPath)
121-
if dryRun {
122-
fmt.Println("Dry-run: no copying performed")
123-
return
117+
if !quiet {
118+
fmt.Printf("Installing bitstream %q as %q\n", fname, installPath)
119+
if dryRun {
120+
fmt.Println("Dry-run: no copying performed")
121+
return
122+
}
124123
}
125124
err = os.MkdirAll(filepath.Dir(installPath), 0755)
126125
if err != nil {
@@ -131,26 +130,23 @@ func installBitstream(fname string, dryRun bool) (err error) {
131130
return errors.Wrap(err, "can't open bitstream file")
132131
}
133132
defer src.Close()
134-
dst, err := os.OpenFile(installPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
133+
flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
134+
if !force {
135+
flags = flags | os.O_EXCL
136+
}
137+
dst, err := os.OpenFile(installPath, flags, 0644)
135138
if err != nil {
139+
if os.IsExist(err) {
140+
return fmt.Errorf("Destination file %q already exist. Use --force to overwrite it", installPath)
141+
}
136142
return errors.Wrap(err, "can't create destination file")
137143
}
138144
defer dst.Close()
139145
_, err = io.Copy(dst, src)
140146
return
141147
}
142148

143-
func fpgaInfo(fname string) error {
144-
switch {
145-
case fpga.IsFpgaFME(fname):
146-
return fmeInfo(fname)
147-
case fpga.IsFpgaPort(fname):
148-
return portInfo(fname)
149-
}
150-
return errors.Errorf("unknown FPGA device file %s", fname)
151-
}
152-
153-
func printBitstreamInfo(fname string) (err error) {
149+
func printBitstreamInfo(fname string, quiet bool) (err error) {
154150
info, err := bitstream.Open(fname)
155151
if err != nil {
156152
return
@@ -162,7 +158,7 @@ func printBitstreamInfo(fname string) (err error) {
162158
fmt.Printf("Unique UUID : %q\n", info.UniqueUUID())
163159
fmt.Printf("Installation Path : %q\n", info.InstallPath(fpgaBitStreamDirectory))
164160
extra := info.ExtraMetadata()
165-
if len(extra) > 0 {
161+
if len(extra) > 0 && !quiet {
166162
fmt.Println("Extra:")
167163
for k, v := range extra {
168164
fmt.Printf("\t%s : %q\n", k, v)
@@ -171,84 +167,168 @@ func printBitstreamInfo(fname string) (err error) {
171167
return
172168
}
173169

174-
func fmeInfo(fname string) error {
170+
func fpgaInfo(fname string, quiet bool) error {
171+
switch {
172+
case fpga.IsFpgaFME(fname):
173+
return fmeInfo(fname, quiet)
174+
case fpga.IsFpgaPort(fname):
175+
return portInfo(fname, quiet)
176+
}
177+
return errors.Errorf("unknown FPGA device file %s", fname)
178+
}
179+
180+
func fmeInfo(fname string, quiet bool) error {
175181
var f fpga.FpgaFME
176182
var err error
177183
f, err = fpga.NewFpgaFME(fname)
178184
if err != nil {
179185
return err
180186
}
181187
defer f.Close()
182-
fmt.Print("API:")
183-
fmt.Println(f.GetAPIVersion())
184-
fmt.Print("CheckExtension:")
185-
fmt.Println(f.CheckExtension())
186-
187-
fmt.Println("GetDevPath: ", f.GetDevPath())
188-
fmt.Println("GetSysFsPath: ", f.GetSysFsPath())
189-
fmt.Println("GetName: ", f.GetName())
188+
return printFpgaFME(f, quiet)
189+
}
190+
191+
func printFpgaFME(f fpga.FpgaFME, quiet bool) (err error) {
192+
fmt.Println("//****** FME ******//")
193+
fmt.Printf("Name : %s\n", f.GetName())
194+
fmt.Printf("Device Node : %s\n", f.GetDevPath())
195+
fmt.Printf("SysFS Path : %s\n", f.GetSysFsPath())
190196
pci, err := f.GetPCIDevice()
191-
fmt.Printf("GetPCIDevice: %+v %+v\n", pci, err)
192-
fmt.Println("GetInterfaceUUID: ", f.GetInterfaceUUID())
193-
fmt.Println("GetPortNums: ", f.GetPortsNum())
194-
return nil
197+
if err != nil {
198+
return
199+
}
200+
printPCIeInfo(pci, quiet)
201+
fmt.Printf("Interface UUID : %s\n", f.GetInterfaceUUID())
202+
if !quiet {
203+
if apiVer, err := f.GetAPIVersion(); err == nil {
204+
fmt.Printf("Kernet API Version : %d\n", apiVer)
205+
}
206+
fmt.Printf("Ports Num : %d\n", f.GetPortsNum())
207+
if id, err := f.GetSocketID(); err == nil {
208+
fmt.Printf("Socket Id : %d\n", id)
209+
}
210+
fmt.Printf("Bitstream Id : %s\n", f.GetBitstreamID())
211+
fmt.Printf("Bitstream Metadata : %s\n", f.GetBitstreamMetadata())
212+
}
213+
214+
return
195215
}
196216

197-
func portInfo(fname string) error {
217+
func portInfo(fname string, quiet bool) error {
198218
var f fpga.FpgaPort
199219
var err error
200220
f, err = fpga.NewFpgaPort(fname)
201221
if err != nil {
202222
return err
203223
}
204224
defer f.Close()
205-
fmt.Print("API:")
206-
fmt.Println(f.GetAPIVersion())
207-
fmt.Print("CheckExtension:")
208-
fmt.Println(f.CheckExtension())
209-
fmt.Print("Reset:")
210-
fmt.Println(f.PortReset())
211-
fmt.Print("PortGetInfo:")
212-
fmt.Println(f.PortGetInfo())
213-
pi, err := f.PortGetInfo()
214-
if err == nil {
215-
for idx := 0; uint32(idx) < pi.Regions; idx++ {
216-
fmt.Printf("PortGetRegionInfo %d\n", idx)
217-
fmt.Println(f.PortGetRegionInfo(uint32(idx)))
218-
}
219-
}
220-
221-
fmt.Println("GetDevPath: ", f.GetDevPath())
222-
fmt.Println("GetSysFsPath: ", f.GetSysFsPath())
223-
fmt.Println("GetName: ", f.GetName())
225+
return printFpgaPort(f, quiet)
226+
}
227+
228+
func printFpgaPort(f fpga.FpgaPort, quiet bool) (err error) {
229+
fmt.Println("//****** PORT ******//")
230+
fmt.Printf("Name : %s\n", f.GetName())
231+
fmt.Printf("Device Node : %s\n", f.GetDevPath())
232+
fmt.Printf("SysFS Path : %s\n", f.GetSysFsPath())
224233
pci, err := f.GetPCIDevice()
225-
fmt.Printf("GetPCIDevice: %+v %+v\n", pci, err)
226-
id, err := f.GetPortID()
227-
fmt.Printf("GetPort: %+v %+v\n", id, err)
228-
fmt.Println("GetAcceleratorTypeUUID: ", f.GetAcceleratorTypeUUID())
229-
fmt.Println("GetInterfaceUUID: ", f.GetInterfaceUUID())
234+
if err != nil {
235+
return
236+
}
237+
printPCIeInfo(pci, quiet)
230238
fme, err := f.GetFME()
231-
fmt.Printf("GetFME: %+v %+v\n", fme, err)
232-
233-
return nil
239+
if err != nil {
240+
return
241+
}
242+
fmt.Printf("FME Name : %s\n", fme.GetName())
243+
num, err := f.GetPortID()
244+
if err != nil {
245+
return
246+
}
247+
fmt.Printf("Port Id : %d\n", num)
248+
fmt.Printf("Interface UUID : %s\n", f.GetInterfaceUUID())
249+
fmt.Printf("Accelerator UUID : %s\n", f.GetAcceleratorTypeUUID())
250+
if !quiet {
251+
if apiVer, err := f.GetAPIVersion(); err == nil {
252+
fmt.Printf("Kernet API Version : %d\n", apiVer)
253+
pi, err := f.PortGetInfo()
254+
if err == nil {
255+
fmt.Printf("Port Regions : %d\n", pi.Regions)
256+
for idx := 0; uint32(idx) < pi.Regions; idx++ {
257+
if ri, err := f.PortGetRegionInfo(uint32(idx)); err == nil {
258+
fmt.Printf("Port Region (Index/Size/Offset) : %d / %d / %d\n", ri.Index, ri.Size, ri.Offset)
259+
}
260+
}
261+
}
262+
}
263+
}
264+
return
234265
}
235266

236-
func doPR(dev, bs string, dryRun bool) error {
267+
func printPCIeInfo(pci *fpga.PCIDevice, quiet bool) {
268+
fmt.Printf("PCIe s:b:d:f : %s\n", pci.BDF)
269+
if pci.PhysFn != nil && !quiet {
270+
fmt.Printf("Physical Function PCIe s:b:d:f : %s\n", pci.PhysFn.BDF)
271+
}
272+
fmt.Printf("Device Id : %s:%s\n", pci.Vendor, pci.Device)
273+
if !quiet {
274+
fmt.Printf("Device Class : %s\n", pci.Class)
275+
fmt.Printf("Local CPUs : %s\n", pci.CPUs)
276+
fmt.Printf("NUMA : %s\n", pci.NUMA)
277+
if pci.VFs != "" {
278+
fmt.Printf("SR-IOV Virtual Functions : %s\n", pci.VFs)
279+
}
280+
if pci.TotalVFs != "" {
281+
fmt.Printf("SR-IOV maximum Virtual Functions : %s\n", pci.TotalVFs)
282+
}
283+
}
284+
return
285+
}
237286

238-
f, err := fpga.NewFpgaPort(dev)
287+
func doPR(dev, fname string, dryRun, quiet bool) (err error) {
288+
fp, err := fpga.NewFpgaPort(dev)
239289
if err != nil {
240-
return err
290+
return
241291
}
242-
defer f.Close()
243-
m, err := bitstream.Open(bs)
292+
defer fp.Close()
293+
bs, err := bitstream.Open(fname)
244294
if err != nil {
245-
return err
295+
return
296+
}
297+
defer bs.Close()
298+
299+
if !quiet {
300+
fmt.Printf("Before: Interface ID: %q AFU ID: %q\n", fp.GetInterfaceUUID(), fp.GetAcceleratorTypeUUID())
301+
fmt.Printf("Programming %q to port %q: ", fname, dev)
302+
}
303+
err = fp.PR(bs, dryRun)
304+
if !quiet {
305+
if err != nil {
306+
fmt.Println("FAILED")
307+
} else {
308+
fmt.Println("OK")
309+
}
310+
fmt.Printf("After : Interface ID: %q AFU ID: %q\n", fp.GetInterfaceUUID(), fp.GetAcceleratorTypeUUID())
246311
}
247-
defer m.Close()
312+
return
313+
}
248314

249-
fmt.Printf("Before programming I %q A %q\n", f.GetInterfaceUUID(), f.GetAcceleratorTypeUUID())
250-
fmt.Printf("Trying to program %s to port %s: ", bs, dev)
251-
fmt.Println(f.PR(m, dryRun))
252-
fmt.Printf("After programming I %q A %q\n", f.GetInterfaceUUID(), f.GetAcceleratorTypeUUID())
315+
func listDevices(listFMEs, listPorts, quiet bool) error {
316+
fmes, ports := fpga.ListFpgaDevices()
317+
if listFMEs {
318+
if !quiet {
319+
fmt.Printf("Detected FPGA FMEs: %d\n", len(fmes))
320+
}
321+
for _, v := range fmes {
322+
fmt.Println(v)
323+
}
324+
}
325+
if listPorts {
326+
if !quiet {
327+
fmt.Printf("Detected FPGA Ports: %d\n", len(ports))
328+
}
329+
for _, v := range ports {
330+
fmt.Println(v)
331+
}
332+
}
253333
return nil
254334
}

pkg/fpga/linux/dfl.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,25 @@ func (f *DflFME) GetInterfaceUUID() (id string) {
275275
return f.CompatID
276276
}
277277

278+
// GetSocketID returns physical socket number, in case NUMA enumeration fails
279+
func (f *DflFME) GetSocketID() (uint32, error) {
280+
if f.SocketID == "" {
281+
return math.MaxUint32, errors.Errorf("n/a")
282+
}
283+
id, err := strconv.ParseUint(f.SocketID, 10, 32)
284+
return uint32(id), err
285+
}
286+
287+
// GetBitstreamID returns FME bitstream id
288+
func (f *DflFME) GetBitstreamID() string {
289+
return f.BitstreamID
290+
}
291+
292+
// GetBitstreamMetadata returns FME bitstream metadata
293+
func (f *DflFME) GetBitstreamMetadata() string {
294+
return f.BitstreamMetadata
295+
}
296+
278297
// Update properties from sysfs
279298
func (f *DflFME) updateProperties() error {
280299
pci, err := f.GetPCIDevice()

0 commit comments

Comments
 (0)