From f42e81e99d7a5c4534accb9195764fabbe6a74db Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 31 Oct 2022 22:47:02 +0100 Subject: [PATCH] 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. --- kernel/disk/ata/hba.cpp | 14 ++++++++++---- kernel/disk/ata/port.cpp | 12 +++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/kernel/disk/ata/hba.cpp b/kernel/disk/ata/hba.cpp index fca68ea3..1035d0b3 100644 --- a/kernel/disk/ata/hba.cpp +++ b/kernel/disk/ata/hba.cpp @@ -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 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++ ) { diff --git a/kernel/disk/ata/port.cpp b/kernel/disk/ata/port.cpp index 3f414b21..0327e120 100644 --- a/kernel/disk/ata/port.cpp +++ b/kernel/disk/ata/port.cpp @@ -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.