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 }