Remove zynq_qemu platform and zynq nic driver

Moved to separate repo at https://github.com/jschlatow/genode-zynq

Fixes genodelabs/genode#4280
This commit is contained in:
Johannes Schlatow 2021-10-04 13:09:03 +02:00 committed by Christian Helmuth
parent 6ecae6adb3
commit 7917c5d9ec
36 changed files with 6 additions and 2899 deletions

View File

@ -1 +0,0 @@
arm_v7a

View File

@ -1 +0,0 @@
0x00100000

View File

@ -1,14 +0,0 @@
REP_INC_DIR += src/bootstrap/board/zynq_qemu
SRC_S += bootstrap/spec/arm/crt0.s
SRC_CC += bootstrap/board/zynq_qemu/platform.cc
SRC_CC += bootstrap/spec/arm/cpu.cc
SRC_CC += bootstrap/spec/arm/cortex_a9_mmu.cc
SRC_CC += bootstrap/spec/arm/gicv2.cc
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
SRC_CC += hw/spec/32bit/memory_map.cc
NR_OF_CPUS = 1
include $(call select_from_repositories,lib/mk/bootstrap-hw.inc)

View File

@ -1,11 +0,0 @@
#
# \brief Build config for Genodes core process
# \author Johannes Schlatow
# \date 2014-12-15
#
# add C++ sources
SRC_CC += platform_services.cc
# include less specific configuration
include $(call select_from_repositories,lib/mk/spec/cortex_a9/core-hw.inc)

View File

@ -1,13 +0,0 @@
#
# \brief Build config for Genodes core process
# \author Johannes Schlatow
# \date 2014-12-15
#
# add include paths
REP_INC_DIR += src/core/board/zynq_qemu
NR_OF_CPUS = 1
# include less specific configuration
include $(call select_from_repositories,lib/mk/spec/arm_v7/core-hw-zynq.inc)

View File

@ -1 +0,0 @@
include $(GENODE_DIR)/repos/base-hw/recipes/src/base-hw_content.inc

View File

@ -1 +0,0 @@
2021-10-13 3233ce8f7b5f3246ace4fbdf810b1632cb147a1a

View File

@ -1,2 +0,0 @@
base-hw
base

View File

@ -1,30 +0,0 @@
/*
* \brief Zynq specific board definitions
* \author Stefan Kalkowski
* \date 2017-02-20
*/
/*
* Copyright (C) 2017 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.
*/
#ifndef _SRC__BOOTSTRAP__SPEC__ZYNQ__BOARD_H_
#define _SRC__BOOTSTRAP__SPEC__ZYNQ__BOARD_H_
#include <hw/spec/arm/zynq_qemu_board.h>
#include <spec/arm/cortex_a9_actlr.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Zynq_qemu_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
}
#endif /* _SRC__BOOTSTRAP__SPEC__ZYNQ__BOARD_H_ */

View File

@ -1,53 +0,0 @@
/*
* \brief Platform implementations specific for base-hw and Zynq
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2017 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.
*/
/* core includes */
#include <platform.h>
using namespace Board;
Bootstrap::Platform::Board::Board()
:
early_ram_regions(Memory_region { RAM_0_BASE + 0x1000,
RAM_0_SIZE - 0x1000 }),
late_ram_regions(Memory_region { RAM_0_BASE, 0x1000 }),
core_mmio(Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { UART_BASE,
UART_SIZE },
Memory_region { PL310_MMIO_BASE,
PL310_MMIO_SIZE })
{ }
bool Cpu::errata(Board::Cpu::Errata) { return false; }
void Cpu::wake_up_all_cpus(void* ip)
{
struct Wakeup_generator : Genode::Mmio
{
struct Core1_boot_addr : Register<0x0, 32> { };
Wakeup_generator(void * const ip) : Mmio(CORE1_ENTRY)
{
write<Core1_boot_addr>((Genode::addr_t)ip);
}
};
Wakeup_generator wgen(ip);
asm volatile("dsb\n"
"sev\n");
}

View File

@ -1,37 +0,0 @@
/*
* \brief Board driver for core on Zynq
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-06-02
*/
/*
* Copyright (C) 2014-2017 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.
*/
#ifndef _CORE__SPEC__ZYNQ_QEMU__BOARD_H_
#define _CORE__SPEC__ZYNQ_QEMU__BOARD_H_
/* base-hw internal includes */
#include <hw/spec/arm/gicv2.h>
#include <hw/spec/arm/zynq_qemu_board.h>
/* base-hw Core includes */
#include <spec/arm/cortex_a9_private_timer.h>
#include <spec/cortex_a9/cpu.h>
namespace Board {
using namespace Hw::Zynq_qemu_board;
class Global_interrupt_controller { };
class Pic : public Hw::Gicv2 { public: Pic(Global_interrupt_controller &) { } };
L2_cache & l2_cache();
}
#endif /* _CORE__SPEC__ZYNQ_QEMU__BOARD_H_ */

View File

@ -1,35 +0,0 @@
/*
* \brief Zynq specific board definitions
* \author Stefan Kalkowski
* \date 2019-05-16
*/
/*
* Copyright (C) 2019 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.
*/
#ifndef _SRC__INCLUDE__HW__SPEC__ARM__ZYNQ_BOARD_H_
#define _SRC__INCLUDE__HW__SPEC__ARM__ZYNQ_BOARD_H_
#include <drivers/defs/zynq_qemu.h>
#include <drivers/uart/xilinx.h>
#include <hw/spec/arm/cortex_a9.h>
#include <hw/spec/arm/pl310.h>
#include <hw/spec/arm/boot_info.h>
namespace Hw::Zynq_qemu_board {
using namespace Zynq_qemu;
using L2_cache = Hw::Pl310;
using Cpu_mmio = Hw::Cortex_a9_mmio<CORTEX_A9_PRIVATE_MEM_BASE>;
using Serial = Genode::Xilinx_uart;
enum {
UART_BASE = UART_0_MMIO_BASE,
};
}
#endif /* _SRC__INCLUDE__HW__SPEC__ARM__ZYNQ_BOARD_H_ */

View File

@ -1,68 +0,0 @@
/*
* \brief MMIO and IRQ definitions common to Xilinx Zynq platforms
* \author Mark Albers
* \author Timo Wischer
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__DEFS__ZYNQ_H_
#define _INCLUDE__DRIVERS__DEFS__ZYNQ_H_
namespace Zynq {
enum {
/* device IO memory */
MMIO_0_BASE = 0xe0000000, /* IOP devices */
MMIO_0_SIZE = 0x10000000,
MMIO_1_BASE = 0xF8000000, /* Programmable register via APB */
MMIO_1_SIZE = 0x02000000,
QSPI_MMIO_BASE = 0xFC000000, /* Quad-SPI */
QSPI_MMIO_SIZE = 0x01000000,
OCM_MMIO_BASE = 0xFFFC0000, /* OCM upper address range */
OCM_MMIO_SIZE = 0x00040000,
/* normal RAM */
RAM_0_BASE = 0x00000000,
/* AXI */
AXI_0_MMIO_BASE = 0x40000000, /* PL AXI Slave port #0 */
AXI_0_MMIO_SIZE = 0x40000000,
AXI_1_MMIO_BASE = 0x80000000, /* PL AXI Slave port #1 */
AXI_1_MMIO_SIZE = 0x40000000,
/* UART controllers */
UART_0_MMIO_BASE = MMIO_0_BASE,
UART_SIZE = 0x1000,
UART_CLOCK = 50*1000*1000,
/* CPU */
CORTEX_A9_PRIVATE_MEM_BASE = 0xf8f00000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000,
/* entrypoint address of secondary cpu */
CORE1_ENTRY = 0xfffffff0,
/* CPU cache */
PL310_MMIO_BASE = MMIO_1_BASE + 0xF02000,
PL310_MMIO_SIZE = 0x1000,
/* TTC (triple timer counter) */
TTC0_MMIO_BASE = MMIO_1_BASE + 0x1000,
TTC0_MMIO_SIZE = 0xfff,
TTC0_IRQ_0 = 42,
/* Ethernet MAC PS */
EMAC_0_MMIO_BASE = 0xE000B000,
EMAC_0_MMIO_SIZE = 0x1000,
EMAC_0_IRQ = 54,
};
};
#endif /* _INCLUDE__DRIVERS__DEFS__ZYNQ_H_ */

View File

@ -1,31 +0,0 @@
/*
* \brief Base driver for the Zynq (QEMU)
* \author Johannes Schlatow
* \date 2015-06-30
*/
/*
* Copyright (C) 2015-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__DEFS__ZYNQ_QEMU_H_
#define _INCLUDE__DRIVERS__DEFS__ZYNQ_QEMU_H_
#include <drivers/defs/zynq.h>
namespace Zynq_qemu {
using namespace Zynq;
enum {
RAM_0_SIZE = 0x40000000, /* 1GiB */
CORTEX_A9_PRIVATE_TIMER_CLK = 100000000,
CORTEX_A9_PRIVATE_TIMER_DIV = 100,
};
};
#endif /* _INCLUDE__DRIVERS__DEFS__ZYNQ_QEMU_H_ */

View File

@ -1,129 +0,0 @@
/*
* \brief Base UART driver for the Xilinx UART PS used on Zynq devices
* \author Johannes Schlatow
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__UART__XILINX_H_
#define _INCLUDE__DRIVERS__UART__XILINX_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode { class Xilinx_uart; }
/**
* Base driver Xilinx UART PS module
*/
class Genode::Xilinx_uart: public Mmio
{
protected:
/**
* Control register
*/
struct Uart_cr : Register<0x00, 32>
{
struct Rx_reset : Bitfield<0, 1> { };
struct Tx_reset : Bitfield<1, 1> { };
struct Rx_enable : Bitfield<2, 1> { };
struct Tx_enable : Bitfield<4, 1> { };
};
/**
* Mode register
*/
struct Uart_mr : Register<0x04, 32>
{
struct Clock_sel : Bitfield<0, 1> { };
struct Parity : Bitfield<3, 3> { enum { NO_PARITY = 4 }; };
};
/**
* Baudgen register
*/
struct Uart_baudgen : Register<0x18, 32>
{
struct Clock_div : Bitfield<0, 16> { };
};
/**
* Status register
*/
struct Uart_sr : Register<0x2C, 32>
{
struct Tx_full : Bitfield<4, 1> { };
};
/**
* FIFO register
*/
struct Uart_fifo : Register<0x30, 32>
{
struct Data : Bitfield<0, 8> { };
};
/**
* Bauddiv register
*/
struct Uart_bauddiv : Register<0x34, 32>
{
struct Bdiv : Bitfield<0,8> { };
};
public:
/**
* Constructor
*
* \param base MMIO base address
* \param clock reference clock
* \param baud_rate targeted baud rate
*/
Xilinx_uart(addr_t const base, unsigned long const clock,
unsigned long const baud_rate) : Mmio(base)
{
/* reset UART */
Uart_cr::access_t uart_cr = 0;
Uart_cr::Tx_reset::set(uart_cr, 1);
Uart_cr::Rx_reset::set(uart_cr, 1);
write<Uart_cr>(uart_cr);
/* set baud rate */
constexpr unsigned div = 4;
write<Uart_bauddiv::Bdiv>(div);
write<Uart_baudgen::Clock_div>(clock / baud_rate / (div + 1));
/* set 8N1 */
Uart_mr::access_t uart_mr = 0;
Uart_mr::Parity::set(uart_mr, Uart_mr::Parity::NO_PARITY);
write<Uart_mr>(uart_mr);
/* enable */
uart_cr = 0;
Uart_cr::Rx_enable::set(uart_cr, 1);
Uart_cr::Tx_enable::set(uart_cr, 1);
write<Uart_cr>(uart_cr);
}
/**
* Transmit ASCII char 'c'
*/
void put_char(char const c)
{
/* wait as long as the transmission buffer is full */
while (read<Uart_sr::Tx_full>()) ;
/* transmit character */
write<Uart_fifo::Data>(c);
}
};
#endif /* _INCLUDE__DRIVERS__UART__XILINX_H_ */

View File

@ -1,3 +0,0 @@
Device drivers needed for scenarios
using one network interface

View File

@ -1,2 +0,0 @@
_/src/zynq_nic_drv
_/raw/drivers_nic-zynq

View File

@ -1 +0,0 @@
2021-10-13 8cfb35f5bb47321172f50d4c15cea9ef2edd3259

View File

@ -1,4 +0,0 @@
content: drivers.config
drivers.config:
cp $(REP_DIR)/recipes/raw/drivers_nic-zynq/$@ $@

View File

@ -1,24 +0,0 @@
<config>
<parent-provides>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Uplink"/>
</parent-provides>
<default caps="100"/>
<start name="nic_drv">
<binary name="zynq_nic_drv"/>
<resource name="RAM" quantum="4M"/>
<config mode="uplink_client"/>
<route> <any-service> <parent/> </any-service> </route>
</start>
</config>

View File

@ -1 +0,0 @@
2021-02-22 0a32b3922e6d0d7f2f6eb53464e7db38476ca355

View File

@ -1,2 +0,0 @@
SRC_DIR = src/drivers/nic/spec/zynq
include $(GENODE_DIR)/repos/base/recipes/src/content.inc

View File

@ -1 +0,0 @@
2021-10-13 ca8cb8596f9f0e760807a398e6e5a535667e791d

View File

@ -1,5 +0,0 @@
base
os
nic_session
uplink_session
nic_driver

View File

@ -1,115 +0,0 @@
/*
* \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-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.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__BUFFER_DESCRIPTOR_H_
#define _INCLUDE__DRIVERS__NIC__GEM__BUFFER_DESCRIPTOR_H_
/* Genode includes */
#include <base/attached_ram_dataspace.h>
#include <util/mmio.h>
using namespace Genode;
class Buffer_descriptor : protected Attached_ram_dataspace, protected Mmio
{
public:
static const size_t BUFFER_DESC_SIZE = 0x08;
static const size_t BUFFER_SIZE = 1600;
private:
size_t _buffer_count;
size_t _head_idx { 0 };
size_t _tail_idx { 0 };
protected:
typedef struct {
uint32_t addr;
uint32_t status;
} descriptor_t;
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; }
inline
void _advance_head()
{
_head_idx = (_head_idx+1) % _buffer_count;
}
inline
void _advance_tail()
{
_tail_idx = (_tail_idx+1) % (_buffer_count);
}
inline
descriptor_t& _head()
{
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; }
void _reset_head() { _head_idx = 0; }
void _reset_tail() { _tail_idx = 0; }
private:
/*
* Noncopyable
*/
Buffer_descriptor(Buffer_descriptor const &);
Buffer_descriptor &operator = (Buffer_descriptor const &);
public:
/*
* start of the ram spave contains all buffer descriptors
* after that the data spaces for the ethernet packages are following
*/
Buffer_descriptor(Genode::Env &env, const size_t buffer_count = 1)
:
Attached_ram_dataspace(env.ram(), env.rm(), BUFFER_DESC_SIZE * buffer_count, UNCACHED),
Genode::Mmio( reinterpret_cast<addr_t>(local_addr<void>()) ),
_buffer_count(buffer_count),
_descriptors(local_addr<descriptor_t>())
{ }
addr_t phys_addr() { return Dataspace_client(cap()).phys_addr(); }
};
#endif /* _INCLUDE__DRIVERS__NIC__GEM__BUFFER_DESCRIPTOR_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
/*
* \brief EMACPS NIC driver for Xilix Zynq-7000
* \author Timo Wischer
* \date 2015-03-10
*/
/*
* Copyright (C) 2015-2017 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.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <drivers/defs/zynq.h>
#include <nic/root.h>
/* NIC driver includes */
#include <drivers/nic/mode.h>
/* local includes */
#include "cadence_gem.h"
namespace Server {
using namespace Genode;
class Gem_session_component;
struct Main;
}
Nic::Mac_address
read_mac_addr_from_config(Genode::Attached_rom_dataspace &config_rom)
{
Nic::Mac_address mac_addr;
/* fall back to fake MAC address (unicast, locally managed) */
mac_addr.addr[0] = 0x02;
mac_addr.addr[1] = 0x00;
mac_addr.addr[2] = 0x00;
mac_addr.addr[3] = 0x00;
mac_addr.addr[4] = 0x00;
mac_addr.addr[5] = 0x01;
/* try using configured MAC address */
try {
Genode::Xml_node nic_config = config_rom.xml().sub_node("nic");
mac_addr = nic_config.attribute_value("mac", mac_addr);
Genode::log("Using configured MAC address ", mac_addr);
} catch (...) { }
return mac_addr;
}
class Server::Gem_session_component : public Cadence_gem
{
private:
Genode::Attached_rom_dataspace _config_rom;
public:
Gem_session_component(Genode::size_t const tx_buf_size,
Genode::size_t const rx_buf_size,
Genode::Allocator &rx_block_md_alloc,
Genode::Env &env)
:
Cadence_gem(tx_buf_size, rx_buf_size, rx_block_md_alloc, env,
Zynq::EMAC_0_MMIO_BASE,
Zynq::EMAC_0_MMIO_SIZE,
Zynq::EMAC_0_IRQ),
_config_rom(env, "config")
{
mac_address(read_mac_addr_from_config(_config_rom));
}
};
struct Server::Main
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Constructible<Nic::Root<Gem_session_component> > _nic_root { };
Constructible<Uplink_client> _uplink_client { };
Main(Env &env) : _env(env)
{
Attached_rom_dataspace config_rom { _env, "config" };
Nic_driver_mode const mode {
read_nic_driver_mode(config_rom.xml()) };
switch (mode) {
case Nic_driver_mode::NIC_SERVER:
_nic_root.construct(_env, _heap );
_env.parent().announce(_env.ep().manage(*_nic_root));
break;
case Nic_driver_mode::UPLINK_CLIENT:
_uplink_client.construct(
_env, _heap, Zynq::EMAC_0_MMIO_BASE, Zynq::EMAC_0_MMIO_SIZE,
Zynq::EMAC_0_IRQ, read_mac_addr_from_config(config_rom));
break;
}
}
};
void Component::construct(Genode::Env &env) { static Server::Main main(env); }

