github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/lsfabric/lsfabric.go (about)

     1  // Copyright 2021 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  //go:build amd64 && linux
     6  // +build amd64,linux
     7  
     8  package main
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"log"
    14  
    15  	"github.com/mvdan/u-root-coreutils/pkg/pci"
    16  )
    17  
    18  const (
    19  	addr  = 0x5c
    20  	dlow  = 0x98
    21  	dhigh = 0x9c
    22  	bad   = 0xffffffff
    23  )
    24  
    25  type instanceType uint8
    26  
    27  // These constants are target id types
    28  const (
    29  	CCM     instanceType = 0
    30  	GCM     instanceType = 1
    31  	NCM     instanceType = 2
    32  	IOMS    instanceType = 3
    33  	CS      instanceType = 4
    34  	NCS     instanceType = 5
    35  	TCDX    instanceType = 6
    36  	PIE     instanceType = 7
    37  	SPF     instanceType = 8
    38  	LLC     instanceType = 9
    39  	CAKE    instanceType = 0xA
    40  	UNKNOWN instanceType = 0xb
    41  )
    42  
    43  type (
    44  	nodeID   uint8
    45  	fabricID uint8
    46  )
    47  
    48  const (
    49  	// BROAD is our way of saying "broadcast address"
    50  	BROAD nodeID = 0xff
    51  )
    52  
    53  func (i *instanceType) String() string {
    54  	switch *i {
    55  	case CCM:
    56  		return "CCM"
    57  	case GCM:
    58  		return "GCM"
    59  	case NCM:
    60  		return "NCM"
    61  	case IOMS:
    62  		return "IOMS"
    63  	case CS:
    64  		return "CS"
    65  	case NCS:
    66  		return "NCS"
    67  	case TCDX:
    68  		return "TCDX"
    69  	case PIE:
    70  		return "PIE"
    71  	case SPF:
    72  		return "SPF"
    73  	case LLC:
    74  		return "LLC"
    75  	case CAKE:
    76  		return "CAKE"
    77  	case UNKNOWN:
    78  		return "UNKNOWN"
    79  	default:
    80  		return fmt.Sprintf("Invalid type %#x", i)
    81  	}
    82  }
    83  
    84  type cfg uint32
    85  
    86  var (
    87  	node  = flag.Uint("node", 0, "which node")
    88  	debug = flag.Bool("d", false, "debug prints")
    89  	v     = func(string, ...interface{}) {}
    90  )
    91  
    92  type config struct {
    93  	NumCPU uint
    94  }
    95  
    96  func (c *config) String() string {
    97  	return fmt.Sprintf("Num CPUS: %d", c.NumCPU)
    98  }
    99  
   100  // Unmarshall implements Unmarshall for a cfg.
   101  func (c cfg) Unmarshal() *config {
   102  	i := uint32(c)
   103  	return &config{
   104  		NumCPU: uint((i>>27)&1 + 1),
   105  	}
   106  }
   107  
   108  // Fabric is a single component in the fabric.
   109  type Fabric struct {
   110  	InstanceID   nodeID
   111  	InstanceType instanceType
   112  	Enabled      bool
   113  	FabricID     uint8
   114  }
   115  
   116  func (f *Fabric) String() string {
   117  	return fmt.Sprintf("InstanceID %#x InstanceType %s Enabled %v FabricID %#x", f.InstanceID, f.InstanceType.String(), f.Enabled, f.FabricID)
   118  }
   119  
   120  // DataFabric supports operations like binary.Read and binary.Write.
   121  // N.B. it is NOT safe to implement something like readat/writeat; arbitrary
   122  // byte reads are not acceptable for this interface.
   123  // The most one can do, as for most such interfaces, is 32- or 64-bit reads/writes.
   124  type DataFabric struct {
   125  	Node           uint8
   126  	PCI            *pci.PCI
   127  	Config         *config
   128  	TotalCount     uint
   129  	PIECount       uint
   130  	IOMSCount      uint
   131  	DiesPerSocket  uint
   132  	CCM0InstanceID nodeID
   133  	Components     []*Fabric
   134  }
   135  
   136  func (d *DataFabric) String() string {
   137  	s := fmt.Sprintf("Node %d TotalCount %d PIECount %d IOMSCount %d DiesPerSocket %d CCM0InstanceID %d Config %s",
   138  		d.Node, d.TotalCount, d.PIECount, d.IOMSCount, d.DiesPerSocket, d.CCM0InstanceID, d.Config)
   139  	for _, f := range d.Components {
   140  		s += "\n" + f.String()
   141  	}
   142  	return s
   143  }
   144  
   145  func (d *DataFabric) address(id nodeID, fun uint8, off uint16) error {
   146  	if fun > 7 {
   147  		return fmt.Errorf("fun is %#x but must be < 8", fun)
   148  	}
   149  	if off&3 != 0 {
   150  		return fmt.Errorf("Target id is %#x but must be 8-byte aligned", off)
   151  	}
   152  	if off >= 2048 {
   153  		return fmt.Errorf("off %#x must be < %#x", off, 2048)
   154  	}
   155  	var targ uint32
   156  	switch id {
   157  	case BROAD:
   158  	default:
   159  		targ = 1 | (uint32(id) << 16)
   160  	}
   161  	targ |= (uint32(fun) << 11) | uint32(off)
   162  	v("address: id %#x fun %#x off %#x -> targ %08x", id, fun, off, targ)
   163  	return d.PCI.WriteConfigRegister(addr, 32, uint64(targ))
   164  }
   165  
   166  // ReadIndirect uses the indirection registers to read from one thing.
   167  func (d *DataFabric) ReadIndirect(id nodeID, fun uint8, off uint16) (uint64, error) {
   168  	if err := d.address(id, fun, off); err != nil {
   169  		return bad, err
   170  	}
   171  	return d.PCI.ReadConfigRegister(dlow, 32)
   172  }
   173  
   174  // ReadBroadcast does the stupid merged read where all bits from all things
   175  // are or'ed. Not sure why anyone ever thought this was useful.
   176  func (d *DataFabric) ReadBroadcast(fun uint8, off uint16) (uint64, error) {
   177  	return d.ReadIndirect(BROAD, fun, off)
   178  }
   179  
   180  func new(n uint8) (*DataFabric, error) {
   181  	if n > 1 {
   182  		return nil, fmt.Errorf("Node is %d, but can only be 0 or 1", n)
   183  	}
   184  	devName := fmt.Sprintf("0000:00:%02x.4", n+0x18)
   185  	r, err := pci.NewBusReader(devName)
   186  	if err != nil {
   187  		return nil, fmt.Errorf("NewBusReader: %v", err)
   188  	}
   189  	devs, err := r.Read()
   190  	if err != nil {
   191  		return nil, fmt.Errorf("reading %s: %v", devName, err)
   192  	}
   193  	if len(devs) != 1 {
   194  		return nil, fmt.Errorf("%q matches more than one device", devName)
   195  	}
   196  
   197  	d := &DataFabric{
   198  		Node:           n,
   199  		PCI:            devs[0],
   200  		TotalCount:     0,
   201  		PIECount:       0,
   202  		IOMSCount:      0,
   203  		DiesPerSocket:  1,
   204  		CCM0InstanceID: 0xff,
   205  	}
   206  	c, err := d.ReadBroadcast(1, 0x200)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	v("config is %#x", c)
   211  	d.Config = cfg(c).Unmarshal()
   212  	if c, err = d.ReadBroadcast(0, 0x40); err != nil {
   213  		return nil, fmt.Errorf("Read TotalCount: %v", err)
   214  	}
   215  	d.TotalCount = uint(uint8(c))
   216  	v("Reg 40 is %#x, totalcount %d", c, d.TotalCount)
   217  	for i := nodeID(0); i < 255 && len(d.Components) < int(d.TotalCount); i++ {
   218  		info0, err := d.ReadIndirect(i, 0, 0x44)
   219  		v("%#x: info0 %#x bit 6 %#x err %v", i, info0, info0&(1<<6), err)
   220  		if err != nil {
   221  			continue
   222  		}
   223  		enabled := (info0 & (1 << 6)) != 0
   224  
   225  		if info0 == 0 && len(d.Components) > 0 {
   226  			continue
   227  		}
   228  		InstanceType := func() instanceType {
   229  			switch info0 & 0xf {
   230  			case 0:
   231  				if d.CCM0InstanceID == 0xff {
   232  					d.CCM0InstanceID = nodeID(i)
   233  				}
   234  				return CCM
   235  			case 1:
   236  				return GCM
   237  			case 2:
   238  				return NCM
   239  			case 3:
   240  				d.IOMSCount++
   241  				return IOMS
   242  			case 4:
   243  				return CS
   244  			case 5:
   245  				return NCS
   246  			case 6:
   247  				return TCDX
   248  			case 7:
   249  				d.PIECount++
   250  				return PIE
   251  			case 8:
   252  				return SPF
   253  			case 9:
   254  				return LLC
   255  			case 10:
   256  				return CAKE
   257  			default:
   258  				return UNKNOWN
   259  			}
   260  		}()
   261  
   262  		ids, err := d.ReadIndirect(i, 0, 0x50)
   263  		if err != nil {
   264  			log.Printf("ReadIndirect(%d, 0, 0x50): %v", i, err)
   265  			continue
   266  		}
   267  		instanceID := uint(ids)
   268  		fabricID := uint8((ids >> 8) & 0x3f)
   269  		if instanceID == 0 && len(d.Components) > 0 {
   270  			log.Printf("WTF")
   271  			continue
   272  		}
   273  		d.Components = append(d.Components, &Fabric{
   274  			InstanceID:   i,
   275  			InstanceType: InstanceType,
   276  			Enabled:      enabled,
   277  			FabricID:     fabricID, // but see below. I am liking Some and None ...
   278  		})
   279  		// result.components.push(FabricComponent { instance_id, instance_type, enabled, fabric_id: if fabric_id != 0 || result.components.len() == 0 { Some(fabric_id) } else { None } }).unwrap();
   280  
   281  	}
   282  
   283  	return d, nil
   284  }
   285  
   286  func main() {
   287  	flag.Parse()
   288  	if *debug {
   289  		v = log.Printf
   290  	}
   291  
   292  	df, err := new(uint8(*node))
   293  	if err != nil {
   294  		log.Fatal(err)
   295  	}
   296  	log.Printf("df is %s", df)
   297  }