dde_linux: wandboard ethernet driver

Fixes #2665
This commit is contained in:
Stefan Kalkowski 2017-11-01 15:49:47 +01:00 committed by Christian Helmuth
parent 590f51dbe1
commit d5dc234a00
16 changed files with 3421 additions and 2 deletions

54
repos/dde_linux/fec.list Normal file
View File

@ -0,0 +1,54 @@
linux-x.x.x/drivers/net/ethernet/freescale/fec.h
linux-x.x.x/drivers/net/ethernet/freescale/fec_main.c
linux-x.x.x/drivers/net/ethernet/freescale/fec_ptp.c
linux-x.x.x/drivers/net/phy/mdio_bus.c
linux-x.x.x/drivers/net/phy/phy_device.c
linux-x.x.x/drivers/net/phy/phy.c
linux-x.x.x/net/core/skbuff.c
linux-x.x.x/net/ethernet/eth.c
linux-x.x.x/include/asm-generic/atomic64.h
linux-x.x.x/include/asm-generic/bitops/non-atomic.h
linux-x.x.x/include/asm-generic/bitops/__ffs.h
linux-x.x.x/include/asm-generic/bitops/__fls.h
linux-x.x.x/include/asm-generic/bitops/ffs.h
linux-x.x.x/include/asm-generic/bitops/fls.h
linux-x.x.x/include/asm-generic/bitops/fls64.h
linux-x.x.x/include/linux/errqueue.h
linux-x.x.x/include/linux/fec.h
linux-x.x.x/include/linux/if_ether.h
linux-x.x.x/include/linux/list.h
linux-x.x.x/include/linux/list_nulls.h
linux-x.x.x/include/linux/log2.h
linux-x.x.x/include/linux/mii.h
linux-x.x.x/include/linux/mod_devicetable.h
linux-x.x.x/include/linux/net.h
linux-x.x.x/include/linux/netdev_features.h
linux-x.x.x/include/linux/phy.h
linux-x.x.x/include/linux/ptp_clock_kernel.h
linux-x.x.x/include/linux/rculist.h
linux-x.x.x/include/linux/rculist_nulls.h
linux-x.x.x/include/linux/skbuff.h
linux-x.x.x/include/linux/socket.h
linux-x.x.x/include/linux/timecounter.h
linux-x.x.x/include/net/dst.h
linux-x.x.x/include/net/dst_ops.h
linux-x.x.x/include/net/neighbour.h
linux-x.x.x/include/net/sock.h
linux-x.x.x/include/net/tcp_states.h
linux-x.x.x/include/net/tso.h
linux-x.x.x/include/uapi/linux/byteorder/little_endian.h
linux-x.x.x/include/uapi/linux/errqueue.h
linux-x.x.x/include/uapi/linux/ethtool.h
linux-x.x.x/include/uapi/linux/if.h
linux-x.x.x/include/uapi/linux/if_ether.h
linux-x.x.x/include/uapi/linux/if_packet.h
linux-x.x.x/include/uapi/linux/mdio.h
linux-x.x.x/include/uapi/linux/mii.h
linux-x.x.x/include/uapi/linux/net.h
linux-x.x.x/include/uapi/linux/net_tstamp.h
linux-x.x.x/include/uapi/linux/neighbour.h
linux-x.x.x/include/uapi/linux/ptp_clock.h
linux-x.x.x/include/uapi/linux/rtnetlink.h
linux-x.x.x/include/uapi/linux/socket.h
linux-x.x.x/include/uapi/linux/sockios.h
linux-x.x.x/include/uapi/linux/swab.h

View File

@ -0,0 +1,5 @@
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/nic/fec
SRC_DIR := $(REP_DIR)/src/drivers/nic/fec
INC_DIR += $(LX_CONTRIB_DIR)/drivers/net/ethernet/freescale
INC_DIR += $(LIB_CACHE_DIR)/fec_nic_include/include/include/include
CC_OPT += -U__linux__ -D__KERNEL__

View File