View File

@ -1,580 +0,0 @@
/*
* \brief Phy driver for Marvell chips
* \author Johannes Schlatow
* \author Timo Wischer
* \date 2015-05-11
*/
/*
* Copyright (C) 2015-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__MARVELL_PHY_H_
#define _INCLUDE__DRIVERS__NIC__GEM__MARVELL_PHY_H_
/* Genode includes */
#include <os/attached_mmio.h>
#include <nic_session/nic_session.h>
#include <timer_session/connection.h>
#include "phyio.h"
namespace Genode
{
enum Eth_speed {
UNDEFINED,
SPEED_10 = 10,
SPEED_100 = 100,
SPEED_1000 = 1000
};
class MII_phy
{
protected:
/**
* \param _OFFSET Offset/number of the register.
*
* For further details See 'Genode::Register'.
*/
template <uint8_t _OFFSET>
struct Phy_register : public Genode::Register<16>
{
enum {
OFFSET = _OFFSET,
};
typedef Phy_register<_OFFSET>
Register_base;
/**
* A region within a register
*
* \param _SHIFT Bit shift of the first bit within the
* compound register.
* \param _WIDTH bit width of the region
*
* For details see 'Genode::Register::Bitfield'.
*/
template <unsigned long _SHIFT, unsigned long _WIDTH>
struct Bitfield : public Genode::Register<16>::
template Bitfield<_SHIFT, _WIDTH>
{
typedef Bitfield<_SHIFT, _WIDTH> Bitfield_base;
/* back reference to containing register */
typedef Phy_register<_OFFSET>
Compound_reg;
};
};
/*************************
* Generic MII registers *
*************************/
/* Basic mode control register */
struct Bmcr : Phy_register<0x00>
{
struct Resv : Bitfield<0, 6> { }; /* Unused... */
struct Speed1000 : Bitfield<6, 1> { }; /* MSB of Speed (1000) */
struct Ctst : Bitfield<7, 1> { }; /* Collision test */
struct Fulldplx : Bitfield<8, 1> { }; /* Full duplex */
struct Anrestart : Bitfield<9, 1> { }; /* Auto negotiation restart */
struct Isolate : Bitfield<10,1> { }; /* Disconnect DP83840 from MII */
struct Pdown : Bitfield<11,1> { }; /* Powerdown the DP83840 */
struct Anenable : Bitfield<12,1> { }; /* Enable auto negotiation */
struct Speed100 : Bitfield<13,1> { }; /* Select 100Mbps */
struct Loopback : Bitfield<14,1> { }; /* TXD loopback bits */
struct Reset : Bitfield<15,1> { }; /* Reset the DP83840 */
};
/* Basic mode status register */
struct Bmsr : Phy_register<0x01>
{
enum {
INVALID = 0xFFFF
};
struct Ercap : Bitfield<0, 1> { }; /* Ext-reg capability */
struct Jcd : Bitfield<1, 1> { }; /* Jabber detected */
struct Lstatus : Bitfield<2, 1> { }; /* Link status */
struct Anegcapable : Bitfield<3, 1> { }; /* Able to do auto-negotiation */
struct Rfault : Bitfield<4, 1> { }; /* Remote fault detected */
struct Anegcomplete: Bitfield<5, 1> { }; /* Auto-negotiation complete */
struct Resv : Bitfield<6, 1> { }; /* Unused... */
struct Estaten : Bitfield<7, 1> { }; /* Extended Status in R15 */
struct Half2_100 : Bitfield<8, 1> { }; /* Can do 100BASE-T2 HDX */
struct Full2_100 : Bitfield<9, 1> { }; /* Can do 100BASE-T2 FDX */
struct Half_10 : Bitfield<10,1> { }; /* Can do 10mbps, half-duplex */
struct Full_10 : Bitfield<11,1> { }; /* Can do 10mbps, full-duplex */
struct Half_100 : Bitfield<12,1> { }; /* Can do 100mbps, half-duplex */
struct Full_100 : Bitfield<13,1> { }; /* Can do 100mbps, full-duplex */
struct Base4_100 : Bitfield<14,1> { }; /* Can do 100mbps, 4k packets */
};
/* ID register 1 */
struct Idr1 : Phy_register<0x02> { };
/* ID register 2 */
struct Idr2 : Phy_register<0x03> { };
/* Advertisement control reg */
struct Advertise : Phy_register<0x04>
{
struct Csma : Bitfield<0, 1> { };
struct Half_10 : Bitfield<5, 1> { }; /* Try for 10mbps half-duplex */
struct FullX_1000 : Bitfield<5, 1> { }; /* Try for 1000BASE-X full-duplex */
struct Full_10 : Bitfield<6, 1> { }; /* Try for 10mbps full-duplex */
struct HalfX_1000 : Bitfield<6, 1> { }; /* Try for 1000BASE-X half-duplex */
struct Half_100 : Bitfield<7, 1> { }; /* Try for 100mbps half-duplex */
struct PauseX_1000 : Bitfield<7, 1> { }; /* Try for 1000BASE-X pause */
struct Full_100 : Bitfield<8, 1> { }; /* Try for 100mbps full-duplex */
struct AsymXPSE_1000: Bitfield<8, 1> { }; /* Try for 1000BASE-X asym pause */
struct Base4_100 : Bitfield<9, 1> { }; /* Try for 100mbps 4k packets */
struct Pause_cap : Bitfield<10,1> { }; /* Try for pause */
struct Pause_asym : Bitfield<11,1> { }; /* Try for asymetrict pause */
struct Rfault : Bitfield<13,1> { }; /* Say we can detect faults */
struct Lpack : Bitfield<14,1> { }; /* Ack link partners response */
struct Npage : Bitfield<15,1> { }; /* Next page bit */
};
/* 1000BASE-T control */
struct Ctrl1000 : Phy_register<0x09>
{
struct Half_1000 : Bitfield<8, 1> { }; /* Advertise 1000BASE-T full duplex */
struct Full_1000 : Bitfield<9, 1> { }; /* Advertise 1000BASE-T half duplex */
};
};
class Marvel_phy : public MII_phy
{
public:
class Phy_timeout_after_reset : public Genode::Exception {};
private:
enum {
PHY_AUTONEGOTIATE_TIMEOUT = 5000
};
Timer::Connection &_timer;
Phyio& _phyio;
int8_t _phyaddr;
bool _link_up;
Eth_speed _eth_speed;
/*************************
* 88E1310 PHY registers *
*************************/
struct Led_ctrl : Phy_register<16>
{
struct Data : Bitfield<0, 4> { };
};
struct Irq_en : Phy_register<18> { };
struct RGMII_ctrl : Phy_register<21> { };
struct Page_select : Phy_register<22> { };
/* 88E1011 PHY Status Register */
struct Phy_stat : Phy_register<0x11>
{
struct Link : Bitfield<10,1> { };
struct Spddone : Bitfield<11,1> { };
struct Duplex : Bitfield<13,1> { };
struct Speed_100 : Bitfield<14,1> { };
struct Speed_1000 : Bitfield<15,1> { };
};
/**
* Read register of detected PHY.
*/
inline uint16_t _phy_read(const uint8_t regnum) const
{
uint16_t val;
_phyio.phy_read(_phyaddr, regnum, val);
return val;
}
/**
* Write register of detected PHY.
*/
inline void _phy_write(const uint8_t regnum, const uint16_t data) const
{
_phyio.phy_write(_phyaddr, regnum, data);
}
/**
* Read PHY register 'T'
*/
template <typename T>
inline typename T::Register_base::access_t phy_read() const
{
typedef typename T::Register_base Register;
return _phy_read(Register::OFFSET);
}
/**
* Read the bitfield 'T' of PHY register
*/
template <typename T>
inline typename T::Bitfield_base::Compound_reg::access_t
phy_read() const
{
typedef typename T::Bitfield_base Bitfield;
typedef typename Bitfield::Compound_reg Register;
return Bitfield::get(_phy_read(Register::OFFSET));
}
/**
* Write PHY register 'T'
*/
template <typename T>
inline void phy_write(uint16_t const val) const
{
typedef typename T::Register_base Register;
return _phy_write(Register::OFFSET, val);
}
/**
* Detect PHY address.
*/
void phy_detection()
{
/* check _phyaddr */
if (_phyaddr != -1) {
Bmsr::access_t phyreg = phy_read<Bmsr>();
if ((phyreg != Bmsr::INVALID) &&
Bmsr::Full_10::get(phyreg) &&
Bmsr::Anegcapable::get(phyreg)) {
/* Found a valid PHY address */
log("default phy address ", (int)_phyaddr, " is valid");
return;
} else {
log("PHY address is not setup correctly ", (int)_phyaddr);
_phyaddr = -1;
}
}
log("detecting phy address");
if (_phyaddr == -1) {
/* detect the PHY address */
for (int i = 31; i >= 0; i--) {
_phyaddr = i;
Bmsr::access_t phyreg = phy_read<Bmsr>();
if ((phyreg != Bmsr::INVALID) &&
Bmsr::Full_10::get(phyreg) &&
Bmsr::Anegcapable::get(phyreg)) {
/* Found a valid PHY address */
log("found valid phy address, ", i);
return;
}
}
}
warning("PHY is not detected");
_phyaddr = -1;
}
uint32_t get_phy_id()
{
uint32_t phy_id = 0;
/* Grab the bits from PHYIR1, and put them
* in the upper half */
phy_id = phy_read<Idr1>() << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_id |= phy_read<Idr2>();
return phy_id;
}
void m88e1310_config()
{
/* LED link and activity */
phy_write<Page_select>(0x0003);
Led_ctrl::access_t led = phy_read<Led_ctrl>();
Led_ctrl::Data::set(led, 0x1);
phy_write<Led_ctrl>(led);
/* Set LED2/INT to INT mode, low active */
phy_write<Page_select>(0x0003);
Irq_en::access_t irq = phy_read<Irq_en>();
irq = (irq & 0x77ff) | 0x0880;
phy_write<Irq_en>(irq);
/* Set RGMII delay */
phy_write<Page_select>(0x0002);
RGMII_ctrl::access_t ctrl = phy_read<RGMII_ctrl>();
ctrl |= 0x0030;
phy_write<RGMII_ctrl>(ctrl);
/* Ensure to return to page 0 */
phy_write<Page_select>(0x0000);
genphy_config_aneg();
phy_reset();
}
int genphy_config_aneg()
{
/**
* Description: If auto-negotiation is enabled, we configure the
* advertising, and then restart auto-negotiation. If it is not
* enabled, then we write the BMCR.
*/
int result = genphy_config_advert();
if (result < 0) /* error */
return result;
if (result == 0) {
log("config not changed");
/* Advertisment hasn't changed, but maybe aneg was never on to
* begin with? Or maybe phy was isolated? */
uint16_t ctl = phy_read<Bmcr>();
if (!Bmcr::Anenable::get(ctl) || Bmcr::Isolate::get(ctl))
result = 1; /* do restart aneg */
} else {
log("config changed");
}
/* Only restart aneg if we are advertising something different
* than we were before. */
if (result > 0)
result = genphy_restart_aneg();
return result;
}
int genphy_config_advert()
{
/**
* Description: Writes MII_ADVERTISE with the appropriate values,
* after sanitizing the values to make sure we only advertise
* what is supported. Returns < 0 on error, 0 if the PHY's advertisement
* hasn't changed, and > 0 if it has changed.
*/
int changed = 0;
/* Setup standard advertisement */
Advertise::access_t adv = phy_read<Advertise>();
Advertise::access_t oldadv = adv;
Advertise::Base4_100::set(adv, 0);
Advertise::Pause_cap::set(adv, 1);
Advertise::Pause_asym::set(adv, 1);
Advertise::Half_10::set(adv, 1);
Advertise::Full_10::set(adv, 1);
Advertise::Half_100::set(adv, 1);
Advertise::Full_100::set(adv, 1);
if (adv != oldadv) {
phy_write<Advertise>(adv);
changed = 1;
}
/* Configure gigabit if it's supported */
adv = phy_read<Ctrl1000>();
oldadv = adv;
Ctrl1000::Full_1000::set(adv, 1);
Ctrl1000::Half_1000::set(adv, 1);
if (adv != oldadv) {
phy_write<Ctrl1000>(adv);
changed = 1;
}
return changed;
}
int genphy_restart_aneg()
{
Bmcr::access_t ctl = phy_read<Bmcr>();
Bmcr::Anenable::set(ctl, 1);
Bmcr::Anrestart::set(ctl, 1);
/* Don't isolate the PHY if we're negotiating */
Bmcr::Isolate::set(ctl, 0);
phy_write<Bmcr>(ctl);
return 0;
}
int phy_reset()
{
int timeout = 500;
Bmcr::access_t reg = phy_read<Bmcr>();
Bmcr::Reset::set(reg, 1);
phy_write<Bmcr>(reg);
/*
* Poll the control register for the reset bit to go to 0 (it is
* auto-clearing). This should happen within 0.5 seconds per the
* IEEE spec.
*/
while (phy_read<Bmcr::Reset>() && timeout--) {
_timer.msleep(1);
}
if (phy_read<Bmcr::Reset>()) {
warning("PHY reset timed out");
throw Phy_timeout_after_reset();
}
return 0;
}
int m88e1011s_startup()
{
genphy_update_link();
m88e1xxx_parse_status();
return 0;
}
int genphy_update_link()
{
/**
* Description: Update the value in phydev->link to reflect the
* current link value. In order to do this, we need to read
* the status register twice, keeping the second value.
*/
/*
* Wait if the link is up, and autonegotiation is in progress
* (ie - we're capable and it's not done)
*/
Bmsr::access_t mii_reg = phy_read<Bmsr>();
/*
* If we already saw the link up, and it hasn't gone down, then
* we don't need to wait for autoneg again
*/
if (_link_up && Bmsr::Lstatus::get(mii_reg))
return 0;
if ( Bmsr::Anegcapable::get(mii_reg) && !Bmsr::Anegcomplete::get(mii_reg) ) {
int i = 0;
Genode::log("waiting for PHY auto negotiation to complete");
while (!Bmsr::Anegcomplete::get(mii_reg)) {
/*
* Timeout reached ?
*/
if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
warning(" TIMEOUT !");
_link_up = false;
return 0;
}
if ((i++ % 500) == 0)
Genode::log(".");
_timer.msleep(1);
mii_reg = phy_read<Bmsr>();
}
Genode::log(" done");
_link_up = true;
} else {
/* Read the link a second time to clear the latched state */
mii_reg = phy_read<Bmsr>();
if (Bmsr::Lstatus::get(mii_reg))
_link_up = true;
else
_link_up = false;
}
return 0;
}
int m88e1xxx_parse_status()
{
/**
* Parse the 88E1011's status register for speed and duplex
* information
*/
Phy_stat::access_t stat = phy_read<Phy_stat>();
if ( Phy_stat::Link::get(stat) &&
!Phy_stat::Spddone::get(stat)) {
int i = 0;
log("waiting for PHY realtime link");
while (!phy_read<Phy_stat::Spddone>()) {
/* Timeout reached ? */
if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
warning(" TIMEOUT !");
_link_up = false;
break;
}
if ((i++ % 1000) == 0)
Genode::log(".");
_timer.msleep(1);
}
log(" done");
_timer.msleep(500);
} else {
if (Phy_stat::Link::get(stat))
_link_up = true;
else
_link_up = false;
}
// TODO change emac configuration if half duplex
if (Phy_stat::Speed_1000::get(stat))
_eth_speed = SPEED_1000;
else if (Phy_stat::Speed_100::get(stat))
_eth_speed = SPEED_100;
else
_eth_speed = SPEED_10;
return 0;
}
public:
Marvel_phy(Phyio& phyio, Timer::Connection &timer)
:
_timer(timer),
_phyio(phyio),
_phyaddr(0),
_link_up(false),
_eth_speed(UNDEFINED)
{ }
void init()
{
phy_detection();
uint32_t phy_id = get_phy_id();
log("the found phy has the id ", Hex(phy_id));
phy_reset();
m88e1310_config();
m88e1011s_startup();
}
Eth_speed eth_speed() { return _eth_speed; }
};
}
#endif /* _INCLUDE__DRIVERS__NIC__GEM__MARVELL_PHY_H_ */

