Conversation
8 tasks
GliAcopo
force-pushed
the
add-15a2ems1.114
branch
from
August 10, 2026 11:49
07347c6 to
0310830
Compare
The battery charge threshold address (0xd7, encoded as 0x80 | percent) was verified A/B against MSI Center under Windows, and by observing charging actually stop at the configured cap with the charger attached. The CPU temperature address (0x68) was verified against coretemp under load. Features that could not be verified on this unit are left UNSUPP rather than inherited from a neighbouring config, since an unverified address on a write path would mean writing to the wrong EC register. leds and kbd_bl in particular must stay UNSUPP: led_classdev_register() with a .default_trigger writes to the EC right after insmod, and leaving them unset is what keeps loading the module a read-only operation. The exception is cpu.rt_fan_speed_address (0x71), taken from the G2 family convention rather than measured: the fan never left its minimum regime in the thermal range reachable on battery, so the value could not be moved. It is a read-only field; see the PR description for the details and an offer to set it UNSUPP instead if preferred. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GliAcopo
force-pushed
the
add-15a2ems1.114
branch
from
August 10, 2026 11:49
0310830 to
b063d8a
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a configuration for the MSI Prestige 16 AI Studio B1VEG (board
MS-15A2), EC firmware15A2EMS1.114.This board is not currently matched by any config, so the module refuses to load on it:
The config is deliberately minimal: it enables only what I could actually verify on the machine. Everything else is
MSI_EC_ADDR_UNSUPPrather than inherited from a neighbouring config, because an unverified address would mean writing to the wrong EC register.Device
board_name)MS-15A20xA0)15A2EMS1.114(release date field:0527202510:09:58)bios_version)E15A2IMS.110Note the EC string and the BIOS string are different values that move independently —
15A2EMS1.114vsE15A2IMS.110. The allow-list needs the EC one. Adding the BIOS string there is a silent no-op: it can never match and produces no error. I made that mistake once early on.Read back with:
What this config enables
charge_control_address = 0xd7— battery charge limit, encoding0x80 | percent.cpu.rt_temp_address = 0x68— verified againstcoretemp, see below.cpu.rt_fan_speed_address = 0x71— the G2 family convention; see the honest caveat below.Everything else is
UNSUPP. Two different reasons:ledsandkbd_blmust stay UNSUPP on this config.led_classdev_register()with a.default_triggerwrites to the EC immediately afterinsmod. Leaving them unset is what keeps module loading a read-only operation, which I verified (see Testing).cooler_boost,shift_mode,fan_mode,super_battery,fn_win_swap,webcam— I have no Windows install on this machine and therefore no way to A/B these against MSI Center. I could have copied the addresses from a neighbouring G2 config and they would probably be right, but "probably right" on a write path is not something I want to submit.I'm happy to fold this into an existing config if you prefer — I can see from the history that configs get merged (
G2_7/G2_8/G2_9were merged away). I kept it separate only because the UNSUPP fields differ from every existing G2 config, and merging would mean asserting addresses I haven't tested.How
0xd7was identified and verified0xd7is already used ascharge_control_addressby 8 existing G2 configs, so this is the family convention rather than a new discovery. What follows is the verification that it is correct on this board.1. Cross-checked against MSI Center under Windows. The limit was set from MSI Center on Windows, then the machine was rebooted into Linux and the register read. This is the part that makes it a confirmation rather than an inference:
0xd7read from Linux0xe40xd00xbc0xd0 = 0x80 | 80,0xbc = 0x80 | 60,0xe4 = 0x80 | 100.2. Write table, via
charge_control_end_thresholdafter applying this config:0xd70xd70xe30xc30xd00xbd0xcb0xbcValues below 10 are rejected by the driver (
-EINVALfromset_end_threshold()), as expected.3. The firmware honors the value, it does not merely store it. With the cap at 67% and the charger attached, charging stopped at exactly 67% with
current_now = 0andADP1/online = 1. Same at 80%. 67 was chosen deliberately at ≥3 points away from 60 and 80, becausecapacityis a rounded integer and a nearby value could have been coincidence. Raising the cap 67 → 80 restarted charging within 10 seconds.Limitation I want to state explicitly: I only tested large changes. Small raises (e.g. 80 → 81) were never tried, so I don't know the dead-band behaviour near the current charge level.
4. The value lives in battery-backed EC RAM. It survives
rmmodand it survives a reboot — both observed. A practical consequence for users: the module is only needed to change the threshold, not to keep it in force. That also means a wrong value persists across reboots, so recovery is: rewrite it, or MSI Center under Windows, or an EC reset (power button held ~1 minute).Register observations
Sampled while running a full-load loop on all 22 threads, on battery. First column is idle before the loop started:
0x68coretempPackage id 0 (°C)0x710xC90x68is verified. It tracksPackage id 0consistently, roughly 1 °C below it, across the whole sweep. After loading the module,cpu/realtime_temperatureread45whilesensorsread+45.0°C.0x71is not independently verified, and I'd rather say so than pretend. It stayed at32throughout. I initially read that as evidence the address was wrong, but the fan never left its minimum regime in the thermal range I can reach on battery (0xC9only moved ±2%), so a constant value is exactly what you'd expect — it isn't evidence either way. I kept0x71because all 21 existing configs use it,32is plausible as a percentage (~1935 RPM against a typical full scale), and it is a read-only field where a wrong address costs a wrong number and nothing more. If you'd preferUNSUPPuntil someone can confirm it under a heavy thermal load on AC, I'll change it.Bonus observation, not used by this config:
0xC9appears to satisfyRPM = 480000 / value—248 → 1935,246 → 1951,241 → 1991, matchingfan1_inputeach time. That's RPM, not the percentagert_fan_speed_addressexpects, so I did not wire it up. Recording it in case it's useful for the family.EC dump
Taken with the
ec_sysmethod from the support guide, with the charge limit at 80% (0xd7 = 0xd0):Relation to #621
#621 is an open support request for the same board (
MS-15A2, Prestige 16 AI Studio B1VFG) with EC firmware15A2EMS1.111. Comparing that dump with mine:0xd7 = 0xe4there, which decodes as0x80 | 100— i.e. the default, no cap set. Consistent with the encoding proposed here, on a different unit and a different firmware revision.I deliberately did not add
15A2EMS1.111to the allow-list. I don't have that firmware and can't test it, and adding it would be presenting an inference as a confirmation. If the reporter of #621 can build this branch and confirm, adding one line covers that revision too. I've commented on #621 pointing here.Testing done
main(d7fbbd8) on kernel 7.0.0-29-generic, no new warnings.integrity).insmodsucceeds;fw_versionreads15A2EMS1.114,fw_release_datereads2025-05-27T10:09:58.0xd7is byte-identical before and afterinsmod(0xd0both times) — loading this config performs no EC write. This is the property the UNSUPPleds/kbd_blfields are protecting.charge_control_end_thresholdreads back80, matching0xd7 = 0xd0.75gives0xcb; writing80gives0xd0. Verified by re-reading the EC directly, not by reading sysfs back.cpu/realtime_temperature=45againstsensors+45.0°C.One thing I noticed but deliberately left out of this PR
charge_control_start_threshold_store()callsset_end_threshold(threshold + 10), so writing start actually writes end. The battery attribute group has nois_visible, sostartis always exposed even on configs where only the end threshold is meaningful. That affects every model, not just this one, so it doesn't belong in a device-support PR — mentioning it only in case it's not already known, and happy to open a separate issue.Template answers, for the record. GPU: Nvidia (RTX 4050 Max-Q) plus an Intel Arc iGPU. No mic/speaker mute LEDs are exposed under Linux —
/sys/class/ledsshows onlycapslock/numlock/scrolllockand a PHY LED. For the remaining physical characteristics (fan count, backlight type, webcam slider, Fn/Win placement) I'd point at #621, which covers the same board; I haven't independently confirmed them, and none of them affect this config since all the corresponding features are left UNSUPP.