@ -0,0 +1,35 @@
#
# Pseudo library to generate a symlink for each header file included by the
# contrib code. Each symlink points to the same 'lx_emul.h' file, which
# provides our emulation of the Linux kernel API.
#
ifeq ($(called_from_lib_mk),yes)
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/nic/fec
LX_EMUL_H := $(REP_DIR)/src/drivers/nic/fec/lx_emul.h
#
# Determine the header files included by the contrib code. For each
# of these header files we create a symlink to 'lx_emul.h'.
#
SCAN_DIRS := $(addprefix $(LX_CONTRIB_DIR)/include/, asm-generic linux net uapi) \
$(addprefix $(LX_CONTRIB_DIR)/, drivers net)
GEN_INCLUDES := $(shell grep -rIh "^\#include .*" $(SCAN_DIRS) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" |\
sort | uniq)
#
# Put Linux headers in 'GEN_INC' dir, since some include use "../../" paths use
# three level include hierarchy
#
GEN_INC := $(shell pwd)/include/include/include
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
all: $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -sf $(LX_EMUL_H) $@
endif

View File

@ -0,0 +1,13 @@
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9147f9f..c63ee5c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3281,7 +3281,7 @@ static inline void skb_remcsum_process(struct sk_buff *skb, void *ptr,
if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) {
__skb_checksum_complete(skb);
- skb_postpull_rcsum(skb, skb->data, ptr - (void *)skb->data);
+ skb_postpull_rcsum(skb, skb->data, (unsigned char*)ptr - skb->data);
}
delta = remcsum_adjust(ptr, skb->csum, start, offset);

View File

@ -1 +1 @@
3a0e15f7cbe9f9a7e59e61c79cfb1463f344c203
82b2f79a8ecbbfeb42de534b776c6b348573bd60

View File

@ -1,7 +1,7 @@
LICENSE := GPLv2
VERSION := 2
DOWNLOADS := dwc_otg.git usb.archive intel_fb.archive lxip.archive \
wifi.archive libnl.archive wpa_supplicant.archive \
wifi.archive fec.archive libnl.archive wpa_supplicant.archive \
fw_3160.archive fw_6000.archive fw_6205a.archive fw_6205b.archive \
fw_7260.archive fw_7265.archive fw_8260.archive fw_1000.archive
@ -79,6 +79,16 @@ DIR(lxip) := $(SRC_DIR_LXIP)
TAR_OPT(lxip) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_LXIP)/g' $(REP_DIR)/lxip.list)
HASH_INPUT += $(REP_DIR)/lxip.list
#
# Freescale Ethernet controller
#
SRC_DIR_FEC := src/drivers/nic/fec
VERSION_FEC := 4.4.3
URL(fec) := https://www.kernel.org/pub/linux/kernel/v4.x/linux-$(VERSION_FEC).tar.xz
SHA(fec) := 336d66925a15ce9077cbf2c38acbdc6c2644e33f
DIR(fec) := $(SRC_DIR_FEC)
TAR_OPT(fec) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_FEC)/g' $(REP_DIR)/fec.list)
HASH_INPUT += $(REP_DIR)/fec.list
#
# libnl sources
@ -176,6 +186,7 @@ PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/lxip*.pat
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/intel*.patch)))
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/usb*.patch)))
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/intel*.patch)))
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/fec_*.patch)))
#IP stack
LXIP_OPT = -p1 -d$(SRC_DIR_LXIP)
@ -212,4 +223,7 @@ PATCH_OPT(patches/intel_fb_export_api.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
PATCH_OPT(patches/intel_fb_drm_remove.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
PATCH_OPT(patches/intel_fb_backlight.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
# Freescale NIC
PATCH_OPT(patches/fec_skbuff_cast.patch) := -p1 -d$(SRC_DIR_FEC)
# vi: set ft=make :

View File

@ -0,0 +1,180 @@
/*
* \brief Freescale ethernet driver component
* \author Stefan Kalkowski
* \date 2017-11-01
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <component.h>
#include <lx_emul.h>
extern "C" {
#include <lxc.h>
};
void Session_component::_run_rx_task(void * args)
{
Rx_data *data = static_cast<Rx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
int ret = 0;
struct napi_struct * n = data->napi;
for (;;) {
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidentally calling ->poll() when NAPI is not scheduled.
*/
if (!test_bit(NAPI_STATE_SCHED, &n->state)) break;
int weight = n->weight;
int work = n->poll(n, weight);
ret += work;
if (work < weight) break;
Genode::warning("Too much incoming traffic, we should schedule RX more intelligent");
}
}
}
void Session_component::_run_tx_task(void * args)
{
Tx_data *data = static_cast<Tx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
net_device * ndev = data->ndev;
struct sk_buff * skb = data->skb;
ndev->netdev_ops->ndo_start_xmit(skb, ndev);
}
}
bool Session_component::_send()
{
using namespace Genode;
/*
* We must not be called from another task, just from the
* packet stream dispatcher.
*/
if (Lx::scheduler().active()) {
warning("scheduler active");
return false;
}
if (!_tx.sink()->ready_to_ack()) { return false; }
if (!_tx.sink()->packet_avail()) { return false; }
Packet_descriptor packet = _tx.sink()->get_packet();
if (!packet.size()) {
warning("invalid tx packet");
return true;
}
enum { HEAD_ROOM = 8 };
struct sk_buff *skb = lxc_alloc_skb(packet.size() + HEAD_ROOM, HEAD_ROOM);
unsigned char *data = lxc_skb_put(skb, packet.size());
Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size());
_tx_data.ndev = _ndev;
_tx_data.skb = skb;
_tx_task.unblock();
Lx::scheduler().schedule();
_tx.sink()->acknowledge_packet(packet);
return true;
}
void Session_component::_handle_rx()
{
while (_rx.source()->ack_avail())
_rx.source()->release_packet(_rx.source()->get_acked_packet());
}
void Session_component::_handle_packet_stream()
{
_handle_rx();
while (_send()) continue;
}
void Session_component::unblock_rx_task(napi_struct * n)
{
_rx_data.napi = n;
_rx_task.unblock();
}
Nic::Mac_address Session_component::mac_address()
{
net_device * dev = fec_get_my_registered_net_device();
return dev ? Nic::Mac_address(dev->dev_addr) : Nic::Mac_address();
}
void Session_component::receive(struct sk_buff *skb)
{
_handle_rx();
if (!_rx.source()->ready_to_submit()) {
Genode::warning("not ready to receive packet");
return;
}
Skb s = skb_helper(skb);
try {
Nic::Packet_descriptor p = _rx.source()->alloc_packet(s.packet_size + s.frag_size);
void *buffer = _rx.source()->packet_content(p);
memcpy(buffer, s.packet, s.packet_size);
if (s.frag_size)
memcpy((char *)buffer + s.packet_size, s.frag, s.frag_size);
_rx.source()->submit_packet(p);
} catch (...) {
Genode::warning("failed to process received packet");
}
}
void Session_component::link_state(bool link)
{
if (link == _has_link) return;
_has_link = link;
_link_state_changed();
}
Session_component::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)
: Nic::Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env),
_ndev(fec_get_my_registered_net_device()),
_has_link(!(_ndev->state & (1UL << __LINK_STATE_NOCARRIER))) {
_register_session_component(*this); }

