diff --git a/repos/dde_linux/fec.list b/repos/dde_linux/fec.list new file mode 100644 index 000000000..90e72bd72 --- /dev/null +++ b/repos/dde_linux/fec.list @@ -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 diff --git a/repos/dde_linux/lib/import/import-fec_nic_include.mk b/repos/dde_linux/lib/import/import-fec_nic_include.mk new file mode 100644 index 000000000..7c410190c --- /dev/null +++ b/repos/dde_linux/lib/import/import-fec_nic_include.mk @@ -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__ diff --git a/repos/dde_linux/lib/mk/fec_nic_include.mk b/repos/dde_linux/lib/mk/fec_nic_include.mk new file mode 100644 index 000000000..e620915a9 --- /dev/null +++ b/repos/dde_linux/lib/mk/fec_nic_include.mk @@ -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 diff --git a/repos/dde_linux/patches/fec_skbuff_cast.patch b/repos/dde_linux/patches/fec_skbuff_cast.patch new file mode 100644 index 000000000..5e63596db --- /dev/null +++ b/repos/dde_linux/patches/fec_skbuff_cast.patch @@ -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); diff --git a/repos/dde_linux/ports/dde_linux.hash b/repos/dde_linux/ports/dde_linux.hash index fec0fa591..f9231242f 100644 --- a/repos/dde_linux/ports/dde_linux.hash +++ b/repos/dde_linux/ports/dde_linux.hash @@ -1 +1 @@ -3a0e15f7cbe9f9a7e59e61c79cfb1463f344c203 +82b2f79a8ecbbfeb42de534b776c6b348573bd60 diff --git a/repos/dde_linux/ports/dde_linux.port b/repos/dde_linux/ports/dde_linux.port index 31bdb8c23..3f400addc 100644 --- a/repos/dde_linux/ports/dde_linux.port +++ b/repos/dde_linux/ports/dde_linux.port @@ -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 : diff --git a/repos/dde_linux/src/drivers/nic/fec/component.cc b/repos/dde_linux/src/drivers/nic/fec/component.cc new file mode 100644 index 000000000..13e404e97 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/component.cc @@ -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 +#include + +extern "C" { +#include +}; + +void Session_component::_run_rx_task(void * args) +{ + Rx_data *data = static_cast(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(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); } diff --git a/repos/dde_linux/src/drivers/nic/fec/component.h b/repos/dde_linux/src/drivers/nic/fec/component.h new file mode 100644 index 000000000..cf1f0b759 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/component.h @@ -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 + +#include + +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_ */ diff --git a/repos/dde_linux/src/drivers/nic/fec/dummy.c b/repos/dde_linux/src/drivers/nic/fec/dummy.c new file mode 100644 index 000000000..b1e3239a1 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/dummy.c @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include + +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; + diff --git a/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc new file mode 100644 index 000000000..6705c883a --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc @@ -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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { struct page; } + +class Addr_to_page_mapping : public Genode::List::Element +{ + private: + + unsigned long _addr { 0 }; + struct page *_page { nullptr }; + + static Genode::List & _list() + { + static Genode::List _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::Element +{ + struct device * dev; /* Linux device */ + + Device(struct device *dev) : dev(dev) { + list()->insert(this); } + + static Genode::List *list() + { + static Genode::List _list; + return &_list; + } +}; + + +class Driver : public Genode::List::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 *list() + { + static Genode::List _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 +#include +#include +#include + +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 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; +} + +} diff --git a/repos/dde_linux/src/drivers/nic/fec/lx_emul.h b/repos/dde_linux/src/drivers/nic/fec/lx_emul.h new file mode 100644 index 000000000..5743821eb --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/lx_emul.h @@ -0,0 +1,1461 @@ +/* + * \brief Freescale ethernet driver Linux emulation environment + * \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__LX_EMUL_H_ +#define _SRC__DRIVERS__NIC__FEC__LX_EMUL_H_ + +#include +#include + +#include + +#include +#include +#include + +void lx_backtrace(void); + +#define DEBUG 0 +#if DEBUG +#define TRACE \ + do { \ + lx_printf("%s not implemented\n", __func__); \ + } while (0) +#else +#define TRACE do { ; } while (0) +#endif + +#define TRACE_AND_STOP \ + do { \ + lx_printf("%s not implemented\n", __func__); \ + lx_backtrace(); \ + BUG(); \ + } while (0) + +#define ASSERT(x) \ + do { \ + if (!(x)) { \ + lx_printf("%s:%u assertion failed\n", __func__, __LINE__); \ + BUG(); \ + } \ + } while (0) + +typedef int clockid_t; + +#define PAGE_SIZE 4096UL + +enum { PAGE_SHIFT = 12 }; +enum { HZ = 100UL, }; + +struct list_head; + +typedef __u16 __le16; +typedef __u32 __le32; +typedef __u64 __le64; +typedef __u16 __be16; +typedef __u32 __be32; +typedef __u64 __be64; +typedef __s64 time64_t; + +#define L1_CACHE_BYTES 32 +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#define __aligned_u64 __u64 __attribute__((aligned(8))) +#define ____cacheline_aligned_in_smp __attribute__((aligned(SMP_CACHE_BYTES))) +#define ____cacheline_aligned __attribute__((aligned(SMP_CACHE_BYTES))) + + +struct iov_iter { }; +size_t iov_iter_count(struct iov_iter *i); + +#define dev_info( dev, format, arg...) lx_printf("dev_info: " format , ## arg) +#define dev_warn( dev, format, arg...) lx_printf("dev_warn: " format , ## arg) +#define dev_WARN( dev, format, arg...) lx_printf("dev_WARN: " format , ## arg) +#define dev_err( dev, format, arg...) lx_printf("dev_error: " format , ## arg) +#define dev_notice(dev, format, arg...) lx_printf("dev_notice: " format , ## arg) +#define dev_crit( dev, format, arg...) lx_printf("dev_crit: " format , ## arg) +#if DEBUG +#define dev_dbg( dev, format, arg...) lx_printf("dev_dbg: " format , ## arg) +#else +#define dev_dbg( dev, format, arg...) +#endif + +#define pr_debug(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__) +#define pr_err(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__) +#define pr_warn(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__) +#define pr_info_once(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__) +#define pr_notice(fmt, ...) printk(KERN_NOTICE fmt, ##__VA_ARGS__) +#define pr_emerg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__) + +#define netdev_err(dev, fmt, args...) lx_printf("netdev_err: " fmt, ##args) +#define netdev_warn(dev, fmt, args...) lx_printf("netdev_warn: " fmt, ##args) +#define netdev_info(dev, fmt, args...) lx_printf("netdev_info: " fmt, ##args) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + ETH_HLEN = 14, + ETH_ALEN = 6, /* octets in one ethernet addr */ + ETH_P_8021Q = 0x8100, /* 802.1Q VLAN Extended Header */ + ETH_P_IP = 0x0800, + ETH_P_IPV6 = 0x86DD, + ETH_P_8021AD = 0x88A8, + VLAN_HLEN = 4, + VLAN_ETH_HLEN = 18, +}; + +typedef int raw_hdlc_proto; +typedef int cisco_proto; +typedef int fr_proto; +typedef int fr_proto_pvc; +typedef int fr_proto_pvc_info; +typedef int sync_serial_settings; +typedef int te1_settings; + +struct callback_head { + struct callback_head *next; + void (*func)(struct callback_head *head); +}; +#define rcu_head callback_head + +#define FIONREAD 0x541B +#define TIOCOUTQ 0x5411 + +struct completion { unsigned int done; void *task; }; +long __wait_completion(struct completion *work, unsigned long timeout); + +enum { + NAPI_STATE_SCHED, + NAPI_STATE_DISABLE, + NAPI_STATE_NPSVC, + NAPI_STATE_HASHED, +}; + +struct napi_struct +{ + struct net_device * dev; + int (*poll)(struct napi_struct *, int); + unsigned long state; + int weight; +}; + +#define writel(value, addr) (*(volatile uint32_t *)(addr) = (value)) +#define readl(addr) (*(volatile uint32_t *)(addr)) + +typedef u64 cycle_t; + +struct timespec64 { + time64_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +extern struct timespec64 ns_to_timespec64(const s64 nsec); + +static inline s64 timespec64_to_ns(const struct timespec64 *ts) +{ + return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec; +} + +#define ktime_to_ns(kt) ((kt).tv64) + +ktime_t ns_to_ktime(u64 ns); + +struct device_node +{ + const char * full_name; +}; + +struct device; +struct device_driver; + +struct bus_type +{ + const char * name; + const struct attribute_group **dev_groups; + + int (*match)(struct device *dev, struct device_driver *drv); + int (*probe)(struct device *dev); + + const struct dev_pm_ops *pm; +}; + +struct device_driver { + const char * name; + struct bus_type *bus; + struct module *owner; + const struct of_device_id*of_match_table; + const struct dev_pm_ops *pm; + int (*probe)(struct device *dev); + int (*remove) (struct device *dev); +}; + +struct class +{ + const char *name; + void (*dev_release)(struct device *dev); +}; + +struct attribute { + const char *name; +}; + +struct attribute_group +{ + struct attribute ** attrs; +}; + +struct device { + char name[32]; + struct device * parent; + struct device_driver *driver; + void * platform_data; + void * driver_data; + const struct attribute_group **groups; + void (*release)(struct device *dev); + struct bus_type *bus; + struct class *class; + struct device_node *of_node; +}; + +struct platform_device { + const char * name; + struct device dev; + const struct platform_device_id * id_entry; +}; + +#define platform_get_device_id(pdev) ((pdev)->id_entry) + +static inline void *platform_get_drvdata(const struct platform_device *pdev) +{ + return pdev->dev.driver_data; +} + +void udelay(unsigned long usecs); + +enum netdev_tx { + NETDEV_TX_OK = 0x00, + NETDEV_TX_BUSY = 0x10, + NETDEV_TX_LOCKED = 0x20, +}; +typedef enum netdev_tx netdev_tx_t; + +struct sk_buff; +struct ifreq; + +#include + +struct net_device_ops { + int (*ndo_open) (struct net_device *dev); + int (*ndo_stop) (struct net_device *dev); + netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev); + void (*ndo_set_rx_mode) (struct net_device *dev); + int (*ndo_change_mtu) (struct net_device *dev, int new_mtu); + int (*ndo_validate_addr) (struct net_device *dev); + void (*ndo_tx_timeout) (struct net_device *dev); + int (*ndo_set_mac_address)(struct net_device *dev, void *addr); + int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); + int (*ndo_set_features)(struct net_device *dev, netdev_features_t features); +}; + +struct net_device_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long collisions; + unsigned long rx_errors; + unsigned long tx_errors; + unsigned long rx_dropped; + unsigned long tx_dropped; + unsigned long rx_length_errors; + unsigned long rx_over_errors; + unsigned long rx_crc_errors; + unsigned long rx_frame_errors; + unsigned long rx_fifo_errors; + unsigned long rx_missed_errors; + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; +}; + +struct netdev_hw_addr { + struct list_head list; + unsigned char addr[32]; +}; + +struct netdev_hw_addr_list { + struct list_head list; + int count; +}; + +enum { NETDEV_ALIGN = 32, GSO_MAX_SEGS = 65535 }; + +enum netdev_state_t { + __LINK_STATE_START, + __LINK_STATE_PRESENT, + __LINK_STATE_NOCARRIER, + __LINK_STATE_LINKWATCH_PENDING, + __LINK_STATE_DORMANT, +}; + +#define MAX_ADDR_LEN 32 + +struct net_device +{ + unsigned long state; + netdev_features_t features; + struct net_device_stats stats; + netdev_features_t hw_features; + const struct net_device_ops *netdev_ops; + const struct ethtool_ops *ethtool_ops; + const struct header_ops *header_ops; + unsigned int flags; + unsigned int priv_flags; + unsigned short hard_header_len; + unsigned long mtu; + unsigned short type; + unsigned char addr_len; + struct netdev_hw_addr_list mc; + unsigned char *dev_addr; + unsigned char broadcast[MAX_ADDR_LEN]; + unsigned long tx_queue_len; + int watchdog_timeo; + struct device dev; + u16 gso_max_segs; + struct phy_device *phydev; +}; + +static inline void *netdev_priv(const struct net_device *dev) { + return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN); } + +#define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1) + +static inline u64 div_u64(u64 dividend, u32 divisor) { return dividend / divisor; } + +struct pps_event_time { + struct timespec64 ts_real; +}; + +size_t copy_from_user(void *to, void const *from, size_t len); +size_t copy_to_user(void *dst, void const *src, size_t len); + +int snprintf(char *buf, size_t size, const char *fmt, ...); + +struct clk +{ + const char * name; + unsigned long rate; +}; + +unsigned long clk_get_rate(struct clk * clk); + +#define module_param_array(macaddr, byte, arg1, arg2); + +# define swab32p __swab32p +# define swab32s __swab32s + +u64 local_clock(void); + +#define do_div(n,base) ({ \ + unsigned long __base = (base); \ + unsigned long __rem; \ + __rem = ((uint64_t)(n)) % __base; \ + (n) = ((uint64_t)(n)) / __base; \ + __rem; \ +}) + +enum { + MSEC_PER_SEC = 1000L, + USEC_PER_SEC = MSEC_PER_SEC * 1000L, +}; + +static inline int rcu_read_lock_held(void) { return 1; } +static inline int rcu_read_lock_bh_held(void) { return 1; } + +unsigned int jiffies_to_usecs(const unsigned long j); + +struct rb_node {}; + +#define __aligned(x) __attribute__((aligned(x))) + +#define kmemcheck_bitfield_begin(name) +#define kmemcheck_bitfield_end(name) + +typedef __u32 __wsum; + +enum { NUMA_NO_NODE = -1 }; + +struct ts_state +{ + char cb[40]; +}; + +struct ts_config +{ + unsigned int (*get_next_block)(unsigned int consumed, + const u8 **dst, + struct ts_config *conf, + struct ts_state *state); + void (*finish)(struct ts_config *conf, + struct ts_state *state); +}; + +struct flow_dissector_key_control +{ + u16 thoff; + u16 addr_type; + u32 flags; +}; + +struct flow_keys +{ + struct flow_dissector_key_control control; +}; + +struct flow_dissector_key {}; + +struct flow_dissector {}; + +extern struct flow_dissector flow_keys_dissector; +extern struct flow_dissector flow_keys_buf_dissector; + +struct flowi4 {}; +struct flowi6 {}; + +__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys); + +bool flow_keys_have_l4(struct flow_keys *keys); + +__u32 __get_hash_from_flowi4(const struct flowi4 *fl4, struct flow_keys *keys); + +bool gfpflags_allow_blocking(const gfp_t gfp_flags); + +struct lock_class_key { }; + +#define lockdep_set_class(lock, key) + +struct page +{ + atomic_t _count; + void *addr; + dma_addr_t paddr; + unsigned long private; +} __attribute((packed)); + +static inline struct page *compound_head(struct page *page) { return page; } + +bool page_is_pfmemalloc(struct page *page); + +void __free_page_frag(void *addr); + +struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order); + +void get_page(struct page *page); +void put_page(struct page *page); + +static inline void *page_address(struct page *page) { return page->addr; }; + +struct page_frag +{ + struct page *page; + __u16 offset; + __u16 size; +}; + +enum dma_data_direction { DMA_FROM_DEVICE = 2 }; + +dma_addr_t dma_map_page(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir); + +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir); + +#define L1_CACHE_BYTES 32 + + +size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); + +__wsum csum_block_add(__wsum csum, __wsum csum2, int offset); +__wsum csum_sub(__wsum csum, __wsum addend); +__wsum csum_partial(const void *buff, int len, __wsum sum); + +typedef struct poll_table_struct { } poll_table; + +size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); +size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i); + +struct partial_page +{ + unsigned int offset; + unsigned int len; +}; + +struct splice_pipe_desc +{ + struct page **pages; + struct partial_page *partial; + int nr_pages; + unsigned int nr_pages_max; + unsigned int flags; + const struct pipe_buf_operations *ops; + void (*spd_release)(struct splice_pipe_desc *, unsigned int); +}; + +struct timespec ktime_to_timespec(const ktime_t kt); + +typedef __u16 __sum16; + +__sum16 csum_fold(__wsum csum); +__wsum csum_add(__wsum csum, __wsum addend); +__wsum remcsum_adjust(void *ptr, __wsum csum, int start, int offset); + +#define htons(x) __cpu_to_be16(x) + +struct iphdr { + __u8 ihl:4; + __u8 version:4; + __u8 tos; + __be16 tot_len; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; +}; + +struct sk_buff; +struct iphdr *ip_hdr(const struct sk_buff *skb); + +typedef unsigned short ushort; + +dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir); + +enum { DMA_TO_DEVICE = 1 }; + +int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); + +void dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir); + +void dev_kfree_skb_any(struct sk_buff *); + +int net_ratelimit(void); + +unsigned int tcp_hdrlen(const struct sk_buff *skb); + +struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, unsigned int index); +void netif_tx_stop_queue(struct netdev_queue *dev_queue); +void netif_tx_wake_queue(struct netdev_queue *dev_queue); +bool netif_queue_stopped(const struct net_device *dev); + +#define CONFIG_ARCH_MXC 1 +#define CONFIG_OF_MDIO 1 + +void rtnl_lock(void); +void rtnl_unlock(void); + +int netif_device_present(struct net_device *); +int netif_running(const struct net_device *dev); +void netif_wake_queue(struct net_device *); +void netif_tx_lock_bh(struct net_device *dev); +void netif_tx_unlock_bh(struct net_device *dev); + +void napi_enable(struct napi_struct *n); +void napi_disable(struct napi_struct *n); + +static inline void __read_once_size(const volatile void *p, void *res, int size) +{ + switch (size) { + case 1: *(__u8 *)res = *(volatile __u8 *)p; break; + case 2: *(__u16 *)res = *(volatile __u16 *)p; break; + case 4: *(__u32 *)res = *(volatile __u32 *)p; break; + case 8: *(__u64 *)res = *(volatile __u64 *)p; break; + default: + barrier(); + __builtin_memcpy((void *)res, (const void *)p, size); + barrier(); + } +} + +#define READ_ONCE(x) \ +({ \ + union { typeof(x) __val; char __c[1]; } __u; \ + __read_once_size(&(x), __u.__c, sizeof(x)); \ + __u.__val; \ +}) + +extern unsigned long find_next_bit(const unsigned long *addr, unsigned long + size, unsigned long offset); +#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) + +#define prefetch(x) __builtin_prefetch(x) +#define prefetchw(x) __builtin_prefetch(x,1) + +#define ntohs(x) __be16_to_cpu(x) + +struct vlan_hdr +{ + __be16 h_vlan_TCI; +}; + +__be16 eth_type_trans(struct sk_buff *, struct net_device *); + +void __vlan_hwaccel_put_tag(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); + +enum gro_result { + GRO_MERGED, + GRO_MERGED_FREE, + GRO_HELD, + GRO_NORMAL, + GRO_DROP, +}; +typedef enum gro_result gro_result_t; + +gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); + +void dma_sync_single_for_device(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir); + +bool napi_schedule_prep(struct napi_struct *n); + +void __napi_schedule(struct napi_struct *n); + +void napi_complete(struct napi_struct *n); + +void *dev_get_platdata(const struct device *dev); + +int is_valid_ether_addr(const u8 *); + +const void *of_get_mac_address(struct device_node *np); + +void eth_hw_addr_random(struct net_device *dev); + +int pm_runtime_get_sync(struct device *dev); + +void reinit_completion(struct completion *x); + +void pm_runtime_mark_last_busy(struct device *dev); + +int pm_runtime_put_autosuspend(struct device *dev); + +int clk_prepare_enable(struct clk *); + +void clk_disable_unprepare(struct clk *); + +struct phy_device *of_phy_connect(struct net_device *dev, struct device_node *phy_np, void (*hndlr)(struct net_device *), u32 flags, int iface); + +const char *dev_name(const struct device *dev); + +void *kmalloc(size_t size, gfp_t flags); +void kfree(const void *); +void *kzalloc(size_t size, gfp_t flags); + +struct mii_bus; +struct device_node *of_get_child_by_name( const struct device_node *node, const char *name); +void of_node_put(struct device_node *node); +int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); + +struct resource *platform_get_resource(struct platform_device *, unsigned, unsigned); + +#include +#include +#include +#include +#include +#include +#include + +int ethtool_op_get_ts_info(struct net_device *, struct ethtool_ts_info *); + +int device_set_wakeup_enable(struct device *dev, bool enable); + +bool device_may_wakeup(struct device *dev); + +int enable_irq_wake(unsigned int irq); +int disable_irq_wake(unsigned int irq); + +struct ethtool_ops { + int(*get_settings)(struct net_device *, struct ethtool_cmd *); + int(*set_settings)(struct net_device *, struct ethtool_cmd *); + void(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); + int(*get_regs_len)(struct net_device *); + void(*get_regs)(struct net_device *, struct ethtool_regs *, void *); + void(*get_wol)(struct net_device *, struct ethtool_wolinfo *); + int(*set_wol)(struct net_device *, struct ethtool_wolinfo *); + int(*nway_reset)(struct net_device *); + u32(*get_link)(struct net_device *); + int(*get_coalesce)(struct net_device *, struct ethtool_coalesce *); + int(*set_coalesce)(struct net_device *, struct ethtool_coalesce *); + void(*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*); + int(*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*); + void(*get_strings)(struct net_device *, u32 stringset, u8 *); + void(*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); + int(*get_sset_count)(struct net_device *, int); + int(*get_ts_info)(struct net_device *, struct ethtool_ts_info *); + int(*get_tunable)(struct net_device *, + const struct ethtool_tunable *, void *); + int(*set_tunable)(struct net_device *, + const struct ethtool_tunable *, const void *); +}; + +u32 ethtool_op_get_link(struct net_device *); + +void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); +void dma_free_coherent(struct device *, size_t size, void *vaddr, dma_addr_t bus); + +void netif_tx_start_all_queues(struct net_device *dev); + +int pinctrl_pm_select_default_state(struct device *dev); + +int pinctrl_pm_select_sleep_state(struct device *dev); + +void netif_tx_disable(struct net_device *dev); + +#include + +#define rcu_assign_pointer(p, v) (p = v); + +#include + +#define netdev_hw_addr_list_for_each(ha, l) \ + list_for_each_entry(ha, &(l)->list, list) + +#define netdev_for_each_mc_addr(ha, dev) \ + netdev_hw_addr_list_for_each(ha, &(dev)->mc) + +void netif_tx_wake_all_queues(struct net_device *); + +int eth_validate_addr(struct net_device *); + +void *dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp); + +int eth_change_mtu(struct net_device *dev, int new_mtu); +int eth_validate_addr(struct net_device *dev); + +void netif_napi_add(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight); + +bool of_device_is_available(const struct device_node *device); +int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value); + +enum { NAPI_POLL_WEIGHT = 64 }; + +#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) + +struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, unsigned int rxqs); + +void *devm_ioremap_resource(struct device *dev, struct resource *res); + +const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev); + +const void *of_get_property(const struct device_node *node, const char *name, int *lenp); + +void platform_set_drvdata(struct platform_device *pdev, void *data); + +struct device_node *of_parse_phandle(const struct device_node *np, const char *phandle_name, int index); + +int of_phy_register_fixed_link(struct device_node *np); +bool of_phy_is_fixed_link(struct device_node *np); +struct device_node *of_node_get(struct device_node *node); +int of_get_phy_mode(struct device_node *np); + +struct clk *devm_clk_get(struct device *dev, const char *id); +struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id); + +void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); +void pm_runtime_use_autosuspend(struct device *dev); +void pm_runtime_get_noresume(struct device *dev); +int pm_runtime_set_active(struct device *dev); +void pm_runtime_enable(struct device *dev); + +int regulator_enable(struct regulator *); + +int platform_get_irq(struct platform_device *, unsigned int); + +void netif_carrier_off(struct net_device *dev); + +int register_netdev(struct net_device *); +void unregister_netdev(struct net_device *); + +void free_netdev(struct net_device *); + +int device_init_wakeup(struct device *dev, bool val); + +int regulator_disable(struct regulator *r); + +void *dev_get_drvdata(const struct device *dev); + +void netif_device_attach(struct net_device *); +void netif_device_detach(struct net_device *dev); + +int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id); + +#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) +#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + +struct platform_driver { + int (*probe)(struct platform_device *); + int (*remove)(struct platform_device *); + struct device_driver driver; + const struct platform_device_id *id_table; +}; + +int platform_driver_register(struct platform_driver *); +void platform_driver_unregister(struct platform_driver *); + +#define module_driver(__driver, __register, __unregister, ...) \ +static int __init __driver##_init(void) \ +{ \ + return __register(&(__driver) , ##__VA_ARGS__); \ +} \ +module_init(__driver##_init); \ +static void __exit __driver##_exit(void) \ +{ \ + __unregister(&(__driver) , ##__VA_ARGS__); \ +} \ +module_exit(__driver##_exit); + +#define module_platform_driver(__platform_driver) \ + module_driver(__platform_driver, platform_driver_register, \ + platform_driver_unregister) + +struct tasklet_struct +{ + void (*func)(unsigned long); + unsigned long data; +}; + +#define PTR_ALIGN(p, a) ({ \ + unsigned long _p = (unsigned long)p; \ + _p = (_p + a - 1) & ~(a - 1); \ + p = (typeof(p))_p; \ + p; \ +}) + +struct kmem_cache; +struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *)); +void kmem_cache_destroy(struct kmem_cache *); +void *kmem_cache_alloc(struct kmem_cache *, gfp_t); +void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags); +void kmem_cache_free(struct kmem_cache *, void *); +void *kmalloc_node_track_caller(size_t size, gfp_t flags, int node); +void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node); + +struct mem_cgroup {}; +typedef int possible_net_t; +typedef int rwlock_t; + +bool gfp_pfmemalloc_allowed(gfp_t); + +struct user_namespace {}; + +struct cred { + struct user_namespace * user_ns; +}; + +struct file { + const struct cred * f_cred; +}; + +struct net; + +struct percpu_counter { + s64 count; +}; + +static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount, gfp_t gfp) +{ + fbc->count = amount; + return 0; +} + +static inline s64 percpu_counter_read(struct percpu_counter *fbc) +{ + return fbc->count; +} + +static inline +void percpu_counter_add(struct percpu_counter *fbc, s64 amount) +{ + fbc->count += amount; +} + +static inline +void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch) +{ + percpu_counter_add(fbc, amount); +} + +s64 percpu_counter_sum_positive(struct percpu_counter *fbc); + +static inline void percpu_counter_inc(struct percpu_counter *fbc) +{ + percpu_counter_add(fbc, 1); +} + +static inline void percpu_counter_dec(struct percpu_counter *fbc) +{ + percpu_counter_add(fbc, -1); +} + +static inline +s64 percpu_counter_read_positive(struct percpu_counter *fbc) +{ + return fbc->count; +} + +void percpu_counter_destroy(struct percpu_counter *fbc); + +s64 percpu_counter_sum(struct percpu_counter *fbc); + +void local_bh_disable(void); +void local_bh_enable(void); + +#include +#include + +static inline int net_eq(const struct net *net1, const struct net *net2) { + return net1 == net2; } + +extern struct net init_net; + +struct net *dev_net(const struct net_device *dev); + +#define read_pnet(pnet) (&init_net) + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +void bitmap_fill(unsigned long *dst, int nbits); +void bitmap_zero(unsigned long *dst, int nbits); + +typedef unsigned seqlock_t; + + +enum { LL_MAX_HEADER = 96 }; + +struct hh_cache +{ + u16 hh_len; + u16 __pad; + seqlock_t hh_lock; + +#define HH_DATA_MOD 16 +#define HH_DATA_OFF(__len) \ + (HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1)) +#define HH_DATA_ALIGN(__len) \ + (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) + unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)]; +}; + +struct seq_net_private { + struct net *net; +}; + +struct seq_file; +struct ctl_table; + +typedef int proc_handler (struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos); + +unsigned read_seqbegin(const seqlock_t *sl); +unsigned read_seqretry(const seqlock_t *sl, unsigned start); + +int dev_queue_xmit(struct sk_buff *skb); + +#define raw_smp_processor_id() 0 + +#define rcu_dereference_bh(p) p +#define rcu_dereference_raw(p) p +#define rcu_dereference_check(p, c) p +#define rcu_dereference(p) p + +struct page_counter +{ + atomic_long_t count; + unsigned long limit; +}; + +struct cg_proto +{ + struct page_counter memory_allocated; + struct percpu_counter sockets_allocated; + int memory_pressure; + long sysctl_mem[3]; +}; + +void page_counter_charge(struct page_counter *counter, unsigned long nr_pages); +unsigned long page_counter_read(struct page_counter *counter); +void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages); + +enum { UNDER_LIMIT, SOFT_LIMIT, OVER_LIMIT }; + +struct inode {}; + +struct vm_area_struct; + +void write_lock_bh(rwlock_t *); +void write_unlock_bh(rwlock_t *); + +struct sock; +struct socket; + +void security_sock_graft(struct sock *, struct socket *); + +u32 prandom_u32(void); + +void rcu_read_lock(void); +void rcu_read_unlock(void); + +bool net_gso_ok(netdev_features_t features, int gso_type); + +size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); + +bool poll_does_not_wait(const poll_table *p); +void poll_wait(struct file *f, wait_queue_head_t *w, poll_table *p); + +struct task_struct +{ + unsigned int flags; + struct page_frag task_frag; +}; + +extern struct task_struct *current; + +int in_softirq(void); + +enum { MAX_SCHEDULE_TIMEOUT = 1000 }; + +#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + +#define write_pnet(pnet, net) do { (void)(net);} while (0) + +#define smp_load_acquire(p) *(p) +#define smp_store_release(p, v) *(p) = v; + +size_t ksize(void *); + +#define kmemcheck_bitfield_begin(name) +#define kmemcheck_bitfield_end(name) +#define kmemcheck_annotate_bitfield(ptr, name) +#define kmemcheck_annotate_variable(var) + +struct page *virt_to_head_page(const void *x); + +#define DEFINE_PER_CPU(type, name) \ + typeof(type) name +#define this_cpu_ptr(ptr) ptr + +struct page_frag_cache +{ + bool pfmemalloc; +}; + +void *__alloc_page_frag(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask); + +unsigned long local_irq_save(unsigned long flags); +void local_irq_restore(unsigned long); + +int in_irq(void); + +void trace_kfree_skb(struct sk_buff *, void *); +void trace_consume_skb(struct sk_buff *); + +struct page *alloc_pages(gfp_t gfp_mask, unsigned int order); + +#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) + +#define page_private(page) ((page)->private) +#define set_page_private(page, v) ((page)->private = (v)) + +void *kmap_atomic(struct page *page); +void kunmap_atomic(void *addr); + +struct page *virt_to_page(const void *x); + +struct pipe_inode_info; + +ssize_t splice_to_pipe(struct pipe_inode_info *, struct splice_pipe_desc *); + +extern const struct pipe_buf_operations nosteal_pipe_buf_ops; + +__wsum csum_partial_ext(const void *buff, int len, __wsum sum); +__wsum csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len); +__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum); +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy((src), (dst), (len), (sum)) + +unsigned int textsearch_find(struct ts_config *, struct ts_state *); + +__be16 skb_network_protocol(struct sk_buff *skb, int *depth); + +bool can_checksum_protocol(netdev_features_t features, __be16 protocol); + +unsigned int skb_gro_offset(const struct sk_buff *skb); + +unsigned int skb_gro_len(const struct sk_buff *skb); + +#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) + +enum { NAPI_GRO_FREE = 1, NAPI_GRO_FREE_STOLEN_HEAD = 2, }; + +struct napi_gro_cb +{ + u16 flush; + u16 count; + u8 same_flow; + u8 free; + struct sk_buff *last; +}; + +enum { + SLAB_HWCACHE_ALIGN = 0x00002000ul, + SLAB_CACHE_DMA = 0x00004000ul, + SLAB_PANIC = 0x00040000ul, + SLAB_LX_DMA = 0x80000000ul, +}; + +void sg_mark_end(struct scatterlist *sg); +void sg_set_buf(struct scatterlist *, const void *, unsigned int); +void sg_set_page(struct scatterlist *, struct page *, unsigned int, unsigned int); + +struct inet_skb_parm { }; + +enum { + IPPROTO_IP = 0, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17, + IPPROTO_AH = 51, +}; + +enum { + IPPROTO_HOPOPTS = 0, + IPPROTO_ROUTING = 43, + IPPROTO_FRAGMENT = 44, + IPPROTO_DSTOPTS = 60, +}; + +void read_lock_bh(rwlock_t *); +void read_unlock_bh(rwlock_t *); + +bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); + +extern struct user_namespace init_user_ns; + +enum { CAP_NET_RAW = 13 }; + +struct tcphdr +{ + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; + __be16 window; + __sum16 check; +}; + +struct tcphdr *tcp_hdr(const struct sk_buff *skb); + +struct udphdr +{ + __sum16 check; +}; + +struct udphdr *udp_hdr(const struct sk_buff *skb); + +struct in6_addr {}; + +struct ipv6hdr +{ + __be16 payload_len; + __u8 nexthdr; + struct in6_addr saddr; + struct in6_addr daddr; +}; + +struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb); + +struct ipv6_opt_hdr +{ + __u8 nexthdr; + __u8 hdrlen; +} __attribute__((packed)); + +struct ip_auth_hdr +{ + __u8 nexthdr; + __u8 hdrlen; +}; + +struct frag_hdr +{ + __u8 nexthdr; + __be16 frag_off; +}; + +#define ipv6_optlen(p) (((p)->hdrlen+1) << 3) +#define ipv6_authlen(p) (((p)->hdrlen+2) << 2) + +enum { IP_OFFSET = 0x1FFF, IP_MF = 0x2000 }; + +enum { IP6_MF = 0x0001, IP6_OFFSET = 0xfff8 }; + +unsigned int ip_hdrlen(const struct sk_buff *skb); + +__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, __wsum sum); + +__sum16 csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, __u32 len, unsigned short proto, __wsum csum); + +void secpath_reset(struct sk_buff *); + +struct tcphdr *inner_tcp_hdr(const struct sk_buff *skb); +unsigned int inner_tcp_hdrlen(const struct sk_buff *skb); + +#define skb_vlan_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) + +void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr); + +#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ +#define VLAN_TAG_PRESENT VLAN_CFI_MASK + +int __vlan_insert_tag(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); + +#define skb_vlan_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) + +void put_device(struct device *dev); + +typedef void (*dr_release_t)(struct device *dev, void *res); +typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); + +void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp); +void devres_add(struct device *dev, void *res); +void devres_free(void *res); +int devres_release(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); + +int dev_set_name(struct device *dev, const char *fmt, ...); + +int device_register(struct device *dev); + +void device_del(struct device *dev); + +int in_interrupt(void); + +int of_driver_match_device(struct device *dev, const struct device_driver *drv); + +struct device_attribute +{ + struct attribute attr; +}; + +#define __ATTRIBUTE_GROUPS(_name) \ + static const struct attribute_group *_name##_groups[] = { \ + &_name##_group, \ + NULL, \ + } + +#define ATTRIBUTE_GROUPS(_name) \ + static const struct attribute_group _name##_group = { \ + .attrs = _name##_attrs, \ + }; \ +__ATTRIBUTE_GROUPS(_name) + + +int sprintf(char *buf, const char *fmt, ...); + +#define __ATTR_NULL { .attr = { .name = NULL } } + +#define __ATTR_RO(name) __ATTR_NULL + +#define DEVICE_ATTR_RO(_name) \ + struct device_attribute dev_attr_##_name = __ATTR_RO(_name) + +int class_register(struct class *cls); +void class_unregister(struct class *cls); + +int bus_register(struct bus_type *bus); +void bus_unregister(struct bus_type *bus); + +#define __stringify(x...) #x + +int request_module(const char *name, ...); + +void device_initialize(struct device *dev); + +extern struct workqueue_struct *system_power_efficient_wq; + +int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev); +void free_irq(unsigned int irq, void *dev_id); +int enable_irq(unsigned int irq); +int disable_irq(unsigned int irq); +int disable_irq_nosync(unsigned int irq); + +void netif_carrier_on(struct net_device *dev); + +typedef struct { + __u8 b[16]; +} uuid_le; + +int device_add(struct device *dev); +struct device *get_device(struct device *dev); + +struct device *bus_find_device_by_name(struct bus_type *bus, struct device *start, const char *name); + +void msleep(unsigned int); + +int device_bind_driver(struct device *dev); +void device_release_driver(struct device *dev); + +struct device *class_find_device(struct class *cls, struct device *start, const void *data, int (*match)(struct device *, const void *)); + +#define for_each_available_child_of_node(parent, child) BUG(); while (0) + +u32 mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap); +u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv); +u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv); + +int driver_register(struct device_driver *drv); +void driver_unregister(struct device_driver *drv); + +int __init netdev_boot_setup(char *str); + +static inline void eth_broadcast_addr(u8 *addr) { + memset(addr, 0xff, ETH_ALEN); } + +static inline void eth_zero_addr(u8 *addr) { + memset(addr, 0x00, ETH_ALEN); } + +static inline bool is_multicast_ether_addr(const u8 *addr) +{ + return 0x01 & addr[0]; +} + +static inline bool is_multicast_ether_addr_64bits(const u8 addr[6+2]) +{ + return is_multicast_ether_addr(addr); +} + +static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], const u8 addr2[6+2]) +{ + u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); + + return (fold << 16) == 0; +} + +static inline bool eth_proto_is_802_3(__be16 proto) +{ + proto &= htons(0xFF00); + return (u16)proto >= (u16)htons(ETH_P_802_3_MIN); +} + +static inline unsigned long compare_ether_header(const void *a, const void *b) +{ + u32 *a32 = (u32 *)((u8 *)a + 2); + u32 *b32 = (u32 *)((u8 *)b + 2); + + return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) | + (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]); + +} + +bool netdev_uses_dsa(struct net_device *dev); + +enum { + IFF_LIVE_ADDR_CHANGE = 0x100000, + IFF_TX_SKB_SHARING = 0x10000, +}; + +enum { ARPHRD_ETHER = 1, }; + +struct neighbour; + +struct header_ops +{ + int (*create) (struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len); + int (*parse)(const struct sk_buff *skb, unsigned char *haddr); + int (*rebuild)(struct sk_buff *skb); + int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type); + void (*cache_update)(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr); +}; + +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); + +enum { NET_NAME_UNKNOWN = 0 }; + +int scnprintf(char *buf, size_t size, const char *fmt, ...); + +void *skb_gro_header_fast(struct sk_buff *skb, unsigned int offset); +void *skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen); +void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen, unsigned int offset); +void skb_gro_pull(struct sk_buff *skb, unsigned int len); +void skb_gro_postpull_rcsum(struct sk_buff *skb, const void *start, unsigned int len); + +struct offload_callbacks +{ + struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb, int nhoff); +}; + +struct packet_offload +{ + __be16 type; + u16 priority; + struct offload_callbacks callbacks; +}; + +struct packet_offload *gro_find_receive_by_type(__be16 type); +struct packet_offload *gro_find_complete_by_type(__be16 type); + +#define fs_initcall(x) + +void dev_add_offload(struct packet_offload *po); + +struct net_device * fec_get_my_registered_net_device(void); + +#include + +#endif /* _SRC__DRIVERS__NIC__FEC__LX_EMUL_H_ */ diff --git a/repos/dde_linux/src/drivers/nic/fec/lxc.c b/repos/dde_linux/src/drivers/nic/fec/lxc.c new file mode 100644 index 000000000..d264b8224 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/lxc.c @@ -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 +#include + +/* local includes */ +#include + + +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); +} diff --git a/repos/dde_linux/src/drivers/nic/fec/lxc.h b/repos/dde_linux/src/drivers/nic/fec/lxc.h new file mode 100644 index 000000000..0bdad76ab --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/lxc.h @@ -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_ */ diff --git a/repos/dde_linux/src/drivers/nic/fec/main.cc b/repos/dde_linux/src/drivers/nic/fec/main.cc new file mode 100644 index 000000000..12cd07101 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/main.cc @@ -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 +#include +#include +#include + +#include + +/* Linux emulation environment includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 root { env, heap }; + + /* Linux task that handles the initialization */ + Genode::Constructible 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(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(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); +} diff --git a/repos/dde_linux/src/drivers/nic/fec/platform.cc b/repos/dde_linux/src/drivers/nic/fec/platform.cc new file mode 100644 index 000000000..a4a46dc0b --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/platform.cc @@ -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 + +#include +#include + + +/**************************** + ** 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); } diff --git a/repos/dde_linux/src/drivers/nic/fec/target.mk b/repos/dde_linux/src/drivers/nic/fec/target.mk new file mode 100644 index 000000000..1a1c2eb89 --- /dev/null +++ b/repos/dde_linux/src/drivers/nic/fec/target.mk @@ -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 =