diff --git a/dde_linux/src/lib/usb/storage/storage.cc b/dde_linux/src/lib/usb/storage/storage.cc index 67e50a85c..08160174c 100644 --- a/dde_linux/src/lib/usb/storage/storage.cc +++ b/dde_linux/src/lib/usb/storage/storage.cc @@ -45,7 +45,7 @@ class Storage_device : public Genode::List::Element, if (verbose) PDBG("ACK packet for block: %llu status: %d", packet->block_number(), cmnd->result); - session->complete_packet(*packet); + session->ack_packet(*packet); Genode::destroy(Genode::env()->heap(), packet); _scsi_free_command(cmnd); } @@ -129,7 +129,7 @@ class Storage_device : public Genode::List::Element, /* send command to host driver */ if (_sdev->host->hostt->queuecommand(_sdev->host, cmnd)) { - throw Io_error(); + throw Request_congestion(); } } diff --git a/gems/src/server/http_blk/main.cc b/gems/src/server/http_blk/main.cc index 03d9da187..c38bdc86d 100644 --- a/gems/src/server/http_blk/main.cc +++ b/gems/src/server/http_blk/main.cc @@ -56,7 +56,7 @@ class Driver : public Block::Driver { _http.cmd_get(block_nr * _block_size, block_count * _block_size, (addr_t)buffer); - session->complete_packet(packet); + session->ack_packet(packet); } }; diff --git a/os/include/block/component.h b/os/include/block/component.h index e3e1c9c40..30ac900d3 100644 --- a/os/include/block/component.h +++ b/os/include/block/component.h @@ -30,21 +30,6 @@ namespace Block { class Block::Session_component : public Block::Session_rpc_object { - public: - - void complete_packet(Packet_descriptor &packet, bool success = true) - { - packet.succeeded(success); - - /* acknowledge packet to the client */ - if (!tx_sink()->ready_to_ack()) { - PWRN("need to wait until ready-for-ack"); - return; - } - - tx_sink()->acknowledge_packet(packet); - } - private: Driver_factory &_driver_factory; @@ -53,80 +38,127 @@ class Block::Session_component : public Block::Session_rpc_object addr_t _rq_phys; Signal_dispatcher _sink_ack; Signal_dispatcher _sink_submit; + bool _req_queue_full; + Packet_descriptor _p_to_handle; + unsigned _p_in_fly; - void _ready_to_submit(unsigned) + /** + * Acknowledge a packet already handled + */ + inline void _ack_packet(Packet_descriptor &packet) { - /* handle requests */ - while (tx_sink()->packet_avail()) { + if (!tx_sink()->ready_to_ack()) + PERR("Not ready to ack!"); - /* blocking-get packet from client */ - Packet_descriptor packet = tx_sink()->get_packet(); - if (!packet.valid()) { - PWRN("received invalid packet"); - continue; - } - - packet.succeeded(true); - - try { - switch (packet.operation()) { - - case Block::Packet_descriptor::READ: - if (_driver.dma_enabled()) - _driver.read_dma(packet.block_number(), - packet.block_count(), - _rq_phys + packet.offset(), - packet); - else - _driver.read(packet.block_number(), - packet.block_count(), - tx_sink()->packet_content(packet), - packet); - break; - - case Block::Packet_descriptor::WRITE: - if (_driver.dma_enabled()) - _driver.write_dma(packet.block_number(), - packet.block_count(), - _rq_phys + packet.offset(), - packet); - else - _driver.write(packet.block_number(), - packet.block_count(), - tx_sink()->packet_content(packet), - packet); - break; - - default: - throw Driver::Io_error(); - } - } catch (Driver::Io_error) { - complete_packet(packet, false); + tx_sink()->acknowledge_packet(packet); + _p_in_fly--; + } + + /** + * Range check packet request + */ + inline bool _range_check(Packet_descriptor &p) { + return p.block_number() + p.block_count() - 1 + < _driver.block_count(); } + + /** + * Handle a single request + */ + void _handle_packet(Packet_descriptor packet) + { + _p_to_handle = packet; + _p_to_handle.succeeded(false); + + /* ignore invalid packets */ + if (!packet.valid() || !_range_check(_p_to_handle)) { + _ack_packet(_p_to_handle); + return; + } + + try { + switch (_p_to_handle.operation()) { + + case Block::Packet_descriptor::READ: + if (_driver.dma_enabled()) + _driver.read_dma(packet.block_number(), + packet.block_count(), + _rq_phys + packet.offset(), + _p_to_handle); + else + _driver.read(packet.block_number(), + packet.block_count(), + tx_sink()->packet_content(packet), + _p_to_handle); + break; + + case Block::Packet_descriptor::WRITE: + if (_driver.dma_enabled()) + _driver.write_dma(packet.block_number(), + packet.block_count(), + _rq_phys + packet.offset(), + _p_to_handle); + else + _driver.write(packet.block_number(), + packet.block_count(), + tx_sink()->packet_content(packet), + _p_to_handle); + break; + + default: + throw Driver::Io_error(); } + } catch (Driver::Request_congestion) { + _req_queue_full = true; + } catch (Driver::Io_error) { + _ack_packet(_p_to_handle); } } - void _ack_avail(unsigned) { } + /** + * Triggered when a packet was placed into the empty submit queue + */ + void _packet_avail(unsigned) + { + /* + * as long as more packets are available, and we're able to ack + * them, and the driver's request queue isn't full, + * direct the packet request to the driver backend + */ + for (; !_req_queue_full && tx_sink()->packet_avail() && + !(_p_in_fly >= tx_sink()->ack_slots_free()); _p_in_fly++) + _handle_packet(tx_sink()->get_packet()); + } + + /** + * Triggered when an ack got removed from the full ack queue + */ + void _ready_to_ack(unsigned) { _packet_avail(0); } public: /** * Constructor + * + * \param rq_ds shared dataspace for packet stream + * \param driver block driver backend + * \param driver_factory factory to create and destroy driver objects + * \param ep entrypoint handling this session component + * \param receiver signal receiver managing signals of the client */ Session_component(Ram_dataspace_capability rq_ds, Driver &driver, Driver_factory &driver_factory, Rpc_entrypoint &ep, Signal_receiver &receiver) - : - Session_rpc_object(rq_ds, ep), - _driver_factory(driver_factory), - _driver(driver), - _rq_ds(rq_ds), - _rq_phys(Dataspace_client(_rq_ds).phys_addr()), - _sink_ack(receiver, *this, &Session_component::_ack_avail), - _sink_submit(receiver, *this, - &Session_component::_ready_to_submit) + : Session_rpc_object(rq_ds, ep), + _driver_factory(driver_factory), + _driver(driver), + _rq_ds(rq_ds), + _rq_phys(Dataspace_client(_rq_ds).phys_addr()), + _sink_ack(receiver, *this, &Session_component::_ready_to_ack), + _sink_submit(receiver, *this, &Session_component::_packet_avail), + _req_queue_full(false), + _p_in_fly(0) { _tx.sigh_ready_to_ack(_sink_ack); _tx.sigh_packet_avail(_sink_submit); @@ -135,11 +167,34 @@ class Block::Session_component : public Block::Session_rpc_object } /** - * Destructor + * 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 */ - ~Session_component() + void ack_packet(Packet_descriptor &packet, bool success = true) { - _driver_factory.destroy(&_driver); + bool ack_queue_full = _p_in_fly >= tx_sink()->ack_slots_free(); + + packet.succeeded(success); + _ack_packet(packet); + + if (!_req_queue_full && !ack_queue_full) + return; + + /* + * when the driver's request queue was full, + * handle last unprocessed packet taken out of submit queue + */ + if (_req_queue_full) { + _req_queue_full = false; + _handle_packet(_p_to_handle); + } + + /* resume packet processing */ + _packet_avail(0); } /** @@ -217,6 +272,14 @@ class Block::Root : public: + /** + * Constructor + * + * \param session_ep entrypoint handling this root component + * \param md_alloc allocator to allocate session components + * \param driver_factory factory to create and destroy driver backend + * \param receiver signal receiver managing signals of the client + */ Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Driver_factory &driver_factory, Signal_receiver &receiver) : diff --git a/os/include/block/driver.h b/os/include/block/driver.h index ecb05671d..aa22f41ec 100644 --- a/os/include/block/driver.h +++ b/os/include/block/driver.h @@ -35,17 +35,19 @@ namespace Block { */ struct Block::Driver { - Session_component *session; + Session_component * session; /* single session component of the driver + * might get used to acknowledge requests */ /** * Exceptions */ - class Io_error : public ::Genode::Exception { }; + class Io_error : public ::Genode::Exception { }; + class Request_congestion : public ::Genode::Exception { }; /** * Request block size for driver and medium */ - virtual Genode::size_t block_size() = 0; + virtual Genode::size_t block_size() = 0; /** * Request capacity of medium in blocks @@ -63,6 +65,11 @@ struct Block::Driver * \param block_number number of first block to read * \param block_count number of blocks to read * \param buffer output buffer for read request + * \param packet packet descriptor from the client + * + * \throw Request_congestion + * + * Note: should be overridden by DMA non-capable devices */ virtual void read(sector_t block_number, Genode::size_t block_count, @@ -76,6 +83,11 @@ struct Block::Driver * \param block_number number of first block to write * \param block_count number of blocks to write * \param buffer buffer for write request + * \param packet packet descriptor from the client + * + * \throw Request_congestion + * + * Note: should be overridden by DMA non-capable, non-ROM devices */ virtual void write(sector_t block_number, Genode::size_t block_count, @@ -89,6 +101,11 @@ struct Block::Driver * \param block_number number of first block to read * \param block_count number of blocks to read * \param phys phyiscal address of read buffer + * \param packet packet descriptor from the client + * + * \throw Request_congestion + * + * Note: should be overridden by DMA capable devices */ virtual void read_dma(sector_t block_number, Genode::size_t block_count, @@ -102,6 +119,11 @@ struct Block::Driver * \param block_number number of first block to write * \param block_count number of blocks to write * \param phys physical address of write buffer + * \param packet packet descriptor from the client + * + * \throw Request_congestion + * + * Note: should be overridden by DMA capable, non-ROM devices */ virtual void write_dma(sector_t block_number, Genode::size_t block_count, @@ -113,6 +135,8 @@ struct Block::Driver * Check if DMA is enabled for driver * * \return true if DMA is enabled, false otherwise + * + * Note: has to be overriden by DMA-capable devices */ virtual bool dma_enabled() { return false; } @@ -124,7 +148,10 @@ struct Block::Driver return Genode::env()->ram_session()->alloc(size, false); } /** - * Synchronize with with device. + * Synchronize with device. + * + * Note: should be overriden by (e.g. intermediate) components, + * which cache data */ virtual void sync() {} }; diff --git a/os/include/os/packet_stream.h b/os/include/os/packet_stream.h index bff78d253..9f6fe3aed 100644 --- a/os/include/os/packet_stream.h +++ b/os/include/os/packet_stream.h @@ -131,8 +131,8 @@ class Packet_descriptor_queue { private: - int _head; - int _tail; + unsigned _head; + unsigned _tail; PACKET_DESCRIPTOR _queue[QUEUE_SIZE]; public: @@ -200,10 +200,18 @@ class Packet_descriptor_queue */ bool single_element() { return (_tail + 1)%QUEUE_SIZE == _head; } + /** * Return true if a single slot is left to be put into the queue */ bool single_slot_free() { return (_head + 2)%QUEUE_SIZE == _tail; } + + /** + * Return number of slots left to be put into the queue + */ + unsigned slots_free() { + return ((_tail > _head) ? _tail - _head + : QUEUE_SIZE - _head + _tail) - 1; } }; @@ -280,6 +288,11 @@ class Packet_descriptor_transmitter if (_tx_queue->single_element()) _rx_ready.submit(); } + + /** + * Return number of slots left to be put into the tx queue + */ + unsigned tx_slots_free() { return _tx_queue->slots_free(); } }; @@ -775,6 +788,12 @@ class Packet_stream_sink : private Packet_stream_base */ bool ready_to_ack() { return _ack_transmitter.ready_for_tx(); } + /** + * Returns number of slots left in the the ack queue + */ + unsigned ack_slots_free() { + return _ack_transmitter.tx_slots_free(); } + /** * Tell the source that the processing of the specified packet is completed * diff --git a/os/src/drivers/ahci/exynos5/ahci_driver.h b/os/src/drivers/ahci/exynos5/ahci_driver.h index 9b1367458..eb9df696f 100644 --- a/os/src/drivers/ahci/exynos5/ahci_driver.h +++ b/os/src/drivers/ahci/exynos5/ahci_driver.h @@ -61,7 +61,7 @@ class Ahci_driver : public Block::Driver { if (_ncq_command(block_nr, block_cnt, phys, 0)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } void write_dma(Block::sector_t block_nr, size_t block_cnt, addr_t phys, @@ -69,7 +69,7 @@ class Ahci_driver : public Block::Driver { if (_ncq_command(block_nr, block_cnt, phys, 1)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } }; diff --git a/os/src/drivers/ahci/include/ahci_driver_base.h b/os/src/drivers/ahci/include/ahci_driver_base.h index 4f5364d2d..5a2f050d7 100644 --- a/os/src/drivers/ahci/include/ahci_driver_base.h +++ b/os/src/drivers/ahci/include/ahci_driver_base.h @@ -66,7 +66,7 @@ class Ahci_driver_base : public Block::Driver { _sanity_check(block_number, block_count); _device->read(block_number, block_count, phys); - if (session) session->complete_packet(packet); + if (session) session->ack_packet(packet); } void write_dma(Block::sector_t block_number, @@ -76,7 +76,7 @@ class Ahci_driver_base : public Block::Driver { _sanity_check(block_number, block_count); _device->write(block_number, block_count, phys); - if (session) session->complete_packet(packet); + if (session) session->ack_packet(packet); } Ram_dataspace_capability alloc_dma_buffer(size_t size) { diff --git a/os/src/drivers/atapi/ata_device.h b/os/src/drivers/atapi/ata_device.h index 2d6894483..d1d6027b1 100644 --- a/os/src/drivers/atapi/ata_device.h +++ b/os/src/drivers/atapi/ata_device.h @@ -124,7 +124,7 @@ namespace Ata { Block::Packet_descriptor &packet) { _read(block_number, block_count, buffer, false); - session->complete_packet(packet); + session->ack_packet(packet); } void write(Block::sector_t block_number, @@ -133,7 +133,7 @@ namespace Ata { Block::Packet_descriptor &packet) { _write(block_number, block_count, buffer, false); - session->complete_packet(packet); + session->ack_packet(packet); } void read_dma(Block::sector_t block_number, @@ -142,7 +142,7 @@ namespace Ata { Block::Packet_descriptor &packet) { _read(block_number, block_count, (char*)phys, true); - session->complete_packet(packet); + session->ack_packet(packet); } void write_dma(Block::sector_t block_number, @@ -151,7 +151,7 @@ namespace Ata { Block::Packet_descriptor &packet) { _write(block_number, block_count, (char*)phys, true); - session->complete_packet(packet); + session->ack_packet(packet); } bool dma_enabled() { return _dma; } diff --git a/os/src/drivers/sd_card/exynos5/driver.h b/os/src/drivers/sd_card/exynos5/driver.h index 8cb2d6dbd..2e16a5f61 100644 --- a/os/src/drivers/sd_card/exynos5/driver.h +++ b/os/src/drivers/sd_card/exynos5/driver.h @@ -104,7 +104,7 @@ class Block::Exynos5_driver : public Block::Driver { if (!_controller.read_blocks_dma(block_number, block_count, phys)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } void write_dma(Block::sector_t block_number, @@ -114,7 +114,7 @@ class Block::Exynos5_driver : public Block::Driver { if (!_controller.write_blocks_dma(block_number, block_count, phys)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } bool dma_enabled() { return _use_dma; } diff --git a/os/src/drivers/sd_card/omap4/driver.h b/os/src/drivers/sd_card/omap4/driver.h index d6d78fa97..11b8f50ab 100644 --- a/os/src/drivers/sd_card/omap4/driver.h +++ b/os/src/drivers/sd_card/omap4/driver.h @@ -97,7 +97,7 @@ class Block::Omap4_driver : public Block::Driver { if (!_controller.read_blocks(block_number, block_count, out_buffer)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } void write(Block::sector_t block_number, @@ -107,7 +107,7 @@ class Block::Omap4_driver : public Block::Driver { if (!_controller.write_blocks(block_number, block_count, buffer)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } void read_dma(Block::sector_t block_number, @@ -117,7 +117,7 @@ class Block::Omap4_driver : public Block::Driver { if (!_controller.read_blocks_dma(block_number, block_count, phys)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } void write_dma(Block::sector_t block_number, @@ -127,7 +127,7 @@ class Block::Omap4_driver : public Block::Driver { if (!_controller.write_blocks_dma(block_number, block_count, phys)) throw Io_error(); - session->complete_packet(packet); + session->ack_packet(packet); } bool dma_enabled() { return _use_dma; } diff --git a/os/src/drivers/sd_card/pl180/sd_card.h b/os/src/drivers/sd_card/pl180/sd_card.h index 76f1eb363..a3655e300 100644 --- a/os/src/drivers/sd_card/pl180/sd_card.h +++ b/os/src/drivers/sd_card/pl180/sd_card.h @@ -107,7 +107,7 @@ class Sd_card : public Block::Driver length, &resp); _hd.read_data(length, out_buffer + (i * BLOCK_SIZE)); } - session->complete_packet(packet); + session->ack_packet(packet); } void write(Block::sector_t block_number, @@ -129,7 +129,7 @@ class Sd_card : public Block::Driver length, &resp); _hd.write_data(length, buffer + (i * BLOCK_SIZE)); } - session->complete_packet(packet); + session->ack_packet(packet); } }; diff --git a/os/src/server/rom_blk/main.cc b/os/src/server/rom_blk/main.cc index 52ea1afe9..a38749f28 100644 --- a/os/src/server/rom_blk/main.cc +++ b/os/src/server/rom_blk/main.cc @@ -76,7 +76,7 @@ class Rom_blk : public Block::Driver /* copy file content to packet payload */ memcpy((void*)buffer, (void*)(_file_addr + offset), size); - session->complete_packet(packet); + session->ack_packet(packet); } }; diff --git a/os/src/test/fb_block_adapter/main.cc b/os/src/test/fb_block_adapter/main.cc index b374d516d..d067b5fbc 100644 --- a/os/src/test/fb_block_adapter/main.cc +++ b/os/src/test/fb_block_adapter/main.cc @@ -74,7 +74,7 @@ class Driver : public Block::Driver Genode::size_t size = block_count * BLOCK_SIZE; Genode::memcpy((void*)buffer, (void*)(_fb_addr + offset), size); - session->complete_packet(packet); + session->ack_packet(packet); } void write(Block::sector_t block_number, @@ -94,7 +94,7 @@ class Driver : public Block::Driver Genode::memcpy((void*)(_fb_addr + offset), (void*)buffer, size); _fb.refresh(0, 0, _fb_mode.width(), _fb_mode.height()); - session->complete_packet(packet); + session->ack_packet(packet); } };