genode/repos/os/src/drivers/nic/gem/rx_buffer_descriptor.h

135 lines
3.2 KiB
C++

/*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Timo Wischer
* \date 2015-03-10
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_
#define _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_
#include "buffer_descriptor.h"
using namespace Genode;
class Rx_buffer_descriptor : public Buffer_descriptor
{
private:
struct Addr : Register<0x00, 32> {
struct Addr31to2 : Bitfield<2, 28> {};
struct Wrap : Bitfield<1, 1> {};
struct Package_available : Bitfield<0, 1> {};
};
struct Status : Register<0x04, 32> {
struct Length : Bitfield<0, 13> {};
struct Start_of_frame : Bitfield<14, 1> {};
struct End_of_frame : Bitfield<15, 1> {};
};
enum { BUFFER_COUNT = 16 };
/**
* @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();
}
public:
Rx_buffer_descriptor() : Buffer_descriptor(BUFFER_COUNT)
{
/*
* mark the last buffer descriptor
* so the dma will start at the beginning again
*/
_descriptors[BUFFER_COUNT-1].addr |= Addr::Wrap::bits(1);
}
bool package_available()
{
for (unsigned int i=0; i<BUFFER_COUNT; i++) {
const bool available = Addr::Package_available::get(_current_descriptor().addr);
if (available) {
return true;
}
_increment_descriptor_index();
}
return false;
}
size_t package_length()
{
if (!package_available())
return 0;
return Status::Length::get(_current_descriptor().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)) {
PWRN("Package splitted over more than one descriptor. Package ignored!");
_set_package_processed();
return 0;
}
const size_t length = Status::Length::get(status);
if (length > max_length) {
PWRN("Buffer for received package to small. Package ignored!");
_set_package_processed();
return 0;
}
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];
PDBG("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]) {
PDBG("%04x: %08x -> %08x", i*4, old_data[i], cur_data[i]);
}
}
memcpy(old_data, cur_data, sizeof(old_data));
}
};
#endif /* _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_ */