Skip to content

Commit 007bf08

Browse files
committed
[refactor] remove duplicated code in nvpci.go
Signed-off-by: Tariq Ibrahim <tibrahim@nvidia.com>
1 parent 75c8133 commit 007bf08

3 files changed

Lines changed: 59 additions & 140 deletions

File tree

pkg/nvmdev/mock.go

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"path/filepath"
2323

2424
"github.com/NVIDIA/go-nvlib/pkg/nvpci"
25-
"github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes"
2625
)
2726

2827
// MockNvmdev mock mdev device.
@@ -99,38 +98,7 @@ func (m *MockNvmdev) AddMockA100Parent(address string, numaNode int) error {
9998
return err
10099
}
101100

102-
vendor, err := os.Create(filepath.Join(deviceDir, "vendor"))
103-
if err != nil {
104-
return err
105-
}
106-
_, err = fmt.Fprintf(vendor, "0x%x", nvpci.PCINvidiaVendorID)
107-
if err != nil {
108-
return err
109-
}
110-
111-
class, err := os.Create(filepath.Join(deviceDir, "class"))
112-
if err != nil {
113-
return err
114-
}
115-
_, err = fmt.Fprintf(class, "0x%x", nvpci.PCI3dControllerClass)
116-
if err != nil {
117-
return err
118-
}
119-
120-
device, err := os.Create(filepath.Join(deviceDir, "device"))
121-
if err != nil {
122-
return err
123-
}
124-
_, err = device.WriteString("0x20bf")
125-
if err != nil {
126-
return err
127-
}
128-
129-
_, err = os.Create(filepath.Join(deviceDir, "nvidia"))
130-
if err != nil {
131-
return err
132-
}
133-
err = os.Symlink(filepath.Join(deviceDir, "nvidia"), filepath.Join(deviceDir, "driver"))
101+
err = nvpci.CreateMockA100SysfsFiles(deviceDir)
134102
if err != nil {
135103
return err
136104
}
@@ -153,43 +121,6 @@ func (m *MockNvmdev) AddMockA100Parent(address string, numaNode int) error {
153121
return err
154122
}
155123

156-
config, err := os.Create(filepath.Join(deviceDir, "config"))
157-
if err != nil {
158-
return err
159-
}
160-
_data := make([]byte, nvpci.PCICfgSpaceStandardSize)
161-
data := bytes.New(&_data)
162-
data.Write16(0, nvpci.PCINvidiaVendorID)
163-
data.Write16(2, uint16(0x20bf))
164-
data.Write8(nvpci.PCIStatusBytePosition, nvpci.PCIStatusCapabilityList)
165-
_, err = config.Write(*data.Raw())
166-
if err != nil {
167-
return err
168-
}
169-
170-
bar0 := []uint64{0x00000000c2000000, 0x00000000c2ffffff, 0x0000000000040200}
171-
resource, err := os.Create(filepath.Join(deviceDir, "resource"))
172-
if err != nil {
173-
return err
174-
}
175-
_, err = fmt.Fprintf(resource, "0x%x 0x%x 0x%x", bar0[0], bar0[1], bar0[2])
176-
if err != nil {
177-
return err
178-
}
179-
180-
pmcID := uint32(0x170000a1)
181-
resource0, err := os.Create(filepath.Join(deviceDir, "resource0"))
182-
if err != nil {
183-
return err
184-
}
185-
_data = make([]byte, bar0[1]-bar0[0]+1)
186-
data = bytes.New(&_data).LittleEndian()
187-
data.Write32(0, pmcID)
188-
_, err = resource0.Write(*data.Raw())
189-
if err != nil {
190-
return err
191-
}
192-
193124
mdevSupportedTypes := []string{"A100-4C", "A100-5C", "A100-8C", "A100-10C",
194125
"A100-20C", "A100-40C", "A100-1-5CME", "A100-1-5C", "A100-2-10C", "A100-3-20C",
195126
"A100-4-20C", "A100-7-40C"}

pkg/nvpci/mock.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (m *MockNvpci) AddMockA100(address string, numaNode int, sriov *SriovInfo)
7979
return err
8080
}
8181

82-
err = createNVIDIAgpuFiles(deviceDir)
82+
err = CreateMockA100SysfsFiles(deviceDir)
8383
if err != nil {
8484
return err
8585
}
@@ -139,7 +139,11 @@ func (m *MockNvpci) AddMockA100(address string, numaNode int, sriov *SriovInfo)
139139
return nil
140140
}
141141

