zynq: zero-copy implementation of nic_drv

- Packet stream buffers are directly passed to DMA.
- Also enables pause frames and checksum offloading.

Issue #3053
This commit is contained in:
Johannes Schlatow
2018-09-29 12:31:49 +02:00
committed by Christian Helmuth
parent 8ad56a6c0e
commit dc0bfd7008
5 changed files with 394 additions and 206 deletions

View File

@ -1,11 +1,12 @@
/* /*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Timo Wischer * \author Timo Wischer
* \author Johannes Schlatow
* \date 2015-03-10 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * 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: public:
static const size_t BUFFER_DESC_SIZE = 0x08; static const size_t BUFFER_DESC_SIZE = 0x08;
static const size_t MAX_PACKAGE_SIZE = 1600; static const size_t BUFFER_SIZE = 1600;
static const size_t BUFFER_SIZE = BUFFER_DESC_SIZE + MAX_PACKAGE_SIZE;
private: private:
const size_t _buffer_count; size_t _buffer_count;
const size_t _buffer_offset; size_t _head_idx { 0 };
size_t _tail_idx { 0 };
unsigned int _descriptor_index;
char* const _buffer;
protected: protected:
typedef struct { typedef struct {
@ -43,27 +41,49 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio
descriptor_t* const _descriptors; 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++; _head_idx = (_head_idx+1) % _buffer_count;
_descriptor_index %= _buffer_count;
} }
inline
descriptor_t& _current_descriptor() void _advance_tail()
{ {
return _descriptors[_descriptor_index]; _tail_idx = (_tail_idx+1) % (_buffer_count);
} }
inline
char * _current_buffer() descriptor_t& _head()
{ {
char * const buffer = &_buffer[MAX_PACKAGE_SIZE * _descriptor_index]; return _descriptors[_head_idx];
return buffer;
} }
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: private:
/* /*
@ -72,6 +92,7 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio
Buffer_descriptor(Buffer_descriptor const &); Buffer_descriptor(Buffer_descriptor const &);
Buffer_descriptor &operator = (Buffer_descriptor const &); Buffer_descriptor &operator = (Buffer_descriptor const &);
public: public:
/* /*
* start of the ram spave contains all buffer descriptors * 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) 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<addr_t>(local_addr<void>()) ), Genode::Mmio( reinterpret_cast<addr_t>(local_addr<void>()) ),
_buffer_count(buffer_count), _buffer_count(buffer_count),
_buffer_offset(BUFFER_DESC_SIZE * buffer_count),
_descriptor_index(0),
_buffer(local_addr<char>() + _buffer_offset),
_descriptors(local_addr<descriptor_t>()) _descriptors(local_addr<descriptor_t>())
{ { }
/*
* 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<buffer_count; i++) {
_descriptors[i].addr = (phys_addr_buffer(i)) & ~0x3;
}
}
addr_t phys_addr() { return Dataspace_client(cap()).phys_addr(); } addr_t phys_addr() { return Dataspace_client(cap()).phys_addr(); }
addr_t phys_addr_buffer(const unsigned int index)
{
return phys_addr() + _buffer_offset + MAX_PACKAGE_SIZE * index;
}
}; };
#endif /* _INCLUDE__DRIVERS__NIC__GEM__BUFFER_DESCRIPTOR_H_ */ #endif /* _INCLUDE__DRIVERS__NIC__GEM__BUFFER_DESCRIPTOR_H_ */

View File

