From b33c35a003b9872de343389b797f1c82f45f1aec Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 23 Dec 2016 14:53:30 +0100 Subject: [PATCH] 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 --- repos/os/include/block/driver.h | 34 ++- repos/os/run/sd_card_bench.run | 22 +- .../src/drivers/sd_card/spec/exynos5/driver.h | 23 +- .../src/drivers/sd_card/spec/exynos5/dwmmc.h | 129 ++++----- .../os/src/drivers/sd_card/spec/imx/driver.h | 116 --------- repos/os/src/drivers/sd_card/spec/imx/sdhc.cc | 194 +++++++------- repos/os/src/drivers/sd_card/spec/imx/sdhc.h | 125 +++++++-- .../os/src/drivers/sd_card/spec/imx53/sdhc.cc | 8 +- .../os/src/drivers/sd_card/spec/imx6/sdhc.cc | 22 +- .../src/drivers/sd_card/spec/omap4/driver.h | 29 +-- .../os/src/drivers/sd_card/spec/omap4/mmchs.h | 178 ++++++------- .../src/drivers/sd_card/spec/pl180/driver.h | 1 + repos/os/src/test/sd_card_bench/main.cc | 244 +++++++++--------- 13 files changed, 543 insertions(+), 582 deletions(-) diff --git a/repos/os/include/block/driver.h b/repos/os/include/block/driver.h index 83dd12eca5..9b4533a3a4 100644 --- a/repos/os/include/block/driver.h +++ b/repos/os/include/block/driver.h @@ -24,13 +24,30 @@ #include 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(); } /** diff --git a/repos/os/run/sd_card_bench.run b/repos/os/run/sd_card_bench.run index b8c3019aba..9ac3108ade 100644 --- a/repos/os/run/sd_card_bench.run +++ b/repos/os/run/sd_card_bench.run @@ -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 { @@ -58,7 +60,11 @@ append config { - + } + +append config "" + +append config { } diff --git a/repos/os/src/drivers/sd_card/spec/exynos5/driver.h b/repos/os/src/drivers/sd_card/spec/exynos5/driver.h index d29d556b59..3edfe5dfdf 100644 --- a/repos/os/src/drivers/sd_card/spec/exynos5/driver.h +++ b/repos/os/src/drivers/sd_card/spec/exynos5/driver.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -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(), - _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; } diff --git a/repos/os/src/drivers/sd_card/spec/exynos5/dwmmc.h b/repos/os/src/drivers/sd_card/spec/exynos5/dwmmc.h index 3acb7bbd17..d6d16b6ce8 100644 --- a/repos/os/src/drivers/sd_card/spec/exynos5/dwmmc.h +++ b/repos/os/src/drivers/sd_card/spec/exynos5/dwmmc.h @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -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 _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()) { - write(~0U); - return true; - } - - if (read()) { - Genode::error("Response error"); - return false; - } - - if (read()) { - Genode::error("Data read timeout"); - return false; - } - - if (read()) { - Genode::error("CRC error"); - return false; + bool success = false; + if (read()) { + Genode::error("Response error"); + } + if (read()) { + Genode::error("Data read timeout"); + } + if (read()) { + Genode::error("CRC error"); + } + if (read()) { + write(~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_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())); - 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())); - 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_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx/driver.h b/repos/os/src/drivers/sd_card/spec/imx/driver.h index 743dc87eb5..7d64b68a67 100644 --- a/repos/os/src/drivers/sd_card/spec/imx/driver.h +++ b/repos/os/src/drivers/sd_card/spec/imx/driver.h @@ -14,123 +14,7 @@ #ifndef _DRIVER_H_ #define _DRIVER_H_ -/* Genode includes */ -#include -#include -#include -#include -#include -#include -#include - /* local includes */ #include -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(), - 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_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc b/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc index cc22c44cbb..e02a6b3514 100644 --- a/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc +++ b/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc @@ -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); - write(xfertyp); + Mmio::write(cmdarg); + Mmio::write(xfertyp); /* wait for command completion */ if (_wait_for_cmd_complete()) { return -1; } /* check for errors */ - R1_response_0::access_t const resp = read(); + R1_response_0::access_t const resp = Mmio::read(); 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(0); + Mmio::write(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); + Mmio::write(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(); - - /* - * Poll for missing signal because interrupts are edge-triggered - * and could thus got lost in the meantime. - */ - if (irq != irq_goal) { - if (!wait_for(irq_goal, _delayer)) { - error("Completion host signal timed out"); - return -1; - } + if (!wait_for(1, _delayer) || + !wait_for(1, _delayer)) + { + error("Completion host signal timed out"); + throw -1; } /* acknowledge completion signals */ - write(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); + + 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::Cc::reg_mask()) { - error("received unexpected host signal"); + if (!wait_for(1, _delayer, 200, 5000)) { + error("command timed out"); return -1; } - write(Irqstat::Cc::reg_mask()); + Mmio::write(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(command.arg); - write(xfertyp); + Mmio::write(command.arg); + Mmio::write(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(); - cid.raw_1 = read(); - cid.raw_2 = read(); - cid.raw_3 = read(); + cid.raw_0 = Mmio::read(); + cid.raw_1 = Mmio::read(); + cid.raw_2 = Mmio::read(); + cid.raw_3 = Mmio::read(); return cid; } @@ -192,70 +192,89 @@ Cid Sdhc::_read_cid() Csd Sdhc::_read_csd() { Csd csd; - csd.csd0 = read(); - csd.csd1 = read(); - csd.csd2 = read(); - csd.csd3 = read(); + csd.csd0 = Mmio::read(); + csd.csd1 = Mmio::read(); + csd.csd2 = Mmio::read(); + csd.csd3 = Mmio::read(); return csd; } unsigned Sdhc::_read_rca() { - Cmdrsp0::access_t const rsp0 = read(); + Cmdrsp0::access_t const rsp0 = Mmio::read(); 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(_adma2_table.base_phys()); - write(BLOCK_SIZE); - write(blk_cnt); + Mmio::write(_adma2_table.base_phys()); + Mmio::write(BLOCK_SIZE); + Mmio::write(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())) { + if (!_supported_host_version(Mmio::read())) { 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() != 0x1aa) { + if (Mmio::read() != 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() != 0x1aa) { + if (Mmio::read() != 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())) { break; } + if (Ocr::Busy::get(Mmio::read())) { 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::access_t wml = Mmio::read(); _watermark_level(wml); - write(wml); + Mmio::write(wml); /* configure ADMA */ - write(Proctl::Dmas::ADMA2); + Mmio::write(Proctl::Dmas::ADMA2); /* configure interrupts for operational mode */ _disable_irqs(); - write(~0); + Mmio::write(~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(1); + Mmio::write(1); _reset_amendments(); /* wait for reset completion */ @@ -444,8 +456,8 @@ int Sdhc::_reset(Delayer &delayer) void Sdhc::_disable_irqs() { - write(0); - write(0); + Mmio::write(0); + Mmio::write(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(irq); - write(irq); + Mmio::write(irq); + Mmio::write(irq); } void Sdhc::_bus_width(Bus_width bus_width) { switch (bus_width) { - case BUS_WIDTH_1: write(Proctl::Dtw::_1BIT); break; - case BUS_WIDTH_4: write(Proctl::Dtw::_4BIT); break; + case BUS_WIDTH_1: Mmio::write(Proctl::Dtw::_1BIT); break; + case BUS_WIDTH_4: Mmio::write(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::access_t sysctl = Mmio::read(); 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); + Mmio::write(sysctl); } void Sdhc::_enable_clock(Clock_divider divider) { - Sysctl::access_t sysctl = read(); + Sysctl::access_t sysctl = Mmio::read(); 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); + Mmio::write(sysctl); _enable_clock_finish(); _delayer.usleep(1000); } diff --git a/repos/os/src/drivers/sd_card/spec/imx/sdhc.h b/repos/os/src/drivers/sd_card/spec/imx/sdhc.h index 8943475d88..cb8150722b 100644 --- a/repos/os/src/drivers/sd_card/spec/imx/sdhc.h +++ b/repos/os/src/drivers/sd_card/spec/imx/sdhc.h @@ -15,9 +15,16 @@ #define _SDHC_H_ /* Genode includes */ +#include +#include +#include #include #include #include +#include +#include +#include +#include /* local includes */ #include @@ -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 _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_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc b/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc index 8cf843d293..2de562c59a 100644 --- a/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc +++ b/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc @@ -98,21 +98,21 @@ void Sdhc::_reset_amendments() * nonetheless which disables clocks that card detection relies * on. */ - Sysctl::access_t sysctl = read(); + Sysctl::access_t sysctl = Mmio::read(); Sysctl::Ipgen::set(sysctl, 1); Sysctl::Hcken::set(sysctl, 1); Sysctl::Peren::set(sysctl, 1); - write(sysctl); + Mmio::write(sysctl); } void Sdhc::_clock_finish(Clock clock) { - write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27); + Mmio::write(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::SDCLK_TIMES_2_POW_27); + Mmio::write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27); } diff --git a/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc b/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc index 5574443fa8..e89f313baf 100644 --- a/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc +++ b/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc @@ -20,7 +20,7 @@ using namespace Genode; void Sdhc::_stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp) { - Mixctrl::access_t mixctrl = read(); + Mixctrl::access_t mixctrl = Mmio::read(); 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); + Mmio::write(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::access_t mixctrl = Mmio::read(); 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); + Mmio::write(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::access_t mixctrl = Mmio::read(); 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); + Mmio::write(mixctrl); } @@ -99,18 +99,18 @@ void Sdhc::_clock_finish(Clock clock) { switch (clock) { case CLOCK_INITIAL: - write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_13); + Mmio::write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_13); _enable_clock(CLOCK_DIV_512); break; case CLOCK_OPERATIONAL: - write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_28); - write(0); + Mmio::write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_28); + Mmio::write(0); _enable_clock(CLOCK_DIV_4); break; } } -void Sdhc::_disable_clock_preparation() { write(0); } +void Sdhc::_disable_clock_preparation() { Mmio::write(0); } -void Sdhc::_enable_clock_finish() { write(0); } +void Sdhc::_enable_clock_finish() { Mmio::write(0); } diff --git a/repos/os/src/drivers/sd_card/spec/omap4/driver.h b/repos/os/src/drivers/sd_card/spec/omap4/driver.h index d99a75f3db..e11b9d38ab 100644 --- a/repos/os/src/drivers/sd_card/spec/omap4/driver.h +++ b/repos/os/src/drivers/sd_card/spec/omap4/driver.h @@ -18,7 +18,6 @@ #include #include #include -#include #include /* 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(), - _delayer, false), + _controller(env.ep(), (addr_t)_mmchs1_mmio.local_addr(), + _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; } diff --git a/repos/os/src/drivers/sd_card/spec/omap4/mmchs.h b/repos/os/src/drivers/sd_card/spec/omap4/mmchs.h index c65a729256..64ecb6f162 100644 --- a/repos/os/src/drivers/sd_card/spec/omap4/mmchs.h +++ b/repos/os/src/drivers/sd_card/spec/omap4/mmchs.h @@ -19,6 +19,7 @@ #include #include #include +#include /* local includes */ #include @@ -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 _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(1, _delayer, 1000*1000, 0) - && !wait_for(1, _delayer)) { - Genode::error("Stat::Tc timed out"); - return false; - } - - /* clear transfer-completed bit */ - write(1); - return true; - } - bool _wait_for_bre() { if (!wait_for(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() == 1) { - - /* clear transfer-completed bit */ - write(1); - - if (read() != 0) - Genode::warning("unexpected state (" - "Stat: ", Genode::Hex(read()), " " - "Blen: ", Genode::Hex(read()), " " - "Nblk: ", read()); - - return true; - } + if (!_block_transfer.pending) { + return; } + if (read() != 1) { Genode::warning("unexpected interrupt, Stat: ", Genode::Hex(read())); + return; } + + write(1); + + if (read() != 0) { + Genode::warning("unexpected state (" + "Stat: ", Genode::Hex(read()), " " + "Blen: ", Genode::Hex(read()), " " + "Nblk: ", read()); + 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_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()); } - /** - * 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(0x200); write(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())); - 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(); } - - 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(0x200); write(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(*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(0x200); write(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())); - 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(0x200); write(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(); } }; diff --git a/repos/os/src/drivers/sd_card/spec/pl180/driver.h b/repos/os/src/drivers/sd_card/spec/pl180/driver.h index c5e81ff2d2..4574b2186d 100644 --- a/repos/os/src/drivers/sd_card/spec/pl180/driver.h +++ b/repos/os/src/drivers/sd_card/spec/pl180/driver.h @@ -27,6 +27,7 @@ namespace Block { class Sdhci_driver; } + class Block::Sdhci_driver : public Block::Driver { private: diff --git a/repos/os/src/test/sd_card_bench/main.cc b/repos/os/src/test/sd_card_bench/main.cc index ec6f977330..83c45b98fb 100644 --- a/repos/os/src/test/sd_card_bench/main.cc +++ b/repos/os/src/test/sd_card_bench/main.cc @@ -14,7 +14,6 @@ /* Genode includes */ #include -#include #include #include #include @@ -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(); - 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
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() }; + 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(); } };