142-
func createNVIDIAgpuFiles(deviceDir string) error {
142+
// CreateMockA100SysfsFiles populates deviceDir with the sysfs attribute files
143+
// of an A100-like GPU (vendor, class, device, subsystem ids, driver symlink,
144+
// config space, and resources). It is shared by mock packages that need an
145+
// NVIDIA PCI device fixture, such as nvmdev.
146+
func CreateMockA100SysfsFiles(deviceDir string) error {
143147
vendor, err := os.Create(filepath.Join(deviceDir, "vendor"))
144148
if err != nil {
145149
return err
@@ -251,7 +255,7 @@ func (m *MockNvpci) createVf(pfAddress string, id, iommu_group, numaNode int) er
251255
return err
252256
}
253257

254-
err = createNVIDIAgpuFiles(deviceDir)
258+
err = CreateMockA100SysfsFiles(deviceDir)
255259
if err != nil {
256260
return err
257261
}

pkg/nvpci/nvpci.go

Lines changed: 51 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package nvpci
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"os"
2223
"path"
@@ -258,6 +259,28 @@ func (p *nvpci) GetNvidiaDeviceByPciBusID(address string) (*NvidiaPCIDevice, err
258259
return p.getNvidiaDeviceByPciBusID(address, nil)
259260
}
260261

262+
// readPCIFieldString reads a sysfs PCI attribute file and returns its contents with any surrounding whitespaces trimmed.
263+
func readPCIFieldString(devicePath, field string) (string, error) {
264+
raw, err := os.ReadFile(path.Join(devicePath, field))
265+
if err != nil {
266+
return "", fmt.Errorf("unable to read PCI %s for %s: %w", field, devicePath, err)
267+
}
268+
return strings.TrimSpace(string(raw)), nil
269+
}
270+
271+
// readPCIField reads a sysfs PCI attribute file and parses it as an unsigned integer.
272+
func readPCIField(devicePath, field string, bitSize int) (uint64, error) {
273+
str, err := readPCIFieldString(devicePath, field)
274+
if err != nil {
275+
return 0, err
276+
}
277+
val, err := strconv.ParseUint(str, 0, bitSize)
278+
if err != nil {
279+
return 0, fmt.Errorf("unable to parse PCI %s for %s: %w", field, devicePath, err)
280+
}
281+
return val, nil
282+
}
283+
261284
func (p *nvpci) getNvidiaDeviceByPciBusID(address string, cache map[string]*NvidiaPCIDevice) (*NvidiaPCIDevice, error) {
262285
if cache != nil {
263286
if pciDevice, exists := cache[address]; exists {
@@ -266,68 +289,51 @@ func (p *nvpci) getNvidiaDeviceByPciBusID(address string, cache map[string]*Nvid
266289
}
267290
devicePath := filepath.Join(p.pciDevicesRoot, address)
268291

269-
vendor, err := os.ReadFile(path.Join(devicePath, "vendor"))
292+
vendorID, err := readPCIField(devicePath, "vendor", 16)
270293
if err != nil {
271-
return nil, fmt.Errorf("unable to read PCI device vendor id for %s: %v", address, err)
272-
}
273-
vendorStr := strings.TrimSpace(string(vendor))
274-
vendorID, err := strconv.ParseUint(vendorStr, 0, 16)
275-
if err != nil {
276-
return nil, fmt.Errorf("unable to convert vendor string to uint16: %v", vendorStr)
294+
return nil, err
277295
}
278296

279297
if uint16(vendorID) != PCINvidiaVendorID && uint16(vendorID) != PCIMellanoxVendorID {
280298
return nil, nil
281299
}
282300

283-
class, err := os.ReadFile(path.Join(devicePath, "class"))
301+
classID, err := readPCIField(devicePath, "class", 32)
284302
if err != nil {
285-
return nil, fmt.Errorf("unable to read PCI device class for %s: %v", address, err)
303+
return nil, err
286304
}
287-
classStr := strings.TrimSpace(string(class))
288-
classID, err := strconv.ParseUint(classStr, 0, 32)
305+
306+
deviceID, err := readPCIField(devicePath, "device", 16)
289307
if err != nil {
290-
return nil, fmt.Errorf("unable to convert class string to uint32: %v", classStr)
308+
return nil, err
291309
}
292310

293-
device, err := os.ReadFile(path.Join(devicePath, "device"))
311+
numaStr, err := readPCIFieldString(devicePath, "numa_node")
294312
if err != nil {
295-
return nil, fmt.Errorf("unable to read PCI device id for %s: %v", address, err)
313+
return nil, err
296314
}
297-
deviceStr := strings.TrimSpace(string(device))
298-
deviceID, err := strconv.ParseUint(deviceStr, 0, 16)
315+
// numa_node is parsed as a signed integer since "-1" is a valid value meaning "no NUMA affinity".
316+
numaNode, err := strconv.ParseInt(numaStr, 0, 64)
299317
if err != nil {
300-
return nil, fmt.Errorf("unable to convert device string to uint16: %v", deviceStr)
318+
return nil, fmt.Errorf("unable to parse PCI numa_node for %s: %w", devicePath, err)
301319
}
302320

303-
var subsystemVendorID uint64
304-
subsystemVendor, err := os.ReadFile(path.Join(devicePath, "subsystem_vendor"))
305-
switch {
306-
case err == nil:
307-
subsystemVendorStr := strings.TrimSpace(string(subsystemVendor))
308-
subsystemVendorID, err = strconv.ParseUint(subsystemVendorStr, 0, 16)
309-
if err != nil {
310-
return nil, fmt.Errorf("unable to convert subsystem vendor string to uint16: %v", subsystemVendorStr)
321+
// Tolerate missing subsystem files: some environments (e.g. certain virtualised or passthrough PCI topologies)
322+
// do not expose them, so the IDs will default to 0.
323+
subsystemVendorID, err := readPCIField(devicePath, "subsystem_vendor", 16)
324+
if err != nil {
325+
if !errors.Is(err, os.ErrNotExist) {
326+
return nil, err
311327
}
312-
case os.IsNotExist(err):
313328
p.logger.Warningf("subsystem_vendor file not found for %s", address)
314-
default:
315-
return nil, fmt.Errorf("unable to read PCI subsystem vendor id for %s: %v", address, err)
316329
}
317330

318-
var subsystemDeviceID uint64
319-
subsystemDevice, err := os.ReadFile(path.Join(devicePath, "subsystem_device"))
320-
switch {
321-
case err == nil:
322-
subsystemDeviceStr := strings.TrimSpace(string(subsystemDevice))
323-
subsystemDeviceID, err = strconv.ParseUint(subsystemDeviceStr, 0, 16)
324-
if err != nil {
325-
return nil, fmt.Errorf("unable to convert subsystem device string to uint16: %v", subsystemDeviceStr)
331+
subsystemDeviceID, err := readPCIField(devicePath, "subsystem_device", 16)
332+
if err != nil {
333+
if !errors.Is(err, os.ErrNotExist) {
334+
return nil, err
326335
}
327-
case os.IsNotExist(err):
328336
p.logger.Warningf("subsystem_device file not found for %s", address)
329-
default:
330-
return nil, fmt.Errorf("unable to read PCI subsystem device id for %s: %v", address, err)
331337
}
332338

333339
driver, err := getDriver(devicePath)
@@ -346,16 +352,6 @@ func (p *nvpci) getNvidiaDeviceByPciBusID(address string, cache map[string]*Nvid
346352
p.logger.Warningf("unable to detect IOMMU FD for %s: %v", address, err)
347353
}
348354

349-
numa, err := os.ReadFile(path.Join(devicePath, "numa_node"))
350-
if err != nil {
351-
return nil, fmt.Errorf("unable to read PCI NUMA node for %s: %v", address, err)
352-
}
353-
numaStr := strings.TrimSpace(string(numa))
354-
numaNode, err := strconv.ParseInt(numaStr, 0, 64)
355-
if err != nil {
356-
return nil, fmt.Errorf("unable to convert NUMA node string to int64: %v", numaNode)
357-
}
358-
359355
config := &ConfigSpace{
360356
Path: path.Join(devicePath, "config"),
361357
}
@@ -532,32 +528,20 @@ func (p *nvpci) GetGPUByIndex(i int) (*NvidiaPCIDevice, error) {
532528
}
533529

534530
func (p *nvpci) getSriovInfoForPhysicalFunction(devicePath string) (sriovInfo SriovInfo, err error) {
535-
totalVfsPath := filepath.Join(devicePath, "sriov_totalvfs")
536-
numVfsPath := filepath.Join(devicePath, "sriov_numvfs")
537-
538531
// No file for sriov_totalvfs exists? Not an SRIOV device, return nil
539-
_, err = os.Stat(totalVfsPath)
532+
_, err = os.Stat(filepath.Join(devicePath, "sriov_totalvfs"))
540533
if err != nil && os.IsNotExist(err) {
541534
return sriovInfo, nil
542535
}
543-
sriovTotalVfs, err := os.ReadFile(totalVfsPath)
544-
if err != nil {
545-
return sriovInfo, fmt.Errorf("unable to read sriov_totalvfs: %v", err)
546-
}
547-
totalVfsStr := strings.TrimSpace(string(sriovTotalVfs))
548-
totalVfsInt, err := strconv.ParseUint(totalVfsStr, 10, 16)
549-
if err != nil {
550-
return sriovInfo, fmt.Errorf("unable to convert sriov_totalvfs to uint64: %v", err)
551-
}
552536

553-
sriovNumVfs, err := os.ReadFile(numVfsPath)
537+
totalVfsInt, err := readPCIField(devicePath, "sriov_totalvfs", 16)
554538
if err != nil {
555-
return sriovInfo, fmt.Errorf("unable to read sriov_numvfs for: %v", err)
539+
return sriovInfo, err
556540
}
557-
numVfsStr := strings.TrimSpace(string(sriovNumVfs))
558-
numVfsInt, err := strconv.ParseUint(numVfsStr, 10, 16)
541+
542+
numVfsInt, err := readPCIField(devicePath, "sriov_numvfs", 16)
559543
if err != nil {
560-
return sriovInfo, fmt.Errorf("unable to convert sriov_numvfs to uint64: %v", err)
544+
return sriovInfo, err
561545
}
562546

563547
sriovInfo = SriovInfo{

0 commit comments

Comments
 (0)