Created
July 3, 2022 09:21
-
-
Save moson-mo/f18731cf73203011a279b90230d29362 to your computer and use it in GitHub Desktop.
Go - Reading/Writing to PCI config registers via sysfs. (example of controlling CPU boosting for a Ryzen mobile processor)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Example of reading/writing to PCI config registers via sysfs. | |
In this example we write to the SMU (MP1 mailbox) of a Ryzen mobile processor | |
to modify a setting that controls CPU's boosting behavior. | |
There are two modes, "power-saving" (which is usually automatically activated when running on battery power) | |
and "max-performance" (when connected to AC) | |
See https://github.com/FlyGoat/RyzenAdj/wiki/Renoir-Tuning-Guide#--power-saving-dc-mode-tune-with-boost-delay | |
for more information. | |
*/ | |
package main | |
import ( | |
"encoding/binary" | |
"fmt" | |
"os" | |
) | |
const ( | |
PCI_DEV_CONFIG_PATH = "/sys/bus/pci/devices/0000:00:00.0/config" | |
PCI_REG_OFFSET_ADDRESS = 0xB8 | |
PCI_REG_OFFSET_DATA = 0xBC | |
MP1_MESSAGE_ADDR = 0x3B10528 | |
MP1_RESPONSE_ADDR = 0x3B10564 | |
) | |
func main() { | |
writeMP1(MP1_RESPONSE_ADDR, 0x0) // clear response | |
writeMP1(MP1_MESSAGE_ADDR, 0x11) // performance mode | |
//writeMP1(MP1_MESSAGE_ADDR, 0x12) // power-saving mode | |
resp := uint32(0) | |
for resp == 0 { | |
resp = readMP1(MP1_RESPONSE_ADDR) // read until we get a response | |
} | |
fmt.Printf("DONE - Response code: %d\n", resp) | |
} | |
func readMP1(addr uint32) uint32 { | |
err := writeConfigRegister(PCI_REG_OFFSET_ADDRESS, (addr &^ 0x3)) | |
if err != nil { | |
panic(err) | |
} | |
val, err := readConfigRegister(PCI_REG_OFFSET_DATA) | |
if err != nil { | |
panic(err) | |
} | |
return val | |
} | |
func writeMP1(addr, data uint32) { | |
err := writeConfigRegister(PCI_REG_OFFSET_ADDRESS, addr) | |
if err != nil { | |
panic(err) | |
} | |
err = writeConfigRegister(PCI_REG_OFFSET_DATA, data) | |
if err != nil { | |
panic(err) | |
} | |
} | |
type barreg struct { | |
offset int64 | |
*os.File | |
} | |
func (r *barreg) Read(b []byte) (int, error) { | |
return r.ReadAt(b, r.offset) | |
} | |
func (r *barreg) Write(b []byte) (int, error) { | |
return r.WriteAt(b, r.offset) | |
} | |
func readConfigRegister(offset int64) (uint32, error) { | |
f, err := os.Open(PCI_DEV_CONFIG_PATH) | |
if err != nil { | |
return 0, err | |
} | |
defer f.Close() | |
var val uint32 | |
err = binary.Read(&barreg{offset: offset, File: f}, binary.LittleEndian, &val) | |
return val, err | |
} | |
func writeConfigRegister(offset int64, val uint32) error { | |
f, err := os.OpenFile(PCI_DEV_CONFIG_PATH, os.O_WRONLY, 0) | |
if err != nil { | |
return err | |
} | |
defer f.Close() | |
err = binary.Write(&barreg{offset: offset, File: f}, binary.LittleEndian, &val) | |
return err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment