github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/pkg/types/pcipath.go (about)

     1  // Copyright (c) 2020 Red Hat
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package types
     7  
     8  import (
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  const (
    15  	pciSlotBits = 5
    16  	maxPciSlot  = (1 << pciSlotBits) - 1
    17  )
    18  
    19  // A PciSlot describes where a PCI device sits on a single bus
    20  //
    21  // This encapsulates the PCI slot number a.k.a device number, which is
    22  // limited to a 5 bit value [0x00..0x1f] by the PCI specification
    23  //
    24  // XXX In order to support multifunction device's we'll need to extend
    25  // this to include the PCI 3-bit function number as well.
    26  type PciSlot struct{ slot uint8 }
    27  
    28  func PciSlotFromString(s string) (PciSlot, error) {
    29  	v, err := strconv.ParseUint(s, 16, pciSlotBits)
    30  	if err != nil {
    31  		return PciSlot{}, err
    32  	}
    33  	// The 5 bit width passed to ParseUint ensures the value is <=
    34  	// maxPciSlot
    35  	return PciSlot{slot: uint8(v)}, nil
    36  }
    37  
    38  func PciSlotFromInt(v int) (PciSlot, error) {
    39  	if v < 0 || v > maxPciSlot {
    40  		return PciSlot{}, fmt.Errorf("PCI slot value 0x%x out of range", v)
    41  	}
    42  	return PciSlot{slot: uint8(v)}, nil
    43  }
    44  
    45  func (slot PciSlot) String() string {
    46  	return fmt.Sprintf("%02x", slot.slot)
    47  }
    48  
    49  // A PciPath describes where a PCI sits in a PCI hierarchy.
    50  //
    51  // Consists of a list of PCI slots, giving the slot of each bridge
    52  // that must be traversed from the PCI root to reach the device,
    53  // followed by the slot of the device itself
    54  //
    55  // When formatted into a string is written as "xx/.../yy/zz" Here, zz
    56  // is the slot of the device on its PCI bridge, yy is the slot of the
    57  // bridge on its parent bridge and so forth until xx is the slot of
    58  // the "most upstream" bridge on the root bus.  If a device is
    59  // connected directly to the root bus, its PciPath is just "zz"
    60  type PciPath struct {
    61  	slots []PciSlot
    62  }
    63  
    64  func (p PciPath) String() string {
    65  	tokens := make([]string, len(p.slots))
    66  	for i, slot := range p.slots {
    67  		tokens[i] = slot.String()
    68  	}
    69  	return strings.Join(tokens, "/")
    70  }
    71  
    72  func (p PciPath) IsNil() bool {
    73  	return p.slots == nil
    74  }
    75  
    76  func PciPathFromString(s string) (PciPath, error) {
    77  	if s == "" {
    78  		return PciPath{}, nil
    79  	}
    80  
    81  	tokens := strings.Split(s, "/")
    82  	slots := make([]PciSlot, len(tokens))
    83  	for i, t := range tokens {
    84  		var err error
    85  		slots[i], err = PciSlotFromString(t)
    86  		if err != nil {
    87  			return PciPath{}, err
    88  		}
    89  	}
    90  	return PciPath{slots: slots}, nil
    91  }
    92  
    93  func PciPathFromSlots(slots ...PciSlot) (PciPath, error) {
    94  	if len(slots) == 0 {
    95  		return PciPath{}, fmt.Errorf("PCI path needs at least one component")
    96  	}
    97  	return PciPath{slots: slots}, nil
    98  }