Skip to content

dev/ichsmb: use hardware semaphore for smbus_callback#1990

Open
ckoehne wants to merge 4 commits intofreebsd:mainfrom
Beckhoff:phab/corvink/ichsmb
Open

dev/ichsmb: use hardware semaphore for smbus_callback#1990
ckoehne wants to merge 4 commits intofreebsd:mainfrom
Beckhoff:phab/corvink/ichsmb

Conversation

@ckoehne
Copy link
Member

@ckoehne ckoehne commented Jan 27, 2026

ICHs provide a hardware bit which can be used as semaphore. Make use of it to
properly implement bus requests and releases and avoid conflicts with BIOS/ACPI
code.

@bsdimp bsdimp added the changes-required Cannot land as is, change requested of submitter label Jan 28, 2026
The current wait loop makes no sense. It has several flaws. First of all, it
blocks in non blocking IO mode. When openening the file with O_NONBLOCK,
SMB_WAIT is unset and smb_poll returns EWOULDBLOCK which causes our loop to
block. Additionally, msleep is called without a timeout. So, it waits until
it's waken up. Unfortunately, the SMBus might be used by BIOS/ACPI code which
can block the bus. If the callback function returns an error in that case, the
wakeup, called by smbus_release_bus will never be called and we're either
waiting forever in the SMB_NOINTR case or for a signal in the SMB_INTR case.

In order to improve the wait loop, we're inlining smbus_poll to be able to exit
early in non blocking IO mode. Additionally, we're setting a timeout for
msleep. This will retry the bus request in case it's blocked by BIOS/ACPI code.

An SMBus can operate at 100 kHz, 400 kHz or 1 MHz. So, sending a single byte
takes 80 us, 20 us or 8 us. Commonly, only a few bytes are send over the SMBus,
so polling in 1 ms (hz / 1000) intervals seems to be reasonal.

Note that we don't have to inline our second use of the smbus_poll function.
The second call is made after the bus was requested and where it can only be
blocked from another call made by ourself. So, we have to wait until the other
request is done which will then call wakeup in smbus_release_bus.
It's currently an endless loop waiting for the hardware to become free.
Unfortunately, the hardware can be used by BIOS/ACPI code too. In case of a
faulty BIOS/ACPI code, the device may not become free and is blocked forever.
To avoid a hanging kernel task add a timeout to this wait loop.

BIOS/ACPI code might block the bus for several transfers before releasing it.
However, the latest SMBus specification version 3.3 [1] defines a maximum
timeout of 35 ms for a single transaction. So, a timeout of 200 ms should give
BIOS/ACPI code enough time for a bunch of transfers.

[1] https://smbus.org/specs/SMBus_3_3_20240512.pdf
As already mentioned in the comment above the interrupt handler, the interrupt
for this device can be shared. The semaphore is acquired by simply reading the
status register. That's done even for spurious interrupts, so we have to
release the semaphore in that case.
ICHs provide a hardware bit which can be used as semaphore. Make use of it to
properly implement bus requests and releases and avoid conflicts with BIOS/ACPI
code.
@ckoehne ckoehne force-pushed the phab/corvink/ichsmb branch from 36b86b1 to 6744390 Compare February 24, 2026 11:58
@ckoehne ckoehne requested review from avg-I and bsdjhb February 24, 2026 12:09
@ckoehne ckoehne removed the changes-required Cannot land as is, change requested of submitter label Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants