Speed up ata(4) 400 ns waits.

Waiting for any non-zero duration currently waits for at least one timer
cycle (10 ms), which is especially expensive during early boot.

The current workaround of simply reading the status 14 times seems really
suspicious although the osdev wiki documents it, but let's see how well it
works on real hardware, it's probably good enough.

Try to determine the initial selected drive to save one drive selection.
This commit is contained in:
Jonas 'Sortie' Termansen 2022-10-31 22:47:02 +01:00
parent bf5a85c1c4
commit f42e81e99d
2 changed files with 19 additions and 7 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2022 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -49,11 +49,17 @@ static unsigned long AllocateDiskNumber()
return InterlockedIncrement(&next_disk_number).o;
}
static void sleep_400_nanoseconds()
static void sleep_400_nanoseconds(uint16_t port_base)
{
// TODO: The clock granularity of 10 ms slows down the early boot.
#if 0
struct timespec delay = timespec_make(0, 400);
Clock* clock = Time::GetClock(CLOCK_BOOTTIME);
clock->SleepDelay(delay);
#else
for ( int i = 0; i < 14; i++ )
inport8(port_base + REG_STATUS);
#endif
}
Channel::Channel()
@ -105,7 +111,7 @@ void Channel::SelectDrive(unsigned int drive_index) // hw_lock locked
outport8(port_base + REG_DRIVE_SELECT, value);
//outport8(port_control, value); // TODO: Or is it port_control we use?
sleep_400_nanoseconds();
sleep_400_nanoseconds(port_base);
// TODO: Do we need to wait for non-busy now? Can this operation fail?
@ -229,7 +235,7 @@ bool Channel::Initialize(Ref<Descriptor> dev, const char* devpath)
busmaster_base = busmasterbar.addr() + 8 * channel_index;
current_drive = (unsigned int) -1; // We don't know.
current_drive = (inport8(port_base + REG_DRIVE_SELECT) >> 4) & 1;
for ( unsigned int i = 0; i < 2; i++ )
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2016, 2018, 2021 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2018, 2021, 2022 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -56,11 +56,17 @@ static void copy_ata_string(char* dest, const char* src, size_t length)
dest[length] = '\0';
}
static void sleep_400_nanoseconds()
static void sleep_400_nanoseconds(uint16_t port_base)
{
// TODO: The clock granularity of 10 ms slows down the early boot.
#if 0
struct timespec delay = timespec_make(0, 400);
Clock* clock = Time::GetClock(CLOCK_BOOTTIME);
clock->SleepDelay(delay);
#else
for ( int i = 0; i < 14; i++ )
inport8(port_base + REG_STATUS);
#endif
}
Port::Port(Channel* channel, unsigned int port_index)
@ -176,7 +182,7 @@ retry_identify_packet:
outport8(channel->port_base + REG_COMMAND,
is_packet_interface ? CMD_IDENTIFY_PACKET : CMD_IDENTIFY);
sleep_400_nanoseconds();
sleep_400_nanoseconds(channel->port_base);
// TODO: The status polling logic should be double-checked against some
// formal specification telling how this should properly be done.