Is it possible to read AHCI registers using setpci on Linux? - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: April 06, 2024, 10:35:11 pm
content: Can anyone tell me if it's possible to use the Linuxsetpciutility to read values from AHCI registers for a PCIe bus SATA controller?I'm trying to definitively determine if a SATA controller is running in legacy IDE emulation mode or AHCI mode.Apparently, according to the AHCI specification, there is an HBA Capabilities ('CAP') register that contains a Supports AHCI Mode Only ('SAM') bit flag, and there is also a Global HBA Control ('GHC') register that contains an AHCI Enable ('AE') bit flag. If the former is '1', then the controller only does AHCI and doesn't support IDE emulation. If it is '0', then you need to check the latter GHC.AE flag to see if it is currently '1' for AHCI or '0' for IDE mode.From the spec document, I know what the register address offsets are, but I've no idea how to translate that to arguments forsetpci. I think AHCI registers are accessed via some kind of PCI MMIO scheme, so it's probably not 1:1 mapping.

author: RoGeorge
author_rank: Super Contributor
timestamp: April 28, 2024, 10:13:42 am
content: I don't know to answer the question, but the Linux kernel should have a Device Tree (DT). The DT is telling the kernel (at boot), what driver to load for each device, and any specific parameters the driver might need. Later, that DT is mapped into a directory tree (in Linux, everything is a file), here mapped at /proc/.For example, if I search for PCI in /proc/ of my desktop PC, there is a /proc/bus/pci/ directory, and a/proc/bus/pci/devicesfile. Inside that file there is a line contaning the textahci, and some addresses/registers.See if you can make use of any of that info, in order to find the address you are interested in, though never tried that myself.No idea if this could help changing the settings you are after, if it applies to your OS flavor, or if it brings anything extra other than setpci can already do/show (I don't know much about setpci). But if it does, then it should be possible to decompile the (binary) device tree that is in use, edit the decompiled DT to add your changes in the DT sources, then recompile the DT (the decompiler/compiler is calleddtc), so to make your changes persistent after a reboot.

author: magic
author_rank: Super Contributor
timestamp: April 28, 2024, 10:46:48 am
content: AFAIKsetpcionly access the configuration address space of PCI. If the registers you are looking for are there then you are set. If they are in some MMIO region, I don't see a way of reading them withsetpci.However, the relatedlspci(with -v flag) will tell you where the MMIO registers are mapped in the CPU physical address space. Knowing this, you could presumably read them by means of/dev/memor something like that (note: in recent times there were some attempts to restrict or completely remove this mechanism on security grounds and I'm not sure how it works in mainstream distributions these days).

author: HwAoRrDk
author_rank: Super Contributor
timestamp: April 28, 2024, 08:39:26 pm
content: I did actually find a way to do it in the end. I meant to come back here and post an update but it slipped my mind.The AHCI register contents memory region is actually exposed in sysfs, in /sys/bus/pci/devices/<device id>/resource5. It is the same "Resource 5" (aka "Region 5", "BAR5") mentioned in lspci verbose output. But you can't just read that file - oh, no, that would be too easy!It has to be accessed using mmap IO. I found a utility on GitHub that will do so:https://github.com/billfarrow/pcimem.Code:$ sudo ./pcimem /sys/bus/pci/devices/0000:01:00.0/resource5 0 w*128/sys/bus/pci/devices/0000:01:00.0/resource5 opened.Target offset is 0x0, page size is 16384mmap(0, 4096, 0x3, 0x1, 3, 0x0)PCI Memory mapped to address 0x7fffa9fbc000.0x0000: 0xEB32FFA10x0004: 0x800000020x0008: 0x000000000x000C: 0x000000030x0010: 0x000102000x0014: 0x000000100x0018: 0x00000000...The arguments to the command tell it to read 128 32-bit words starting from offset zero. The AHCI register space on my particular SATA controller is 512 bytes, because it only features 2 ports. With more ports the register space will be larger.The GHC.AE (AHCI mode enabled) register flag is bit 31 of the word at offset 0x0004. You can see here that it is set.