/* * \brief Emulation of Linux kernel interfaces * \author Norman Feske * \author Sebastian Sumpf * \date 2012-01-29 */ /* * Copyright (C) 2012-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* Genode includes */ #include #include #include #include #include /* Local includes */ #include "routine.h" #include "signal.h" #include "lx_emul.h" #include "platform/lx_mem.h" /* DDE kit includes */ extern "C" { #include #include #include #include #include #include } namespace Genode { class Slab_backend_alloc; class Slab_alloc; } /** * Back-end allocator for Genode's slab allocator */ class Genode::Slab_backend_alloc : public Genode::Allocator, public Genode::Rm_connection { private: enum { VM_SIZE = 24 * 1024 * 1024, /* size of VM region to reserve */ BLOCK_SIZE = 1024 * 1024, /* 1 MB */ ELEMENTS = VM_SIZE / BLOCK_SIZE, /* MAX number of dataspaces in VM */ }; addr_t _base; /* virt. base address */ Genode::Cache_attribute _cached; /* non-/cached RAM */ Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */ addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */ int _index; /* current index in ds_cap */ Allocator_avl _range; /* manage allocations */ bool _alloc_block() { if (_index == ELEMENTS) { PERR("Slab-backend exhausted!"); return false; } try { _ds_cap[_index] = Backend_memory::alloc(BLOCK_SIZE, _cached); /* attach at index * BLOCK_SIZE */ Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0); /* lookup phys. address */ _ds_phys[_index] = Dataspace_client(_ds_cap[_index]).phys_addr(); } catch (...) { return false; } /* return base + offset in VM area */ addr_t block_base = _base + (_index * BLOCK_SIZE); ++_index; _range.add_range(block_base, BLOCK_SIZE); return true; } public: Slab_backend_alloc(Genode::Cache_attribute cached) : Rm_connection(0, VM_SIZE), _cached(cached), _index(0), _range(env()->heap()) { /* reserver attach us, anywere */ _base = env()->rm_session()->attach(dataspace()); } /** * Allocate */ bool alloc(size_t size, void **out_addr) { bool done = _range.alloc(size, out_addr); if (done) return done; done = _alloc_block(); if (!done) { PERR("Backend allocator exhausted\n"); return false; } return _range.alloc(size, out_addr); } void free(void *addr, size_t /* size */) { } size_t overhead(size_t size) { return 0; } bool need_size_for_free() const override { return false; } /** * Return phys address for given virtual addr. */ addr_t phys_addr(addr_t addr) { if (addr < _base || addr >= (_base + VM_SIZE)) return ~0UL; int index = (addr - _base) / BLOCK_SIZE; /* physical base of dataspace */ addr_t phys = _ds_phys[index]; if (!phys) return ~0UL; /* add offset */ phys += (addr - _base - (index * BLOCK_SIZE)); return phys; } /** * Translate given physical address to virtual address * * \return virtual address, or 0 if no translation exists */ addr_t virt_addr(addr_t phys) { for (unsigned i = 0; i < ELEMENTS; i++) { if (_ds_cap[i].valid() && phys >= _ds_phys[i] && phys < _ds_phys[i] + BLOCK_SIZE) return _base + i*BLOCK_SIZE + phys - _ds_phys[i]; } PWRN("virt_addr(0x%lx) - no translation", phys); return 0; } addr_t start() const { return _base; } addr_t end() const { return _base + VM_SIZE - 1; } }; /** * Slab allocator using our back-end allocator */ class Genode::Slab_alloc : public Genode::Slab { private: size_t _calculate_block_size(size_t object_size) { size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block); return align_addr(block_size, 12); } public: Slab_alloc(size_t object_size, Slab_backend_alloc *allocator) : Slab(object_size, _calculate_block_size(object_size), 0, allocator) { } inline addr_t alloc() { addr_t result; return (Slab::alloc(slab_size(), (void **)&result) ? result : 0); } }; /** * Memory interface used used for Linux emulation */ class Malloc { private: enum { SLAB_START_LOG2 = 3, /* 8 B */ SLAB_STOP_LOG2 = 16, /* 64 KB */ NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1, }; typedef Genode::addr_t addr_t; typedef Genode::Slab_alloc Slab_alloc; typedef Genode::Slab_backend_alloc Slab_backend_alloc; Slab_backend_alloc *_back_allocator; Slab_alloc *_allocator[NUM_SLABS]; Genode::Cache_attribute _cached; /* cached or un-cached memory */ addr_t _start; /* VM region of this allocator */ addr_t _end; /** * Set 'value' at 'addr' */ void _set_at(addr_t addr, addr_t value) { *((addr_t *)addr) = value; } /** * Retrieve slab index belonging to given address */ unsigned _slab_index(Genode::addr_t **addr) { using namespace Genode; /* get index */ addr_t index = *(*addr - 1); /* * If index large, we use aligned memory, retrieve beginning of slab entry * and read index from there */ if (index > 32) { *addr = (addr_t *)*(*addr - 1); index = *(*addr - 1); } return index; } public: Malloc(Slab_backend_alloc *alloc, Genode::Cache_attribute cached) : _back_allocator(alloc), _cached(cached), _start(alloc->start()), _end(alloc->end()) { /* init slab allocators */ for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) _allocator[i - SLAB_START_LOG2] = new (Genode::env()->heap()) Slab_alloc(1U << i, alloc); } /** * Alloc in slabs */ void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0) { using namespace Genode; /* += slab index + aligment size */ size += sizeof(addr_t) + (align > 2 ? (1 << align) : 0); int msb = Genode::log2(size); if (size > (1U << msb)) msb++; if (size < (1U << SLAB_START_LOG2)) msb = SLAB_STOP_LOG2; if (msb > SLAB_STOP_LOG2) { PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached); return 0; } addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc(); if (!addr) { PERR("Failed to get slab for %u", 1 << msb); return 0; } _set_at(addr, msb - SLAB_START_LOG2); addr += sizeof(addr_t); if (align > 2) { /* save */ addr_t ptr = addr; addr_t align_val = (1U << align); addr_t align_mask = align_val - 1; /* align */ addr = (addr + align_val) & ~align_mask; /* write start address before aligned address */ _set_at(addr - sizeof(addr_t), ptr); } if (phys) *phys = _back_allocator->phys_addr(addr); return (addr_t *)addr; } void free(void const *a) { using namespace Genode; addr_t *addr = (addr_t *)a; unsigned nr = _slab_index(&addr); _allocator[nr]->free((void *)(addr - 1)); } Genode::addr_t phys_addr(void *a) { return _back_allocator->phys_addr((addr_t)a); } Genode::addr_t virt_addr(Genode::addr_t phys) { return _back_allocator->virt_addr(phys); } /** * Belongs given address to this allocator */ bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); } /** * Cached memory allocator */ static Malloc *mem() { static Slab_backend_alloc _b(Genode::CACHED); static Malloc _m(&_b, Genode::CACHED); return &_m; } /** * DMA allocator */ static Malloc *dma() { static Slab_backend_alloc _b(Genode::UNCACHED); static Malloc _m(&_b, Genode::UNCACHED); return &_m; } }; /*********************** ** Atomic operations ** ***********************/ /* * Actually not atomic, for now */ unsigned int atomic_read(atomic_t *p) { return *(volatile int *)p; } void atomic_inc(atomic_t *v) { (*(volatile int *)v)++; } void atomic_dec(atomic_t *v) { (*(volatile int *)v)--; } void atomic_add(int i, atomic_t *v) { (*(volatile int *)v) += i; } void atomic_sub(int i, atomic_t *v) { (*(volatile int *)v) -= i; } void atomic_set(atomic_t *p, unsigned int v) { (*(volatile int *)p) = v; } /******************* ** linux/mutex.h ** *******************/ void mutex_init (struct mutex *m) { if (m->lock) dde_kit_lock_init (&m->lock); } void mutex_lock (struct mutex *m) { if (m->lock) dde_kit_lock_lock ( m->lock); } void mutex_unlock(struct mutex *m) { if (m->lock) dde_kit_lock_unlock( m->lock); } /************************************* ** Memory allocation, linux/slab.h ** *************************************/ void *kmalloc(size_t size, gfp_t flags) { void *addr = flags & GFP_NOIO ? Malloc::dma()->alloc(size) : Malloc::mem()->alloc(size); unsigned long a = (unsigned long)addr; if (a & 0x3) PERR("Unaligned kmalloc %lx", a); //PDBG("Kmalloc: [%lx-%lx) from %p", a, a + size, __builtin_return_address(0)); return addr; } void *kzalloc(size_t size, gfp_t flags) { void *addr = kmalloc(size, flags); if (addr) Genode::memset(addr, 0, size); return addr; } void *kcalloc(size_t n, size_t size, gfp_t flags) { if (size != 0 && n > ~0UL / size) return 0; return kzalloc(n * size, flags); } void kfree(const void *p) { if (Malloc::mem()->inside((Genode::addr_t)p)) Malloc::mem()->free(p); if (Malloc::dma()->inside((Genode::addr_t)p)) Malloc::dma()->free(p); } /********************* ** linux/vmalloc.h ** *********************/ void *vzalloc(unsigned long size) { void *ptr = dde_kit_simple_malloc(size); if (ptr) Genode::memset(ptr, 0, size); return ptr; } void vfree(void *addr) { dde_kit_simple_free(addr); } /****************** ** linux/kref.h ** ******************/ void kref_init(struct kref *kref) { dde_kit_log(DEBUG_KREF,"%s ref: %p", __func__, kref); kref->refcount.v = 1; } void kref_get(struct kref *kref) { kref->refcount.v++; dde_kit_log(DEBUG_KREF, "%s ref: %p c: %d", __func__, kref, kref->refcount.v); } int kref_put(struct kref *kref, void (*release) (struct kref *kref)) { dde_kit_log(DEBUG_KREF, "%s: ref: %p c: %d", __func__, kref, kref->refcount.v); if (!--kref->refcount.v) { release(kref); return 1; } return 0; } /********************* ** linux/uaccess.h ** *********************/ size_t copy_to_user(void *dst, void const *src, size_t len) { if (dst && src && len) memcpy(dst, src, len); return 0; } size_t copy_from_user(void *dst, void const *src, size_t len) { if (dst && src && len) memcpy(dst, src, len); return 0; } bool access_ok(int access, void *addr, size_t size) { return 1; } /******************** ** linux/string.h ** ********************/ void *_memcpy(void *d, const void *s, size_t n) { return Genode::memcpy(d, s, n); } inline void *memset(void *s, int c, size_t n) { return Genode::memset(s, c, n); } int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { Genode::String_console sc(buf, size); sc.vprintf(fmt, args); return sc.len(); } int snprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; va_start(args, fmt); Genode::String_console sc(buf, size); sc.vprintf(fmt, args); va_end(args); return sc.len(); } int scnprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; va_start(args, fmt); Genode::String_console sc(buf, size); sc.vprintf(fmt, args); va_end(args); return sc.len(); } int strcmp(const char *s1, const char *s2) { return Genode::strcmp(s1, s2); } size_t strlen(const char *s) { return Genode::strlen(s); } size_t strlcat(char *dest, const char *src, size_t dest_size) { size_t len_d = strlen(dest); size_t len_s = strlen(src); if (len_d > dest_size) return 0; size_t len = dest_size - len_d - 1; memcpy(dest + len_d, src, len); dest[len_d + len] = 0; return len; } size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); if (size) { size_t len = (ret >= size) ? size - 1 : ret; Genode::memcpy(dest, src, len); dest[len] = '\0'; } return ret; } void *kmemdup(const void *src, size_t len, gfp_t gfp) { void *ptr = kmalloc(len, gfp); memcpy(ptr, src, len); return ptr; } void *memscan(void *addr, int c, size_t size) { unsigned char* p = (unsigned char *)addr; for (size_t s = 0; s < size; s++, p++) if (*p == c) break; return (void *)p; } /****************** ** linux/log2.h ** ******************/ int ilog2(u32 n) { return Genode::log2(n); } /******************** ** linux/slab.h ** ********************/ struct kmem_cache { const char *name; /* cache name */ unsigned size; /* object size */ struct dde_kit_slab *dde_kit_slab_cache; /* backing DDE kit cache */ }; struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long falgs, void (*ctor)(void *)) { dde_kit_log(DEBUG_SLAB, "\"%s\" obj_size=%zd", name, size); struct kmem_cache *cache; if (!name) { printk("kmem_cache name reqeuired\n"); return 0; } cache = (struct kmem_cache *)dde_kit_simple_malloc(sizeof(*cache)); if (!cache) { printk("No memory for slab cache\n"); return 0; } /* initialize a physically contiguous cache for kmem */ if (!(cache->dde_kit_slab_cache = dde_kit_slab_init(size))) { printk("DDE kit slab init failed\n"); dde_kit_simple_free(cache); return 0; } cache->name = name; cache->size = size; return cache; } void kmem_cache_destroy(struct kmem_cache *cache) { dde_kit_log(DEBUG_SLAB, "\"%s\"", cache->name); dde_kit_slab_destroy(cache->dde_kit_slab_cache); dde_kit_simple_free(cache); } void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags) { void *ret; dde_kit_log(DEBUG_SLAB, "\"%s\" flags=%x", cache->name, flags); ret = dde_kit_slab_alloc(cache->dde_kit_slab_cache); /* return here in case of error */ if (!ret) return 0; /* zero page */ memset(ret, 0, cache->size); return ret; } void kmem_cache_free(struct kmem_cache *cache, void *objp) { dde_kit_log(DEBUG_SLAB, "\"%s\" (%p)", cache->name, objp); dde_kit_slab_free(cache->dde_kit_slab_cache, objp); } /********************** ** asm-generic/io.h ** **********************/ void *_ioremap(resource_size_t phys_addr, unsigned long size, int wc) { dde_kit_addr_t map_addr; if (dde_kit_request_mem(phys_addr, size, wc, &map_addr)) { PERR("Failed to request I/O memory: [%zx,%lx)", phys_addr, phys_addr + size); return 0; } return (void *)map_addr; } void *ioremap_wc(resource_size_t phys_addr, unsigned long size) { return _ioremap(phys_addr, size, 1); } void *ioremap(resource_size_t offset, unsigned long size) { return _ioremap(offset, size, 0); } void *devm_ioremap(struct device *dev, resource_size_t offset, unsigned long size) { return ioremap(offset, size); } void *devm_ioremap_nocache(struct device *dev, resource_size_t offset, unsigned long size) { return ioremap(offset, size); } void *devm_ioremap_resource(struct device *dev, struct resource *res) { return _ioremap(res->start, res->end - res->start, 0); } void *phys_to_virt(unsigned long address) { return (void *)Malloc::dma()->virt_addr(address); } /******************** ** linux/device.h ** ********************/ /** * Simple driver management class */ 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; bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true; dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p", _drv->name, ret, _drv->bus->match); return ret; } /** * Probe device with driver */ int probe(struct device *dev) { dev->driver = _drv; if (dev->bus->probe) { dde_kit_log(DEBUG_DRIVER, "Probing device bus %p", dev->bus->probe); return dev->bus->probe(dev); } else if (_drv->probe) { dde_kit_log(DEBUG_DRIVER, "Probing driver: %s", _drv->name); return _drv->probe(dev); } return 0; } }; int driver_register(struct device_driver *drv) { dde_kit_log(DEBUG_DRIVER, "%s at %p", drv->name, drv); new (Genode::env()->heap()) 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); dde_kit_log(DEBUG_DRIVER, "Probe return %d", ret); if (!ret) return 0; } return 0; } int device_register(struct device *dev) { //XXX: initialize DMA pools (see device_initialize) return device_add(dev); } void *dev_get_drvdata(const struct device *dev) { return dev->driver_data; } int dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; return 0; } const char *dev_name(const struct device *dev) { return dev->name; } long find_next_zero_bit_le(const void *addr, unsigned long size, unsigned long offset) { unsigned long max_size = sizeof(long) * 8; if (offset >= max_size) { PWRN("Offset greater max size"); return offset + size; } for (; offset < max_size; offset++) if (!(*(unsigned long*)addr & (1L << offset))) return offset; PERR("No zero bit findable"); return offset + size; } void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) { return kzalloc(size, gfp); } void *dev_get_platdata(const struct device *dev) { PDBG("called"); return (void *)dev->platform_data; } /******************************* ** linux/byteorder/generic.h ** *******************************/ u16 get_unaligned_le16(const void *p) { const struct __una_u16 *ptr = (const struct __una_u16 *)p; return ptr->x; } void put_unaligned_le16(u16 val, void *p) { struct __una_u16 *ptr = (struct __una_u16 *)p; ptr->x = val; } u32 get_unaligned_le32(const void *p) { const struct __una_u32 *ptr = (const struct __una_u32 *)p; return ptr->x; } void put_unaligned_le32(u32 val, void *p) { struct __una_u32 *ptr = (struct __una_u32 *)p; ptr->x = val; } u64 get_unaligned_le64(const void *p) { const struct __una_u64 *ptr = (const struct __una_u64 *)p; return ptr->x; } void put_unaligned_le64(u64 val, void *p) { struct __una_u64 *ptr = (struct __una_u64 *)p; ptr->x = val; } /********************************** ** linux/bitops.h, asm/bitops.h ** **********************************/ int fls(int x) { if (!x) return 0; for (int i = 31; i >= 0; i--) if (x & (1 << i)) return i + 1; return 0; } /******************* ** linux/delay.h ** *******************/ static Timer::Connection _timer; void udelay(unsigned long usecs) { _timer.usleep(usecs); } void msleep(unsigned int msecs) { _timer.msleep(msecs); } void mdelay(unsigned long msecs) { msleep(msecs); } /********************* ** linux/jiffies.h ** *********************/ /* * We use DDE kit's jiffies in 100Hz granularity. */ enum { JIFFIES_TICK_MS = 1000 / DDE_KIT_HZ }; unsigned long msecs_to_jiffies(const unsigned int m) { return m / JIFFIES_TICK_MS; } long time_after_eq(long a, long b) { return (a - b) >= 0; } long time_after(long a, long b) { return (b - a) < 0; } /********* ** DMA ** *********/ struct dma_pool { size_t size; int align; }; struct dma_pool *dma_pool_create(const char *name, struct device *d, size_t size, size_t align, size_t alloc) { dde_kit_log(DEBUG_DMA, "size: %zx align:%zx %p", size, align, __builtin_return_address((0))); if (align & (align - 1)) return 0; dma_pool *pool = new(Genode::env()->heap()) dma_pool; pool->align = Genode::log2((int)align); pool->size = size; return pool; } void dma_pool_destroy(struct dma_pool *d) { dde_kit_log(DEBUG_DMA, "close"); destroy(Genode::env()->heap(), d); } void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma) { void *addr; addr = dma_alloc_coherent(0, d->size, dma, 0); dde_kit_log(DEBUG_DMA, "addr: %p size %zx align %x phys: %lx pool %p", addr, d->size, d->align, *dma, d); return addr; } void dma_pool_free(struct dma_pool *d, void *vaddr, dma_addr_t a) { dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, d->size); Malloc::dma()->free(vaddr); } void *dma_alloc_coherent(struct device *, size_t size, dma_addr_t *dma, gfp_t) { void *addr = Malloc::dma()->alloc(size, PAGE_SHIFT, dma); if (!addr) return 0; dde_kit_log(DEBUG_DMA, "DMA pool alloc addr: %p size %zx align: %d, phys: %lx", addr, size, PAGE_SHIFT, *dma); return addr; } void dma_free_coherent(struct device *, size_t size, void *vaddr, dma_addr_t) { dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, size); Malloc::dma()->free(vaddr); } /************************* ** linux/dma-mapping.h ** *************************/ /** * Translate virt to phys using DDE-kit */ dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { dma_addr_t phys = (dma_addr_t)Malloc::dma()->phys_addr(ptr); if (phys == ~0UL) PERR("translation virt->phys %p->%lx failed, return ip %p", ptr, phys, __builtin_return_address(0)); dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys); return phys; } dma_addr_t dma_map_page(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir) { dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx offs: %zx", page->virt, page->phys, offset); return page->phys + offset; } int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { return nents; } /********************* ** linux/kthread.h ** *********************/ struct task_struct *kthread_run(int (*fn)(void *), void *arg, const char *n, ...) { dde_kit_log(DEBUG_THREAD, "Run %s", n); Routine::add(fn, arg, n); return 0; } struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...) { /* * This is just called for delayed device scanning (see * 'drivers/usb/storage/usb.c') */ dde_kit_log(DEBUG_THREAD, "Create %s", namefmt); Routine::add(threadfn, data, namefmt); return 0; } /************************* ** linux/scatterlist.h ** *************************/ struct scatterlist *sg_next(struct scatterlist *sg) { if (sg->last) return 0; return sg++; } struct page *sg_page(struct scatterlist *sg) { if (!sg) return 0; return (page *)sg->page_link; } void *sg_virt(struct scatterlist *sg) { if (!sg || !sg->page_link) return 0; struct page *page = (struct page *)sg->page_link; return (void *)((unsigned long)page->virt + sg->offset); } /******************** ** linux/ioport.h ** ********************/ resource_size_t resource_size(const struct resource *res) { return res->end - res->start + 1; } struct resource * devm_request_mem_region(struct device *dev, resource_size_t start, resource_size_t n, const char *name) { struct resource *r = (struct resource *)kzalloc(sizeof(struct resource), GFP_KERNEL); r->start = start; r->end = start + n - 1; r->name = name; return r; } /**************** ** Networking ** ****************/ /************************* ** linux/etherdevice.h ** *************************/ struct net_device *alloc_etherdev(int sizeof_priv) { net_device *dev = new (Genode::env()->heap()) net_device(); dev->mtu = 1500; dev->hard_header_len = 0; dev->priv = kzalloc(sizeof_priv, 0); dev->dev_addr = dev->_dev_addr; memset(dev->_dev_addr, 0, sizeof(dev->_dev_addr)); return dev; } int is_valid_ether_addr(const u8 *addr) { /* is multicast */ if ((addr[0] & 0x1)) return 0; /* zero */ if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) return 0; return 1; } /***************** ** linux/mii.h ** *****************/ /** * Restart NWay (autonegotiation) for this interface */ int mii_nway_restart (struct mii_if_info *mii) { int bmcr; int r = -EINVAL; enum { BMCR_ANENABLE = 0x1000, /* enable auto negotiation */ BMCR_ANRESTART = 0x200, /* auto negotation restart */ }; /* if autoneg is off, it's an error */ bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); if (bmcr & BMCR_ANENABLE) { printk("Reanable\n"); bmcr |= BMCR_ANRESTART; mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr); r = 0; } return r; } int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { ecmd->duplex = DUPLEX_FULL; return 0; } u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv) { u8 cap = 0; if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) { cap = FLOW_CTRL_TX | FLOW_CTRL_RX; } else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) { if (lcladv & ADVERTISE_PAUSE_CAP) cap = FLOW_CTRL_RX; else if (rmtadv & ADVERTISE_PAUSE_CAP) cap = FLOW_CTRL_TX; } return cap; } int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS) return 1; return 0; } unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, unsigned int init_media) { if (mii_link_ok(mii)) netif_carrier_on(mii->dev); else netif_carrier_off(mii->dev); return 0; } /****************** ** linux/log2.h ** ******************/ int rounddown_pow_of_two(u32 n) { return 1U << Genode::log2(n); } /****************** ** linux/wait.h ** ******************/ void init_waitqueue_head(wait_queue_head_t *q) { q->q = 0; } void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { if (q->q) { PERR("Non-empty wait queue"); return; } q->q = wait; } void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { if (q->q != wait) { PERR("Remove unkown element from wait queue"); return; } q->q = 0; } int waitqueue_active(wait_queue_head_t *q) { return q->q ? 1 : 0; }