ahci: refactor code for suspend/resume

This commit is a preparation commit for suspend/resume. The commit
refactors the code in order to consolidate all Platform resources into one
instance. All users within the driver should access the resources with
with_* functions, which checks whether the device resource is usable. The
callers are not allowed to store any references to the provided resources.

Issue #5101
This commit is contained in:
Alexander Boettcher 2023-12-21 14:01:09 +01:00 committed by Christian Helmuth
parent 8b3a339817
commit cde4d4aee0
5 changed files with 683 additions and 457 deletions

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2015-2020 Genode Labs GmbH
* Copyright (C) 2015-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -219,15 +219,15 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
** Ahci::Protocol interface **
******************************/
unsigned init(Port &port) override
unsigned init(Port &port, Port_mmio &mmio) override
{
/* identify device */
Command_table table(port.command_table_range(0),
port.device_info_dma_addr, 0x1000);
table.fis.identify_device();
port.execute(0);
port.execute(0, mmio);
port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1),
mmio.wait_for_any(port.delayer, Port::Is::Dss::Equal(1),
Port::Is::Pss::Equal(1),
Port::Is::Dhrs::Equal(1));
@ -249,27 +249,26 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
cmd_slots = 1;
_slots.limit((size_t)cmd_slots);
port.ack_irq();
port.ack_irq(mmio);
return cmd_slots;
}
void handle_irq(Port &port) override
void handle_irq(Port &port, Port_mmio &mmio) override
{
unsigned is = port.read<Port::Is>();
unsigned is = mmio.read<Port::Is>();
/* ncg */
if (_ncq_support(port) && Port::Is::Fpdma_irq::get(is))
do {
port.ack_irq();
}
while (Port::Is::Sdbs::get(port.read<Port::Is>()));
port.ack_irq(mmio);
} while (Port::Is::Sdbs::get(mmio.read<Port::Is>()));
/* normal dma */
else if (Port::Is::Dma_ext_irq::get(port.read<Port::Is>()))
port.ack_irq();
else if (Port::Is::Dma_ext_irq::get(mmio.read<Port::Is>()))
port.ack_irq(mmio);
_slot_states = port.read<Port::Ci>() | port.read<Port::Sact>();
port.stop();
_slot_states = mmio.read<Port::Ci>() | mmio.read<Port::Sact>();
port.stop(mmio);
_syncing = false;
}
@ -284,7 +283,8 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
void writeable(bool rw) override { _writeable = rw; }
Response submit(Port &port, Block::Request const request) override
Response submit(Port &port, Block::Request const &request,
Port_mmio &mmio) override
{
Block::Operation const op = request.operation;
@ -327,9 +327,9 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
} else if (_ncq_support(port)) {
table.fis.fpdma(write == false, op.block_number, op.count, slot);
/* ensure that 'Cmd::St' is 1 before writing 'Sact' */
port.start();
port.start(mmio);
/* set pending */
port.write<Port::Sact>(1U << slot);
mmio.write<Port::Sact>(1U << slot);
} else {
table.fis.dma_ext(write == false, op.block_number, op.count);
}
@ -339,12 +339,12 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
header.write<Command_header::Bits::W>(write ? 1 : 0);
header.clear_byte_count();
port.execute(slot);
port.execute(slot, mmio);
return Response::ACCEPTED;
}
Block::Request completed(Port & /* port */) override
Block::Request completed(Port_mmio &) override
{
Block::Request r { };

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2015-2020 Genode Labs GmbH
* Copyright (C) 2015-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -18,9 +18,9 @@
#include <util/endian.h>
namespace Atapi {
class Protocol;
using namespace Ahci;
using namespace Genode;
class Protocol;
using namespace Ahci;
using namespace Genode;
}
class Atapi::Protocol : public Ahci::Protocol, Noncopyable
@ -31,34 +31,34 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
block_number_t _block_count { 0 };
size_t _block_size { 2048 };
void _atapi_command(Port &port)
void _atapi_command(Port &port, Port_mmio &mmio)
{
Command_header header(port.command_header_range(0));
header.atapi_command();
header.clear_byte_count();
port.execute(0);
port.execute(0, mmio);
}
void _read_sense(Port &port)
void _read_sense(Port &port, Port_mmio &mmio)
{
Command_table table(port.command_table_range(0),
port.device_info_dma_addr, 0x1000);
table.fis.atapi();
table.atapi_cmd.read_sense();
_atapi_command(port);
_atapi_command(port, mmio);
}
void _test_unit_ready(Port &port)
void _test_unit_ready(Port &port, Port_mmio &mmio)
{
Command_table table(port.command_table_range(0), 0, 0);
table.fis.atapi();
table.atapi_cmd.test_unit_ready();
_atapi_command(port);
_atapi_command(port, mmio);
}
void _read_capacity(Port &port)
void _read_capacity(Port &port, Port_mmio &mmio)
{
Command_table table(port.command_table_range(0),
port.device_info_dma_addr, 0x1000);
@ -67,16 +67,16 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
table.atapi_cmd.read_capacity();
_atapi_command(port);
_atapi_command(port, mmio);
}
void _start_unit(Port &port)
void _start_unit(Port &port, Port_mmio &mmio)
{
Command_table table(port.command_table_range(0), 0, 0);
table.fis.atapi();
table.atapi_cmd.start_unit();
_atapi_command(port);
_atapi_command(port, mmio);
}
public:
@ -85,41 +85,41 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
** Ahci::Protocol interface **
******************************/
unsigned init(Port &port) override
unsigned init(Port &port, Port_mmio &mmio) override
{
port.write<Port::Cmd::Atapi>(1);
mmio.write<Port::Cmd::Atapi>(1);
retry<Port::Polling_timeout>(
[&] {
_start_unit(port);
port.wait_for_any(port.delayer,
_start_unit(port, mmio);
mmio.wait_for_any(port.delayer,
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
Port::Is::Dhrs::Equal(1));
port.ack_irq();
port.ack_irq(mmio);
/* read sense */
_read_sense(port);
port.wait_for_any(port.delayer,
_read_sense(port, mmio);
mmio.wait_for_any(port.delayer,
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
Port::Is::Dhrs::Equal(1));
port.ack_irq();
port.ack_irq(mmio);
/* test unit ready */
_test_unit_ready(port);
port.wait_for(port.delayer, Port::Is::Dhrs::Equal(1));
port.ack_irq();
_test_unit_ready(port, mmio);
mmio.wait_for(port.delayer, Port::Is::Dhrs::Equal(1));
port.ack_irq(mmio);
Device_fis f(*port.fis);
/* check if devic is ready */
if (!f.read<Device_fis::Status::Device_ready>() || f.read<Device_fis::Error>())
throw Port::Polling_timeout();
_read_capacity(port);
port.wait_for_any(port.delayer,
_read_capacity(port, mmio);
mmio.wait_for_any(port.delayer,
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
Port::Is::Dhrs::Equal(1));
port.ack_irq();
port.ack_irq(mmio);
_block_count = host_to_big_endian(((unsigned *)port.device_info->start)[0]) + 1;
_block_size = host_to_big_endian(((unsigned *)port.device_info->start)[1]);
@ -137,14 +137,15 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
.writeable = false };
}
void handle_irq(Port &port) override
void handle_irq(Port &port, Port_mmio &mmio) override
{
port.ack_irq();
port.ack_irq(mmio);
}
void writeable(bool) override { }
Response submit(Port &port, Block::Request const request) override
Response submit(Port &port, Block::Request const &request,
Port_mmio &mmio) override
{
if (request.operation.type != Block::Operation::Type::READ ||
port.sanity_check(request) == false || port.dma_base == 0)
@ -172,15 +173,14 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
header.write<Command_header::Bits::W>(0);
header.clear_byte_count();
/* set pending */
port.execute(0);
port.execute(0, mmio);
return Response::ACCEPTED;
}
Block::Request completed(Port &port) override
Block::Request completed(Port_mmio &mmio) override
{
if (!_pending.operation.valid() || port.read<Port::Ci>())
if (!_pending.operation.valid() || mmio.read<Port::Ci>())
return Block::Request();
Block::Request request = _pending;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2016-2020 Genode Labs GmbH
* Copyright (C) 2016-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -49,30 +49,26 @@ class Ahci::Driver : Noncopyable
private:
Env &_env;
Dispatch &_dispatch;
struct Timer_delayer : Mmio<0>::Delayer, Timer::Connection
{
using Timer::Connection::Connection;
void usleep(uint64_t us) override { Timer::Connection::usleep(us); }
} _delayer { _env };
};
Signal_handler<Driver> _handler { _env.ep(), *this, &Driver::handle_irq };
Env & _env;
Dispatch & _dispatch;
Timer_delayer _delayer { _env };
Signal_handler<Driver> _handler { _env.ep(), *this, &Driver::handle_irq };
Resources _resources { _env, _handler };
Platform::Connection _plat { _env };
Platform::Device _device { _plat };
Hba _hba { _device, _handler, _plat };
Constructible<Ata::Protocol> _ata[MAX_PORTS];
Constructible<Ata::Protocol> _ata [MAX_PORTS];
Constructible<Atapi::Protocol> _atapi[MAX_PORTS];
Constructible<Port> _ports[MAX_PORTS];
bool _enable_atapi;
unsigned _scan_ports(Region_map &rm)
unsigned _scan_ports(Region_map &rm, Platform::Connection &plat, Hba &hba)
{
log("port scan:");
@ -80,17 +76,17 @@ class Ahci::Driver : Noncopyable
for (unsigned index = 0; index < MAX_PORTS; index++) {
if (_hba.port_implemented(index) == false)
continue;
Port_base port(index, plat, hba, _delayer);
Port_base port(index, _plat, _hba, _delayer);
if (port.implemented() == false)
continue;
bool enabled = false;
if (port.ata()) {
try {
_ata[index].construct();
_ports[index].construct(*_ata[index], rm, _plat,
_hba, _delayer, index);
_ports[index].construct(*_ata[index], rm, plat,
hba, _delayer, index);
enabled = true;
} catch (...) { }
@ -98,8 +94,8 @@ class Ahci::Driver : Noncopyable
} else if (port.atapi() && _enable_atapi) {
try {
_atapi[index].construct();
_ports[index].construct(*_atapi[index], rm, _plat,
_hba, _delayer, index);
_ports[index].construct(*_atapi[index], rm, plat,
hba, _delayer, index);
enabled = true;
} catch (...) { }
@ -121,11 +117,15 @@ class Ahci::Driver : Noncopyable
: _env(env), _dispatch(dispatch), _enable_atapi(support_atapi)
{
/* search for devices */
unsigned port_count = _scan_ports(env.rm());
_resources.with_platform([&](auto &platform) {
_resources.with_hba([&](auto &hba) {
unsigned port_count = _scan_ports(env.rm(), platform, hba);
if (port_count != _hba.port_count())
log("controller port count differs from detected ports (CAP.NP=",
Hex(_hba.cap_np_value()), ",PI=", Hex(_hba.pi_value()), ")");
if (port_count != hba.port_count())
log("controller port count differs from detected ports (CAP.NP=",
Hex(hba.cap_np_value()), ",PI=", Hex(hba.pi_value()), ")");
});
});
}
/**
@ -133,12 +133,14 @@ class Ahci::Driver : Noncopyable
*/
void handle_irq()
{
_hba.handle_irq([&] (unsigned port) {
if (_ports[port].constructed())
_ports[port]->handle_irq();
_resources.with_hba([&](auto &hba) {
hba.handle_irq([&] (unsigned port) {
if (_ports[port].constructed())
_ports[port]->handle_irq();
/* handle (pending) requests */
_dispatch.session(port);
/* handle (pending) requests */
_dispatch.session(port);
}, [&]() { error("hba handle_irq failed"); });
});
}
@ -295,19 +297,15 @@ struct Ahci::Block_session_component : Rpc_object<Block::Session>,
};
struct Ahci::Main : Rpc_object<Typed_root<Block::Session>>,
Dispatch
struct Ahci::Main : Rpc_object<Typed_root<Block::Session>>, Dispatch
{
Env &env;
Attached_rom_dataspace config { env, "config" };
Constructible<Ahci::Driver> driver { };
Constructible<Reporter> reporter { };
Env & env;
Attached_rom_dataspace config { env, "config" };
Constructible<Ahci::Driver> driver { };
Constructible<Reporter> reporter { };
Constructible<Block_session_component> block_session[Driver::MAX_PORTS];
Main(Env &env)
: env(env)
Main(Env &env) : env(env)
{
log("--- Starting AHCI driver ---");
bool support_atapi = config.xml().attribute_value("atapi", false);

View File

@ -1,11 +1,11 @@
/*
* \brief Utilitize used by the AHCI driver
* \brief Utilities used by the AHCI driver
* \author Josef Soentgen
* \date 2018-03-05
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.