mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 02:01:38 +00:00
parent
5528434fb6
commit
ed8f71e459
@ -1,35 +1,25 @@
|
||||
assert_spec x86
|
||||
|
||||
set mke2fs [installed_command mke2fs]
|
||||
set dd [installed_command dd]
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
set build_components {
|
||||
create_boot_directory
|
||||
build {
|
||||
core init timer
|
||||
drivers/platform
|
||||
drivers/acpi
|
||||
drivers/ahci
|
||||
app/pci_decode
|
||||
server/report_rom
|
||||
app/block_tester
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
#
|
||||
# Build EXT2-file-system image
|
||||
#
|
||||
set mke2fs [installed_command mke2fs]
|
||||
set dd [installed_command dd]
|
||||
catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 }
|
||||
catch { exec $mke2fs -F bin/ext2.raw }
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
set config {
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
@ -45,20 +35,78 @@ set config {
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>}
|
||||
</start>
|
||||
|
||||
append_platform_drv_config
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<policy label="pci_decode -> system" report="acpi_drv -> acpi"/>
|
||||
<policy label="platform_drv -> devices" report="pci_decode -> devices"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="acpi_drv" caps="350">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<route>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="pci_decode" caps="350">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label="system"> <child name="report_rom"/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="platform_drv" caps="100" managing_system="yes">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides>
|
||||
<service name="Platform"/>
|
||||
</provides>
|
||||
<route>
|
||||
<service name="ROM" label="devices"> <child name="report_rom"/> </service>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<service name="IRQ"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="IO_PORT"> <parent/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Timer"> <parent/> </service>
|
||||
</route>
|
||||
<config>
|
||||
<report devices="yes"/>
|
||||
<policy label="ahci_drv -> "> <pci class="AHCI"/> </policy>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
append config {
|
||||
<start name="ahci_report_rom">
|
||||
<binary name="report_rom"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
|
||||
<start name="ahci_drv">
|
||||
<resource name="RAM" quantum="10M" />
|
||||
<provides><service name="Block" /></provides>
|
||||
@ -72,6 +120,7 @@ append config {
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="test-ahci">
|
||||
<binary name="block_tester" />
|
||||
<resource name="RAM" quantum="50M" />
|
||||
@ -86,6 +135,7 @@ append config {
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="test-ahci-atapi">
|
||||
<binary name="block_tester" />
|
||||
<resource name="RAM" quantum="50M" />
|
||||
@ -101,16 +151,13 @@ append config {
|
||||
</start>
|
||||
</config> }
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
set boot_modules { core ld.lib.so init timer ahci_drv report_rom block_tester }
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
build_boot_image {
|
||||
core ld.lib.so init timer
|
||||
pci_decode platform_drv report_rom acpi_drv
|
||||
ahci_drv report_rom block_tester }
|
||||
|
||||
append qemu_args " -nographic -device ahci,id=ahci -boot d "
|
||||
append qemu_args " -drive id=disk,file=bin/ext2.raw,format=raw,if=none -device ide-hd,drive=disk,bus=ahci.0 "
|
||||
|
@ -16,19 +16,18 @@
|
||||
#define _AHCI__AHCI_H_
|
||||
|
||||
#include <block/request_stream.h>
|
||||
#include <os/attached_mmio.h>
|
||||
#include <platform_session/device.h>
|
||||
#include <os/reporter.h>
|
||||
#include <util/retry.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
static bool constexpr verbose = false;
|
||||
|
||||
namespace Ahci {
|
||||
using namespace Genode;
|
||||
|
||||
struct Missing_controller : Exception { };
|
||||
|
||||
class Platform;
|
||||
struct Protocol;
|
||||
struct Port;
|
||||
struct Port_base;
|
||||
@ -39,47 +38,70 @@ namespace Ahci {
|
||||
using block_count_t = Block::block_count_t;
|
||||
}
|
||||
|
||||
class Ahci::Platform
|
||||
{
|
||||
private :
|
||||
|
||||
Data _data;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Return base address and size of HBA device registers
|
||||
*/
|
||||
addr_t _mmio_base() const;
|
||||
|
||||
public:
|
||||
|
||||
Platform(Env &env) : _data(env) { };
|
||||
|
||||
/**
|
||||
* Register interrupt signal context
|
||||
*/
|
||||
void sigh_irq(Signal_context_capability sigh);
|
||||
void ack_irq();
|
||||
|
||||
/**
|
||||
* DMA
|
||||
*/
|
||||
Ram_dataspace_capability alloc_dma_buffer(size_t size);
|
||||
void free_dma_buffer(Ram_dataspace_capability ds);
|
||||
addr_t dma_addr(Ram_dataspace_capability);
|
||||
};
|
||||
|
||||
/**
|
||||
* HBA definitions
|
||||
*/
|
||||
struct Ahci::Hba : Ahci::Platform,
|
||||
Mmio
|
||||
struct Ahci::Hba : private Platform::Device::Mmio
|
||||
{
|
||||
Mmio::Delayer &_delayer;
|
||||
using Platform::Device::Mmio::base;
|
||||
using Index = Platform::Device::Mmio::Index;
|
||||
|
||||
Hba(Env &env, Mmio::Delayer &delayer)
|
||||
: Platform(env), Mmio(_mmio_base()), _delayer(delayer) { }
|
||||
Platform::Device::Irq _irq;
|
||||
|
||||
/*
|
||||
* mmio region of AHCI controller is always in BAR 5
|
||||
*/
|
||||
class No_bar : Genode::Exception { };
|
||||
|
||||
Index _mmio_index(Platform::Connection &platform)
|
||||
{
|
||||
unsigned index = 0;
|
||||
unsigned bar5 = ~0u;
|
||||
|
||||
platform.update();
|
||||
|
||||
platform.with_xml([&] (Xml_node & xml) {
|
||||
xml.with_optional_sub_node("device", [&] (Xml_node xml) {
|
||||
xml.for_each_sub_node("io_mem", [&] (Xml_node node) {
|
||||
unsigned bar = node.attribute_value("pci_bar", ~0u);
|
||||
if (bar == 5) bar5 = index;
|
||||
index++;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (bar5 == ~0u) {
|
||||
error("MMIO region of HBA (BAR 5) not found. Try adding\n"
|
||||
"<policy info=\"yes\" ...>\n"
|
||||
"to platform driver configuration.");
|
||||
throw No_bar();
|
||||
}
|
||||
|
||||
return { bar5 };
|
||||
}
|
||||
|
||||
Hba(Platform::Device & dev,
|
||||
Signal_context_capability cap,
|
||||
Platform::Connection & platform)
|
||||
:
|
||||
Platform::Device::Mmio(dev, _mmio_index(platform)),
|
||||
_irq(dev)
|
||||
{
|
||||
log("version: "
|
||||
"major=", Hex(read<Hba::Version::Major>()), " "
|
||||
"minor=", Hex(read<Hba::Version::Minor>()));
|
||||
log("command slots: ", command_slots());
|
||||
log("native command queuing: ", ncq() ? "yes" : "no");
|
||||
log("64-bit support: ", supports_64bit() ? "yes" : "no");
|
||||
|
||||
_irq.sigh(cap);
|
||||
|
||||
/* enable AHCI */
|
||||
write<Ghc::Ae>(1);
|
||||
|
||||
/* enable interrupts */
|
||||
write<Ghc::Ie>(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Host capabilites
|
||||
@ -116,7 +138,7 @@ struct Ahci::Hba : Ahci::Platform,
|
||||
void ack_irq()
|
||||
{
|
||||
write<Is>(read<Is>());
|
||||
Platform::ack_irq();
|
||||
_irq.ack();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,16 +157,24 @@ struct Ahci::Hba : Ahci::Platform,
|
||||
|
||||
struct Cap2 : Register<0x24, 32> { };
|
||||
|
||||
void init()
|
||||
bool port_implemented(unsigned port) const
|
||||
{
|
||||
/* enable AHCI */
|
||||
write<Ghc::Ae>(1);
|
||||
|
||||
/* enable interrupts */
|
||||
write<Ghc::Ie>(1);
|
||||
return read<Hba::Pi>() & (1u << port);
|
||||
}
|
||||
|
||||
Mmio::Delayer &delayer() { return _delayer; }
|
||||
template <typename FN>
|
||||
void handle_irq(FN const & fn)
|
||||
{
|
||||
unsigned port_list = read<Hba::Is>();
|
||||
while (port_list) {
|
||||
unsigned port = log2(port_list);
|
||||
port_list &= ~(1U << port);
|
||||
fn(port);
|
||||
}
|
||||
|
||||
/* clear status register */
|
||||
ack_irq();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -434,8 +464,10 @@ struct Ahci::Port_base : Mmio
|
||||
ATAPI_SIG_QEMU = 0xeb140000, /* will be fixed in Qemu */
|
||||
};
|
||||
|
||||
unsigned index { };
|
||||
Hba &hba;
|
||||
unsigned index { };
|
||||
Platform::Connection &plat;
|
||||
Hba &hba;
|
||||
Mmio::Delayer &delayer;
|
||||
|
||||
/**
|
||||
* Port signature
|
||||
@ -445,13 +477,14 @@ struct Ahci::Port_base : Mmio
|
||||
static constexpr addr_t offset() { return 0x100; }
|
||||
static constexpr size_t size() { return 0x80; }
|
||||
|
||||
Port_base(unsigned index, Hba &hba)
|
||||
Port_base(unsigned index, Platform::Connection &plat, Hba &hba,
|
||||
Mmio::Delayer &delayer)
|
||||
: Mmio(hba.base() + offset() + (index * size())),
|
||||
index(index), hba(hba) { }
|
||||
index(index), plat(plat), hba(hba), delayer(delayer) { }
|
||||
|
||||
bool implemented() const
|
||||
{
|
||||
return hba.read<Hba::Pi>() & (1u << index);
|
||||
return hba.port_implemented(index);
|
||||
}
|
||||
|
||||
bool ata() const { return read<Sig>() == ATA_SIG; }
|
||||
@ -488,6 +521,7 @@ struct Ahci::Port : private Port_base
|
||||
using Port_base::Register_set::Polling_timeout;
|
||||
using Port_base::index;
|
||||
using Port_base::hba;
|
||||
using Port_base::delayer;
|
||||
|
||||
struct Not_ready : Exception { };
|
||||
|
||||
@ -507,10 +541,10 @@ struct Ahci::Port : private Port_base
|
||||
addr_t device_info = 0;
|
||||
addr_t dma_base = 0; /* physical address of DMA memory */
|
||||
|
||||
Port(Protocol &protocol, Region_map &rm, Hba &hba,
|
||||
unsigned index)
|
||||
Port(Protocol &protocol, Region_map &rm, Platform::Connection & plat,
|
||||
Hba &hba, Mmio::Delayer &delayer, unsigned index)
|
||||
:
|
||||
Port_base(index, hba),
|
||||
Port_base(index, plat, hba, delayer),
|
||||
protocol(protocol), rm(rm)
|
||||
{
|
||||
reset();
|
||||
@ -519,7 +553,7 @@ struct Ahci::Port : private Port_base
|
||||
|
||||
stop();
|
||||
|
||||
wait_for(hba.delayer(), Cmd::Cr::Equal(0));
|
||||
wait_for(delayer, Cmd::Cr::Equal(0));
|
||||
|
||||
init();
|
||||
|
||||
@ -540,17 +574,17 @@ struct Ahci::Port : private Port_base
|
||||
{
|
||||
if (device_ds.valid()) {
|
||||
rm.detach((void *)cmd_list);
|
||||
hba.free_dma_buffer(device_ds);
|
||||
plat.free_dma_buffer(device_ds);
|
||||
}
|
||||
|
||||
if (cmd_ds.valid()) {
|
||||
rm.detach((void *)cmd_table);
|
||||
hba.free_dma_buffer(cmd_ds);
|
||||
plat.free_dma_buffer(cmd_ds);
|
||||
}
|
||||
|
||||
if (device_info_ds.valid()) {
|
||||
rm.detach((void*)device_info);
|
||||
hba.free_dma_buffer(device_info_ds);
|
||||
plat.free_dma_buffer(device_info_ds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,14 +713,14 @@ struct Ahci::Port : private Port_base
|
||||
return;
|
||||
|
||||
try {
|
||||
wait_for(hba.delayer(), Tfd::Sts_bsy::Equal(0));
|
||||
wait_for(delayer, Tfd::Sts_bsy::Equal(0));
|
||||
} catch (Polling_timeout) {
|
||||
error("HBA busy unable to start command processing.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wait_for(hba.delayer(), Tfd::Sts_drq::Equal(0));
|
||||
wait_for(delayer, Tfd::Sts_drq::Equal(0));
|
||||
} catch (Polling_timeout) {
|
||||
error("HBA in DRQ unable to start command processing.");
|
||||
return;
|
||||
@ -758,7 +792,7 @@ struct Ahci::Port : private Port_base
|
||||
throw Not_ready();
|
||||
},
|
||||
[&] {
|
||||
hba.delayer().usleep(1000);
|
||||
delayer.usleep(1000);
|
||||
status = read<Ssts>();
|
||||
}, 10);
|
||||
}
|
||||
@ -782,11 +816,11 @@ struct Ahci::Port : private Port_base
|
||||
warning("CMD.ST bit set during device reset --> unknown behavior");
|
||||
|
||||
write<Sctl::Det>(1);
|
||||
hba.delayer().usleep(1000);
|
||||
delayer.usleep(1000);
|
||||
write<Sctl::Det>(0);
|
||||
|
||||
try {
|
||||
wait_for(hba.delayer(), Ssts::Dec::Equal(Ssts::Dec::ESTABLISHED));
|
||||
wait_for(delayer, Ssts::Dec::Equal(Ssts::Dec::ESTABLISHED));
|
||||
} catch (Polling_timeout) {
|
||||
warning("Port reset failed");
|
||||
}
|
||||
@ -846,10 +880,10 @@ struct Ahci::Port : private Port_base
|
||||
|
||||
void setup_memory()
|
||||
{
|
||||
device_ds = hba.alloc_dma_buffer(0x1000);
|
||||
device_ds = plat.alloc_dma_buffer(0x1000, CACHED);
|
||||
|
||||
/* command list 1K */
|
||||
addr_t phys = hba.dma_addr(device_ds);
|
||||
addr_t phys = plat.dma_addr(device_ds);
|
||||
cmd_list = (addr_t)rm.attach(device_ds);
|
||||
command_list_base(phys);
|
||||
|
||||
@ -861,14 +895,14 @@ struct Ahci::Port : private Port_base
|
||||
* (FIS receive running) to clear
|
||||
*/
|
||||
write<Cmd::Fre>(0);
|
||||
wait_for(hba.delayer(), Cmd::Fr::Equal(0));
|
||||
wait_for(delayer, Cmd::Fr::Equal(0));
|
||||
fis_rcv_base(phys + 1024);
|
||||
|
||||
/* command table */
|
||||
size_t cmd_size = align_addr(cmd_slots * Command_table::size(), 12);
|
||||
cmd_ds = hba.alloc_dma_buffer(cmd_size);
|
||||
cmd_ds = plat.alloc_dma_buffer(cmd_size, CACHED);
|
||||
cmd_table = (addr_t)rm.attach(cmd_ds);
|
||||
phys = hba.dma_addr(cmd_ds);
|
||||
phys = plat.dma_addr(cmd_ds);
|
||||
|
||||
/* set command table addresses in command list */
|
||||
for (unsigned i = 0; i < cmd_slots; i++) {
|
||||
@ -877,8 +911,8 @@ struct Ahci::Port : private Port_base
|
||||
}
|
||||
|
||||
/* dataspace for device info */
|
||||
device_info_ds = hba.alloc_dma_buffer(0x1000);
|
||||
device_info_dma_addr = hba.dma_addr(device_info_ds);
|
||||
device_info_ds = plat.alloc_dma_buffer(0x1000, CACHED);
|
||||
device_info_dma_addr = plat.dma_addr(device_info_ds);
|
||||
device_info = rm.attach(device_info_ds);
|
||||
}
|
||||
|
||||
@ -921,15 +955,15 @@ struct Ahci::Port : private Port_base
|
||||
{
|
||||
if (dma_base) return Ram_dataspace_capability();
|
||||
|
||||
Ram_dataspace_capability dma = hba.alloc_dma_buffer(size);
|
||||
dma_base = hba.dma_addr(dma);
|
||||
Ram_dataspace_capability dma = plat.alloc_dma_buffer(size, CACHED);
|
||||
dma_base = plat.dma_addr(dma);
|
||||
return dma;
|
||||
}
|
||||
|
||||
void free_buffer(Ram_dataspace_capability ds)
|
||||
{
|
||||
dma_base = 0;
|
||||
hba.free_dma_buffer(ds);
|
||||
plat.free_dma_buffer(ds);
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -227,9 +227,9 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
|
||||
table.fis.identify_device();
|
||||
port.execute(0);
|
||||
|
||||
port.wait_for_any(port.hba.delayer(), Port::Is::Dss::Equal(1),
|
||||
Port::Is::Pss::Equal(1),
|
||||
Port::Is::Dhrs::Equal(1));
|
||||
port.wait_for_any(port.delayer, Port::Is::Dss::Equal(1),
|
||||
Port::Is::Pss::Equal(1),
|
||||
Port::Is::Dhrs::Equal(1));
|
||||
|
||||
_identity.construct(port.device_info);
|
||||
serial.construct(*_identity);
|
||||
|
@ -93,21 +93,21 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
|
||||
[&] {
|
||||
|
||||
_start_unit(port);
|
||||
port.wait_for_any(port.hba.delayer(),
|
||||
port.wait_for_any(port.delayer,
|
||||
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
|
||||
Port::Is::Dhrs::Equal(1));
|
||||
port.ack_irq();
|
||||
|
||||
/* read sense */
|
||||
_read_sense(port);
|
||||
port.wait_for_any(port.hba.delayer(),
|
||||
port.wait_for_any(port.delayer,
|
||||
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
|
||||
Port::Is::Dhrs::Equal(1));
|
||||
port.ack_irq();
|
||||
|
||||
/* test unit ready */
|
||||
_test_unit_ready(port);
|
||||
port.wait_for(port.hba.delayer(), Port::Is::Dhrs::Equal(1));
|
||||
port.wait_for(port.delayer, Port::Is::Dhrs::Equal(1));
|
||||
port.ack_irq();
|
||||
|
||||
Device_fis f(port.fis_base);
|
||||
@ -116,7 +116,7 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
|
||||
throw Port::Polling_timeout();
|
||||
|
||||
_read_capacity(port);
|
||||
port.wait_for_any(port.hba.delayer(),
|
||||
port.wait_for_any(port.delayer,
|
||||
Port::Is::Dss::Equal(1), Port::Is::Pss::Equal(1),
|
||||
Port::Is::Dhrs::Equal(1));
|
||||
port.ack_irq();
|
||||
|
@ -55,39 +55,30 @@ class Ahci::Driver : Noncopyable
|
||||
|
||||
struct Timer_delayer : Mmio::Delayer, Timer::Connection
|
||||
{
|
||||
Timer_delayer(Env &env)
|
||||
: Timer::Connection(env) { }
|
||||
using Timer::Connection::Connection;
|
||||
|
||||
void usleep(uint64_t us) override { Timer::Connection::usleep(us); }
|
||||
} _delayer { _env };
|
||||
|
||||
Hba _hba { _env, _delayer };
|
||||
Signal_handler<Driver> _handler { _env.ep(), *this, &Driver::handle_irq };
|
||||
|
||||
Platform::Connection _plat { _env };
|
||||
Platform::Device _device { _plat };
|
||||
Hba _hba { _device, _handler, _plat };
|
||||
|
||||
Constructible<Ata::Protocol> _ata[MAX_PORTS];
|
||||
Constructible<Atapi::Protocol> _atapi[MAX_PORTS];
|
||||
Constructible<Port> _ports[MAX_PORTS];
|
||||
|
||||
Signal_handler<Driver> _irq { _env.ep(), *this, &Driver::handle_irq };
|
||||
bool _enable_atapi;
|
||||
|
||||
void _info()
|
||||
{
|
||||
log("version: "
|
||||
"major=", Hex(_hba.read<Hba::Version::Major>()), " "
|
||||
"minor=", Hex(_hba.read<Hba::Version::Minor>()));
|
||||
log("command slots: ", _hba.command_slots());
|
||||
log("native command queuing: ", _hba.ncq() ? "yes" : "no");
|
||||
log("64-bit support: ", _hba.supports_64bit() ? "yes" : "no");
|
||||
}
|
||||
bool _enable_atapi;
|
||||
|
||||
void _scan_ports(Region_map &rm)
|
||||
{
|
||||
log("number of ports: ", _hba.port_count(), " pi: ",
|
||||
Hex(_hba.read<Hba::Pi>()));
|
||||
log("number of ports: ", _hba.port_count());
|
||||
|
||||
for (unsigned index = 0; index < MAX_PORTS; index++) {
|
||||
|
||||
Port_base port(index, _hba);
|
||||
Port_base port(index, _plat, _hba, _delayer);
|
||||
|
||||
if (port.implemented() == false)
|
||||
continue;
|
||||
@ -96,7 +87,8 @@ class Ahci::Driver : Noncopyable
|
||||
if (port.ata()) {
|
||||
try {
|
||||
_ata[index].construct();
|
||||
_ports[index].construct(*_ata[index], rm, _hba, index);
|
||||
_ports[index].construct(*_ata[index], rm, _plat,
|
||||
_hba, _delayer, index);
|
||||
enabled = true;
|
||||
} catch (...) { }
|
||||
|
||||
@ -104,7 +96,8 @@ class Ahci::Driver : Noncopyable
|
||||
} else if (port.atapi() && _enable_atapi) {
|
||||
try {
|
||||
_atapi[index].construct();
|
||||
_ports[index].construct(*_atapi[index], rm, _hba, index);
|
||||
_ports[index].construct(*_atapi[index], rm, _plat,
|
||||
_hba, _delayer, index);
|
||||
enabled = true;
|
||||
} catch (...) { }
|
||||
|
||||
@ -121,14 +114,6 @@ class Ahci::Driver : Noncopyable
|
||||
Driver(Env &env, Dispatch &dispatch, bool support_atapi)
|
||||
: _env(env), _dispatch(dispatch), _enable_atapi(support_atapi)
|
||||
{
|
||||
_info();
|
||||
|
||||
/* register irq handler */
|
||||
_hba.sigh_irq(_irq);
|
||||
|
||||
/* initialize HBA (IRQs, memory) */
|
||||
_hba.init();
|
||||
|
||||
/* search for devices */
|
||||
_scan_ports(env.rm());
|
||||
}
|
||||
@ -138,22 +123,15 @@ class Ahci::Driver : Noncopyable
|
||||
*/
|
||||
void handle_irq()
|
||||
{
|
||||
unsigned port_list = _hba.read<Hba::Is>();
|
||||
while (port_list) {
|
||||
unsigned port = log2(port_list);
|
||||
port_list &= ~(1U << port);
|
||||
|
||||
/* ack irq */
|
||||
_hba.handle_irq([&] (unsigned port) {
|
||||
if (_ports[port].constructed())
|
||||
_ports[port]->handle_irq();
|
||||
|
||||
/* handle (pending) requests */
|
||||
_dispatch.session(port);
|
||||
}
|
||||
|
||||
/* clear status register */
|
||||
_hba.ack_irq();
|
||||
});
|
||||
}
|
||||
|
||||
Port &port(Session_label const &label, Session_policy const &policy)
|
||||
{
|
||||
/* try read device port number attribute */
|
||||
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for PCI-bus platforms
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2020-01-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include <ahci.h>
|
||||
|
||||
Ahci::Data::Data(Env &env)
|
||||
: env(env)
|
||||
{
|
||||
pci_device_cap = pci.with_upgrade(
|
||||
[&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE,
|
||||
CLASS_MASK); });
|
||||
|
||||
if (!pci_device_cap.valid()) {
|
||||
throw Missing_controller();
|
||||
}
|
||||
|
||||
/* construct pci client */
|
||||
pci_device.construct(pci_device_cap);
|
||||
log("AHCI found ("
|
||||
"vendor: ", Hex(pci_device->vendor_id()), " "
|
||||
"device: ", Hex(pci_device->device_id()), " "
|
||||
"class: ", Hex(pci_device->class_code()), ")");
|
||||
|
||||
/* map base address of controller */
|
||||
Io_mem_session_capability iomem_cap = pci_device->io_mem(pci_device->phys_bar_to_virt(AHCI_BASE_ID));
|
||||
iomem.construct(env.rm(), Io_mem_session_client(iomem_cap).dataspace());
|
||||
|
||||
uint16_t cmd = (uint16_t)pci_device->config_read(PCI_CMD, ::Platform::Device::ACCESS_16BIT);
|
||||
cmd |= 0x2; /* respond to memory space accesses */
|
||||
cmd |= 0x4; /* enable bus master */
|
||||
_config_write(PCI_CMD, cmd, ::Platform::Device::ACCESS_16BIT);
|
||||
|
||||
irq.construct(pci_device->irq(0));
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
** Platform interface **
|
||||
************************/
|
||||
|
||||
Genode::addr_t Ahci::Platform::_mmio_base() const
|
||||
{
|
||||
return addr_t(_data.iomem->local_addr<addr_t>());
|
||||
}
|
||||
|
||||
|
||||
void Ahci::Platform::sigh_irq(Signal_context_capability sigh)
|
||||
{
|
||||
_data.irq->sigh(sigh);
|
||||
ack_irq();
|
||||
}
|
||||
|
||||
|
||||
void Ahci::Platform::ack_irq() { _data.irq->ack_irq(); }
|
||||
|
||||
|
||||
Genode::Ram_dataspace_capability Ahci::Platform::alloc_dma_buffer(size_t size)
|
||||
{
|
||||
size_t donate = size;
|
||||
|
||||
return retry<Genode::Out_of_ram>(
|
||||
[&] () {
|
||||
return retry<Genode::Out_of_caps>(
|
||||
[&] () { return _data.pci.alloc_dma_buffer(size, Genode::UNCACHED); },
|
||||
[&] () { _data.pci.upgrade_caps(2); });
|
||||
},
|
||||
[&] () {
|
||||
_data.pci.upgrade_ram(donate);
|
||||
donate = donate * 2 > size ? 4096 : donate * 2;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Ahci::Platform::free_dma_buffer(Genode::Ram_dataspace_capability ds)
|
||||
{
|
||||
_data.pci.free_dma_buffer(ds);
|
||||
}
|
||||
|
||||
|
||||
Genode::addr_t Ahci::Platform::dma_addr(Genode::Ram_dataspace_capability ds)
|
||||
{
|
||||
return _data.pci.dma_addr(ds);
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
#ifndef _AHCI__SPEC__X86__PLATFORM_H_
|
||||
#define _AHCI__SPEC__X86__PLATFORM_H_
|
||||
/*
|
||||
* \brief Driver for PCI-bus platforms
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2020-01-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include <irq_session/connection.h>
|
||||
#include <legacy/x86/platform_session/connection.h>
|
||||
#include <legacy/x86/platform_device/client.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
namespace Ahci {
|
||||
struct Data;
|
||||
using namespace Genode;
|
||||
}
|
||||
|
||||
struct Ahci::Data
|
||||
{
|
||||
enum Pci_config {
|
||||
CLASS_MASS_STORAGE = 0x10000u,
|
||||
SUBCLASS_AHCI = 0x600u,
|
||||
CLASS_MASK = 0xffff00u,
|
||||
AHCI_DEVICE = CLASS_MASS_STORAGE | SUBCLASS_AHCI,
|
||||
AHCI_BASE_ID = 0x5, /* resource id of ahci base addr <bar 5> */
|
||||
PCI_CMD = 0x4,
|
||||
};
|
||||
|
||||
Genode::Env &env;
|
||||
|
||||
Platform::Connection pci { env };
|
||||
Platform::Device_capability pci_device_cap { };
|
||||
Constructible<Platform::Device_client> pci_device { };
|
||||
Constructible<Irq_session_client> irq { };
|
||||
Constructible<Attached_dataspace> iomem { };
|
||||
|
||||
Data(Env &env);
|
||||
|
||||
void _config_write(uint8_t op, uint16_t cmd,
|
||||
Platform::Device::Access_size width)
|
||||
{
|
||||
size_t donate = 4096;
|
||||
retry<Platform::Out_of_ram>(
|
||||
[&] () {
|
||||
retry<Platform::Out_of_caps>(
|
||||
[&] () { pci_device->config_write(op, cmd, width); },
|
||||
[&] () { pci.upgrade_caps(2); });
|
||||
},
|
||||
[&] () {
|
||||
pci.upgrade_ram(donate);
|
||||
donate *= 2;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* _AHCI__SPEC__X86__PLATFORM_H_ */
|
@ -1,7 +0,0 @@
|
||||
TARGET = ahci_drv
|
||||
REQUIRES = x86
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/drivers/ahci/spec/x86
|
||||
|
||||
include $(REP_DIR)/src/drivers/ahci/target.inc
|
||||
|
@ -1,8 +0,0 @@
|
||||
SRC_CC += main.cc platform.cc
|
||||
INC_DIR += $(REP_DIR)/src/drivers/ahci
|
||||
LIBS += base
|
||||
|
||||
CC_CXX_WARN_STRICT_CONVERSION =
|
||||
|
||||
vpath platform.cc $(PRG_DIR)
|
||||
vpath %.cc $(REP_DIR)/src/drivers/ahci
|
8
repos/os/src/drivers/ahci/target.mk
Normal file
8
repos/os/src/drivers/ahci/target.mk
Normal file
@ -0,0 +1,8 @@
|
||||
TARGET = ahci_drv
|
||||
SRC_CC += main.cc
|
||||
INC_DIR += $(PRG_DIR)
|
||||
LIBS += base
|
||||
|
||||
CC_CXX_WARN_STRICT_CONVERSION =
|
||||
|
||||
vpath %.cc $(PRG_DIR)
|
Loading…
x
Reference in New Issue
Block a user