mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
zynq: improve nic driver error handling
also be more verbose about detected errors fixes #3320
This commit is contained in:
parent
739317a83f
commit
9097c80269
@ -84,6 +84,9 @@ class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio
|
||||
size_t _head_index() const { return _head_idx; }
|
||||
size_t _tail_index() const { return _tail_idx; }
|
||||
|
||||
void _reset_head() { _head_idx = 0; }
|
||||
void _reset_tail() { _tail_idx = 0; }
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
|
@ -145,8 +145,11 @@ namespace Genode
|
||||
*/
|
||||
struct Tx_status : Register<0x14, 32>
|
||||
{
|
||||
struct Tx_complete : Bitfield<5, 1> {};
|
||||
struct Tx_go : Bitfield<3, 1> {};
|
||||
struct Tx_hresp_nok : Bitfield<8, 1> {};
|
||||
struct Tx_err_underrun : Bitfield<6, 1> {};
|
||||
struct Tx_complete : Bitfield<5, 1> {};
|
||||
struct Tx_err_bufexh : Bitfield<4, 1> {};
|
||||
struct Tx_go : Bitfield<3, 1> {};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -170,6 +173,7 @@ namespace Genode
|
||||
*/
|
||||
struct Rx_status : Register<0x20, 32>
|
||||
{
|
||||
struct Rx_hresp_nok : Bitfield<3, 1> {};
|
||||
struct Rx_overrun : Bitfield<2, 1> {};
|
||||
struct Frame_received : Bitfield<1, 1> {};
|
||||
struct Buffer_not_available : Bitfield<0, 1> {};
|
||||
@ -261,6 +265,22 @@ namespace Genode
|
||||
struct Counter : Bitfield<0, 16> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Counter for tx underrun errors
|
||||
*/
|
||||
struct Tx_underrun : Register<0x134, 32>
|
||||
{
|
||||
struct Counter : Bitfield<0, 10> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Counter for deferred transmission frames
|
||||
*/
|
||||
struct Tx_deferred: Register<0x148, 32>
|
||||
{
|
||||
struct Counter : Bitfield<0, 18> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Counter for the successfully received frames
|
||||
*/
|
||||
@ -487,12 +507,12 @@ namespace Genode
|
||||
virtual void _handle_irq()
|
||||
{
|
||||
/* 16.3.9 Receiving Frames */
|
||||
/* read interrupt status, to detect the interrupt reasone */
|
||||
/* read interrupt status, to detect the interrupt reason */
|
||||
const Interrupt_status::access_t status = read<Interrupt_status>();
|
||||
const Rx_status::access_t rxStatus = read<Rx_status>();
|
||||
const Tx_status::access_t txStatus = read<Tx_status>();
|
||||
|
||||
if ( Interrupt_status::Rx_complete::get(status) ) {
|
||||
|
||||
while (_rx_buffer.next_packet()) {
|
||||
|
||||
_handle_acks();
|
||||
@ -512,14 +532,50 @@ namespace Genode
|
||||
else {
|
||||
_handle_acks();
|
||||
}
|
||||
|
||||
|
||||
/* handle Rx/Tx errors */
|
||||
if ( Tx_status::Tx_hresp_nok::get(txStatus)
|
||||
|| Rx_status::Rx_hresp_nok::get(rxStatus)) {
|
||||
|
||||
write<Control::Tx_en>(0);
|
||||
write<Control::Rx_en>(0);
|
||||
|
||||
_tx_buffer.reset(*_tx.sink());
|
||||
_rx_buffer.reset();
|
||||
|
||||
write<Control::Tx_en>(1);
|
||||
write<Control::Rx_en>(1);
|
||||
|
||||
write<Tx_status>(Tx_status::Tx_hresp_nok::bits(1));
|
||||
write<Rx_status>(Rx_status::Rx_hresp_nok::bits(1));
|
||||
Genode::error("Rx/Tx error: resetting both");
|
||||
}
|
||||
|
||||
/* handle Tx errors */
|
||||
if ( Tx_status::Tx_err_underrun::get(txStatus)
|
||||
|| Tx_status::Tx_err_bufexh::get(txStatus)) {
|
||||
|
||||
write<Control::Tx_en>(0);
|
||||
_tx_buffer.reset(*_tx.sink());
|
||||
write<Control::Tx_en>(1);
|
||||
|
||||
Genode::error("Tx error: resetting transceiver");
|
||||
}
|
||||
|
||||
/* handle Rx error */
|
||||
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));
|
||||
|
||||
/* reset the receiver because this may lead to a deadlock */
|
||||
write<Control::Rx_en>(0);
|
||||
_rx_buffer.reset();
|
||||
write<Control::Rx_en>(1);
|
||||
|
||||
print_stats = true;
|
||||
Genode::error("Rx overrun");
|
||||
Genode::error("Rx overrun - packet buffer overflow");
|
||||
}
|
||||
if (Interrupt_status::Rx_used_read::get(status)) {
|
||||
/* tried to use buffer descriptor with used bit set */
|
||||
@ -529,8 +585,9 @@ namespace Genode
|
||||
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");
|
||||
Genode::error("Rx used - the Nic client is not fast enough");
|
||||
}
|
||||
if (Interrupt_status::Pause_zero::get(status)) {
|
||||
Genode::warning("Pause ended.");
|
||||
@ -555,6 +612,8 @@ namespace Genode
|
||||
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>();
|
||||
const uint32_t underrun = read<Tx_underrun::Counter>();
|
||||
const uint32_t deferred = read<Tx_deferred::Counter>();
|
||||
|
||||
Genode::warning("Received: ", received);
|
||||
Genode::warning(" pause frames: ", pause_rx);
|
||||
@ -566,6 +625,8 @@ namespace Genode
|
||||
Genode::warning(" TCP chk failed: ", tcp_chk);
|
||||
Genode::warning("Transmitted: ", transmit);
|
||||
Genode::warning(" pause frames: ", pause_tx);
|
||||
Genode::warning(" underrun: ", underrun);
|
||||
Genode::warning(" deferred: ", deferred);
|
||||
}
|
||||
|
||||
_irq.ack_irq();
|
||||
|
@ -96,17 +96,22 @@ class Rx_buffer_descriptor : public Buffer_descriptor
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for (size_t i=0; i <= _max_index(); i++) {
|
||||
_descriptors[i].status = 0;
|
||||
Addr::Used::set(_descriptors[i].addr, 0);
|
||||
}
|
||||
_reset_head();
|
||||
}
|
||||
|
||||
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;
|
||||
if (_head_available())
|
||||
return true;
|
||||
|
||||
_advance_head();
|
||||
}
|
||||
|
||||
return false;
|
||||
_advance_head();
|
||||
return _head_available();
|
||||
}
|
||||
|
||||
Nic::Packet_descriptor get_packet_descriptor()
|
||||
|
@ -34,7 +34,11 @@ 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> {};
|
||||
struct Chksum_err : Bitfield<20, 3> {};
|
||||
struct Crc_present: Bitfield<16, 1> {};
|
||||
struct Late_collision: Bitfield<26, 1> {};
|
||||
struct Corrupt: Bitfield<27, 1> {};
|
||||
struct Retry_limit: Bitfield<29, 1> {};
|
||||
};
|
||||
|
||||
Timer::Connection &_timer;
|
||||
@ -74,29 +78,51 @@ class Tx_buffer_descriptor : public Buffer_descriptor
|
||||
}
|
||||
}
|
||||
|
||||
void submit_acks(Nic::Session::Rx::Sink &sink)
|
||||
void reset(Nic::Session::Rx::Sink &sink)
|
||||
{
|
||||
/* ack all packets that are still queued */
|
||||
submit_acks(sink, true);
|
||||
|
||||
/* reset head and tail */
|
||||
_reset_head();
|
||||
_reset_tail();
|
||||
}
|
||||
|
||||
void submit_acks(Nic::Session::Rx::Sink &sink, bool force=false)
|
||||
{
|
||||
/* the tail marks the descriptor for which we wait to
|
||||
* be handed over to software */
|
||||
for (size_t i=0; i <= _queued(); i++) {
|
||||
for (size_t i=0; i < _queued(); i++) {
|
||||
/* stop if still in use by hardware */
|
||||
if (!Status::Used::get(_tail().status))
|
||||
if (!Status::Used::get(_tail().status) && !force)
|
||||
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);
|
||||
else
|
||||
warning("Invalid packet descriptor");
|
||||
|
||||
/* erase address so that we don't send an ack again */
|
||||
_tail().addr = 0;
|
||||
|
||||
/* TODO optionally, we may evaluate the Tx status here */
|
||||
/* evaluate Tx status */
|
||||
if (Status::Retry_limit::get(_tail().status))
|
||||
warning("Retry limit exceeded");
|
||||
|
||||
if (Status::Corrupt::get(_tail().status))
|
||||
warning("Transmit frame corruption");
|
||||
|
||||
if (Status::Late_collision::get(_tail().status))
|
||||
warning("Late collision error");
|
||||
|
||||
if (Status::Crc_present::get(_tail().status))
|
||||
warning("CRC already present - this impedes checksum offloading");
|
||||
}
|
||||
|
||||
_advance_tail();
|
||||
|
Loading…
x
Reference in New Issue
Block a user