View File

@ -0,0 +1,75 @@
/*
* \brief Freescale ethernet driver component
* \author Stefan Kalkowski
* \date 2017-11-01
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SRC__DRIVERS__NIC__FEC__COMPONENT_H_
#define _SRC__DRIVERS__NIC__FEC__COMPONENT_H_
/* Genode includes */
#include <nic/root.h>
#include <lx_kit/scheduler.h>
extern "C" {
struct net_device;
struct napi_struct;
struct sk_buff;
}
class Session_component : public Nic::Session_component
{
private:
struct Tx_data
{
net_device * ndev;
sk_buff * skb;
};
struct Rx_data
{
struct napi_struct * napi;
};
net_device * _ndev = nullptr;
bool _has_link = false;
Tx_data _tx_data;
Rx_data _rx_data;
static void _run_tx_task(void * args);
static void _run_rx_task(void * args);
static void _register_session_component(Session_component &);
Lx::Task _tx_task { _run_tx_task, &_tx_data, "tx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
Lx::Task _rx_task { _run_rx_task, &_rx_data, "rx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
bool _send();
void _handle_rx();
void _handle_packet_stream() override;
public:
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);
Nic::Mac_address mac_address() override;
bool link_state() override { return _has_link; }
void link_state(bool link);
void receive(struct sk_buff *skb);
void unblock_rx_task(napi_struct * n);
};
#endif /* _SRC__DRIVERS__NIC__FEC__COMPONENT_H_ */

View File

@ -0,0 +1,368 @@
#include <lx_emul.h>
#include <linux/phy.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/skbuff.h>
#include <linux/timecounter.h>
#include <net/tso.h>
size_t copy_from_user(void *to, void const *from, size_t len)
{
TRACE_AND_STOP;
return -1;
}
size_t copy_to_user(void *dst, void const *src, size_t len)
{
TRACE_AND_STOP;
return -1;
}
bool device_may_wakeup(struct device *dev)
{
TRACE_AND_STOP;
return -1;
}
void device_release_driver(struct device *dev)
{
TRACE_AND_STOP;
}
int disable_irq(unsigned int irq)
{
TRACE_AND_STOP;
return -1;
}
int disable_irq_nosync(unsigned int irq)
{
TRACE_AND_STOP;
return -1;
}
int disable_irq_wake(unsigned int irq)
{
TRACE_AND_STOP;
return -1;
}
void dma_free_coherent(struct device * d, size_t size, void *vaddr, dma_addr_t bus)
{
TRACE_AND_STOP;
}
void dst_release(struct dst_entry *dst)
{
TRACE_AND_STOP;
}
int enable_irq_wake(unsigned int irq)
{
TRACE_AND_STOP;
return -1;
}
int enable_irq(unsigned int irq)
{
TRACE_AND_STOP;
return -1;
}
void eth_hw_addr_random(struct net_device *dev)
{
TRACE_AND_STOP;
}
u32 ethtool_op_get_link(struct net_device * d)
{
TRACE_AND_STOP;
return -1;
}
int ethtool_op_get_ts_info(struct net_device * d, struct ethtool_ts_info * i)
{
TRACE_AND_STOP;
return -1;
}
bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
{
TRACE_AND_STOP;
return -1;
}
void free_irq(unsigned int irq, void *dev_id)
{
TRACE_AND_STOP;
}
void free_netdev(struct net_device * d)
{
TRACE_AND_STOP;
}
bool gfp_pfmemalloc_allowed(gfp_t g)
{
TRACE_AND_STOP;
return -1;
}
int in_irq(void)
{
TRACE_AND_STOP;
return -1;
}
struct iphdr *ip_hdr(const struct sk_buff *skb)
{
TRACE_AND_STOP;
return NULL;
}
void *kmap_atomic(struct page *page)
{
TRACE_AND_STOP;
return NULL;
}
void kunmap_atomic(void *addr)
{
TRACE_AND_STOP;
}
void netif_tx_disable(struct net_device *dev)
{
TRACE_AND_STOP;
}
void netif_tx_stop_queue(struct netdev_queue *dev_queue)
{
TRACE_AND_STOP;
}
void netif_tx_wake_all_queues(struct net_device * d)
{
TRACE_AND_STOP;
}
void netif_tx_wake_queue(struct netdev_queue *dev_queue)
{
TRACE_AND_STOP;
}
int net_ratelimit(void)
{
TRACE_AND_STOP;
return -1;
}
ktime_t ns_to_ktime(u64 ns)
{
ktime_t ret;
TRACE_AND_STOP;
return ret;
}
struct timespec64 ns_to_timespec64(const s64 nsec)
{
struct timespec64 ret;
TRACE_AND_STOP;
return ret;
}
bool of_device_is_available(const struct device_node *device)
{
TRACE_AND_STOP;
return -1;
}
const void *of_get_mac_address(struct device_node *np)
{
TRACE_AND_STOP;
return NULL;
}
int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
{
TRACE_AND_STOP;
return -1;
}
struct device_node *of_node_get(struct device_node *node)
{
TRACE_AND_STOP;
return NULL;
}
void of_node_put(struct device_node *node)
{
TRACE_AND_STOP;
}
struct phy_device *of_phy_connect(struct net_device *dev, struct device_node *phy_np, void (*hndlr)(struct net_device *), u32 flags, int iface)
{
TRACE_AND_STOP;
return NULL;
}
int of_phy_register_fixed_link(struct device_node *np)
{
TRACE_AND_STOP;
return -1;
}
int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
{
TRACE_AND_STOP;
return -1;
}
void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
{
TRACE_AND_STOP;
}
int ptp_clock_index(struct ptp_clock *ptp)
{
TRACE_AND_STOP;
return -1;
}
int ptp_clock_unregister(struct ptp_clock *ptp)
{
TRACE_AND_STOP;
return -1;
}
int regulator_disable(struct regulator *r)
{
TRACE_AND_STOP;
return -1;
}
resource_size_t resource_size(const struct resource *res)
{
TRACE_AND_STOP;
return -1;
}
void rtnl_lock(void)
{
TRACE_AND_STOP;
}
void rtnl_unlock(void)
{
TRACE_AND_STOP;
}
bool page_is_pfmemalloc(struct page *page)
{
TRACE_AND_STOP;
return -1;
}
void put_page(struct page *page)
{
TRACE_AND_STOP;
}
void read_lock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
void read_unlock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
unsigned int tcp_hdrlen(const struct sk_buff *skb)
{
TRACE_AND_STOP;
return -1;
}
u64 timecounter_cyc2time(struct timecounter *tc, cycle_t cycle_tstamp)
{
TRACE_AND_STOP;
return -1;
}
u64 timecounter_read(struct timecounter *tc)
{
TRACE_AND_STOP;
return -1;
}
void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size)
{
TRACE_AND_STOP;
}
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, int size, bool is_last)
{
TRACE_AND_STOP;
}
int tso_count_descs(struct sk_buff *skb)
{
TRACE_AND_STOP;
return -1;
}
void tso_start(struct sk_buff *skb, struct tso_t *tso)
{
TRACE_AND_STOP;
}
void unregister_netdev(struct net_device * d)
{
TRACE_AND_STOP;
}
void __vlan_hwaccel_put_tag(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
{
TRACE_AND_STOP;
}
void module_put(struct module *mod)
{
TRACE_AND_STOP;
}
void put_device(struct device *dev)
{
TRACE_AND_STOP;
}
int strcmp(const char *s1, const char *s2)
{
TRACE_AND_STOP;
return -1;
}
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
{
TRACE_AND_STOP;
return -1;
}
void class_unregister(struct class *cls)
{
TRACE_AND_STOP;
}
void bus_unregister(struct bus_type *bus)
{
TRACE_AND_STOP;
}
void driver_unregister(struct device_driver *drv)
{
TRACE_AND_STOP;
}
struct user_namespace init_user_ns;
int sysctl_tstamp_allow_data;

View File

@ -0,0 +1,910 @@
/*
* \brief Emulation of Linux kernel interfaces
* \author Stefan Kalkowski
* \date 2018-01-16
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/**
* Unconditionally include common Genode headers _before_ lx_emul.h to
* prevent shenanigans with macro definitions.
*/
#include <base/attached_io_mem_dataspace.h>
#include <base/env.h>
#include <base/snprintf.h>
#include <os/backtrace.h>
#include <component.h>
#include <lx_emul.h>
#include <lx_emul/impl/kernel.h>
#include <lx_emul/impl/delay.h>
#include <lx_emul/impl/slab.h>
#include <lx_emul/impl/work.h>
#include <lx_emul/impl/spinlock.h>
#include <lx_emul/impl/mutex.h>
#include <lx_emul/impl/sched.h>
#include <lx_emul/impl/timer.h>
#include <lx_emul/impl/completion.h>
#include <lx_kit/irq.h>
extern "C" { struct page; }
class Addr_to_page_mapping : public Genode::List<Addr_to_page_mapping>::Element
{
private:
unsigned long _addr { 0 };
struct page *_page { nullptr };
static Genode::List<Addr_to_page_mapping> & _list()
{
static Genode::List<Addr_to_page_mapping> _l;
return _l;
}
public:
Addr_to_page_mapping(unsigned long addr, struct page *page)
: _addr(addr), _page(page) { }
static void insert(struct page * page)
{
Addr_to_page_mapping *m = (Addr_to_page_mapping*)
Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping));
m->_addr = (unsigned long)page->addr;
m->_page = page;
_list().insert(m);
}
static struct page * remove(unsigned long addr)
{
for (Addr_to_page_mapping *m = _list().first(); m; m = m->next())
if (m->_addr == addr) {
struct page * ret = m->_page;
_list().remove(m);
Lx::Malloc::mem().free(m);
return ret;
}
return nullptr;
}
};
struct Device : Genode::List<Device>::Element
{
struct device * dev; /* Linux device */
Device(struct device *dev) : dev(dev) {
list()->insert(this); }
static Genode::List<Device> *list()
{
static Genode::List<Device> _list;
return &_list;
}
};
class Driver : public Genode::List<Driver>::Element
{
private:
struct device_driver * _drv; /* Linux driver */
public:
Driver(struct device_driver *drv) : _drv(drv)
{
list()->insert(this);
}
/**
* List of all currently registered drivers
*/
static Genode::List<Driver> *list()
{
static Genode::List<Driver> _list;
return &_list;
}
/**
* Match device and drivers
*/
bool match(struct device *dev)
{
/*
* Don't try if buses don't match, since drivers often use 'container_of'
* which might cast the device to non-matching type
*/
if (_drv->bus != dev->bus)
return false;
return _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
}
/**
* Probe device with driver
*/
int probe(struct device *dev)
{
dev->driver = _drv;
if (dev->bus->probe) return dev->bus->probe(dev);
else if (_drv->probe)
return _drv->probe(dev);
return 0;
}
};
static Session_component * session = nullptr;
void Session_component::_register_session_component(Session_component & s) {
session = &s; }
#include <lx_emul/extern_c_begin.h>
#include <linux/phy.h>
#include <linux/timecounter.h>
#include <lx_emul/extern_c_end.h>
extern "C" {
void lx_backtrace()
{
Genode::backtrace();
}
int platform_driver_register(struct platform_driver * drv)
{
static platform_device pd_fec;
static const char * name = "2188000.ethernet";
pd_fec.name = name;
return drv->probe(&pd_fec);
}
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
unsigned char name_assign_type,
void (*setup)(struct net_device *),
unsigned int txqs, unsigned int rxqs)
{
size_t alloc_size = ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
alloc_size += sizeof_priv;
alloc_size += NETDEV_ALIGN - 1;
struct net_device *p = (struct net_device*) kzalloc(alloc_size,
GFP_KERNEL);
struct net_device *dev = PTR_ALIGN(p, NETDEV_ALIGN);
INIT_LIST_HEAD(&dev->mc.list);
dev->mc.count = 0;
dev->gso_max_segs = GSO_MAX_SEGS;
static const struct ethtool_ops default_ethtool_ops { };
if (!dev->ethtool_ops) dev->ethtool_ops = &default_ethtool_ops;
dev->dev_addr = (unsigned char*) kzalloc(ETH_ALEN, GFP_KERNEL);
return dev;
}
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
for (; matches && matches->compatible[0]; matches++)
if (Genode::strcmp(matches->compatible, "fsl,imx6q-fec") == 0)
return matches;
return NULL;
}
void * devm_ioremap_resource(struct device *dev, struct resource *res)
{
static Genode::Attached_io_mem_dataspace io_ds(Lx_kit::env().env(),
0x2188000, 0x1000);
return io_ds.local_addr<void>();
}
void platform_set_drvdata(struct platform_device *pdev, void *data)
{
pdev->dev.driver_data = data;
}
int of_get_phy_mode(struct device_node *np)
{
for (int i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
if (!Genode::strcmp("rgmii", phy_modes((phy_interface_t)i)))
return i;
return -ENODEV;
}
ktime_t ktime_get_real(void)
{
Lx::timer_update_jiffies();
return ktime_get();
}
void timecounter_init(struct timecounter *tc, const struct cyclecounter *cc, u64 start_tstamp)
{
tc->cc = cc;
tc->cycle_last = cc->read(cc);
tc->nsec = start_tstamp;
tc->mask = (1ULL << cc->shift) - 1;
tc->frac = 0;
}
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
void *addr = Lx::Malloc::dma().alloc_large(size);
static unsigned waechter = 0;
ASSERT(!waechter++);
*dma_handle = (dma_addr_t) addr;
return addr;
}
void *dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp)
{
dma_addr_t dma_addr;
void *addr = Lx::Malloc::dma().alloc(size, 12, &dma_addr);
*dma_handle = dma_addr;
return addr;
}
dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction)
{
dma_addr_t dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(cpu_addr);
if (dma_addr == ~0UL)
Genode::error(__func__, ": virtual address ", cpu_addr,
" not registered for DMA");
return dma_addr;
}
int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return (dma_addr == ~0UL) ? 1 : 0;
}
void *dev_get_platdata(const struct device *dev)
{
return dev->platform_data;
}
int netif_running(const struct net_device *dev)
{
return dev->state & (1 << __LINK_STATE_START);
}
void netif_carrier_on(struct net_device *dev)
{
dev->state &= ~(1UL << __LINK_STATE_NOCARRIER);
if (session) session->link_state(true);
}
void netif_carrier_off(struct net_device *dev)
{
dev->state |= 1UL << __LINK_STATE_NOCARRIER;
if (session) session->link_state(false);
}
int netif_device_present(struct net_device * d)
{
TRACE;
return 1;
}
int platform_get_irq(struct platform_device * d, unsigned int i)
{
if (i > 1) return -1;
return 150 + i;
}
int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
{
Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev_id);
return 0;
}
struct clk *devm_clk_get(struct device *dev, const char *id)
{
static struct clk clocks[] {
{ "ipg", 66*1000*1000 },
{ "ahb", 132*1000*1000 },
{ "enet_clk_ref", 500*1000*1000 } };
for (unsigned i = 0; i < (sizeof(clocks) / sizeof(struct clk)); i++)
if (Genode::strcmp(clocks[i].name, id) == 0)
return &clocks[i];
return NULL;
}
unsigned long clk_get_rate(struct clk * clk)
{
if (!clk) return 0;
return clk->rate;
}
int is_valid_ether_addr(const u8 * a)
{
for (unsigned i = 0; i < ETH_ALEN; i++)
if (a[i] != 0 && a[i] != 255) return 1;
return 0;
}
static struct net_device * my_net_device = nullptr;
int register_netdev(struct net_device * d)
{
my_net_device = d;
d->state |= (1 << __LINK_STATE_START) | (1UL << __LINK_STATE_NOCARRIER);
int err = d->netdev_ops->ndo_open(d);
if (err) {
Genode::error("ndo_open() failed: ", err);
return err;
}
return 0;
}
struct net_device * fec_get_my_registered_net_device()
{
return my_net_device;
}
void *kmem_cache_alloc_node(struct kmem_cache *cache, gfp_t, int)
{
return (void*)cache->alloc();
}
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
size_t size = PAGE_SIZE << order;
page->addr = Lx::Malloc::dma().alloc(size, 12);
if (!page->addr) {
Genode::error("alloc_pages: ", size, " failed");
kfree(page);
return 0;
}
Addr_to_page_mapping::insert(page);
atomic_set(&page->_count, 1);
return page;
}
void get_page(struct page *page)
{
atomic_inc(&page->_count);
}
void *__alloc_page_frag(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask)
{
struct page *page = alloc_pages(GFP_LX_DMA, fragsz / PAGE_SIZE);
if (!page) return nullptr;
return page->addr;
}
void __free_page_frag(void *addr)
{
struct page *page = Addr_to_page_mapping::remove((unsigned long)addr);
if (!atomic_dec_and_test(&page->_count))
Genode::error("page reference count != 0");
Lx::Malloc::dma().free(page->addr);
kfree(page);
}
int driver_register(struct device_driver *drv)
{
new (Lx::Malloc::mem()) Driver(drv);
return 0;
}
int device_add(struct device *dev)
{
if (dev->driver)
return 0;
/* foreach driver match and probe device */
for (Driver *driver = Driver::list()->first(); driver; driver = driver->next())
if (driver->match(dev)) {
int ret = driver->probe(dev);
if (!ret) return 0;
}
return 0;
}
void device_del(struct device *dev)
{
if (dev->driver && dev->driver->remove)
dev->driver->remove(dev);
}
int device_register(struct device *dev)
{
return device_add(dev);
}
void reinit_completion(struct completion *work)
{
init_completion(work);
}
static void _completion_timeout(unsigned long t)
{
Lx::Task *task = (Lx::Task *)t;
task->unblock();
}
long __wait_completion(struct completion *work, unsigned long timeout)
{
timer_list t;
Lx::timer_update_jiffies();
unsigned long j = timeout ? jiffies + timeout : 0;
if (timeout) {
setup_timer(&t, _completion_timeout, (unsigned long)Lx::scheduler().current());
mod_timer(&t, timeout);
}
while (!work->done) {
if (j && j <= jiffies) {
lx_log(1, "timeout jiffies %lu", jiffies);
return 0;
}
Lx::Task *task = Lx::scheduler().current();
work->task = (void *)task;
task->block_and_schedule();
}
if (timeout)
del_timer(&t);
work->done = 0;
return j ? j - jiffies : 1;
}
int request_module(const char *format, ...)
{
TRACE;
return 0;
}
size_t strlcpy(char *dest, const char *src, size_t size)
{
size_t ret = Genode::strlen(src);
if (size) {
size_t len = (ret >= size) ? size - 1 : ret;
Genode::memcpy(dest, src, len);
dest[len] = '\0';
}
return ret;
}
void local_irq_restore(unsigned long f) { }
unsigned long local_irq_save(unsigned long flags) { return flags; }
int pm_runtime_get_sync(struct device *dev)
{
return 0;
}
void pm_runtime_mark_last_busy(struct device *dev) { }
int in_interrupt(void)
{
return 0;
}
int pm_runtime_put_autosuspend(struct device *dev)
{
return 0;
}
int dev_set_name(struct device *dev, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
Genode::String_console sc(dev->name, 32);
sc.vprintf(fmt, args);
va_end(args);
new (Lx::Malloc::mem()) Device(dev);
return 0;
}
int bus_register(struct bus_type *bus)
{
TRACE;
return 0;
}
struct device *bus_find_device_by_name(struct bus_type *bus, struct device *start, const char *name)
{
for (Device *dev = Device::list()->first(); dev; dev = dev->next()) {
if (Genode::strcmp(dev->dev->name, name) == 0)
return dev->dev;
}
return nullptr;
}
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
napi->dev = dev;
napi->poll = poll;
napi->state = NAPI_STATE_SCHED;
napi->weight = weight;
}
const char *dev_name(const struct device *dev)
{
return dev->name;
}
extern "C" void consume_skb(struct sk_buff *skb);
void dev_kfree_skb_any(struct sk_buff * sk)
{
consume_skb(sk);
}
void napi_enable(struct napi_struct *n)
{
clear_bit(NAPI_STATE_SCHED, &n->state);
clear_bit(NAPI_STATE_NPSVC, &n->state);
}
void napi_disable(struct napi_struct *n)
{
set_bit(NAPI_STATE_SCHED, &n->state);
set_bit(NAPI_STATE_NPSVC, &n->state);
}
void __napi_schedule(struct napi_struct *n)
{
if (session) session->unblock_rx_task(n);
}
bool napi_schedule_prep(struct napi_struct *n)
{
return !test_and_set_bit(NAPI_STATE_SCHED, &n->state);
}
void napi_complete(struct napi_struct *n)
{
clear_bit(NAPI_STATE_SCHED, &n->state);
}
unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
{
unsigned long i = offset / BITS_PER_LONG;
offset -= (i * BITS_PER_LONG);
for (; offset < size; offset++)
if (addr[i] & (1UL << offset))
return offset + (i * BITS_PER_LONG);
return size;
}
gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
if (session) session->receive(skb);
dev_kfree_skb(skb);
return GRO_NORMAL;
}
void dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
// FIXME
TRACE;
}
bool netif_queue_stopped(const struct net_device *dev)
{
// FIXME
TRACE;
return 0;
}
/*********************
** DUMMY FUNCTIONS **
*********************/
void clk_disable_unprepare(struct clk * c)
{
TRACE;
}
int clk_prepare_enable(struct clk * c)
{
TRACE;
return 0;
}
void device_initialize(struct device *dev)
{
TRACE;
}
int device_init_wakeup(struct device *dev, bool val)
{
TRACE;
return 0;
}
struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id)
{
TRACE;
return NULL;
}
struct device_node *of_get_child_by_name( const struct device_node *node, const char *name)
{
TRACE;
return NULL;
}
struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, unsigned int index)
{
TRACE;
return NULL;
}
const void *of_get_property(const struct device_node *node, const char *name, int *lenp)
{
TRACE;
return NULL;
}
struct device_node *of_parse_phandle(const struct device_node *np, const char *phandle_name, int index)
{
TRACE;
return NULL;
}
bool of_phy_is_fixed_link(struct device_node *np)
{
TRACE;
return 0;
}
int pinctrl_pm_select_default_state(struct device *dev)
{
TRACE;
return -1;
}
int pinctrl_pm_select_sleep_state(struct device *dev)
{
TRACE;
return -1;
}
struct resource *platform_get_resource(struct platform_device * d, unsigned r1, unsigned r2)
{
TRACE;
return NULL;
}
void pm_runtime_enable(struct device *dev)
{
TRACE;
}
void pm_runtime_get_noresume(struct device *dev)
{
TRACE;
}
int pm_runtime_set_active(struct device *dev)
{
TRACE;
return 0;
}
void pm_runtime_set_autosuspend_delay(struct device *dev, int delay)
{
TRACE;
}
void pm_runtime_use_autosuspend(struct device *dev)
{
TRACE;
}
struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, struct device *parent)
{
TRACE;
return NULL;
}
int regulator_enable(struct regulator * d)
{
TRACE;
return 0;
}
int of_driver_match_device(struct device *dev, const struct device_driver *drv)
{
TRACE;
return 0;
}
int class_register(struct class_ *cls)
{
TRACE;
return 0;
}
int try_module_get(struct module *mod)
{
TRACE;
return -1;
}
struct device *get_device(struct device *dev)
{
TRACE;
return NULL;
}
int device_bind_driver(struct device *dev)
{
TRACE;
return 0;
}
void netif_tx_start_all_queues(struct net_device *dev)
{
TRACE;
}
void netif_tx_lock_bh(struct net_device *dev)
{
TRACE;
}
int device_set_wakeup_enable(struct device *dev, bool enable)
{
TRACE;
return 0;
}
void trace_consume_skb(struct sk_buff * sb)
{
TRACE;
}
void trace_kfree_skb(struct sk_buff * sb, void * p)
{
TRACE;
}
void netif_tx_unlock_bh(struct net_device *dev)
{
TRACE;
}
void netif_wake_queue(struct net_device * d)
{
TRACE;
}
bool netdev_uses_dsa(struct net_device *dev)
{
TRACE;
return false;
}
void dma_sync_single_for_device(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
TRACE;
}
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size,
enum dma_data_direction dir)
{
TRACE;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
/*
* \brief Linux emulation code
* \author Josef Soentgen
* \date 2014-03-07
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* linux includes */
#include <lx_emul.h>
#include <linux/skbuff.h>
/* local includes */
#include <lxc.h>
struct Skb skb_helper(struct sk_buff *skb)
{
struct Skb helper;
skb_push(skb, ETH_HLEN);
helper.packet = skb->data;
helper.packet_size = ETH_HLEN;
helper.frag = 0;
helper.frag_size = 0;
/**
* If received packets are too large (as of now 128 bytes) the actually
* payload is put into a fragment. Otherwise the payload is stored directly
* in the sk_buff.
*/
if (skb_shinfo(skb)->nr_frags) {
if (skb_shinfo(skb)->nr_frags > 1)
printk("more than 1 fragment in skb: %p nr_frags: %d", skb,
skb_shinfo(skb)->nr_frags);
skb_frag_t *f = &skb_shinfo(skb)->frags[0];
helper.frag = skb_frag_address(f);
helper.frag_size = skb_frag_size(f);
}
else
helper.packet_size += skb->len;
return helper;
}
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom)
{
struct sk_buff *skb = alloc_skb(len + headroom, GFP_KERNEL | GFP_LX_DMA);
skb_reserve(skb, headroom);
return skb;
}
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len)
{
return skb_put(skb, len);
}

View File

@ -0,0 +1,40 @@
/*
* \brief Lx C env
* \author Josef Soentgen
* \date 2016-03-04
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LXC_H_
#define _LXC_H_
/*
* The sk_buff struct contains empty array members whose
* size differs between C and C++. Since we want to access
* certain members of the sk_buff from C++ we have to use
* a uniform format useable from both languages.W
*
* Note: we pull struct skb_buff as well as size_t from
* headers included before this one.
*/
struct Skb
{
void *packet;
size_t packet_size;
void *frag;
size_t frag_size;
};
struct Skb skb_helper(struct sk_buff *skb);
bool is_eapol(struct sk_buff *skb);
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom);
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len);
#endif /* _LXC_H_ */

View File

@ -0,0 +1,111 @@
/*
* \brief Freescale ethernet driver
* \author Stefan Kalkowski
* \date 2017-10-19
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <component.h>
/* Linux emulation environment includes */
#include <lx_emul.h>
#include <lx_kit/env.h>
#include <lx_kit/malloc.h>
#include <lx_kit/scheduler.h>
#include <lx_kit/timer.h>
#include <lx_kit/irq.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/work.h>
/* Linux module functions */
extern "C" int module_fec_driver_init();
extern "C" int subsys_phy_init();
extern "C" void skb_init();
static void run_linux(void * m);
struct workqueue_struct *system_wq;
struct workqueue_struct *system_power_efficient_wq;
unsigned long jiffies;
struct Main
{
Genode::Env &env;
Genode::Entrypoint &ep { env.ep() };
Genode::Attached_rom_dataspace config { env, "config" };
Genode::Heap heap { env.ram(), env.rm() };
Nic::Root<Session_component> root { env, heap };
/* Linux task that handles the initialization */
Genode::Constructible<Lx::Task> linux;
Main(Genode::Env &env) : env(env)
{
Genode::log("--- freescale ethernet driver ---");
Lx_kit::construct_env(env);
/* init singleton Lx::Scheduler */
Lx::scheduler(&env);
//Lx::pci_init(env, env.ram(), heap);
Lx::malloc_init(env, heap);
/* init singleton Lx::Timer */
Lx::timer(&env, &ep, &heap, &jiffies);
/* init singleton Lx::Irq */
Lx::Irq::irq(&ep, &heap);
/* init singleton Lx::Work */
Lx::Work::work_queue(&heap);
linux.construct(run_linux, reinterpret_cast<void*>(this),
"linux", Lx::Task::PRIORITY_0, Lx::scheduler());
/* give all task a first kick before returning */
Lx::scheduler().schedule();
}
void announce() { env.parent().announce(ep.manage(root)); }
Lx::Task &linux_task() { return *linux; }
};
static void run_linux(void * m)
{
Main & main = *reinterpret_cast<Main*>(m);
system_wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
system_power_efficient_wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
skb_init();
subsys_phy_init();
module_fec_driver_init();
main.announce();
while (1) Lx::scheduler().current()->block_and_schedule();
}
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics */
env.exec_static_constructors();
static Main m(env);
}

