diff --git a/repos/os/src/drivers/nic/spec/gem/buffer_descriptor.h b/repos/os/src/drivers/nic/spec/gem/buffer_descriptor.h index c0989c8b1..9fb69934e 100644 --- a/repos/os/src/drivers/nic/spec/gem/buffer_descriptor.h +++ b/repos/os/src/drivers/nic/spec/gem/buffer_descriptor.h @@ -1,11 +1,12 @@ /* * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \author Timo Wischer + * \author Johannes Schlatow * \date 2015-03-10 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2018 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -25,15 +26,12 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio { public: static const size_t BUFFER_DESC_SIZE = 0x08; - static const size_t MAX_PACKAGE_SIZE = 1600; - static const size_t BUFFER_SIZE = BUFFER_DESC_SIZE + MAX_PACKAGE_SIZE; + static const size_t BUFFER_SIZE = 1600; private: - const size_t _buffer_count; - const size_t _buffer_offset; - - unsigned int _descriptor_index; - char* const _buffer; + size_t _buffer_count; + size_t _head_idx { 0 }; + size_t _tail_idx { 0 }; protected: typedef struct { @@ -43,27 +41,49 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio descriptor_t* const _descriptors; + /* set the maximum descriptor index */ + inline + void _max_index(size_t max_index) { _buffer_count = max_index+1; }; + /* get the maximum descriptor index */ + inline + unsigned _max_index() { return _buffer_count-1; } - void _increment_descriptor_index() + inline + void _advance_head() { - _descriptor_index++; - _descriptor_index %= _buffer_count; + _head_idx = (_head_idx+1) % _buffer_count; } - - descriptor_t& _current_descriptor() + inline + void _advance_tail() { - return _descriptors[_descriptor_index]; + _tail_idx = (_tail_idx+1) % (_buffer_count); } - - char * _current_buffer() + inline + descriptor_t& _head() { - char * const buffer = &_buffer[MAX_PACKAGE_SIZE * _descriptor_index]; - return buffer; + return _descriptors[_head_idx]; } + inline + descriptor_t& _tail() + { + return _descriptors[_tail_idx]; + } + + size_t _queued() const + { + if (_head_idx >= _tail_idx) + return _head_idx - _tail_idx; + else + return _head_idx + _buffer_count - _tail_idx; + } + + size_t _head_index() const { return _head_idx; } + size_t _tail_index() const { return _tail_idx; } + private: /* @@ -72,6 +92,7 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio Buffer_descriptor(Buffer_descriptor const &); Buffer_descriptor &operator = (Buffer_descriptor const &); + public: /* * start of the ram spave contains all buffer descriptors @@ -79,33 +100,13 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio */ Buffer_descriptor(Genode::Env &env, const size_t buffer_count = 1) : - Attached_ram_dataspace(env.ram(), env.rm(), BUFFER_SIZE * buffer_count, UNCACHED), + Attached_ram_dataspace(env.ram(), env.rm(), BUFFER_DESC_SIZE * buffer_count, UNCACHED), Genode::Mmio( reinterpret_cast(local_addr()) ), _buffer_count(buffer_count), - _buffer_offset(BUFFER_DESC_SIZE * buffer_count), - _descriptor_index(0), - _buffer(local_addr() + _buffer_offset), _descriptors(local_addr()) - { - /* - * Save address of _buffer. - * Has to be the physical address and not the virtual addresse, - * because the dma controller of the nic will use it. - * Ignore lower two bits, - * because this are status bits. - */ - for (unsigned int i=0; i {}; struct Clear_statistics : Bitfield<5, 1> {}; struct Start_tx : Bitfield<9, 1> {}; + struct Tx_pause : Bitfield<11, 1> {}; static access_t init() { return Mgmt_port_en::bits(1) | @@ -75,6 +76,7 @@ namespace Genode struct No_broadcast : Bitfield<5, 1> {}; struct Multi_hash_en : Bitfield<6, 1> {}; struct Gige_en : Bitfield<10, 1> {}; + struct Pause_en : Bitfield<13, 1> {}; struct Fcs_remove : Bitfield<17, 1> {}; struct Mdc_clk_div : Bitfield<18, 3> { enum { @@ -82,6 +84,8 @@ namespace Genode DIV_224 = 0b111, }; }; + struct Dis_cp_pause : Bitfield<23, 1> {}; + struct Rx_chksum_en : Bitfield<24, 1> {}; struct Ignore_rx_fcs : Bitfield<26, 1> {}; }; @@ -100,6 +104,7 @@ namespace Genode */ struct Dma_config : Register<0x10, 32> { + struct Disc_when_no_ahb : Bitfield<24,1> {}; struct Rx_pktbuf_memsz_sel : Bitfield<8, 2> { enum { SPACE_8KB = 0x3, @@ -115,15 +120,25 @@ namespace Genode BUFFER_1600B = 0x19, }; }; + struct Csum_gen_en : Bitfield<11, 1> { }; + struct Burst_len : Bitfield<0, 5> { + enum { + INCR16 = 0x10, + INCR8 = 0x08, + INCR4 = 0x04, + SINGLE = 0x01 + }; + }; static access_t init() { return Ahb_mem_rx_buf_size::bits(Ahb_mem_rx_buf_size::BUFFER_1600B) | Rx_pktbuf_memsz_sel::bits(Rx_pktbuf_memsz_sel::SPACE_8KB) | - Tx_pktbuf_memsz_sel::bits(Tx_pktbuf_memsz_sel::SPACE_4KB); + Tx_pktbuf_memsz_sel::bits(Tx_pktbuf_memsz_sel::SPACE_4KB) | + Disc_when_no_ahb::bits(1) | + Csum_gen_en::bits(1) | + Burst_len::bits(Burst_len::INCR16); } - - // TODO possibly enable transmition check sum offloading }; /** @@ -151,36 +166,40 @@ namespace Genode struct Addr : Bitfield<0, 32> {}; }; - /** * Receive status register */ struct Rx_status : Register<0x20, 32> { - struct Frame_reveived : Bitfield<1, 1> {}; + struct Rx_overrun : Bitfield<2, 1> {}; + struct Frame_received : Bitfield<1, 1> {}; struct Buffer_not_available : Bitfield<0, 1> {}; }; - /** * Interrupt status register */ struct Interrupt_status : Register<0x24, 32> { - struct Rx_used_read : Bitfield<3, 1> {}; - struct Rx_complete : Bitfield<1, 1> {}; + struct Rx_used_read : Bitfield<2, 1> {}; + struct Rx_complete : Bitfield<1, 1> {}; + struct Pause_zero : Bitfield<13,1> {}; + struct Pause_received : Bitfield<12,1> {}; + struct Rx_overrun : Bitfield<10,1> {}; }; - /** * Interrupt enable register */ struct Interrupt_enable : Register<0x28, 32> { - struct Rx_complete : Bitfield<1, 1> {}; + struct Rx_used_read : Bitfield<2, 1> {}; + struct Rx_complete : Bitfield<1, 1> {}; + struct Pause_zero : Bitfield<13,1> {}; + struct Pause_received : Bitfield<12,1> {}; + struct Rx_overrun : Bitfield<10,1> {}; }; - /** * Interrupt disable register */ @@ -189,7 +208,6 @@ namespace Genode struct Rx_complete : Bitfield<1, 1> {}; }; - /** * PHY maintenance register */ @@ -210,7 +228,6 @@ namespace Genode struct Data : Bitfield<0, 16> {}; }; - /** * MAC hash register */ @@ -220,7 +237,6 @@ namespace Genode struct High_hash : Bitfield<32, 16> { }; }; - /** * MAC Addresse */ @@ -230,7 +246,6 @@ namespace Genode struct High_addr : Bitfield<32, 16> { }; }; - /** * Counter for the successfully transmitted frames */ @@ -239,6 +254,13 @@ namespace Genode struct Counter : Bitfield<0, 32> { }; }; + /** + * Counter for the transmitted pause frames + */ + struct Pause_transmitted : Register<0x114, 32> + { + struct Counter : Bitfield<0, 16> { }; + }; /** * Counter for the successfully received frames @@ -248,15 +270,62 @@ namespace Genode struct Counter : Bitfield<0, 32> { }; }; + /** + * Counter for resource error statistics + */ + struct Rx_resource_errors : Register<0x1A0, 32> + { + struct Counter : Bitfield<0, 18> { }; + }; /** - * Counter for the successfully received frames + * Counter for overrun statistics */ struct Rx_overrun_errors : Register<0x1A4, 32> { struct Counter : Bitfield<0, 10> { }; }; + /** + * Counter for IP checksum errors + */ + struct Rx_ip_chksum_errors : Register<0x1A8, 32> + { + struct Counter : Bitfield<0, 8> { }; + }; + + /** + * Counter for TCP checksum errors + */ + struct Rx_tcp_chksum_errors : Register<0x1AC, 32> + { + struct Counter : Bitfield<0, 8> { }; + }; + + /** + * Counter for UDP checksum errors + */ + struct Rx_udp_chksum_errors : Register<0x1B0, 32> + { + struct Counter : Bitfield<0, 8> { }; + }; + + /** + * Counter for FCS errors + */ + struct Rx_fcs_errors : Register<0x190, 32> + { + struct Counter : Bitfield<0, 10> { }; + }; + + /** + * Counter for pause frames received + */ + struct Pause_received : Register<0x164, 32> + { + struct Counter : Bitfield<0, 16> { }; + }; + class Phy_timeout_for_idle : public Genode::Exception {}; class Unkown_ethernet_speed : public Genode::Exception {}; @@ -278,10 +347,14 @@ namespace Genode /* 1. Program the Network Configuration register (gem.net_cfg) */ write( + Config::Gige_en::bits(1) | Config::Speed_100::bits(1) | + Config::Pause_en::bits(1) | Config::Full_duplex::bits(1) | Config::Multi_hash_en::bits(1) | Config::Mdc_clk_div::bits(Config::Mdc_clk_div::DIV_32) | + Config::Dis_cp_pause::bits(1) | + Config::Rx_chksum_en::bits(1) | Config::Fcs_remove::bits(1) ); @@ -312,12 +385,14 @@ namespace Genode write(1); rclk = (0 << 4) | (1 << 0); clk = (1 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + log("Autonegotiation result: 1Gbit/s"); break; case SPEED_100: write(0); write(1); rclk = 1 << 0; clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + log("Autonegotiation result: 100Mbit/s"); break; case SPEED_10: write(0); @@ -325,6 +400,7 @@ namespace Genode rclk = 1 << 0; /* FIXME untested */ clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + log("Autonegotiation result: 10Mbit/s"); break; default: throw Unkown_ethernet_speed(); @@ -333,7 +409,11 @@ namespace Genode /* 16.3.6 Configure Interrupts */ - write(Interrupt_enable::Rx_complete::bits(1)); + write(Interrupt_enable::Rx_complete::bits(1) | + Interrupt_enable::Rx_overrun::bits(1) | + Interrupt_enable::Pause_received::bits(1) | + Interrupt_enable::Pause_zero::bits(1) | + Interrupt_enable::Rx_used_read::bits(1)); } void _deinit() @@ -394,6 +474,14 @@ namespace Genode _mdio_wait(); } + inline void _handle_acks() + { + while (_rx.source()->ack_avail()) { + Nic::Packet_descriptor p = _rx.source()->get_acked_packet(); + _rx_buffer.reset_descriptor(p); + } + } + virtual void _handle_irq() { /* 16.3.9 Receiving Frames */ @@ -401,51 +489,82 @@ namespace Genode const Interrupt_status::access_t status = read(); const Rx_status::access_t rxStatus = read(); - /* FIXME strangely, this handler is also called without any status bit set in Interrupt_status */ if ( Interrupt_status::Rx_complete::get(status) ) { - while (_rx_buffer.package_available()) { - // TODO use this buffer directly as the destination for the DMA controller - // to minimize the overrun errors - const size_t buffer_size = _rx_buffer.package_length(); + while (_rx_buffer.next_packet()) { - /* allocate rx packet buffer */ - Nic::Packet_descriptor p; - try { - p = _rx.source()->alloc_packet(buffer_size); - } catch (Session::Rx::Source::Packet_alloc_failed) { return; } + _handle_acks(); - char *dst = (char *)_rx.source()->packet_content(p); - - /* - * copy data from rx buffer to new allocated buffer. - * Has to be copied, - * because the extern allocater possibly is using the cache. - */ - if ( _rx_buffer.get_package(dst, buffer_size) != buffer_size ) { - PWRN("Package not fully copiied. Package ignored."); - break; - } - - /* clearing error flags */ - write(1); - write(1); - - /* comit buffer to system services */ - _rx.source()->submit_packet(p); + Nic::Packet_descriptor p = _rx_buffer.get_packet_descriptor(); + if (_rx.source()->packet_valid(p)) + _rx.source()->submit_packet(p); + else + Genode::error("invalid packet descriptor ", Genode::Hex(p.offset()), + " size ", Genode::Hex(p.size())); } - /* check, if there was lost some packages */ - const uint16_t lost_packages = read(); - if (lost_packages > 0) { - PWRN("%d packages lost (%d packages successfully received)!", - lost_packages, read()); - } - - /* reset reveive complete interrupt */ - write(Rx_status::Frame_reveived::bits(1)); + /* reset receive complete interrupt */ + write(Rx_status::Frame_received::bits(1)); write(Interrupt_status::Rx_complete::bits(1)); } + else { + _handle_acks(); + } + + bool print_stats = false; + if (Interrupt_status::Rx_overrun::get(status)) { + write(1); + write(Interrupt_status::Rx_overrun::bits(1)); + write(Rx_status::Rx_overrun::bits(1)); + print_stats = true; + Genode::error("Rx overrun"); + } + if (Interrupt_status::Rx_used_read::get(status)) { + /* tried to use buffer descriptor with used bit set */ + /* we sent a pause frame because the buffer appears to + * be full + */ + write(1); + write(Interrupt_status::Rx_used_read::bits(1)); + write(Rx_status::Buffer_not_available::bits(1)); + print_stats = true; + Genode::error("Rx used"); + } + if (Interrupt_status::Pause_zero::get(status)) { + Genode::warning("Pause ended."); + write(Interrupt_status::Pause_zero::bits(1)); + print_stats = true; + } + if (Interrupt_status::Pause_received::get(status)) { + Genode::warning("Pause frame received."); + write(Interrupt_status::Pause_received::bits(1)); + print_stats = true; + } + + if (print_stats) { + /* check, if there was lost some packages */ + const uint32_t received = read(); + const uint32_t pause_rx = read(); + const uint32_t res_err = read(); + const uint32_t overrun = read(); + const uint32_t fcs_err = read(); + const uint32_t ip_chk = read(); + const uint32_t udp_chk = read(); + const uint32_t tcp_chk = read(); + const uint32_t transmit = read(); + const uint32_t pause_tx = read(); + + Genode::warning("Received: ", received); + Genode::warning(" pause frames: ", pause_rx); + Genode::warning(" resource errors: ", res_err); + Genode::warning(" overrun errors: ", overrun); + Genode::warning(" FCS errors: ", fcs_err); + Genode::warning(" IP chk failed: ", ip_chk); + Genode::warning(" UDP chk failed: ", udp_chk); + Genode::warning(" TCP chk failed: ", tcp_chk); + Genode::warning("Transmitted: ", transmit); + Genode::warning(" pause frames: ", pause_tx); + } _irq.ack_irq(); } @@ -465,7 +584,9 @@ namespace Genode Genode::Attached_mmio(env, base, size), Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env), _timer(env), - _sys_ctrl(env, _timer), _tx_buffer(env, _timer), _rx_buffer(env), + _sys_ctrl(env, _timer), + _tx_buffer(env, *_tx.sink(), _timer), + _rx_buffer(env, *_rx.source()), _irq(env, irq), _irq_handler(env.ep(), *this, &Cadence_gem::_handle_irq), _phy(*this, _timer) @@ -511,6 +632,10 @@ namespace Genode bool _send() { + /* first, see whether we can acknowledge any + * previously sent packet */ + _tx_buffer.submit_acks(*_tx.sink()); + if (!_tx.sink()->ready_to_ack()) return false; @@ -523,12 +648,14 @@ namespace Genode return true; } - char *src = (char *)_tx.sink()->packet_content(packet); + try { + _tx_buffer.add_to_queue(packet); + write(Control::start_tx()); + } catch (Tx_buffer_descriptor::Package_send_timeout) { + Genode::warning("Package Tx timeout"); + return false; + } - _tx_buffer.add_to_queue(src, packet.size()); - write(Control::start_tx()); - - _tx.sink()->acknowledge_packet(packet); return true; } @@ -557,10 +684,9 @@ namespace Genode void _handle_packet_stream() override { - while (_rx.source()->ack_avail()) - _rx.source()->release_packet(_rx.source()->get_acked_packet()); + _handle_acks(); - while (_send()) ; + while (_send()); } }; } diff --git a/repos/os/src/drivers/nic/spec/gem/main.cc b/repos/os/src/drivers/nic/spec/gem/main.cc index 11d340cbc..ae92ad4f1 100644 --- a/repos/os/src/drivers/nic/spec/gem/main.cc +++ b/repos/os/src/drivers/nic/spec/gem/main.cc @@ -59,7 +59,6 @@ class Server::Gem_session_component : public Cadence_gem try { Genode::Xml_node nic_config = _config_rom.xml().sub_node("nic"); nic_config.attribute("mac").value(&mac_addr); - Genode::log("Using configured MAC address ", mac_addr); } catch (...) { /* fall back to fake MAC address (unicast, locally managed) */ mac_addr.addr[0] = 0x02; @@ -70,6 +69,8 @@ class Server::Gem_session_component : public Cadence_gem mac_addr.addr[5] = 0x01; } + Genode::log("Using MAC address ", mac_addr); + /* set mac address */ mac_address(mac_addr); } diff --git a/repos/os/src/drivers/nic/spec/gem/rx_buffer_descriptor.h b/repos/os/src/drivers/nic/spec/gem/rx_buffer_descriptor.h index ff4bacc8b..b70fb05a0 100644 --- a/repos/os/src/drivers/nic/spec/gem/rx_buffer_descriptor.h +++ b/repos/os/src/drivers/nic/spec/gem/rx_buffer_descriptor.h @@ -1,11 +1,12 @@ /* * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \author Timo Wischer + * \author Johannes Schlatow * \date 2015-03-10 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2018 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -22,10 +23,11 @@ using namespace Genode; class Rx_buffer_descriptor : public Buffer_descriptor { private: + struct Addr : Register<0x00, 32> { - struct Addr31to2 : Bitfield<2, 28> {}; + struct Addr31to2 : Bitfield<2, 30> {}; struct Wrap : Bitfield<1, 1> {}; - struct Package_available : Bitfield<0, 1> {}; + struct Used : Bitfield<0, 1> {}; }; struct Status : Register<0x04, 32> { struct Length : Bitfield<0, 13> {}; @@ -33,102 +35,101 @@ class Rx_buffer_descriptor : public Buffer_descriptor struct End_of_frame : Bitfield<15, 1> {}; }; - enum { BUFFER_COUNT = 16 }; + enum { MAX_BUFFER_COUNT = 1024 }; + addr_t const _phys_base; - /** - * @brief _set_buffer_processed resets the available flag - * So the DMA controller can use this buffer for an received package. - * The buffer index will be incremented, too. - * So the right sequenz of packages will be keeped. - */ - void _set_package_processed() - { - /* reset package available for new package */ - _current_descriptor().addr &= ~Addr::Package_available::bits(1); - /* use next buffer descriptor for next package */ - _increment_descriptor_index(); + void _reset_descriptor(unsigned const i, addr_t phys_addr) { + if (i > _max_index()) + return; + + /* clear status */ + _descriptors[i].status = 0; + + /* set physical buffer address and set not used by SW + * last descriptor must be marked by Wrap bit + */ + _descriptors[i].addr = + (phys_addr & Addr::Addr31to2::reg_mask()) + | Addr::Wrap::bits(i == _max_index()); } + inline bool _head_available() + { + return Addr::Used::get(_head().addr) + && Status::Length::get(_head().status); + } public: - Rx_buffer_descriptor(Genode::Env &env) : Buffer_descriptor(env, BUFFER_COUNT) + Rx_buffer_descriptor(Genode::Env &env, + Nic::Session::Tx::Source &source) + : Buffer_descriptor(env, MAX_BUFFER_COUNT), + _phys_base(Dataspace_client(source.dataspace()).phys_addr()) { - /* - * mark the last buffer descriptor - * so the dma will start at the beginning again - */ - _descriptors[BUFFER_COUNT-1].addr |= Addr::Wrap::bits(1); + for (size_t i=0; i <= _max_index(); i++) { + try { + Nic::Packet_descriptor p = source.alloc_packet(BUFFER_SIZE); + _reset_descriptor(i, _phys_base + p.offset()); + } catch (Nic::Session::Rx::Source::Packet_alloc_failed) { + /* set new _buffer_count */ + _max_index(i-1); + /* set wrap bit */ + _descriptors[_max_index()].addr |= Addr::Wrap::bits(1); + break; + } + } + + Genode::log("Initialised ", _max_index()+1, " RX buffer descriptors"); } - - bool package_available() + bool reset_descriptor(Packet_descriptor pd) { - for (unsigned int i=0; i max_length) { - warning("Buffer for received package to small. Package ignored!"); + + /* reset status */ + _head().status = 0; - _set_package_processed(); - return 0; - } - - const char* const src_buffer = _current_buffer(); - memcpy(package, src_buffer, length); - - _set_package_processed(); - - - return length; + return Nic::Packet_descriptor((addr_t)Addr::Addr31to2::masked(_head().addr) - _phys_base, length); } - void show_mem_diffs() - { - static unsigned int old_data[0x1F]; - - log("Rx buffer:"); - const unsigned int* const cur_data = local_addr(); - for (unsigned i=0; i ", Hex(cur_data[i])); - } - } - memcpy(old_data, cur_data, sizeof(old_data)); - } }; #endif /* _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_ */ diff --git a/repos/os/src/drivers/nic/spec/gem/tx_buffer_descriptor.h b/repos/os/src/drivers/nic/spec/gem/tx_buffer_descriptor.h index c732dc974..ee0fd4631 100644 --- a/repos/os/src/drivers/nic/spec/gem/tx_buffer_descriptor.h +++ b/repos/os/src/drivers/nic/spec/gem/tx_buffer_descriptor.h @@ -1,11 +1,12 @@ /* * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \author Timo Wischer + * \author Johannes Schlatow * \date 2015-03-10 */ /* - * Copyright (C) 2015-2017 Genode Labs GmbH + * Copyright (C) 2015-2018 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -25,7 +26,7 @@ using namespace Genode; class Tx_buffer_descriptor : public Buffer_descriptor { private: - enum { BUFFER_COUNT = 2 }; + enum { BUFFER_COUNT = 1024 }; struct Addr : Register<0x00, 32> {}; struct Status : Register<0x04, 32> { @@ -33,51 +34,109 @@ class Tx_buffer_descriptor : public Buffer_descriptor struct Last_buffer : Bitfield<15, 1> {}; struct Wrap : Bitfield<30, 1> {}; struct Used : Bitfield<31, 1> {}; + struct Chksum_err : Bitfield<20, 2> {}; }; - class Package_send_timeout : public Genode::Exception {}; - Timer::Connection &_timer; - public: - Tx_buffer_descriptor(Genode::Env &env, Timer::Connection &timer) - : Buffer_descriptor(env, BUFFER_COUNT), _timer(timer) - { - for (unsigned int i=0; i _max_index()) + return; + + /* set physical buffer address */ + _descriptors[i].addr = phys_addr; + + /* set used by SW, also we do not use frame scattering */ + _descriptors[i].status = Status::Used::bits(1) | + Status::Last_buffer::bits(1); + + /* last buffer must be marked by Wrap bit */ + if (i == _max_index()) + _descriptors[i].status |= Status::Wrap::bits(1); } + public: - void add_to_queue(const char* const packet, const size_t size) + class Package_send_timeout : public Genode::Exception {}; + + Tx_buffer_descriptor(Genode::Env &env, + Nic::Session::Rx::Sink &sink, + Timer::Connection &timer) + : Buffer_descriptor(env, BUFFER_COUNT), _timer(timer), + _phys_base(Dataspace_client(sink.dataspace()).phys_addr()) { - if (size > MAX_PACKAGE_SIZE) { + for (size_t i=0; i <= _max_index(); i++) { + /* configure all descriptors with address 0, which we + * interpret as invalid */ + _reset_descriptor(i, 0x0); + } + } + + void submit_acks(Nic::Session::Rx::Sink &sink) + { + /* the tail marks the descriptor for which we wait to + * be handed over to software */ + for (size_t i=0; i <= _queued(); i++) { + /* stop if still in use by hardware */ + if (!Status::Used::get(_tail().status)) + break; + + /* if descriptor has been configured properly */ + if (_tail().addr != 0) { + + /* build packet descriptor from buffer descriptor + * and acknowledge packet */ + const size_t length = Status::Length::get(_tail().status); + Nic::Packet_descriptor p((addr_t)_tail().addr - _phys_base, length); + if (sink.packet_valid(p)) + sink.acknowledge_packet(p); + + /* erase address so that we don't send an ack again */ + _tail().addr = 0; + + /* TODO optionally, we may evaluate the Tx status here */ + } + + _advance_tail(); + } + } + + void add_to_queue(Nic::Packet_descriptor p) + { + /* the head marks the descriptor that we use next for + * handing over the packet to hardware */ + if (p.size() > BUFFER_SIZE) { warning("Ethernet package to big. Not sent!"); return; } - /* wait until the used bit is set (timeout after 200ms) */ - uint32_t timeout = 200; - while ( !Status::Used::get(_current_descriptor().status) ) { - if (timeout <= 0) { - throw Package_send_timeout(); - } - timeout--; - - _timer.msleep(1); + addr_t const packet_phys = _phys_base + p.offset(); + if (packet_phys & 0x1f) { + warning("Packet is not aligned properly."); } + /* wait until the used bit is set (timeout after 10ms) */ + uint32_t timeout = 10000; + while ( !Status::Used::get(_head().status) ) { + if (timeout == 0) { + throw Package_send_timeout(); + } + timeout -= 1000; - memcpy(_current_buffer(), packet, size); + /* TODO buffer is full, instead of sleeping we should + * therefore wait for tx_complete interrupt */ + _timer.usleep(1000); + } - _current_descriptor().status &= Status::Length::clear_mask(); - _current_descriptor().status |= Status::Length::bits(size); + _reset_descriptor(_head_index(), packet_phys); + _head().status |= Status::Length::bits(p.size()); - /* unset the unset bit */ - _current_descriptor().status &= Status::Used::clear_mask(); + /* unset the used bit */ + _head().status &= Status::Used::clear_mask(); - _increment_descriptor_index(); + _advance_head(); } };