Skip to content

Commit 9ec9b2c

Browse files
authored
Add nushell port of autoaspm (#1070)
This is a Nushell port of https://github.com/notthebee/AutoASPM written mostly as an exercise in binary operations in Nushell. There are several undocumented magic constants in the code that hail back from the original version that was supposed to be here: https://www.uwsg.indiana.edu/hypermail/linux/kernel/1006.2/02177.html
1 parent 61bb4f6 commit 9ec9b2c

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

sourced/AutoASPM/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## AutoASPM
2+
3+
Simple script to enable [Active State Power Management](https://en.wikipedia.org/wiki/Active_State_Power_Management) on all of your PCIe devices
4+
5+
This script supports only Linux systems
6+
7+
This is a Nushell port of [auto-ASPM.py](https://github.com/notthebee/AutoASPM) written mostly as an exercise in binary operations in Nushell.
8+
There are several undocumented magic constants in the code that hail back from the original [enable_aspm](https://www.uwsg.indiana.edu/hypermail/linux/kernel/1006.2/02177.html) script
9+
10+
### Usage
11+
12+
1. Ensure you have following binaries available on `PATH`: `lspci` `setpci`, those come as part of `pciutils` package on most distros
13+
2. Run the script as root (Necessary because regular users cannot access low-level device information needed for the script to work)

sourced/AutoASPM/auto_aspm.nu

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env nu
2+
3+
const aspm = {
4+
DISABLED: 0b00
5+
L0s: 0b01
6+
L1: 0b10
7+
L0sL1: 0b11
8+
}
9+
10+
def get-bytes-for-device [
11+
device: string
12+
]: nothing -> binary {
13+
lspci -s $device -xxx
14+
| lines
15+
| skip
16+
| compact -e
17+
| split column -c ':'
18+
| get column2
19+
| split row ' '
20+
| compact -e
21+
| str join
22+
| decode hex
23+
| if ($in|bytes length) < 256 {
24+
print $"Invalid byte length detected for device ($device) aborting"
25+
exit
26+
} else {
27+
$in
28+
}
29+
}
30+
31+
def find-bytes [
32+
bytes: binary
33+
pos: int
34+
]: nothing -> int {
35+
# absolute black magic
36+
let result = ($bytes|bytes at $pos..$pos|into int)
37+
if $result != 0x10 {
38+
find-bytes $bytes ($result + 0x1)
39+
} else {
40+
return ($result + 0x10)
41+
}
42+
}
43+
44+
def patch-device [
45+
device: string
46+
aspm_value: string
47+
] {
48+
let bytes = (get-bytes-for-device $device)
49+
let byte_position = (find-bytes $bytes 0x34) #no one really knows where this value comes from
50+
let byte_to_patch = (
51+
$bytes
52+
| bytes at $byte_position..$byte_position
53+
| into int
54+
)
55+
# no idea
56+
if ($byte_to_patch| bits and 0b11) == ($aspm|get $aspm_value) {
57+
print $"($device) already has ASPM ($aspm_value) enabled"
58+
} else {
59+
print $"Enabling ASPM ($aspm_value) for device ($device)"
60+
let new_byte_value = (
61+
$byte_to_patch
62+
| bits shr 2 #no idea why we bitshift right and left
63+
| bits shl 2
64+
| bits or ($aspm|get $aspm_value)
65+
)
66+
patch-byte $device $byte_position $new_byte_value
67+
print $"Enabled ASPM ($aspm_value) for device ($device)"
68+
}
69+
}
70+
71+
def patch-byte [
72+
device: string
73+
position: int
74+
value: int
75+
] {
76+
setpci -s $device $"($position|format number|get upperhex).B=($value|format number|get upperhex)"
77+
}
78+
79+
def get-supported-devices []: nothing -> table<address: string, supported_aspm: string> {
80+
lspci -vv
81+
| lines
82+
| split list ''
83+
| each {|device|
84+
85+
let address = (
86+
$device
87+
| first
88+
| split row ' '
89+
| first
90+
)
91+
92+
let params = ($device|skip)
93+
94+
if ($params|find "ASPM"|is-empty) or ($params|find "ASPM not supported"|is-not-empty) {
95+
null
96+
} else {
97+
let supported_aspm = (
98+
$params
99+
| parse -r "ASPM (L[L0-1s ]*),"
100+
| get capture0.0
101+
| str replace " " ""
102+
)
103+
{address: $address, supported_aspm: $supported_aspm}
104+
}
105+
}
106+
}
107+
108+
if not (is-admin) {
109+
error make -u {
110+
msg: "This script needs to be run as root"
111+
}
112+
}
113+
if $nu.os-info.name != "linux" {
114+
error make -u {
115+
msg: "This script needs to run under Linux"
116+
}
117+
}
118+
if (which lspci setpci|length) < 2 {
119+
error make -u {
120+
msg: "lspci and setpci need to be available in PATH"
121+
}
122+
}
123+
124+
for device in (get-supported-devices) {
125+
patch-device $device.address $device.supported_aspm
126+
}

0 commit comments

Comments
 (0)