mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
sd_card: get rid of wait_for_irq
Most implementations use a Signal_handler now to acknowledge the packet instead of waiting for the transfer completion. The exceptions to that are the non-DMA implementations for RPI and PL180 Ref #2206
This commit is contained in:
parent
9e1f3259c5
commit
b33c35a003
@ -24,13 +24,30 @@
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
namespace Block {
|
||||
class Driver_session_base;
|
||||
class Driver_session;
|
||||
class Driver;
|
||||
struct Driver_factory;
|
||||
};
|
||||
|
||||
|
||||
class Block::Driver_session : public Block::Session_rpc_object
|
||||
struct Block::Driver_session_base
|
||||
{
|
||||
/**
|
||||
* Acknowledges a packet processed by the driver to the client
|
||||
*
|
||||
* \param packet the packet to acknowledge
|
||||
* \param success indicated whether the processing was successful
|
||||
*
|
||||
* \throw Ack_congestion
|
||||
*/
|
||||
virtual void ack_packet(Packet_descriptor &packet,
|
||||
bool success) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Block::Driver_session : public Driver_session_base,
|
||||
public Block::Session_rpc_object
|
||||
{
|
||||
public:
|
||||
|
||||
@ -44,17 +61,6 @@ class Block::Driver_session : public Block::Session_rpc_object
|
||||
Driver_session(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Rpc_entrypoint &ep)
|
||||
: Session_rpc_object(tx_ds, ep) { }
|
||||
|
||||
/**
|
||||
* Acknowledges a packet processed by the driver to the client
|
||||
*
|
||||
* \param packet the packet to acknowledge
|
||||
* \param success indicated whether the processing was successful
|
||||
*
|
||||
* \throw Ack_congestion
|
||||
*/
|
||||
virtual void ack_packet(Packet_descriptor &packet,
|
||||
bool success) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -65,7 +71,7 @@ class Block::Driver
|
||||
{
|
||||
private:
|
||||
|
||||
Driver_session *_session = nullptr;
|
||||
Driver_session_base *_session = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
@ -214,7 +220,7 @@ class Block::Driver
|
||||
*
|
||||
* Session might get used to acknowledge requests.
|
||||
*/
|
||||
void session(Driver_session *session) {
|
||||
void session(Driver_session_base *session) {
|
||||
if (!(_session = session)) session_invalidated(); }
|
||||
|
||||
/**
|
||||
|
@ -2,13 +2,13 @@
|
||||
# Check for platform support
|
||||
#
|
||||
|
||||
if {[expr ![have_spec exynos5] && \
|
||||
![have_spec omap4] && \
|
||||
![have_spec imx6] && \
|
||||
![have_spec imx53] && \
|
||||
![have_spec pl180] && \
|
||||
![have_spec rpi]]} \
|
||||
{
|
||||
if {[have_spec pl180]} { set buffer_size_kib [expr 12 * 1024]
|
||||
} elseif {[have_spec imx6]} { set buffer_size_kib [expr 1024]
|
||||
} elseif {[have_spec imx53]} { set buffer_size_kib [expr 1024]
|
||||
} elseif {[have_spec rpi]} { set buffer_size_kib [expr 4 * 1024]
|
||||
} elseif {[have_spec omap4]} { set buffer_size_kib [expr 4 * 1024]
|
||||
} elseif {[have_spec exynos5]} { set buffer_size_kib [expr 1024]
|
||||
} else {
|
||||
puts "\n Run script is not supported on this platform. \n";
|
||||
exit 0;
|
||||
}
|
||||
@ -29,6 +29,7 @@ append_platform_drv_build_components
|
||||
build $build_components
|
||||
create_boot_directory
|
||||
|
||||
|
||||
#
|
||||
# Install the config
|
||||
#
|
||||
@ -51,6 +52,7 @@ append config {
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
|
||||
append config {
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
@ -58,7 +60,11 @@ append config {
|
||||
</start>
|
||||
<start name="sd_card_bench">
|
||||
<resource name="RAM" quantum="16M"/>
|
||||
<provides><service name="Block"/></provides>
|
||||
<provides><service name="Block"/></provides>}
|
||||
|
||||
append config "<config buffer_size_kib=\"$buffer_size_kib\"/>"
|
||||
|
||||
append config {
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <base/log.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <block/component.h>
|
||||
#include <os/server.h>
|
||||
#include <regulator_session/connection.h>
|
||||
|
||||
@ -32,7 +31,8 @@ namespace Block {
|
||||
}
|
||||
|
||||
|
||||
class Block::Sdhci_driver : public Block::Driver
|
||||
class Block::Sdhci_driver : public Block::Driver,
|
||||
public Sd_ack_handler
|
||||
{
|
||||
private:
|
||||
|
||||
@ -81,7 +81,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
_clock_regulator(env),
|
||||
_mmio(MSH_BASE, MSH_SIZE),
|
||||
_controller(env.ep(), (addr_t)_mmio.local_addr<void>(),
|
||||
_delayer, true),
|
||||
_delayer, *this, true),
|
||||
_use_dma(true)
|
||||
{
|
||||
Sd_card::Card_info const card_info = _controller.card_info();
|
||||
@ -90,6 +90,9 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
Genode::log("capacity: ", card_info.capacity_mb(), " MiB");
|
||||
}
|
||||
|
||||
void handle_ack(Block::Packet_descriptor pkt, bool success) {
|
||||
ack_packet(pkt, success); }
|
||||
|
||||
|
||||
/*****************************
|
||||
** Block::Driver interface **
|
||||
@ -110,14 +113,12 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
return o;
|
||||
}
|
||||
|
||||
void read_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
void read_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.read_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.read_blocks_dma(block_number, block_count, phys, packet);
|
||||
}
|
||||
|
||||
void write_dma(Block::sector_t block_number,
|
||||
@ -125,9 +126,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.write_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.write_blocks_dma(block_number, block_count, phys, packet);
|
||||
}
|
||||
|
||||
bool dma_enabled() { return _use_dma; }
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <irq_session/connection.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <util/mmio.h>
|
||||
#include <block/component.h>
|
||||
|
||||
#include <sd_card.h>
|
||||
|
||||
@ -268,6 +269,11 @@ struct Dwmmc : Genode::Mmio
|
||||
};
|
||||
|
||||
|
||||
struct Sd_ack_handler {
|
||||
virtual void handle_ack(Block::Packet_descriptor pkt, bool success) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Exynos5_msh_controller : private Dwmmc, Sd_card::Host_controller
|
||||
{
|
||||
private:
|
||||
@ -325,9 +331,16 @@ struct Exynos5_msh_controller : private Dwmmc, Sd_card::Host_controller
|
||||
Delayer &_delayer;
|
||||
Sd_card::Card_info _card_info;
|
||||
|
||||
Genode::Irq_connection _irq;
|
||||
Genode::Signal_receiver _irq_rec;
|
||||
Genode::Signal_context _irq_ctx;
|
||||
struct Block_transfer
|
||||
{
|
||||
Block::Packet_descriptor packet;
|
||||
bool pending = false;
|
||||
|
||||
} _block_transfer;
|
||||
|
||||
Sd_ack_handler &_ack_handler;
|
||||
Genode::Signal_handler<Exynos5_msh_controller> _irq_handler;
|
||||
Genode::Irq_connection _irq;
|
||||
|
||||
Sd_card::Card_info _init()
|
||||
{
|
||||
@ -473,51 +486,42 @@ struct Exynos5_msh_controller : private Dwmmc, Sd_card::Host_controller
|
||||
return true;
|
||||
}
|
||||
|
||||
void _wait_for_irq()
|
||||
void _handle_irq()
|
||||
{
|
||||
/*
|
||||
* Acknowledge the IRQ first to implicitly activate
|
||||
* receiving of further IRQ signals on the first usage
|
||||
* of this method.
|
||||
*/
|
||||
_irq.ack_irq();
|
||||
_irq_rec.wait_for_signal();
|
||||
}
|
||||
|
||||
bool _wait_for_transfer_complete()
|
||||
{
|
||||
while (1) {
|
||||
_wait_for_irq();
|
||||
if (!_block_transfer.pending) {
|
||||
return; }
|
||||
|
||||
if (read<Rintsts::Data_transfer_over>()) {
|
||||
write<Rintsts>(~0U);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (read<Rintsts::Response_error>()) {
|
||||
Genode::error("Response error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read<Rintsts::Data_read_timeout>()) {
|
||||
Genode::error("Data read timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read<Rintsts::Data_crc_error>()) {
|
||||
Genode::error("CRC error");
|
||||
return false;
|
||||
bool success = false;
|
||||
if (read<Rintsts::Response_error>()) {
|
||||
Genode::error("Response error");
|
||||
}
|
||||
if (read<Rintsts::Data_read_timeout>()) {
|
||||
Genode::error("Data read timeout");
|
||||
}
|
||||
if (read<Rintsts::Data_crc_error>()) {
|
||||
Genode::error("CRC error");
|
||||
}
|
||||
if (read<Rintsts::Data_transfer_over>()) {
|
||||
write<Rintsts>(~0U);
|
||||
if (!_issue_command(Sd_card::Stop_transmission())) {
|
||||
Genode::error("unable to stop transmission");
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
_block_transfer.pending = false;
|
||||
_ack_handler.handle_ack(_block_transfer.packet, success);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
enum { IRQ_NUMBER = Genode::Board_base::SDMMC0_IRQ };
|
||||
|
||||
Exynos5_msh_controller(Server::Entrypoint &ep,
|
||||
Genode::addr_t const mmio_base, Delayer &delayer,
|
||||
Sd_ack_handler &ack_handler,
|
||||
bool use_dma)
|
||||
: Dwmmc(mmio_base),
|
||||
_idmac_desc_ds(Genode::env()->ram_session(),
|
||||
@ -525,13 +529,15 @@ struct Exynos5_msh_controller : private Dwmmc, Sd_card::Host_controller
|
||||
Genode::UNCACHED),
|
||||
_idmac_desc(_idmac_desc_ds.local_addr<Idmac_desc>()),
|
||||
_idmac_desc_phys(Genode::Dataspace_client(_idmac_desc_ds.cap()).phys_addr()),
|
||||
_delayer(delayer), _card_info(_init()), _irq(IRQ_NUMBER)
|
||||
_delayer(delayer), _card_info(_init()),
|
||||
_ack_handler(ack_handler),
|
||||
_irq_handler(ep, *this, &Exynos5_msh_controller::_handle_irq),
|
||||
_irq(IRQ_NUMBER)
|
||||
{
|
||||
_irq.sigh(_irq_rec.manage(&_irq_ctx));
|
||||
_irq.sigh(_irq_handler);
|
||||
_irq.ack_irq();
|
||||
}
|
||||
|
||||
~Exynos5_msh_controller() { _irq_rec.dissolve(&_irq_ctx); }
|
||||
|
||||
bool _issue_command(Sd_card::Command_base const &command)
|
||||
{
|
||||
if (verbose)
|
||||
@ -661,49 +667,44 @@ struct Exynos5_msh_controller : private Dwmmc, Sd_card::Host_controller
|
||||
return _card_info;
|
||||
}
|
||||
|
||||
bool read_blocks_dma(Block::sector_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys)
|
||||
void read_blocks_dma(Block::sector_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys, Block::Packet_descriptor pkt)
|
||||
{
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
if (!_setup_idmac_descriptor_table(block_count, buffer_phys))
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
if (!_issue_command(Sd_card::Read_multiple_block(block_number))) {
|
||||
Genode::error("Read_multiple_block failed, Status: ",
|
||||
Genode::Hex(read<Status>()));
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
|
||||
bool complete = _wait_for_transfer_complete();
|
||||
|
||||
if (!_issue_command(Sd_card::Stop_transmission())) {
|
||||
Genode::error("unable to stop transmission");
|
||||
return false;
|
||||
}
|
||||
|
||||
return complete;
|
||||
}
|
||||
|
||||
bool write_blocks_dma(Block::sector_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys)
|
||||
void write_blocks_dma(Block::sector_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys, Block::Packet_descriptor pkt)
|
||||
{
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
if (!_setup_idmac_descriptor_table(block_count, buffer_phys))
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
if (!_issue_command(Sd_card::Write_multiple_block(block_number))) {
|
||||
Genode::error("Read_multiple_block failed, Status: ",
|
||||
Genode::Hex(read<Status>()));
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
|
||||
bool complete = _wait_for_transfer_complete();
|
||||
|
||||
if (!_issue_command(Sd_card::Stop_transmission())) {
|
||||
Genode::error("unable to stop transmission");
|
||||
return false;
|
||||
}
|
||||
|
||||
return complete;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* _DRIVERS__SD_CARD__SPEC__EXYNOS5__DWMMC_H_ */
|
||||
|
@ -14,123 +14,7 @@
|
||||
#ifndef _DRIVER_H_
|
||||
#define _DRIVER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <base/log.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <block/component.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <os/server.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sdhc.h>
|
||||
|
||||
namespace Block {
|
||||
using namespace Genode;
|
||||
class Sdhci_driver;
|
||||
}
|
||||
|
||||
|
||||
class Block::Sdhci_driver : public Block::Driver
|
||||
{
|
||||
private:
|
||||
|
||||
struct Timer_delayer : Timer::Connection, Mmio::Delayer
|
||||
{
|
||||
/**
|
||||
* Implementation of 'Delayer' interface
|
||||
*/
|
||||
void usleep(unsigned us) { Timer::Connection::usleep(us); }
|
||||
} _delayer;
|
||||
|
||||
Attached_io_mem_dataspace _sdhc_mmio;
|
||||
Sdhc _controller;
|
||||
|
||||
bool const _use_dma;
|
||||
|
||||
public:
|
||||
|
||||
Sdhci_driver(Env &)
|
||||
:
|
||||
_sdhc_mmio(Board_base::SDHC_MMIO_BASE, Board_base::SDHC_MMIO_SIZE),
|
||||
_controller((addr_t)_sdhc_mmio.local_addr<void>(),
|
||||
Board_base::SDHC_IRQ, _delayer, true),
|
||||
_use_dma(true)
|
||||
{
|
||||
Sd_card::Card_info const card_info = _controller.card_info();
|
||||
|
||||
log("SD card detected");
|
||||
log("capacity: ", card_info.capacity_mb(), " MiB");
|
||||
}
|
||||
|
||||
|
||||
/*****************************
|
||||
** Block::Driver interface **
|
||||
*****************************/
|
||||
|
||||
Genode::size_t block_size() { return 512; }
|
||||
|
||||
virtual Block::sector_t block_count()
|
||||
{
|
||||
return _controller.card_info().capacity_mb() * 1024 * 2;
|
||||
}
|
||||
|
||||
Block::Session::Operations ops()
|
||||
{
|
||||
Block::Session::Operations o;
|
||||
o.set_operation(Block::Packet_descriptor::READ);
|
||||
o.set_operation(Block::Packet_descriptor::WRITE);
|
||||
return o;
|
||||
}
|
||||
|
||||
void read(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
char *out_buffer,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.read_blocks(block_number, block_count, out_buffer))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
}
|
||||
|
||||
void write(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
char const *buffer,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.write_blocks(block_number, block_count, buffer))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
}
|
||||
|
||||
void read_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.read_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
}
|
||||
|
||||
void write_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.write_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
}
|
||||
|
||||
bool dma_enabled() { return _use_dma; }
|
||||
|
||||
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) {
|
||||
return Genode::env()->ram_session()->alloc(size, UNCACHED); }
|
||||
|
||||
void free_dma_buffer(Genode::Ram_dataspace_capability c) {
|
||||
return Genode::env()->ram_session()->free(c); }
|
||||
};
|
||||
|
||||
#endif /* _DRIVER_H_ */
|
||||
|
@ -49,14 +49,14 @@ int Sdhc::_wait_for_card_ready_mbw()
|
||||
|
||||
/* send command as soon as the host allows it */
|
||||
if (_wait_for_cmd_allowed()) { return -1; }
|
||||
write<Cmdarg>(cmdarg);
|
||||
write<Xfertyp>(xfertyp);
|
||||
Mmio::write<Cmdarg>(cmdarg);
|
||||
Mmio::write<Xfertyp>(xfertyp);
|
||||
|
||||
/* wait for command completion */
|
||||
if (_wait_for_cmd_complete()) { return -1; }
|
||||
|
||||
/* check for errors */
|
||||
R1_response_0::access_t const resp = read<Cmdrsp0>();
|
||||
R1_response_0::access_t const resp = Mmio::read<Cmdrsp0>();
|
||||
if (R1_response_0::Error::get(resp)) {
|
||||
error("Reading card status after multiblock write failed");
|
||||
return -1;
|
||||
@ -72,7 +72,7 @@ int Sdhc::_wait_for_card_ready_mbw()
|
||||
int Sdhc::_stop_transmission()
|
||||
{
|
||||
/* write argument register */
|
||||
write<Cmdarg>(0);
|
||||
Mmio::write<Cmdarg>(0);
|
||||
|
||||
/* write command register */
|
||||
Xfertyp::access_t xfertyp = 0;
|
||||
@ -82,7 +82,7 @@ int Sdhc::_stop_transmission()
|
||||
Xfertyp::Cicen::set(xfertyp, 1);
|
||||
Xfertyp::Rsptyp::set(xfertyp, Xfertyp::Rsptyp::_48BIT_BUSY);
|
||||
_stop_transmission_finish_xfertyp(xfertyp);
|
||||
write<Xfertyp>(xfertyp);
|
||||
Mmio::write<Xfertyp>(xfertyp);
|
||||
|
||||
/* wait for command completion */
|
||||
if (_wait_for_cmd_complete()) { return -1; }
|
||||
@ -90,8 +90,14 @@ int Sdhc::_stop_transmission()
|
||||
}
|
||||
|
||||
|
||||
int Sdhc::_wait_for_cmd_complete_mb(bool const r)
|
||||
void Sdhc::_handle_irq()
|
||||
{
|
||||
_irq.ack_irq();
|
||||
|
||||
/* the handler is only for block transfers, on other commands we poll */
|
||||
if (!_block_transfer.pending) {
|
||||
return; }
|
||||
|
||||
/*
|
||||
* The host signals on multi-block transfers seem to be broken.
|
||||
* Synchronizing to "Transfer Complete" before returning from transfers
|
||||
@ -99,38 +105,33 @@ int Sdhc::_wait_for_cmd_complete_mb(bool const r)
|
||||
* done with other controllers - isn't sufficient. Instead, both "Transfer
|
||||
* Complete" and "Command Complete" must be gathered.
|
||||
*/
|
||||
Irqstat::access_t constexpr irq_goal =
|
||||
Irq::Cc::reg_mask() | Irq::Tc::reg_mask();
|
||||
|
||||
/* wait for a first signal */
|
||||
_wait_for_irq();
|
||||
Irqstat::access_t const irq = read<Irqstat>();
|
||||
|
||||
/*
|
||||
* Poll for missing signal because interrupts are edge-triggered
|
||||
* and could thus got lost in the meantime.
|
||||
*/
|
||||
if (irq != irq_goal) {
|
||||
if (!wait_for<Irqstat>(irq_goal, _delayer)) {
|
||||
error("Completion host signal timed out");
|
||||
return -1;
|
||||
}
|
||||
if (!wait_for<Irqstat::Cc>(1, _delayer) ||
|
||||
!wait_for<Irqstat::Tc>(1, _delayer))
|
||||
{
|
||||
error("Completion host signal timed out");
|
||||
throw -1;
|
||||
}
|
||||
/* acknowledge completion signals */
|
||||
write<Irqstat>(irq_goal);
|
||||
return _wait_for_cmd_complete_mb_finish(r);
|
||||
Irqstat::access_t irqstat = 0;
|
||||
Irqstat::Cc::set(irqstat, 1);
|
||||
Irqstat::Tc::set(irqstat, 1);
|
||||
Mmio::write<Irqstat>(irqstat);
|
||||
|
||||
if (_wait_for_cmd_complete_mb_finish(_block_transfer.read)) {
|
||||
throw -1; }
|
||||
|
||||
_block_transfer.pending = false;
|
||||
ack_packet(_block_transfer.packet, true);
|
||||
}
|
||||
|
||||
|
||||
int Sdhc::_wait_for_cmd_complete()
|
||||
{
|
||||
/* wait for "Command Completion" signal and acknowledge it */
|
||||
_wait_for_irq();
|
||||
if (read<Irqstat>() != Irqstat::Cc::reg_mask()) {
|
||||
error("received unexpected host signal");
|
||||
if (!wait_for<Irqstat::Cc>(1, _delayer, 200, 5000)) {
|
||||
error("command timed out");
|
||||
return -1;
|
||||
}
|
||||
write<Irqstat>(Irqstat::Cc::reg_mask());
|
||||
Mmio::write<Irqstat>(Irqstat::Cc::reg_mask());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -169,22 +170,21 @@ bool Sdhc::_issue_command(Command_base const & command)
|
||||
}
|
||||
/* version-dependent transfer settings and issue command */
|
||||
_issue_cmd_finish_xfertyp(xfertyp, transfer, multiblock, reading);
|
||||
write<Cmdarg>(command.arg);
|
||||
write<Xfertyp>(xfertyp);
|
||||
Mmio::write<Cmdarg>(command.arg);
|
||||
Mmio::write<Xfertyp>(xfertyp);
|
||||
|
||||
/* wait for completion */
|
||||
return multiblock ? !_wait_for_cmd_complete_mb(reading) :
|
||||
!_wait_for_cmd_complete();
|
||||
/* for block transfers there's a signal handler, on other commands poll */
|
||||
return transfer ? true : !_wait_for_cmd_complete();
|
||||
}
|
||||
|
||||
|
||||
Cid Sdhc::_read_cid()
|
||||
{
|
||||
Cid cid;
|
||||
cid.raw_0 = read<Rsp136_0>();
|
||||
cid.raw_1 = read<Rsp136_1>();
|
||||
cid.raw_2 = read<Rsp136_2>();
|
||||
cid.raw_3 = read<Rsp136_3>();
|
||||
cid.raw_0 = Mmio::read<Rsp136_0>();
|
||||
cid.raw_1 = Mmio::read<Rsp136_1>();
|
||||
cid.raw_2 = Mmio::read<Rsp136_2>();
|
||||
cid.raw_3 = Mmio::read<Rsp136_3>();
|
||||
return cid;
|
||||
}
|
||||
|
||||
@ -192,70 +192,89 @@ Cid Sdhc::_read_cid()
|
||||
Csd Sdhc::_read_csd()
|
||||
{
|
||||
Csd csd;
|
||||
csd.csd0 = read<Rsp136_0>();
|
||||
csd.csd1 = read<Rsp136_1>();
|
||||
csd.csd2 = read<Rsp136_2>();
|
||||
csd.csd3 = read<Rsp136_3>();
|
||||
csd.csd0 = Mmio::read<Rsp136_0>();
|
||||
csd.csd1 = Mmio::read<Rsp136_1>();
|
||||
csd.csd2 = Mmio::read<Rsp136_2>();
|
||||
csd.csd3 = Mmio::read<Rsp136_3>();
|
||||
return csd;
|
||||
}
|
||||
|
||||
|
||||
unsigned Sdhc::_read_rca()
|
||||
{
|
||||
Cmdrsp0::access_t const rsp0 = read<Cmdrsp0>();
|
||||
Cmdrsp0::access_t const rsp0 = Mmio::read<Cmdrsp0>();
|
||||
return Send_relative_addr::Response::Rca::get(rsp0);
|
||||
}
|
||||
|
||||
|
||||
bool Sdhc::read_blocks(size_t, size_t, char *)
|
||||
{
|
||||
error("block transfer without DMA not supported by now");
|
||||
error("block transfer without DMA not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Sdhc::write_blocks(size_t, size_t, char const *)
|
||||
{
|
||||
error("block transfer without DMA not supported by now");
|
||||
error("block transfer without DMA not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Sdhc::read_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys)
|
||||
bool Sdhc::read_blocks_dma(Block::Packet_descriptor packet,
|
||||
size_t blk_nr,
|
||||
size_t blk_cnt,
|
||||
addr_t buf_phys)
|
||||
{
|
||||
if (_prepare_dma_mb(blk_cnt, buf_phys)) { return false; }
|
||||
if (_prepare_dma_mb(packet, true, blk_cnt, buf_phys)) { return false; }
|
||||
|
||||
return issue_command(Read_multiple_block(blk_nr));
|
||||
}
|
||||
|
||||
|
||||
bool Sdhc::write_blocks_dma(size_t blk_nr, size_t blk_cnt,
|
||||
addr_t buf_phys)
|
||||
bool Sdhc::write_blocks_dma(Block::Packet_descriptor packet,
|
||||
size_t blk_nr,
|
||||
size_t blk_cnt,
|
||||
addr_t buf_phys)
|
||||
{
|
||||
if (_prepare_dma_mb(blk_cnt, buf_phys)) { return false; }
|
||||
if (_prepare_dma_mb(packet, false, blk_cnt, buf_phys)) { return false; }
|
||||
|
||||
return issue_command(Write_multiple_block(blk_nr));
|
||||
}
|
||||
|
||||
|
||||
Sdhc::Sdhc(addr_t const base,
|
||||
unsigned const irq,
|
||||
Delayer &delayer,
|
||||
bool const use_dma)
|
||||
Sdhc::Sdhc(Env &env)
|
||||
:
|
||||
Mmio(base), _irq(irq), _delayer(delayer), _card_info(_init()),
|
||||
_use_dma(use_dma)
|
||||
{ }
|
||||
|
||||
|
||||
int Sdhc::_prepare_dma_mb(size_t blk_cnt, addr_t buf_phys)
|
||||
Attached_mmio(Board_base::SDHC_MMIO_BASE, Board_base::SDHC_MMIO_SIZE),
|
||||
_irq_handler(env.ep(), *this, &Sdhc::_handle_irq), _irq(Board_base::SDHC_IRQ),
|
||||
_card_info(_init()), _use_dma(true)
|
||||
{
|
||||
log("SD card detected");
|
||||
log("capacity: ", card_info().capacity_mb(), " MiB");
|
||||
}
|
||||
|
||||
|
||||
int Sdhc::_prepare_dma_mb(Block::Packet_descriptor packet,
|
||||
bool reading,
|
||||
size_t blk_cnt,
|
||||
addr_t buf_phys)
|
||||
{
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
|
||||
/* write ADMA2 table to DMA */
|
||||
size_t const req_size = blk_cnt * BLOCK_SIZE;
|
||||
if (_adma2_table.setup_request(req_size, buf_phys)) { return -1; }
|
||||
|
||||
/* configure DMA at host */
|
||||
write<Adsaddr>(_adma2_table.base_phys());
|
||||
write<Blkattr::Blksize>(BLOCK_SIZE);
|
||||
write<Blkattr::Blkcnt>(blk_cnt);
|
||||
Mmio::write<Adsaddr>(_adma2_table.base_phys());
|
||||
Mmio::write<Blkattr::Blksize>(BLOCK_SIZE);
|
||||
Mmio::write<Blkattr::Blkcnt>(blk_cnt);
|
||||
|
||||
_block_transfer.read = reading;
|
||||
_block_transfer.packet = packet;
|
||||
_block_transfer.pending = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -279,24 +298,17 @@ int Sdhc::_wait_for_cmd_allowed()
|
||||
}
|
||||
|
||||
|
||||
void Sdhc::_wait_for_irq()
|
||||
{
|
||||
/* acknowledge IRQ first, to activate IRQ propagation initially */
|
||||
_irq.ack_irq();
|
||||
_irq_rec.wait_for_signal();
|
||||
}
|
||||
|
||||
|
||||
Card_info Sdhc::_init()
|
||||
{
|
||||
/* install IRQ signal */
|
||||
_irq.sigh(_irq_rec.manage(&_irq_ctx));
|
||||
_irq.sigh(_irq_handler);
|
||||
_irq.ack_irq();
|
||||
|
||||
/* configure host for initialization stage */
|
||||
if (_reset(_delayer)) { _detect_err("Host reset failed"); }
|
||||
_disable_irqs();
|
||||
|
||||
if (!_supported_host_version(read<Hostver>())) {
|
||||
if (!_supported_host_version(Mmio::read<Hostver>())) {
|
||||
error("host version not supported");
|
||||
throw Detection_failed();
|
||||
}
|
||||
@ -332,7 +344,7 @@ Card_info Sdhc::_init()
|
||||
if (!issue_command(Send_if_cond())) {
|
||||
_detect_err("Send_if_cond command failed"); }
|
||||
|
||||
if (read<Cmdrsp0>() != 0x1aa) {
|
||||
if (Mmio::read<Cmdrsp0>() != 0x1aa) {
|
||||
_detect_err("Unexpected response of Send_if_cond command"); }
|
||||
|
||||
/*
|
||||
@ -352,7 +364,7 @@ Card_info Sdhc::_init()
|
||||
if (!issue_command(Send_if_cond())) {
|
||||
_detect_err("Send_if_cond failed"); }
|
||||
|
||||
if (read<Cmdrsp0>() != 0x1aa) {
|
||||
if (Mmio::read<Cmdrsp0>() != 0x1aa) {
|
||||
_detect_err("Unexpected response of Send_if_cond command"); }
|
||||
|
||||
/*
|
||||
@ -369,7 +381,7 @@ Card_info Sdhc::_init()
|
||||
if (!issue_command(Sd_send_op_cond(0x200000, true))) {
|
||||
_detect_err("Sd_send_op_cond command failed"); }
|
||||
|
||||
if (Ocr::Busy::get(read<Cmdrsp0>())) { break; }
|
||||
if (Ocr::Busy::get(Mmio::read<Cmdrsp0>())) { break; }
|
||||
_delayer.usleep(1000);
|
||||
}
|
||||
if (!i) { _detect_err("Could not power-on SD card"); }
|
||||
@ -405,16 +417,16 @@ Card_info Sdhc::_init()
|
||||
_detect_err("Set_blocklen command failed"); }
|
||||
|
||||
/* configure host buffer */
|
||||
Wml::access_t wml = read<Wml>();
|
||||
Wml::access_t wml = Mmio::read<Wml>();
|
||||
_watermark_level(wml);
|
||||
write<Wml>(wml);
|
||||
Mmio::write<Wml>(wml);
|
||||
|
||||
/* configure ADMA */
|
||||
write<Proctl::Dmas>(Proctl::Dmas::ADMA2);
|
||||
Mmio::write<Proctl::Dmas>(Proctl::Dmas::ADMA2);
|
||||
|
||||
/* configure interrupts for operational mode */
|
||||
_disable_irqs();
|
||||
write<Irqstat>(~0);
|
||||
Mmio::write<Irqstat>(~0);
|
||||
_enable_irqs();
|
||||
return card_info;
|
||||
}
|
||||
@ -430,7 +442,7 @@ void Sdhc::_detect_err(char const * const err)
|
||||
int Sdhc::_reset(Delayer &delayer)
|
||||
{
|
||||
/* start reset */
|
||||
write<Sysctl::Rsta>(1);
|
||||
Mmio::write<Sysctl::Rsta>(1);
|
||||
_reset_amendments();
|
||||
|
||||
/* wait for reset completion */
|
||||
@ -444,8 +456,8 @@ int Sdhc::_reset(Delayer &delayer)
|
||||
|
||||
void Sdhc::_disable_irqs()
|
||||
{
|
||||
write<Irqstaten>(0);
|
||||
write<Irqsigen>(0);
|
||||
Mmio::write<Irqstaten>(0);
|
||||
Mmio::write<Irqsigen>(0);
|
||||
}
|
||||
|
||||
|
||||
@ -464,16 +476,16 @@ void Sdhc::_enable_irqs()
|
||||
Irq::Debe::set(irq, 1);
|
||||
Irq::Ac12e::set(irq, 1);
|
||||
Irq::Dmae::set(irq, 1);
|
||||
write<Irqstaten>(irq);
|
||||
write<Irqsigen>(irq);
|
||||
Mmio::write<Irqstaten>(irq);
|
||||
Mmio::write<Irqsigen>(irq);
|
||||
}
|
||||
|
||||
|
||||
void Sdhc::_bus_width(Bus_width bus_width)
|
||||
{
|
||||
switch (bus_width) {
|
||||
case BUS_WIDTH_1: write<Proctl::Dtw>(Proctl::Dtw::_1BIT); break;
|
||||
case BUS_WIDTH_4: write<Proctl::Dtw>(Proctl::Dtw::_4BIT); break;
|
||||
case BUS_WIDTH_1: Mmio::write<Proctl::Dtw>(Proctl::Dtw::_1BIT); break;
|
||||
case BUS_WIDTH_4: Mmio::write<Proctl::Dtw>(Proctl::Dtw::_4BIT); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,19 +493,19 @@ void Sdhc::_bus_width(Bus_width bus_width)
|
||||
void Sdhc::_disable_clock()
|
||||
{
|
||||
_disable_clock_preparation();
|
||||
Sysctl::access_t sysctl = read<Sysctl>();
|
||||
Sysctl::access_t sysctl = Mmio::read<Sysctl>();
|
||||
Sysctl::Ipgen::set(sysctl, 0);
|
||||
Sysctl::Hcken::set(sysctl, 0);
|
||||
Sysctl::Peren::set(sysctl, 0);
|
||||
Sysctl::Dvs::set(sysctl, Sysctl::Dvs::DIV1);
|
||||
Sysctl::Sdclkfs::set(sysctl, Sysctl::Sdclkfs::DIV1);
|
||||
write<Sysctl>(sysctl);
|
||||
Mmio::write<Sysctl>(sysctl);
|
||||
}
|
||||
|
||||
|
||||
void Sdhc::_enable_clock(Clock_divider divider)
|
||||
{
|
||||
Sysctl::access_t sysctl = read<Sysctl>();
|
||||
Sysctl::access_t sysctl = Mmio::read<Sysctl>();
|
||||
Sysctl::Ipgen::set(sysctl, 1);
|
||||
Sysctl::Hcken::set(sysctl, 1);
|
||||
Sysctl::Peren::set(sysctl, 1);
|
||||
@ -511,7 +523,7 @@ void Sdhc::_enable_clock(Clock_divider divider)
|
||||
Sysctl::Sdclkfs::set(sysctl, Sysctl::Sdclkfs::DIV32);
|
||||
break;
|
||||
}
|
||||
write<Sysctl>(sysctl);
|
||||
Mmio::write<Sysctl>(sysctl);
|
||||
_enable_clock_finish();
|
||||
_delayer.usleep(1000);
|
||||
}
|
||||
|
@ -15,9 +15,16 @@
|
||||
#define _SDHC_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <base/sleep.h>
|
||||
#include <block/driver.h>
|
||||
#include <block/component.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <os/attached_mmio.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sd_card.h>
|
||||
@ -26,7 +33,9 @@
|
||||
namespace Genode { class Sdhc; }
|
||||
|
||||
|
||||
class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
class Genode::Sdhc : public Attached_mmio,
|
||||
public Block::Driver,
|
||||
public Sd_card::Host_controller
|
||||
{
|
||||
private:
|
||||
|
||||
@ -179,17 +188,30 @@ class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
|
||||
enum Clock_divider { CLOCK_DIV_4, CLOCK_DIV_8, CLOCK_DIV_512 };
|
||||
|
||||
Irq_connection _irq;
|
||||
Signal_receiver _irq_rec;
|
||||
Signal_context _irq_ctx;
|
||||
Delayer & _delayer;
|
||||
Sd_card::Card_info _card_info;
|
||||
bool const _use_dma;
|
||||
Adma2::Table _adma2_table;
|
||||
struct Timer_delayer : Timer::Connection, Mmio::Delayer
|
||||
{
|
||||
void usleep(unsigned us) { Timer::Connection::usleep(us); }
|
||||
|
||||
} _delayer;
|
||||
|
||||
struct Block_transfer
|
||||
{
|
||||
Block::Packet_descriptor packet;
|
||||
bool pending = false;
|
||||
bool read;
|
||||
|
||||
} _block_transfer;
|
||||
|
||||
Signal_handler<Sdhc> _irq_handler;
|
||||
Irq_connection _irq;
|
||||
Sd_card::Card_info _card_info;
|
||||
bool const _use_dma;
|
||||
Adma2::Table _adma2_table;
|
||||
|
||||
static bool _supported_host_version(Hostver::access_t hostver);
|
||||
static void _watermark_level(Wml::access_t &wml);
|
||||
|
||||
void _handle_irq();
|
||||
void _detect_err(char const * const err);
|
||||
void _disable_irqs();
|
||||
void _enable_irqs();
|
||||
@ -200,7 +222,6 @@ class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
void _enable_clock_finish();
|
||||
void _clock(Clock clock);
|
||||
void _clock_finish(Clock clock);
|
||||
void _wait_for_irq();
|
||||
int _reset(Delayer & delayer);
|
||||
void _reset_amendments();
|
||||
int _wait_for_cmd_allowed();
|
||||
@ -208,9 +229,8 @@ class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
int _wait_for_card_ready_mbw();
|
||||
int _stop_transmission();
|
||||
void _stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp);
|
||||
int _wait_for_cmd_complete_mb(bool const r);
|
||||
int _wait_for_cmd_complete_mb_finish(bool const reading);
|
||||
int _prepare_dma_mb(size_t blk_cnt, addr_t buf_phys);
|
||||
int _prepare_dma_mb(Block::Packet_descriptor packet, bool reading, size_t blk_cnt, addr_t buf_phys);
|
||||
bool _issue_cmd_finish_xfertyp(Xfertyp::access_t &xfertyp,
|
||||
bool const transfer,
|
||||
bool const multiblock,
|
||||
@ -232,18 +252,8 @@ class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param base local base address of MMIO registers
|
||||
* \param irq host-interrupt ID
|
||||
* \param delayer delayer timing of MMIO accesses
|
||||
* \param use_dma wether to use DMA or direct IO for transfers
|
||||
*/
|
||||
Sdhc(addr_t const base,
|
||||
unsigned const irq,
|
||||
Delayer &delayer,
|
||||
bool const use_dma);
|
||||
|
||||
~Sdhc() { _irq_rec.dissolve(&_irq_ctx); }
|
||||
Sdhc(Env &env);
|
||||
|
||||
|
||||
/****************************************
|
||||
@ -252,10 +262,77 @@ class Genode::Sdhc : public Sd_card::Host_controller, public Mmio
|
||||
|
||||
bool read_blocks(size_t, size_t, char *);
|
||||
bool write_blocks(size_t, size_t, char const *);
|
||||
bool read_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys);
|
||||
bool write_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys);
|
||||
bool read_blocks_dma(Block::Packet_descriptor packet, size_t blk_nr, size_t blk_cnt, addr_t buf_phys);
|
||||
bool write_blocks_dma(Block::Packet_descriptor packet, size_t blk_nr, size_t blk_cnt, addr_t buf_phys);
|
||||
|
||||
Sd_card::Card_info card_info() const { return _card_info; }
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
** Block::Driver interface **
|
||||
*****************************/
|
||||
|
||||
Genode::size_t block_size() { return 512; }
|
||||
|
||||
virtual Block::sector_t block_count()
|
||||
{
|
||||
return card_info().capacity_mb() * 1024 * 2;
|
||||
}
|
||||
|
||||
Block::Session::Operations ops()
|
||||
{
|
||||
Block::Session::Operations o;
|
||||
o.set_operation(Block::Packet_descriptor::READ);
|
||||
o.set_operation(Block::Packet_descriptor::WRITE);
|
||||
return o;
|
||||
}
|
||||
|
||||
void read(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
char *out_buffer,
|
||||
Block::Packet_descriptor &packet)
|
||||
{
|
||||
// if (!read_blocks(block_number, block_count, out_buffer))
|
||||
throw Io_error();
|
||||
}
|
||||
|
||||
void write(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
char const *buffer,
|
||||
Block::Packet_descriptor &packet)
|
||||
{
|
||||
// if (!write_blocks(block_number, block_count, buffer))
|
||||
throw Io_error();
|
||||
}
|
||||
|
||||
void read_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
Block::Packet_descriptor &packet)
|
||||
{
|
||||
if (!read_blocks_dma(packet, block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
}
|
||||
|
||||
void write_dma(Block::sector_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t phys,
|
||||
Block::Packet_descriptor &packet)
|
||||
{
|
||||
if (!write_blocks_dma(packet, block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
}
|
||||
|
||||
bool dma_enabled() { return _use_dma; }
|
||||
|
||||
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) {
|
||||
return Genode::env()->ram_session()->alloc(size, UNCACHED); }
|
||||
|
||||
void free_dma_buffer(Genode::Ram_dataspace_capability c) {
|
||||
return Genode::env()->ram_session()->free(c); }
|
||||
};
|
||||
|
||||
namespace Block { using Sdhci_driver = Genode::Sdhc; }
|
||||
|
||||
#endif /* _SDHC_H_ */
|
||||
|
@ -98,21 +98,21 @@ void Sdhc::_reset_amendments()
|
||||
* nonetheless which disables clocks that card detection relies
|
||||
* on.
|
||||
*/
|
||||
Sysctl::access_t sysctl = read<Sysctl>();
|
||||
Sysctl::access_t sysctl = Mmio::read<Sysctl>();
|
||||
Sysctl::Ipgen::set(sysctl, 1);
|
||||
Sysctl::Hcken::set(sysctl, 1);
|
||||
Sysctl::Peren::set(sysctl, 1);
|
||||
write<Sysctl>(sysctl);
|
||||
Mmio::write<Sysctl>(sysctl);
|
||||
}
|
||||
|
||||
|
||||
void Sdhc::_clock_finish(Clock clock)
|
||||
{
|
||||
write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27);
|
||||
Mmio::write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27);
|
||||
switch (clock) {
|
||||
case CLOCK_INITIAL: _enable_clock(CLOCK_DIV_512); break;
|
||||
case CLOCK_OPERATIONAL: _enable_clock(CLOCK_DIV_8); break; }
|
||||
write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27);
|
||||
Mmio::write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27);
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@ using namespace Genode;
|
||||
|
||||
void Sdhc::_stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp)
|
||||
{
|
||||
Mixctrl::access_t mixctrl = read<Mixctrl>();
|
||||
Mixctrl::access_t mixctrl = Mmio::read<Mixctrl>();
|
||||
Mixctrl::Dmaen::set(mixctrl, 1);
|
||||
Mixctrl::Bcen::set(mixctrl, 1);
|
||||
Mixctrl::Ac12en::set(mixctrl, 0);
|
||||
@ -29,7 +29,7 @@ void Sdhc::_stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp)
|
||||
Mixctrl::Msbsel::set(mixctrl, 1);
|
||||
Mixctrl::Nibblepos::set(mixctrl, 0);
|
||||
Mixctrl::Ac23en::set(mixctrl, 0);
|
||||
write<Mixctrl>(mixctrl);
|
||||
Mmio::write<Mixctrl>(mixctrl);
|
||||
}
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@ bool Sdhc::_issue_cmd_finish_xfertyp(Xfertyp::access_t &,
|
||||
bool const multiblock,
|
||||
bool const reading)
|
||||
{
|
||||
Mixctrl::access_t mixctrl = read<Mixctrl>();
|
||||
Mixctrl::access_t mixctrl = Mmio::read<Mixctrl>();
|
||||
Mixctrl::Dmaen ::set(mixctrl, transfer && multiblock && _use_dma);
|
||||
Mixctrl::Bcen ::set(mixctrl, transfer);
|
||||
Mixctrl::Ac12en ::set(mixctrl, 0);
|
||||
@ -59,7 +59,7 @@ bool Sdhc::_issue_cmd_finish_xfertyp(Xfertyp::access_t &,
|
||||
if (_wait_for_cmd_allowed()) {
|
||||
return false; }
|
||||
|
||||
write<Mixctrl>(mixctrl);
|
||||
Mmio::write<Mixctrl>(mixctrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ void Sdhc::_watermark_level(Wml::access_t &wml)
|
||||
void Sdhc::_reset_amendments()
|
||||
{
|
||||
/* the USDHC doesn't reset the Mixer Control register automatically */
|
||||
Mixctrl::access_t mixctrl = read<Mixctrl>();
|
||||
Mixctrl::access_t mixctrl = Mmio::read<Mixctrl>();
|
||||
Mixctrl::Dmaen::set(mixctrl, 0);
|
||||
Mixctrl::Bcen::set(mixctrl, 0);
|
||||
Mixctrl::Ac12en::set(mixctrl, 0);
|
||||
@ -91,7 +91,7 @@ void Sdhc::_reset_amendments()
|
||||
Mixctrl::Nibblepos::set(mixctrl, 0);
|
||||
Mixctrl::Ac23en::set(mixctrl, 0);
|
||||
Mixctrl::Always_ones::set(mixctrl, 1);
|
||||
write<Mixctrl>(mixctrl);
|
||||
Mmio::write<Mixctrl>(mixctrl);
|
||||
}
|
||||
|
||||
|
||||
@ -99,18 +99,18 @@ void Sdhc::_clock_finish(Clock clock)
|
||||
{
|
||||
switch (clock) {
|
||||
case CLOCK_INITIAL:
|
||||
write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_13);
|
||||
Mmio::write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_13);
|
||||
_enable_clock(CLOCK_DIV_512);
|
||||
break;
|
||||
case CLOCK_OPERATIONAL:
|
||||
write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_28);
|
||||
write<Sysctl::Ipp_rst_n>(0);
|
||||
Mmio::write<Sysctl::Dtocv>(Sysctl::Dtocv::SDCLK_TIMES_2_POW_28);
|
||||
Mmio::write<Sysctl::Ipp_rst_n>(0);
|
||||
_enable_clock(CLOCK_DIV_4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sdhc::_disable_clock_preparation() { write<Vendspec::Frc_sdclk_on>(0); }
|
||||
void Sdhc::_disable_clock_preparation() { Mmio::write<Vendspec::Frc_sdclk_on>(0); }
|
||||
|
||||
void Sdhc::_enable_clock_finish() { write<Vendspec::Frc_sdclk_on>(0); }
|
||||
void Sdhc::_enable_clock_finish() { Mmio::write<Vendspec::Frc_sdclk_on>(0); }
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <base/log.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <block/component.h>
|
||||
#include <os/server.h>
|
||||
|
||||
/* local includes */
|
||||
@ -30,7 +29,8 @@ namespace Block {
|
||||
}
|
||||
|
||||
|
||||
class Block::Sdhci_driver : public Block::Driver
|
||||
class Block::Sdhci_driver : public Block::Driver,
|
||||
public Sd_ack_handler
|
||||
{
|
||||
private:
|
||||
|
||||
@ -60,11 +60,11 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
|
||||
struct Dma_not_supported : Exception { };
|
||||
|
||||
Sdhci_driver(Env &)
|
||||
Sdhci_driver(Env &env)
|
||||
:
|
||||
_mmchs1_mmio(MMCHS1_MMIO_BASE, MMCHS1_MMIO_SIZE),
|
||||
_controller((addr_t)_mmchs1_mmio.local_addr<void>(),
|
||||
_delayer, false),
|
||||
_controller(env.ep(), (addr_t)_mmchs1_mmio.local_addr<void>(),
|
||||
_delayer, *this, false),
|
||||
_use_dma(false)
|
||||
{
|
||||
if (_use_dma) { throw Dma_not_supported(); }
|
||||
@ -74,6 +74,9 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
Genode::log("capacity: ", card_info.capacity_mb(), " MiB");
|
||||
}
|
||||
|
||||
void handle_ack(Block::Packet_descriptor pkt, bool success) {
|
||||
ack_packet(pkt, success); }
|
||||
|
||||
|
||||
/*****************************
|
||||
** Block::Driver interface **
|
||||
@ -99,9 +102,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
char *out_buffer,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.read_blocks(block_number, block_count, out_buffer))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.read_blocks(block_number, block_count, out_buffer, packet);
|
||||
}
|
||||
|
||||
void write(Block::sector_t block_number,
|
||||
@ -109,9 +110,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
char const *buffer,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.write_blocks(block_number, block_count, buffer))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.write_blocks(block_number, block_count, buffer, packet);
|
||||
}
|
||||
|
||||
void read_dma(Block::sector_t block_number,
|
||||
@ -119,9 +118,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.read_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.read_blocks_dma(block_number, block_count, phys, packet);
|
||||
}
|
||||
|
||||
void write_dma(Block::sector_t block_number,
|
||||
@ -129,9 +126,7 @@ class Block::Sdhci_driver : public Block::Driver
|
||||
Genode::addr_t phys,
|
||||
Packet_descriptor &packet)
|
||||
{
|
||||
if (!_controller.write_blocks_dma(block_number, block_count, phys))
|
||||
throw Io_error();
|
||||
ack_packet(packet);
|
||||
_controller.write_blocks_dma(block_number, block_count, phys, packet);
|
||||
}
|
||||
|
||||
bool dma_enabled() { return _use_dma; }
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <block/component.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sd_card.h>
|
||||
@ -355,7 +356,6 @@ struct Mmchs : Genode::Mmio
|
||||
Genode::error("reset of cmd line timed out (src != 0)");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -484,10 +484,22 @@ struct Mmchs : Genode::Mmio
|
||||
};
|
||||
|
||||
|
||||
struct Sd_ack_handler {
|
||||
virtual void handle_ack(Block::Packet_descriptor pkt, bool success) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
{
|
||||
private:
|
||||
|
||||
struct Block_transfer
|
||||
{
|
||||
Block::Packet_descriptor packet;
|
||||
bool pending = false;
|
||||
|
||||
} _block_transfer;
|
||||
|
||||
Delayer &_delayer;
|
||||
Sd_card::Card_info _card_info;
|
||||
bool const _use_dma;
|
||||
@ -500,9 +512,9 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
Adma_desc::access_t * const _adma_desc;
|
||||
Genode::addr_t const _adma_desc_phys;
|
||||
|
||||
Genode::Irq_connection _irq;
|
||||
Genode::Signal_receiver _irq_rec;
|
||||
Genode::Signal_context _irq_ctx;
|
||||
Sd_ack_handler &_ack_handler;
|
||||
Genode::Signal_handler<Omap4_hsmmc_controller> _irq_handler;
|
||||
Genode::Irq_connection _irq;
|
||||
|
||||
Sd_card::Card_info _init()
|
||||
{
|
||||
@ -690,19 +702,6 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _wait_for_transfer_complete()
|
||||
{
|
||||
if (!wait_for<Stat::Tc>(1, _delayer, 1000*1000, 0)
|
||||
&& !wait_for<Stat::Tc>(1, _delayer)) {
|
||||
Genode::error("Stat::Tc timed out");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* clear transfer-completed bit */
|
||||
write<Stat::Tc>(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _wait_for_bre()
|
||||
{
|
||||
if (!wait_for<Pstate::Bre>(1, _delayer, 1000*1000, 0)
|
||||
@ -723,38 +722,29 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _wait_for_transfer_complete_irq()
|
||||
void _handle_irq()
|
||||
{
|
||||
/*
|
||||
* XXX For now, the driver works fully synchronous. We merely use
|
||||
* the interrupt mechanism to yield CPU time to concurrently
|
||||
* running processes.
|
||||
*/
|
||||
for (;;) {
|
||||
/*
|
||||
* We ack the IRQ first to implicitly active receiving
|
||||
* IRQ signals when entering this loop for the first time.
|
||||
*/
|
||||
_irq.ack_irq();
|
||||
_irq_rec.wait_for_signal();
|
||||
_irq.ack_irq();
|
||||
|
||||
/* check for transfer completion */
|
||||
if (read<Stat::Tc>() == 1) {
|
||||
|
||||
/* clear transfer-completed bit */
|
||||
write<Stat::Tc>(1);
|
||||
|
||||
if (read<Stat>() != 0)
|
||||
Genode::warning("unexpected state ("
|
||||
"Stat: ", Genode::Hex(read<Stat>()), " "
|
||||
"Blen: ", Genode::Hex(read<Blk::Blen>()), " "
|
||||
"Nblk: ", read<Blk::Nblk>());
|
||||
|
||||
return true;
|
||||
}
|
||||
if (!_block_transfer.pending) {
|
||||
return; }
|
||||
|
||||
if (read<Stat::Tc>() != 1) {
|
||||
Genode::warning("unexpected interrupt, Stat: ", Genode::Hex(read<Stat>()));
|
||||
return;
|
||||
}
|
||||
|
||||
write<Stat::Tc>(1);
|
||||
|
||||
if (read<Stat>() != 0) {
|
||||
Genode::warning("unexpected state ("
|
||||
"Stat: ", Genode::Hex(read<Stat>()), " "
|
||||
"Blen: ", Genode::Hex(read<Blk::Blen>()), " "
|
||||
"Nblk: ", read<Blk::Nblk>());
|
||||
return;
|
||||
}
|
||||
_block_transfer.pending = false;
|
||||
_ack_handler.handle_ack(_block_transfer.packet, true);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -766,8 +756,9 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
*
|
||||
* \param mmio_base local base address of MMIO registers
|
||||
*/
|
||||
Omap4_hsmmc_controller(Genode::addr_t const mmio_base, Delayer &delayer,
|
||||
bool use_dma)
|
||||
Omap4_hsmmc_controller(Genode::Entrypoint &ep,
|
||||
Genode::addr_t const mmio_base, Delayer &delayer,
|
||||
Sd_ack_handler &ack_handler, bool use_dma)
|
||||
:
|
||||
Mmchs(mmio_base), _delayer(delayer), _card_info(_init()),
|
||||
_use_dma(use_dma),
|
||||
@ -776,13 +767,14 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
Genode::UNCACHED),
|
||||
_adma_desc(_adma_desc_ds.local_addr<Adma_desc::access_t>()),
|
||||
_adma_desc_phys(Genode::Dataspace_client(_adma_desc_ds.cap()).phys_addr()),
|
||||
_ack_handler(ack_handler),
|
||||
_irq_handler(ep, *this, &Omap4_hsmmc_controller::_handle_irq),
|
||||
_irq(IRQ_NUMBER)
|
||||
{
|
||||
_irq.sigh(_irq_rec.manage(&_irq_ctx));
|
||||
_irq.sigh(_irq_handler);
|
||||
_irq.ack_irq();
|
||||
}
|
||||
|
||||
~Omap4_hsmmc_controller() { _irq_rec.dissolve(&_irq_ctx); }
|
||||
|
||||
|
||||
/****************************************
|
||||
** Sd_card::Host_controller interface **
|
||||
@ -897,22 +889,23 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
return Sd_card::Send_relative_addr::Response::Rca::get(read<Rsp10>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data blocks from SD card
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool read_blocks(size_t block_number, size_t block_count, char *out_buffer)
|
||||
void read_blocks(size_t block_number, size_t block_count, char *out_buffer,
|
||||
Block::Packet_descriptor pkt)
|
||||
{
|
||||
using namespace Sd_card;
|
||||
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
write<Blk::Blen>(0x200);
|
||||
write<Blk::Nblk>(block_count);
|
||||
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
if (!issue_command(Read_multiple_block(block_number))) {
|
||||
Genode::error("Read_multiple_block failed, Stat: ",
|
||||
Genode::Hex(read<Stat>()));
|
||||
return false;
|
||||
Genode::error("Read_multiple_block failed");
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
|
||||
size_t const num_accesses = block_count*512/sizeof(Data::access_t);
|
||||
@ -920,29 +913,29 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
|
||||
for (size_t i = 0; i < num_accesses; i++) {
|
||||
if (!_wait_for_bre())
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
|
||||
*dst++ = read<Data>();
|
||||
}
|
||||
|
||||
return _wait_for_transfer_complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data blocks to SD card
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool write_blocks(size_t block_number, size_t block_count, char const *buffer)
|
||||
void write_blocks(size_t block_number, size_t block_count, char const *buffer,
|
||||
Block::Packet_descriptor pkt)
|
||||
{
|
||||
using namespace Sd_card;
|
||||
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
write<Blk::Blen>(0x200);
|
||||
write<Blk::Nblk>(block_count);
|
||||
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
if (!issue_command(Write_multiple_block(block_number))) {
|
||||
Genode::error("Write_multiple_block failed");
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
|
||||
size_t const num_accesses = block_count*512/sizeof(Data::access_t);
|
||||
@ -950,59 +943,56 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
|
||||
|
||||
for (size_t i = 0; i < num_accesses; i++) {
|
||||
if (!_wait_for_bwe())
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
|
||||
write<Data>(*src++);
|
||||
}
|
||||
|
||||
return _wait_for_transfer_complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data blocks from SD card via master DMA
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool read_blocks_dma(size_t block_number, size_t block_count,
|
||||
Genode::addr_t out_buffer_phys)
|
||||
void read_blocks_dma(size_t block_number, size_t block_count,
|
||||
Genode::addr_t out_buffer_phys,
|
||||
Block::Packet_descriptor pkt)
|
||||
{
|
||||
using namespace Sd_card;
|
||||
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
write<Blk::Blen>(0x200);
|
||||
write<Blk::Nblk>(block_count);
|
||||
|
||||
_setup_adma_descriptor_table(block_count, out_buffer_phys);
|
||||
|
||||
if (!issue_command(Read_multiple_block(block_number))) {
|
||||
Genode::error("Read_multiple_block failed, Stat: ",
|
||||
Genode::Hex(read<Stat>()));
|
||||
return false;
|
||||
}
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
return _wait_for_transfer_complete_irq();
|
||||
if (!issue_command(Read_multiple_block(block_number))) {
|
||||
Genode::error("Read_multiple_block failed");
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data blocks to SD card via master DMA
|
||||
*
|
||||
* \return true on success
|
||||
*/
|
||||
bool write_blocks_dma(size_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys)
|
||||
void write_blocks_dma(size_t block_number, size_t block_count,
|
||||
Genode::addr_t buffer_phys,
|
||||
Block::Packet_descriptor pkt)
|
||||
{
|
||||
using namespace Sd_card;
|
||||
|
||||
if (_block_transfer.pending) {
|
||||
throw Block::Driver::Request_congestion(); }
|
||||
|
||||
write<Blk::Blen>(0x200);
|
||||
write<Blk::Nblk>(block_count);
|
||||
|
||||
_setup_adma_descriptor_table(block_count, buffer_phys);
|
||||
|
||||
_block_transfer.packet = pkt;
|
||||
_block_transfer.pending = true;
|
||||
|
||||
if (!issue_command(Write_multiple_block(block_number))) {
|
||||
Genode::error("Write_multiple_block failed");
|
||||
return false;
|
||||
throw Block::Driver::Io_error();
|
||||
}
|
||||
|
||||
return _wait_for_transfer_complete_irq();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,7 @@ namespace Block {
|
||||
class Sdhci_driver;
|
||||
}
|
||||
|
||||
|
||||
class Block::Sdhci_driver : public Block::Driver
|
||||
{
|
||||
private:
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/config.h>
|
||||
@ -24,146 +23,137 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Operation
|
||||
{
|
||||
virtual void operator () (Block::Driver &driver,
|
||||
Genode::addr_t block_number,
|
||||
Genode::size_t block_count,
|
||||
Genode::addr_t buffer_phys,
|
||||
char *buffer_virt) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* \param total_size total number of bytes to read
|
||||
* \param request_size number of bytes per request
|
||||
*/
|
||||
static void run_benchmark(Block::Driver &driver,
|
||||
Timer::Session &timer,
|
||||
char *buffer_virt,
|
||||
Genode::addr_t buffer_phys,
|
||||
Genode::size_t buffer_size,
|
||||
Genode::size_t request_size,
|
||||
Operation &operation)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("request_size=", request_size, " bytes");
|
||||
|
||||
size_t const time_before_ms = timer.elapsed_ms();
|
||||
|
||||
size_t num_requests = buffer_size / request_size;
|
||||
|
||||
/*
|
||||
* Trim number of requests if it would take to much time
|
||||
*/
|
||||
if (num_requests > 320) {
|
||||
buffer_size = 320 * request_size;
|
||||
num_requests = buffer_size / request_size;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_requests; i++)
|
||||
{
|
||||
size_t const block_count = request_size / driver.block_size();
|
||||
addr_t const block_number = i*block_count;
|
||||
|
||||
operation(driver, block_number, block_count,
|
||||
buffer_phys + i*request_size,
|
||||
buffer_virt + i*request_size);
|
||||
}
|
||||
|
||||
size_t const time_after_ms = timer.elapsed_ms();
|
||||
size_t const duration_ms = time_after_ms - time_before_ms;
|
||||
|
||||
/*
|
||||
* Convert bytes per milliseconds to kilobytes per seconds
|
||||
*
|
||||
* (total_size / 1024) / (duration_ms / 1000)
|
||||
*/
|
||||
size_t const buffer_size_kb = buffer_size / 1024;
|
||||
size_t const throughput_kb_per_sec = (1000*buffer_size_kb) / duration_ms;
|
||||
|
||||
log(" duration: ", duration_ms, " ms");
|
||||
log(" amount: ", buffer_size_kb, " KiB");
|
||||
log(" throughput: ", throughput_kb_per_sec, " KiB/sec");
|
||||
}
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Main(Env &env)
|
||||
using Packet_descriptor = Block::Packet_descriptor;
|
||||
|
||||
struct Block_operation_failed : Exception { };
|
||||
|
||||
enum Operation { READ, WRITE };
|
||||
|
||||
struct Driver_session : Block::Driver_session_base
|
||||
{
|
||||
log("--- SD card benchmark ---");
|
||||
Signal_transmitter sig;
|
||||
unsigned long nr_of_acks { 0 };
|
||||
|
||||
Driver_session(Signal_context_capability sig) : sig(sig) { }
|
||||
|
||||
static Block::Sdhci_driver driver(env);
|
||||
bool const use_dma = driver.dma_enabled();
|
||||
|
||||
static Timer::Connection timer;
|
||||
|
||||
long const request_sizes[] = {
|
||||
512, 1024, 2048, 4096, 8192, 16384, 32768, 64*1024, 128*1024, 0 };
|
||||
|
||||
/* total size of communication buffer */
|
||||
size_t const buffer_size = 10 * 1024 * 1024;
|
||||
|
||||
/* allocate read/write buffer */
|
||||
static Attached_ram_dataspace buffer(&env.ram(), buffer_size, Genode::UNCACHED);
|
||||
char * const buffer_virt = buffer.local_addr<char>();
|
||||
addr_t const buffer_phys = Dataspace_client(buffer.cap()).phys_addr();
|
||||
|
||||
/*
|
||||
* Benchmark reading from SD card
|
||||
*/
|
||||
|
||||
log("\n-- reading from SD card (", use_dma ? "" : "not ", "using DMA) --");
|
||||
|
||||
struct Read : Operation
|
||||
void ack_packet(Packet_descriptor &, bool success)
|
||||
{
|
||||
void operator () (Block::Driver &driver,
|
||||
addr_t number, size_t count, addr_t phys, char *virt)
|
||||
{
|
||||
Block::Packet_descriptor p;
|
||||
if (driver.dma_enabled())
|
||||
driver.read_dma(number, count, phys, p);
|
||||
else
|
||||
driver.read(number, count, virt, p);
|
||||
}
|
||||
} read_operation;
|
||||
|
||||
for (unsigned i = 0; request_sizes[i]; i++) {
|
||||
run_benchmark(driver, timer, buffer_virt, buffer_phys, buffer_size,
|
||||
request_sizes[i], read_operation);
|
||||
if (!success) {
|
||||
throw Block_operation_failed(); }
|
||||
nr_of_acks++;
|
||||
sig.submit();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Benchmark writing to SD card
|
||||
*
|
||||
* We write back the content of the buffer, which we just filled during the
|
||||
* read benchmark. If both read and write succeed, the SD card will retain
|
||||
* its original content.
|
||||
*/
|
||||
Env &env;
|
||||
Packet_descriptor pkt;
|
||||
unsigned long time_before_ms;
|
||||
Timer::Connection timer;
|
||||
Operation operation { READ };
|
||||
Signal_handler<Main> ack_handler { env.ep(), *this, &Main::update_state };
|
||||
Driver_session drv_session { ack_handler };
|
||||
Block::Sdhci_driver drv { env };
|
||||
size_t const buf_size_kib { config()->xml_node()
|
||||
.attribute_value("buffer_size_kib",
|
||||
(size_t)0) };
|
||||
size_t const buf_size { buf_size_kib * 1024 };
|
||||
Attached_ram_dataspace buf { &env.ram(), buf_size, UNCACHED };
|
||||
char *buf_virt { buf.local_addr<char>() };
|
||||
addr_t buf_phys { Dataspace_client(buf.cap())
|
||||
.phys_addr() };
|
||||
size_t buf_off_done { 0 };
|
||||
size_t buf_off_pend { 0 };
|
||||
unsigned req_size_id { 0 };
|
||||
size_t req_sizes[9] { 512, 1024, 1024 * 2, 1024 * 4,
|
||||
1024 * 8, 1024 * 16, 1024 * 32,
|
||||
1024 * 64, 1024 * 128 };
|
||||
|
||||
log("\n-- writing to SD card (", use_dma ? "" : "not ", "using DMA) --");
|
||||
size_t req_size() const { return req_sizes[req_size_id]; }
|
||||
|
||||
struct Write : Operation
|
||||
{
|
||||
void operator () (Block::Driver &driver,
|
||||
addr_t number, size_t count, addr_t phys, char *virt)
|
||||
{
|
||||
Block::Packet_descriptor p;
|
||||
if (driver.dma_enabled())
|
||||
driver.write_dma(number, count, phys, p);
|
||||
else
|
||||
driver.write(number, count, virt, p);
|
||||
void update_state()
|
||||
{
|
||||
/* raise done counter and check if the buffer is full */
|
||||
buf_off_done += drv_session.nr_of_acks * req_size();
|
||||
drv_session.nr_of_acks = 0;
|
||||
if (buf_off_done == buf_size) {
|
||||
|
||||
/* print stats for the current request size */
|
||||
unsigned long const time_after_ms = timer.elapsed_ms();
|
||||
unsigned long const duration_ms = time_after_ms - time_before_ms;
|
||||
size_t const kib_per_sec = (1000 * buf_size_kib) /
|
||||
duration_ms;
|
||||
log(" duration: ", duration_ms, " ms");
|
||||
log(" amount: ", buf_size_kib, " KiB");
|
||||
log(" throughput: ", kib_per_sec, " KiB/sec");
|
||||
|
||||
/* go to next request size */
|
||||
buf_off_pend = 0;
|
||||
buf_off_done = 0;
|
||||
req_size_id++;
|
||||
|
||||
/* check if we have done all request sizes for an operation */
|
||||
if (req_size_id == sizeof(req_sizes)/sizeof(req_sizes[0])) {
|
||||
|
||||
/* go to next operation or end the test */
|
||||
log("");
|
||||
req_size_id = 0;
|
||||
switch (operation) {
|
||||
case READ:
|
||||
operation = WRITE;
|
||||
log("-- writing to SD card --");
|
||||
break;
|
||||
case WRITE:
|
||||
log("--- SD card benchmark finished ---");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} write_operation;
|
||||
log(" request size ", req_size(), " bytes");
|
||||
time_before_ms = timer.elapsed_ms();
|
||||
}
|
||||
/* issue as many requests for the current request size as possible */
|
||||
try {
|
||||
size_t const cnt = req_size() / drv.block_size();
|
||||
for (; buf_off_pend < buf_size; buf_off_pend += req_size()) {
|
||||
|
||||
for (unsigned i = 0; request_sizes[i]; i++)
|
||||
run_benchmark(driver, timer, buffer_virt, buffer_phys, buffer_size,
|
||||
request_sizes[i], write_operation);
|
||||
/* calculate block offset */
|
||||
addr_t const nr = buf_off_pend / drv.block_size();
|
||||
|
||||
log("\n--- SD card benchmark finished ---");
|
||||
if (drv.dma_enabled()) {
|
||||
|
||||
/* request with DMA */
|
||||
addr_t const phys = buf_phys + buf_off_pend;
|
||||
switch (operation) {
|
||||
case READ: drv.read_dma(nr, cnt, phys, pkt); break;
|
||||
case WRITE: drv.write_dma(nr, cnt, phys, pkt); break; }
|
||||
|
||||
} else {
|
||||
|
||||
/* request without DMA */
|
||||
char *const virt = buf_virt + buf_off_pend;
|
||||
switch (operation) {
|
||||
case READ: drv.read(nr, cnt, virt, pkt); break;
|
||||
case WRITE: drv.write(nr, cnt, virt, pkt); break; }
|
||||
}
|
||||
}
|
||||
} catch (Block::Driver::Request_congestion) { }
|
||||
}
|
||||
|
||||
Main(Env &env) : env(env)
|
||||
{
|
||||
log("");
|
||||
log("--- SD card benchmark (", drv.dma_enabled() ? "with" : "no", " DMA) ---");
|
||||
|
||||
drv.session(&drv_session);
|
||||
|
||||
/* start issuing requests */
|
||||
log("");
|
||||
log("-- reading from SD card --");
|
||||
log(" request size ", req_size(), " bytes");
|
||||
time_before_ms = timer.elapsed_ms();
|
||||
update_state();
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user