View File

@ -0,0 +1,39 @@
/*
* \brief Platform driver relevant lx_kit backend functions
* \author Stefan Kalkowski
* \date 2017-11-01
*
* Taken from the USB driver.
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/ram_allocator.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/env.h>
/****************************
** lx_kit/backend_alloc.h **
****************************/
void backend_alloc_init(Genode::Env&, Genode::Ram_session&,
Genode::Allocator&)
{
/* intentionally left blank */
}
Genode::Ram_dataspace_capability
Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) {
return Lx_kit::env().env().ram().alloc(size, cached); }
void Lx::backend_free(Genode::Ram_dataspace_capability cap) {
return Lx_kit::env().env().ram().free(cap); }

View File

@ -0,0 +1,49 @@
REQUIRES = arm_v7
TARGET = nic_drv
LIBS = base lx_kit_setjmp fec_nic_include
SRC_CC = main.cc platform.cc lx_emul.cc component.cc
SRC_C += dummy.c lxc.c
INC_DIR += $(PRG_DIR)
# lx_kit
SRC_CC += env.cc irq.cc malloc.cc scheduler.cc timer.cc work.cc printf.cc
INC_DIR += $(REP_DIR)/src/include
INC_DIR += $(REP_DIR)/src/include/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm_v7
INC_DIR += $(REP_DIR)/src/lib/usb/include/spec/arm
# contrib code
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/nic/fec
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/net/ethernet/freescale/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/net/phy/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/net/core/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/net/ethernet/*.c))
INC_DIR += $(LX_CONTRIB_DIR)/include
#
# Linux sources are C89 with GNU extensions
#
CC_C_OPT += -std=gnu89
#
# Reduce build noise of compiling contrib code
#
CC_OPT_fec_ptp = -Wno-unused-but-set-variable -Wno-unused-variable \
-Wno-maybe-uninitialized -Wno-uninitialized
CC_OPT_fec_main = -Wno-unused-but-set-variable -Wno-unused-variable \
-Wno-pointer-sign -Wno-int-conversion -Wno-unused-function \
-Wno-uninitialized
CC_OPT_skbuff = -Wno-pointer-sign -Wno-int-conversion -Wno-uninitialized
CC_OPT_mdio_bus = -Wno-implicit-int -Wno-unused-function -Wno-pointer-sign
CC_OPT_eth = -Wno-pointer-sign -Wno-unused-function
CC_OPT_phy = -Wno-unused-function -Wno-unused-but-set-variable
vpath %.c $(LX_CONTRIB_DIR)/drivers/net/ethernet/freescale
vpath %.c $(LX_CONTRIB_DIR)/drivers/net/phy
vpath %.c $(LX_CONTRIB_DIR)/net/core
vpath %.c $(LX_CONTRIB_DIR)/net/ethernet
vpath %.cc $(PRG_DIR)
vpath %.cc $(REP_DIR)/src/lx_kit
CC_CXX_WARN_STRICT =