github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/pci/devices.go (about)

     1  // Copyright 2012-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package pci
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  )
    14  
    15  // Devices contains a slice of one or more PCI devices
    16  type Devices []*PCI
    17  
    18  // Print prints information to an io.Writer
    19  func (d Devices) Print(o io.Writer, verbose, confSize int) error {
    20  	for _, pci := range d {
    21  		if _, err := fmt.Fprintf(o, "%s\n", pci.String()); err != nil {
    22  			return err
    23  		}
    24  		var extraNL bool
    25  		// Make sure we have read enough config space to satisfy the verbose and confSize requests.
    26  		// If len(pci.Config) is > 64, that's the only test we need.
    27  		if (verbose > 1 || confSize > 64) && len(pci.Config) < 256 {
    28  			return os.ErrPermission
    29  		}
    30  		if verbose >= 1 {
    31  			c := pci.Config
    32  			if _, err := fmt.Fprintf(o, "\tControl: %s\n\tStatus: %s\n\tLatency: %d", pci.Control.String(), pci.Status.String(), pci.Latency); err != nil {
    33  				return err
    34  			}
    35  			if pci.Bridge {
    36  				// Bus: primary=00, secondary=05, subordinate=0c, sec-latency=0
    37  				// I/O behind bridge: 00002000-00002fff [size=4K]
    38  				// Memory behind bridge: f0000000-f1ffffff [size=32M]
    39  				// Prefetchable memory behind bridge: 00000000f2900000-00000000f29fffff [size=1M]
    40  				if _, err := fmt.Fprintf(o, ", Cache Line Size: %d bytes", c[CacheLineSize]); err != nil {
    41  					return err
    42  				}
    43  				if _, err := fmt.Fprintf(o, "\n\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%s",
    44  					pci.Primary, pci.Secondary, pci.Subordinate, pci.SecLatency); err != nil {
    45  					return err
    46  				}
    47  				// I hate this code.
    48  				// I miss Rust tuples at times.
    49  				for _, e := range []struct {
    50  					h, f string
    51  					b, l uint64
    52  				}{
    53  					{h: "\n\tI/O behind bridge: ", f: "%#08x-%#08x [size=%#x]", b: pci.IO.Base, l: pci.IO.Lim},
    54  					{h: "\n\tMemory behind bridge: ", f: "%#08x-%#08x [size=%#x]", b: pci.Mem.Base, l: pci.Mem.Lim},
    55  					{h: "\n\tPrefetchable memory behind bridge: ", f: "%#08x-%#08x [size=%#x]", b: pci.PrefMem.Base, l: pci.PrefMem.Lim},
    56  				} {
    57  					s := e.h + " [disabled]"
    58  					if e.b != 0 {
    59  						sz := e.l - e.b + 1
    60  						s = fmt.Sprintf(e.h+e.f, e.b, e.l, sz)
    61  					}
    62  					if _, err := fmt.Fprintf(o, s); err != nil {
    63  						return err
    64  					}
    65  				}
    66  			}
    67  			fmt.Fprintf(o, "\n")
    68  			if pci.IRQPin != 0 {
    69  				if _, err := fmt.Fprintf(o, "\tInterrupt: pin %X routed to IRQ %X\n", 9+pci.IRQPin, pci.IRQLine); err != nil {
    70  					return err
    71  				}
    72  			}
    73  			if !pci.Bridge {
    74  				for _, b := range pci.BARS {
    75  					if _, err := fmt.Fprintf(o, "\t%v\n", b.String()); err != nil {
    76  						return err
    77  					}
    78  				}
    79  			}
    80  			extraNL = true
    81  		}
    82  
    83  		if confSize > 0 {
    84  			r := io.LimitReader(bytes.NewBuffer(pci.Config), int64(confSize))
    85  			e := hex.Dumper(o)
    86  			if _, err := io.Copy(e, r); err != nil {
    87  				return err
    88  			}
    89  			extraNL = true
    90  		}
    91  		// lspci likes that extra line of separation
    92  		if extraNL {
    93  			fmt.Fprintf(o, "\n")
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  // SetVendorDeviceName sets all numeric IDs of all the devices
   100  // using the pci device SetVendorDeviceName.
   101  func (d Devices) SetVendorDeviceName() {
   102  	for _, p := range d {
   103  		p.SetVendorDeviceName()
   104  	}
   105  }
   106  
   107  // ReadConfig reads the config info for all the devices.
   108  func (d Devices) ReadConfig() error {
   109  	for _, p := range d {
   110  		if err := p.ReadConfig(); err != nil {
   111  			return err
   112  		}
   113  	}
   114  	return nil
   115  }
   116  
   117  // ReadConfigRegister reads the config info for all the devices.
   118  func (d Devices) ReadConfigRegister(offset, size int64) ([]uint64, error) {
   119  	var vals []uint64
   120  	for _, p := range d {
   121  		val, err := p.ReadConfigRegister(offset, size)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		vals = append(vals, val)
   126  	}
   127  	return vals, nil
   128  }
   129  
   130  // WriteConfigRegister writes the config info for all the devices.
   131  func (d Devices) WriteConfigRegister(offset, size int64, val uint64) error {
   132  	for _, p := range d {
   133  		if err := p.WriteConfigRegister(offset, size, val); err != nil {
   134  			return err
   135  		}
   136  	}
   137  	return nil
   138  }