@ -1,12 +1,12 @@
/* /*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Johannes Schlatow
* \author Timo Wischer * \author Timo Wischer
* \author Johannes Schlatow
* \date 2015-03-10 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -52,6 +52,7 @@ namespace Genode
struct Mgmt_port_en : Bitfield<4, 1> {}; struct Mgmt_port_en : Bitfield<4, 1> {};
struct Clear_statistics : Bitfield<5, 1> {}; struct Clear_statistics : Bitfield<5, 1> {};
struct Start_tx : Bitfield<9, 1> {}; struct Start_tx : Bitfield<9, 1> {};
struct Tx_pause : Bitfield<11, 1> {};
static access_t init() { static access_t init() {
return Mgmt_port_en::bits(1) | return Mgmt_port_en::bits(1) |
@ -75,6 +76,7 @@ namespace Genode
struct No_broadcast : Bitfield<5, 1> {}; struct No_broadcast : Bitfield<5, 1> {};
struct Multi_hash_en : Bitfield<6, 1> {}; struct Multi_hash_en : Bitfield<6, 1> {};
struct Gige_en : Bitfield<10, 1> {}; struct Gige_en : Bitfield<10, 1> {};
struct Pause_en : Bitfield<13, 1> {};
struct Fcs_remove : Bitfield<17, 1> {}; struct Fcs_remove : Bitfield<17, 1> {};
struct Mdc_clk_div : Bitfield<18, 3> { struct Mdc_clk_div : Bitfield<18, 3> {
enum { enum {
@ -82,6 +84,8 @@ namespace Genode
DIV_224 = 0b111, DIV_224 = 0b111,
}; };
}; };
struct Dis_cp_pause : Bitfield<23, 1> {};
struct Rx_chksum_en : Bitfield<24, 1> {};
struct Ignore_rx_fcs : Bitfield<26, 1> {}; struct Ignore_rx_fcs : Bitfield<26, 1> {};
}; };
@ -100,6 +104,7 @@ namespace Genode
*/ */
struct Dma_config : Register<0x10, 32> struct Dma_config : Register<0x10, 32>
{ {
struct Disc_when_no_ahb : Bitfield<24,1> {};
struct Rx_pktbuf_memsz_sel : Bitfield<8, 2> { struct Rx_pktbuf_memsz_sel : Bitfield<8, 2> {
enum { enum {
SPACE_8KB = 0x3, SPACE_8KB = 0x3,
@ -115,15 +120,25 @@ namespace Genode
BUFFER_1600B = 0x19, 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() static access_t init()
{ {
return Ahb_mem_rx_buf_size::bits(Ahb_mem_rx_buf_size::BUFFER_1600B) | 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) | 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> {}; struct Addr : Bitfield<0, 32> {};
}; };
/** /**
* Receive status register * Receive status register
*/ */
struct Rx_status : Register<0x20, 32> 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> {}; struct Buffer_not_available : Bitfield<0, 1> {};
}; };
/** /**
* Interrupt status register * Interrupt status register
*/ */
struct Interrupt_status : Register<0x24, 32> struct Interrupt_status : Register<0x24, 32>
{ {
struct Rx_used_read : Bitfield<3, 1> {}; struct Rx_used_read : Bitfield<2, 1> {};
struct Rx_complete : Bitfield<1, 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 * Interrupt enable register
*/ */
struct Interrupt_enable : Register<0x28, 32> struct Interrupt_enable : Register<0x28, 32>
{ {
struct Rx_used_read : Bitfield<2, 1> {};
struct Rx_complete : Bitfield<1, 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 * Interrupt disable register
*/ */
@ -189,7 +208,6 @@ namespace Genode
struct Rx_complete : Bitfield<1, 1> {}; struct Rx_complete : Bitfield<1, 1> {};
}; };
/** /**
* PHY maintenance register * PHY maintenance register
*/ */
@ -210,7 +228,6 @@ namespace Genode
struct Data : Bitfield<0, 16> {}; struct Data : Bitfield<0, 16> {};
}; };
/** /**
* MAC hash register * MAC hash register
*/ */
@ -220,7 +237,6 @@ namespace Genode
struct High_hash : Bitfield<32, 16> { }; struct High_hash : Bitfield<32, 16> { };
}; };
/** /**
* MAC Addresse * MAC Addresse
*/ */
@ -230,7 +246,6 @@ namespace Genode
struct High_addr : Bitfield<32, 16> { }; struct High_addr : Bitfield<32, 16> { };
}; };
/** /**
* Counter for the successfully transmitted frames * Counter for the successfully transmitted frames
*/ */
@ -239,6 +254,13 @@ namespace Genode
struct Counter : Bitfield<0, 32> { }; 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 * Counter for the successfully received frames
@ -248,15 +270,62 @@ namespace Genode
struct Counter : Bitfield<0, 32> { }; 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 Rx_overrun_errors : Register<0x1A4, 32>
{ {
struct Counter : Bitfield<0, 10> { }; 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 Phy_timeout_for_idle : public Genode::Exception {};
class Unkown_ethernet_speed : 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) */ /* 1. Program the Network Configuration register (gem.net_cfg) */
write<Config>( write<Config>(
Config::Gige_en::bits(1) |
Config::Speed_100::bits(1) | Config::Speed_100::bits(1) |
Config::Pause_en::bits(1) |
Config::Full_duplex::bits(1) | Config::Full_duplex::bits(1) |
Config::Multi_hash_en::bits(1) | Config::Multi_hash_en::bits(1) |
Config::Mdc_clk_div::bits(Config::Mdc_clk_div::DIV_32) | 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) Config::Fcs_remove::bits(1)
); );
@ -312,12 +385,14 @@ namespace Genode
write<Config::Gige_en>(1); write<Config::Gige_en>(1);
rclk = (0 << 4) | (1 << 0); rclk = (0 << 4) | (1 << 0);
clk = (1 << 20) | (8 << 8) | (0 << 4) | (1 << 0); clk = (1 << 20) | (8 << 8) | (0 << 4) | (1 << 0);
log("Autonegotiation result: 1Gbit/s");
break; break;
case SPEED_100: case SPEED_100:
write<Config::Gige_en>(0); write<Config::Gige_en>(0);
write<Config::Speed_100>(1); write<Config::Speed_100>(1);
rclk = 1 << 0; rclk = 1 << 0;
clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0);
log("Autonegotiation result: 100Mbit/s");
break; break;
case SPEED_10: case SPEED_10:
write<Config::Gige_en>(0); write<Config::Gige_en>(0);
@ -325,6 +400,7 @@ namespace Genode
rclk = 1 << 0; rclk = 1 << 0;
/* FIXME untested */ /* FIXME untested */
clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0);
log("Autonegotiation result: 10Mbit/s");
break; break;
default: default:
throw Unkown_ethernet_speed(); throw Unkown_ethernet_speed();
@ -333,7 +409,11 @@ namespace Genode
/* 16.3.6 Configure Interrupts */ /* 16.3.6 Configure Interrupts */
write<Interrupt_enable>(Interrupt_enable::Rx_complete::bits(1)); write<Interrupt_enable>(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() void _deinit()
@ -394,6 +474,14 @@ namespace Genode
_mdio_wait(); _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() virtual void _handle_irq()
{ {
/* 16.3.9 Receiving Frames */ /* 16.3.9 Receiving Frames */
@ -401,51 +489,82 @@ namespace Genode
const Interrupt_status::access_t status = read<Interrupt_status>(); const Interrupt_status::access_t status = read<Interrupt_status>();
const Rx_status::access_t rxStatus = read<Rx_status>(); const Rx_status::access_t rxStatus = read<Rx_status>();
/* FIXME strangely, this handler is also called without any status bit set in Interrupt_status */
if ( Interrupt_status::Rx_complete::get(status) ) { if ( Interrupt_status::Rx_complete::get(status) ) {
while (_rx_buffer.package_available()) { while (_rx_buffer.next_packet()) {
// 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();
/* allocate rx packet buffer */ _handle_acks();
Nic::Packet_descriptor p;
try {
p = _rx.source()->alloc_packet(buffer_size);
} catch (Session::Rx::Source::Packet_alloc_failed) { return; }
char *dst = (char *)_rx.source()->packet_content(p); Nic::Packet_descriptor p = _rx_buffer.get_packet_descriptor();
if (_rx.source()->packet_valid(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<Interrupt_status::Rx_used_read>(1);
write<Rx_status::Buffer_not_available>(1);
/* comit buffer to system services */
_rx.source()->submit_packet(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 */ /* reset receive complete interrupt */
const uint16_t lost_packages = read<Rx_overrun_errors::Counter>(); write<Rx_status>(Rx_status::Frame_received::bits(1));
if (lost_packages > 0) {
PWRN("%d packages lost (%d packages successfully received)!",
lost_packages, read<Frames_received>());
}
/* reset reveive complete interrupt */
write<Rx_status>(Rx_status::Frame_reveived::bits(1));
write<Interrupt_status>(Interrupt_status::Rx_complete::bits(1)); write<Interrupt_status>(Interrupt_status::Rx_complete::bits(1));
} }
else {
_handle_acks();
}
bool print_stats = false;
if (Interrupt_status::Rx_overrun::get(status)) {
write<Control::Tx_pause>(1);
write<Interrupt_status>(Interrupt_status::Rx_overrun::bits(1));
write<Rx_status>(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<Control::Tx_pause>(1);
write<Interrupt_status>(Interrupt_status::Rx_used_read::bits(1));
write<Rx_status>(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>(Interrupt_status::Pause_zero::bits(1));
print_stats = true;
}
if (Interrupt_status::Pause_received::get(status)) {
Genode::warning("Pause frame received.");
write<Interrupt_status>(Interrupt_status::Pause_received::bits(1));
print_stats = true;
}
if (print_stats) {
/* check, if there was lost some packages */
const uint32_t received = read<Frames_received>();
const uint32_t pause_rx = read<Pause_received::Counter>();
const uint32_t res_err = read<Rx_resource_errors::Counter>();
const uint32_t overrun = read<Rx_overrun_errors::Counter>();
const uint32_t fcs_err = read<Rx_fcs_errors::Counter>();
const uint32_t ip_chk = read<Rx_ip_chksum_errors::Counter>();
const uint32_t udp_chk = read<Rx_udp_chksum_errors::Counter>();
const uint32_t tcp_chk = read<Rx_tcp_chksum_errors::Counter>();
const uint32_t transmit = read<Frames_transmitted>();
const uint32_t pause_tx = read<Pause_transmitted::Counter>();
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(); _irq.ack_irq();
} }
@ -465,7 +584,9 @@ namespace Genode
Genode::Attached_mmio(env, base, size), Genode::Attached_mmio(env, base, size),
Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env), Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env),
_timer(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(env, irq),
_irq_handler(env.ep(), *this, &Cadence_gem::_handle_irq), _irq_handler(env.ep(), *this, &Cadence_gem::_handle_irq),
_phy(*this, _timer) _phy(*this, _timer)
@ -511,6 +632,10 @@ namespace Genode
bool _send() bool _send()
{ {
/* first, see whether we can acknowledge any
* previously sent packet */
_tx_buffer.submit_acks(*_tx.sink());
if (!_tx.sink()->ready_to_ack()) if (!_tx.sink()->ready_to_ack())
return false; return false;
@ -523,12 +648,14 @@ namespace Genode
return true; return true;
} }
char *src = (char *)_tx.sink()->packet_content(packet); try {
_tx_buffer.add_to_queue(packet);
_tx_buffer.add_to_queue(src, packet.size());
write<Control>(Control::start_tx()); write<Control>(Control::start_tx());
} catch (Tx_buffer_descriptor::Package_send_timeout) {
Genode::warning("Package Tx timeout");
return false;
}
_tx.sink()->acknowledge_packet(packet);
return true; return true;
} }
@ -557,8 +684,7 @@ namespace Genode
void _handle_packet_stream() override void _handle_packet_stream() override
{ {
while (_rx.source()->ack_avail()) _handle_acks();
_rx.source()->release_packet(_rx.source()->get_acked_packet());
while (_send()); while (_send());
} }

View File

@ -59,7 +59,6 @@ class Server::Gem_session_component : public Cadence_gem
try { try {
Genode::Xml_node nic_config = _config_rom.xml().sub_node("nic"); Genode::Xml_node nic_config = _config_rom.xml().sub_node("nic");
nic_config.attribute("mac").value(&mac_addr); nic_config.attribute("mac").value(&mac_addr);
Genode::log("Using configured MAC address ", mac_addr);
} catch (...) { } catch (...) {
/* fall back to fake MAC address (unicast, locally managed) */ /* fall back to fake MAC address (unicast, locally managed) */
mac_addr.addr[0] = 0x02; mac_addr.addr[0] = 0x02;
@ -70,6 +69,8 @@ class Server::Gem_session_component : public Cadence_gem
mac_addr.addr[5] = 0x01; mac_addr.addr[5] = 0x01;
} }
Genode::log("Using MAC address ", mac_addr);
/* set mac address */ /* set mac address */
mac_address(mac_addr); mac_address(mac_addr);
} }

View File

@ -1,11 +1,12 @@
/* /*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Timo Wischer * \author Timo Wischer
* \author Johannes Schlatow
* \date 2015-03-10 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * 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 class Rx_buffer_descriptor : public Buffer_descriptor
{ {
private: private:
struct Addr : Register<0x00, 32> { struct Addr : Register<0x00, 32> {
struct Addr31to2 : Bitfield<2, 28> {}; struct Addr31to2 : Bitfield<2, 30> {};
struct Wrap : Bitfield<1, 1> {}; struct Wrap : Bitfield<1, 1> {};
struct Package_available : Bitfield<0, 1> {}; struct Used : Bitfield<0, 1> {};
}; };
struct Status : Register<0x04, 32> { struct Status : Register<0x04, 32> {
struct Length : Bitfield<0, 13> {}; struct Length : Bitfield<0, 13> {};
@ -33,102 +35,101 @@ class Rx_buffer_descriptor : public Buffer_descriptor
struct End_of_frame : Bitfield<15, 1> {}; struct End_of_frame : Bitfield<15, 1> {};
}; };
enum { BUFFER_COUNT = 16 }; enum { MAX_BUFFER_COUNT = 1024 };
addr_t const _phys_base;
/** void _reset_descriptor(unsigned const i, addr_t phys_addr) {
* @brief _set_buffer_processed resets the available flag if (i > _max_index())
* So the DMA controller can use this buffer for an received package. return;
* The buffer index will be incremented, too.
* So the right sequenz of packages will be keeped. /* clear status */
_descriptors[i].status = 0;
/* set physical buffer address and set not used by SW
* last descriptor must be marked by Wrap bit
*/ */
void _set_package_processed() _descriptors[i].addr =
{ (phys_addr & Addr::Addr31to2::reg_mask())
/* reset package available for new package */ | Addr::Wrap::bits(i == _max_index());
_current_descriptor().addr &= ~Addr::Package_available::bits(1);
/* use next buffer descriptor for next package */
_increment_descriptor_index();
} }
inline bool _head_available()
{
return Addr::Used::get(_head().addr)
&& Status::Length::get(_head().status);
}
public: 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())
{ {
/* for (size_t i=0; i <= _max_index(); i++) {
* mark the last buffer descriptor try {
* so the dma will start at the beginning again Nic::Packet_descriptor p = source.alloc_packet(BUFFER_SIZE);
*/ _reset_descriptor(i, _phys_base + p.offset());
_descriptors[BUFFER_COUNT-1].addr |= Addr::Wrap::bits(1); } 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<BUFFER_COUNT; i++) { addr_t const phys = _phys_base + pd.offset();
const bool available = Addr::Package_available::get(_current_descriptor().addr);
if (available) { for (size_t i=0; i <= _max_index(); i++) {
_advance_tail();
if (Addr::Addr31to2::masked(_tail().addr) == phys) {
_reset_descriptor(_tail_index(), phys);
return true; return true;
} }
}
return false;
}
_increment_descriptor_index(); bool next_packet()
{
/* Find next available descriptor (head) holding a packet. */
for (unsigned int i=0; i < _max_index(); i++) {
if (_head_available())
return true;
_advance_head();
} }
return false; return false;
} }
Nic::Packet_descriptor get_packet_descriptor()
size_t package_length()
{ {
if (!package_available()) if (!_head_available())
return 0; return Nic::Packet_descriptor(0, 0);
return Status::Length::get(_current_descriptor().status); const Status::access_t status = _head().status;
}
size_t get_package(char* const package, const size_t max_length)
{
if (!package_available())
return 0;
const Status::access_t status = _current_descriptor().status;
if (!Status::Start_of_frame::get(status) || !Status::End_of_frame::get(status)) { if (!Status::Start_of_frame::get(status) || !Status::End_of_frame::get(status)) {
warning("Package splitted over more than one descriptor. Package ignored!"); warning("Packet split over more than one descriptor. Packet ignored!");
_set_package_processed(); _reset_descriptor(_head_index(), _head().addr);
return 0; return Nic::Packet_descriptor(0, 0);
} }
const size_t length = Status::Length::get(status); const size_t length = Status::Length::get(status);
if (length > max_length) {
warning("Buffer for received package to small. Package ignored!");
_set_package_processed(); /* reset status */
return 0; _head().status = 0;
return Nic::Packet_descriptor((addr_t)Addr::Addr31to2::masked(_head().addr) - _phys_base, length);
} }
const char* const src_buffer = _current_buffer();
memcpy(package, src_buffer, length);
_set_package_processed();
return length;
}
void show_mem_diffs()
{
static unsigned int old_data[0x1F];
log("Rx buffer:");
const unsigned int* const cur_data = local_addr<unsigned int>();
for (unsigned i=0; i<sizeof(old_data)/sizeof(old_data[0]); i++) {
if (cur_data[i] != old_data[i]) {
log(i*4, ": ", Hex(old_data[i]), " -> ", Hex(cur_data[i]));
}
}
memcpy(old_data, cur_data, sizeof(old_data));
}
}; };
#endif /* _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_ */ #endif /* _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_ */