View File

@ -1,31 +0,0 @@
/*
* \brief Phy driver for Marvell chips
* \author Timo Wischer
* \date 2015-05-11
*/
/*
* Copyright (C) 2015-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__PHYIO_H_
#define _INCLUDE__DRIVERS__NIC__GEM__PHYIO_H_
namespace Genode
{
class Phyio
{
public:
virtual void phy_write(const uint8_t phyaddr, const uint8_t regnum, const uint16_t data) = 0;
virtual void phy_read(const uint8_t phyaddr, const uint8_t regnum, uint16_t &data) = 0;
virtual ~Phyio() { }
};
}
#endif /* _INCLUDE__DRIVERS__NIC__GEM__PHYIO_H_ */

View File

@ -1,150 +0,0 @@
/*
* \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-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.
*/
#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;
struct Rx_buffer_source
{
virtual ~Rx_buffer_source() { }
virtual Dataspace_capability dataspace() = 0;
virtual Packet_descriptor alloc_packet(size_t size) = 0;
};
class Rx_buffer_descriptor : public Buffer_descriptor
{
private:
struct Addr : Register<0x00, 32> {
struct Addr31to2 : Bitfield<2, 30> {};
struct Wrap : Bitfield<1, 1> {};
struct Used : 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 { MAX_BUFFER_COUNT = 1024 };
addr_t const _phys_base;
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,
Rx_buffer_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++) {
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 reset_descriptor(Packet_descriptor pd)
{
addr_t const phys = _phys_base + pd.offset();
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 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()
{
if (_head_available())
return true;
_advance_head();
return _head_available();
}
Nic::Packet_descriptor get_packet_descriptor()
{
if (!_head_available())
return Nic::Packet_descriptor(0, 0);
const Status::access_t status = _head().status;
if (!Status::Start_of_frame::get(status) || !Status::End_of_frame::get(status)) {
warning("Packet split over more than one descriptor. Packet ignored!");
_reset_descriptor(_head_index(), _head().addr);
return Nic::Packet_descriptor(0, 0);
}
const size_t length = Status::Length::get(status);
/* reset status */
_head().status = 0;
return Nic::Packet_descriptor((addr_t)Addr::Addr31to2::masked(_head().addr) - _phys_base, length);
}
};
#endif /* _INCLUDE__DRIVERS__NIC__GEM__RX_BUFFER_DESCRIPTOR_H_ */

View File

@ -1,154 +0,0 @@
/*
* \brief Base EMAC driver for the Xilinx EMAC PS used on Zynq devices
* \author Timo Wischer
* \date 2015-03-10
*/
/*
* Copyright (C) 2015-2017 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.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__SYSTEM_CONTROL_H_
#define _INCLUDE__DRIVERS__NIC__GEM__SYSTEM_CONTROL_H_
/* Genode includes */
#include <os/attached_mmio.h>
#include <timer_session/connection.h>
#include <drivers/defs/zynq.h>
using namespace Genode;
class System_control : private Genode::Attached_mmio
{
private:
struct Lock : Register<0x4, 32> {
enum { MAGIC = 0x767B };
};
struct Unlock : Register<0x8, 32> {
enum { MAGIC = 0xDF0D };
};
struct Gem0_rclk_ctrl : Register<0x138, 32> { };
struct Gem0_clk_ctrl : Register<0x140, 32> { };
struct Mio_pin_16 : Register<0x740, 32> {
struct Tri_state_enable : Bitfield<0, 1> {};
struct Level_0_mux : Bitfield<1, 1> {
enum { ETH0 = 0b1 };
};
struct Fast_cmos_edge : Bitfield<8, 1> {};
struct IO_type : Bitfield<9, 3> {
enum { LVCMOS18 = 0b001 };
};
static access_t FAST_LVCMOS18_ETH0() {
return Fast_cmos_edge::bits(1) |
IO_type::bits(IO_type::LVCMOS18) |
Level_0_mux::bits(Level_0_mux::ETH0);
}
static access_t FAST_LVCMOS18_ETH0_TRISTATE() {
return FAST_LVCMOS18_ETH0() |
Tri_state_enable::bits(1);
}
};
struct Mio_pin_17 : Register<0x744, 32> { };
struct Mio_pin_18 : Register<0x748, 32> { };
struct Mio_pin_19 : Register<0x74C, 32> { };
struct Mio_pin_20 : Register<0x750, 32> { };
struct Mio_pin_21 : Register<0x754, 32> { };
struct Mio_pin_22 : Register<0x758, 32> { };
struct Mio_pin_23 : Register<0x75C, 32> { };
struct Mio_pin_24 : Register<0x760, 32> { };
struct Mio_pin_25 : Register<0x764, 32> { };
struct Mio_pin_26 : Register<0x768, 32> { };
struct Mio_pin_27 : Register<0x76C, 32> { };
struct Mio_pin_52 : Register<0x7D0, 32> {
struct Level_3_mux : Bitfield<5, 3> {
enum { MDIO0 = 0b100 };
};
static access_t LVCMOS18_MDIO0() {
return Mio_pin_16::IO_type::bits(Mio_pin_16::IO_type::LVCMOS18) |
Level_3_mux::bits(Level_3_mux::MDIO0);
}
};
struct Mio_pin_53 : Register<0x7D4, 32> { };
struct Gpio_b_ctrl : Register<0xB00, 32> {
struct Vref_enable : Bitfield<0, 1> {};
};
class Lock_guard
{
private:
System_control& _sys_ctrl;
void _unlock() { _sys_ctrl.write<Unlock>(Unlock::MAGIC); }
void _lock() { _sys_ctrl.write<Lock>(Lock::MAGIC); }
public:
Lock_guard(System_control& sys_ctrl) : _sys_ctrl(sys_ctrl)
{
_unlock();
}
~Lock_guard()
{
_lock();
}
};
unsigned int old_data[0x300];
Timer::Connection &_timer;
public:
System_control(Genode::Env &env, Timer::Connection &timer) :
Attached_mmio(env, Zynq::MMIO_1_BASE, 0xB80),
_timer(timer)
{
Lock_guard lock(*this);
write<Mio_pin_16>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_17>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_18>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_19>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_20>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_21>(Mio_pin_16::FAST_LVCMOS18_ETH0());
write<Mio_pin_22>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_23>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_24>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_25>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_26>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_27>(Mio_pin_16::FAST_LVCMOS18_ETH0_TRISTATE());
write<Mio_pin_52>(Mio_pin_52::LVCMOS18_MDIO0());
write<Mio_pin_53>(Mio_pin_52::LVCMOS18_MDIO0());
// TODO possibly not needed because uboot do not enable this register
/* enable internel VRef */
write<Gpio_b_ctrl>(Gpio_b_ctrl::Vref_enable::bits(1));
}
void set_clk(uint32_t clk, uint32_t rclk)
{
Lock_guard lock(*this);
write<Gem0_clk_ctrl>(clk);
write<Gem0_rclk_ctrl>(rclk);
_timer.msleep(100);
}
};
#endif /* _INCLUDE__DRIVERS__NIC__GEM__SYSTEM_CONTROL_H_ */

View File

@ -1,5 +0,0 @@
REQUIRES = arm_v7
TARGET = zynq_nic_drv
SRC_CC = main.cc
LIBS = base nic_driver
INC_DIR += $(PRG_DIR)

View File

@ -1,181 +0,0 @@
/*
* \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-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.
*/
#ifndef _INCLUDE__DRIVERS__NIC__GEM__TX_BUFFER_DESCRIPTOR_H_
#define _INCLUDE__DRIVERS__NIC__GEM__TX_BUFFER_DESCRIPTOR_H_
#include <base/log.h>
#include <timer_session/connection.h>
#include "buffer_descriptor.h"
using namespace Genode;
struct Tx_buffer_sink
{
virtual ~Tx_buffer_sink() { }
virtual Dataspace_capability dataspace() = 0;
virtual void acknowledge_packet(Packet_descriptor packet) = 0;
virtual bool packet_valid(Packet_descriptor packet) = 0;
};
class Tx_buffer_descriptor : public Buffer_descriptor
{
private:
enum { BUFFER_COUNT = 1024 };
struct Addr : Register<0x00, 32> {};
struct Status : Register<0x04, 32> {
struct Length : Bitfield<0, 14> {};
struct Last_buffer : Bitfield<15, 1> {};
struct Wrap : Bitfield<30, 1> {};
struct Used : Bitfield<31, 1> {};
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;
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:
class Package_send_timeout : public Genode::Exception {};
Tx_buffer_descriptor(Genode::Env &env,
Tx_buffer_sink &sink,
Timer::Connection &timer)
: Buffer_descriptor(env, BUFFER_COUNT), _timer(timer),
_phys_base(Dataspace_client(sink.dataspace()).phys_addr())
{
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 reset(Tx_buffer_sink &sink)
{
/* ack all packets that are still queued */
submit_acks(sink, true);
/* reset head and tail */
_reset_head();
_reset_tail();
}
void submit_acks(Tx_buffer_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++) {
/* stop if still in use by hardware */
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;
/* 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();
}
}
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;
}
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;
/* 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());
/* unset the used bit */
_head().status &= Status::Used::clear_mask();
_advance_head();
}
};
#endif /* _INCLUDE__DRIVERS__NIC__GEM__TX_BUFFER_DESCRIPTOR_H_ */

View File

@ -0,0 +1,5 @@
#
# Board-support for Xilinx Zynq-7000 SoC
#
#REPOSITORIES += $(GENODE_DIR)/repos/zynq

View File

@ -12,7 +12,6 @@ QEMU_RUN_OPT := --include power_on/qemu --include log/qemu
# local variable for run-tool arguments that depend on the used board
BOARD_RUN_OPT(pbxa9) = $(QEMU_RUN_OPT)
BOARD_RUN_OPT(virt_qemu) = $(QEMU_RUN_OPT)
BOARD_RUN_OPT(zynq_qemu) = $(QEMU_RUN_OPT)
##
## Qemu arguments, effective when using the run tool's 'power_on/qemu' back end

View File

@ -87,7 +87,7 @@ $(BUILD_DIR)/etc:
BUILD_CONF_X86 := run_x86 run_boot_dir repos repos_x86
BUILD_CONF_ARM_V6 := run_arm_v6 run_boot_dir repos
BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos
BUILD_CONF_ARM_V7 := run_arm_v7 run_boot_dir repos repos_arm_v7
BUILD_CONF(arm_v6) := $(BUILD_CONF_ARM_V6)
BUILD_CONF(arm_v7a) := $(BUILD_CONF_ARM_V7)
BUILD_CONF(arm_v8a) := run_arm_v8 run_boot_dir repos