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 }