View File

@ -1,11 +1,12 @@
/* /*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices * \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Timo Wischer * \author Timo Wischer
* \author Johannes Schlatow
* \date 2015-03-10 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * 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 class Tx_buffer_descriptor : public Buffer_descriptor
{ {
private: private:
enum { BUFFER_COUNT = 2 }; enum { BUFFER_COUNT = 1024 };
struct Addr : Register<0x00, 32> {}; struct Addr : Register<0x00, 32> {};
struct Status : Register<0x04, 32> { struct Status : Register<0x04, 32> {
@ -33,51 +34,109 @@ class Tx_buffer_descriptor : public Buffer_descriptor
struct Last_buffer : Bitfield<15, 1> {}; struct Last_buffer : Bitfield<15, 1> {};
struct Wrap : Bitfield<30, 1> {}; struct Wrap : Bitfield<30, 1> {};
struct Used : Bitfield<31, 1> {}; struct Used : Bitfield<31, 1> {};
struct Chksum_err : Bitfield<20, 2> {};
}; };
class Package_send_timeout : public Genode::Exception {};
Timer::Connection &_timer; Timer::Connection &_timer;
addr_t const _phys_base;
void _reset_descriptor(unsigned const i, addr_t phys_addr) {
if (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: public:
Tx_buffer_descriptor(Genode::Env &env, Timer::Connection &timer)
: Buffer_descriptor(env, BUFFER_COUNT), _timer(timer) 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())
{ {
for (unsigned int i=0; i<BUFFER_COUNT; i++) { for (size_t i=0; i <= _max_index(); i++) {
_descriptors[i].status = Status::Used::bits(1) | Status::Last_buffer::bits(1); /* configure all descriptors with address 0, which we
* interpret as invalid */
_reset_descriptor(i, 0x0);
} }
_descriptors[BUFFER_COUNT-1].status |= Status::Wrap::bits(1);
} }
void submit_acks(Nic::Session::Rx::Sink &sink)
void add_to_queue(const char* const packet, const size_t size)
{ {
if (size > MAX_PACKAGE_SIZE) { /* 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!"); warning("Ethernet package to big. Not sent!");
return; return;
} }
/* wait until the used bit is set (timeout after 200ms) */ addr_t const packet_phys = _phys_base + p.offset();
uint32_t timeout = 200; if (packet_phys & 0x1f) {
while ( !Status::Used::get(_current_descriptor().status) ) { warning("Packet is not aligned properly.");
if (timeout <= 0) { }
/* 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(); throw Package_send_timeout();
} }
timeout--; timeout -= 1000;
_timer.msleep(1); /* TODO buffer is full, instead of sleeping we should
* therefore wait for tx_complete interrupt */
_timer.usleep(1000);
} }
_reset_descriptor(_head_index(), packet_phys);
_head().status |= Status::Length::bits(p.size());
memcpy(_current_buffer(), packet, size); /* unset the used bit */
_head().status &= Status::Used::clear_mask();
_current_descriptor().status &= Status::Length::clear_mask(); _advance_head();
_current_descriptor().status |= Status::Length::bits(size);
/* unset the unset bit */
_current_descriptor().status &= Status::Used::clear_mask();
_increment_descriptor_index();
} }
}; };