q35: five seconds of boot spent waiting on disks that are not there
/proc/interrupts on q35 said "LOSING 526" ticks: 5 s of boot with interrupts off. Timing each step of kmain() found two waits: - AHCI sent a COMRESET to every empty port and waited a second for a link. DET = 0 is "no device", so only DET = 1 is worth a reset now (after 20 ms of grace for a drive that is still spinning up). - ideinit() read 0xFF from a bus with no IDE controller, took the BSY bit for a busy drive, and waited out its 1 s timeout. A status of 0xFF means no controller and is answered at once. That is every PC with SATA disks. q35 now loses 33 ticks, under the flag; i440fx still roots on IDE and loses none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
This commit is contained in:
parent
d7352c0db0
commit
c1e52e172f
2 changed files with 25 additions and 0 deletions
|
|
@ -130,6 +130,18 @@ void
|
|||
ideinit(void)
|
||||
{
|
||||
initlock(&idelock, "ide");
|
||||
|
||||
// No controller at all: the bus floats and the status port reads 0xFF.
|
||||
// That has BSY set, so idewait() below took it for a drive that was still
|
||||
// busy and waited out its full second -- a second of every boot on q35 and
|
||||
// on any PC whose disks are SATA, which is all of them. 0xFF is not a
|
||||
// status any drive reports (BSY and DRDY are never both set), so it can be
|
||||
// answered at once.
|
||||
if(inb(0x1f7) == 0xFF){
|
||||
kinfo("ide: no controller at the legacy ports\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// ISA signalling: edge-triggered, active high. Everything at a fixed
|
||||
// legacy port is wired this way; PCI devices are not.
|
||||
irq_register(IRQ_IDE, ide_irq, 0, "ide", 0);
|
||||
|
|
|
|||
|
|
@ -167,9 +167,22 @@ port_stop(volatile uint8 *r)
|
|||
static int
|
||||
port_link(volatile uint8 *r)
|
||||
{
|
||||
// A drive told to spin up a moment ago takes a few milliseconds to be seen
|
||||
// at all; give it twenty before calling the port empty.
|
||||
uint32 ssts = rd(r, PX_SSTS);
|
||||
for (int i = 0; i < 20 && (ssts & 0xF) == 0; i++) {
|
||||
microdelay(1000);
|
||||
ssts = rd(r, PX_SSTS);
|
||||
}
|
||||
if ((ssts & 0xF) == 3)
|
||||
return 1;
|
||||
// DET = 0 is "no device detected": an empty port, not a slow one. This
|
||||
// used to COMRESET every empty port and wait a second for an answer that
|
||||
// could not come -- four seconds of boot on a q35 with one disk, all of it
|
||||
// with interrupts off. Only a device that is detected without a link
|
||||
// (DET = 1) is worth the reset.
|
||||
if ((ssts & 0xF) != 1)
|
||||
return 0;
|
||||
|
||||
wr(r, PX_SCTL, (rd(r, PX_SCTL) & ~0xFu) | 1); // DET = 1: COMRESET
|
||||
microdelay(2000); // at least 1 ms
|
||||
|
|
|
|||
Loading…
Reference in a new issue