mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 02:01:38 +00:00
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:
parent
8b3a339817
commit
cde4d4aee0
File diff suppressed because it is too large
Load Diff
@ -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 { };
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user