I have just run into a problem with a project that might need a bit
of atrocious kernel hacking. And as I don't quite know what I am doing :),
I thought it would be a good idea to find out whether I am setting myself
up for misery....
The project I am working on is an emulator, which however gives a high level
of hardware access to the emulated system. In particular, the emulated system
is supposed to be able to use all the PCI devices (more correctly: functions)
that are not actually in use by the kernel itself. Interrupts are mapped into
user space signals through Dmitry A. Fedorov's irq patch, and then mapped into
the emulated machine's interrupt mechanism.
This works wonderfully right now; Using for example a PCI-NE2k in the emulated
machine is rock stable.
However, there is one problem --- The emulated machine can be reset at any
time. On a real machine, this would send a RESET signal to the PCI bus,
sending all devices back to inactive, harmless settings.
In the emulation, however, no such hardware signal is generated on the
real, physical PCI bus (and if it was, the devices under linux' control
would reset as well, which would be very bad). On the other hand, I cannot
just let the devices remain active, because any interrupts they generate
won't be cleared (the device drivers running on the emulated machine are
no longer there to clear them)[1]. So whenever a reset occurs in the emulation,
I need to gracefully shut down the devices under emulator control, back
to bootup state, without touching the devices under linux' control....
After doing a fair bit of reading, it appears to me that my best bet is to
move the devices into power management mode D3hot, and back to D0, and then
restore the bootup config space settings (which I would have saved earlier,
before any drivers messed around with them). My understanding is that this
should safely put the cards back into the same inactive state they were in
right after power-up; In particular, that they won't be generating interrupts
or busmaster traffic anymore?!?
There are some issues I am not quite clear on, however:
* There seem to be contradicting opinions on whether all PCI devices
are safe to take to D3hot and back to D0. While some sources say
that *all* PCI devices support D3, some disagree. Is there a definitive
source on that one?
* The documentation only says that one should *assume* all registers to
be lost after a D3->D0 transition. Does that mean that theoretically,
a device is at liberty to *not* become inactive through the D0->D3->D0
cycling?
* I have found only one rather vague source on how long the D3->D0
transition might take (which says to wait 10ms). Is there some more
authoritive information available somewhere?
* Do I need to manually disable the Busmaster, I/O and memory response
bits in the command register before the D0->D3 transition, or is it
safe to simply send PCI devices to sleep from any active state?
* If a PCI device is holding its interrupt line active at the time I do
the D0->D3->D0 cycling, will my action result in the line becoming
inactive?
Lots of questions, and not enough PCI hardware to do exhaustive testing
with... Thus I am appealing to the people who actually know how this stuff
is supposed to work :)
Any ideas?
Bernie
P.S.: If you are replying to this in the intel.other_components.pci_chipsets
group, please leave the linux group in --- it appears my server doesn't
actually carry the intel one. Thanks.
[1]: Of course, this in itself isn't a problem yet. The problem comes up if
the now unhandled PCI device shares its interrupt with another, still
handled device; Due to the other device, the interrupt controller will
be programmed to have the interrupt line enabled, and due to the
unhandled device, the interrupt will never get inactive. Baaaad
combination :(
--
Thomas --- Jefferson --- still surv--
John Adams
2nd President of the US
Last words, 4 July 1826