blob: d6f36feb0854967714b13d1d2a082c16c076b9d0 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
/*
* bcmos_system.h
* Maple System Services
* posix port: simulation
*/
#ifndef BCMOS_SYSTEM_H_
#define BCMOS_SYSTEM_H_
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/stddef.h>
#include <linux/skbuff.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/compiler.h>
#include <linux/random.h>
#include <linux/ctype.h>
#include <linux/time.h>
#include <asm/io.h>
#define BCMOS_IRQ_SINGLE 0
#define BCMOS_IRQ_SHARED IRQF_SHARED
/* Re-define GNU typeof as ISO __typeof__ */
#define typeof __typeof__
#define strtol(s,p,b) simple_strtol(s,p,b)
/* Specify here which system functions are inlined */
#define BCMOS_FASTLOCK_INLINE
#define BCMOS_SEM_INLINE
#define BCMOS_MUTEX_INLINE
#ifdef ENABLE_LOG
#define BCMOS_TRACE_IN_DEV_LOG
#endif
#if !defined(BCMOS_TRACE_IN_DEV_LOG) && !defined(BCMOS_TRACE_PRINTF)
#define BCMOS_TRACE_PRINTF
#endif
/* #define BCMOS_BYTE_POOL_ALLOC_FREE_INLINE */
#define BCMOS_MALLOC_FREE_INLINE
/* #define BCMOS_CALLOC_INLINE */
#define BCMOS_BUF_OS_SPECIFIC
#define BCMOS_BUF_INLINE
#define BCMOS_INTERRUPT_INLINE
#define BCMOS_TIMESTAMP_INLINE
/* #define BCMOS_DMA_ALLOC_FREE_INLINE */
#define BCMOS_VIRT_TO_PHYS_INLINE
#define BCMOS_CACHE_INLINE
/* Uncommentthe following line if h/w supports DMA cache coherency */
/* #define BCMOS_DMA_CACHE_COHERENCY */
/* getchar, putchar are not support. define as inline and proviude dummy targets */
#define BCMOS_GETCHAR_INLINE
#define BCMOS_PUTCHAR_INLINE
#include "bcmos_common.h"
static inline void bcm_pci_write32(volatile uint32_t *address, uint32_t value)
{
writel(value, address);
}
static inline uint32_t bcm_pci_read32(const volatile uint32_t *address)
{
return readl(address);
}
void _bcmos_backtrace(void);
int bcmos_sys_vprintf(const char *format, va_list args);
/*
* Memory allocation
*/
/* Allocate DMAable memory from the main heap */
static inline void *bcmos_alloc(uint32_t size)
{
return kmalloc(size, GFP_DMA);
}
/* Release memory to the main pool */
static inline void bcmos_free(void *ptr)
{
return kfree(ptr);
}
static inline void *bcmos_alloc_not_cache(int32_t size)
{
return kmalloc(size, GFP_KERNEL);
}
static inline void bcmos_free_not_cache(void *dest)
{
kfree(dest);
}
/*
* Synchronization
*/
/* Mutex control block */
struct bcmos_mutex
{
struct mutex m; /**< linux kernel mutex */
};
/* Create recursive mutex */
static inline bcmos_errno bcmos_mutex_create(bcmos_mutex *mutex, uint32_t flags, const char *name)
{
mutex_init(&mutex->m);
return BCM_ERR_OK;
}
/* Destroy mutex */
static inline void bcmos_mutex_destroy(bcmos_mutex *mutex)
{
mutex_destroy(&mutex->m);
}
/* Lock mutex */
static inline void bcmos_mutex_lock(bcmos_mutex *mutex)
{
mutex_lock(&mutex->m);
}
/* Release mutex */
static inline void bcmos_mutex_unlock(bcmos_mutex *mutex)
{
mutex_unlock(&mutex->m);
}
/** Fast lock control block */
struct bcmos_fastlock
{
spinlock_t m;
};
/** Fastlock initializer. Can be used instead of calling bcmos_fastlock_init() */
#define BCMOS_FASTLOCK_INITIALIZER { SPINLOCK_UNLOCKED }
/* Init fastlock */
static inline void bcmos_fastlock_init(bcmos_fastlock *lock, uint32_t flags)
{
spin_lock_init(&lock->m);
}
/* Take fast lock */
static inline long bcmos_fastlock_lock(bcmos_fastlock *lock)
{
unsigned long flags;
spin_lock_irqsave(&lock->m, flags);
return (long)flags;
}
/* Release fast lock */
static inline void bcmos_fastlock_unlock(bcmos_fastlock *lock, long flags)
{
spin_unlock_irqrestore(&lock->m, (unsigned long)flags);
}
/** Semaphore control block */
struct bcmos_sem
{
struct semaphore s; /**< linux kernel semaphore */
};
/* Create semaphore */
static inline bcmos_errno bcmos_sem_create(bcmos_sem *sem, uint32_t count, uint32_t flags, const char *name)
{
sema_init(&sem->s, count);
return BCM_ERR_OK;
}
/* Destroy semaphore */
static inline void bcmos_sem_destroy(bcmos_sem *sem)
{
}
/* Wait for semaphore */
bcmos_errno bcmos_sem_wait(bcmos_sem *sem, uint32_t timeout);
/* Increment semaphore counter */
static inline void bcmos_sem_post(bcmos_sem *sem)
{
up(&sem->s);
}
/*
* Timers
*/
/** System timer */
struct bcmos_sys_timer
{
struct timer_list t; /**< linux timer */
bcmos_sys_timer_handler handler; /**< Timer handler */
void *data; /**< Parameter to be passed to the handler */
};
/* Get current timestamp (us) */
static inline uint32_t bcmos_timestamp(void)
{
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
monotonic_to_bootbased(&uptime);
return uptime.tv_sec * USEC_PER_SEC + uptime.tv_nsec / NSEC_PER_USEC;
}
/* Get current timestamp (us) */
static inline uint64_t bcmos_timestamp64(void)
{
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
monotonic_to_bootbased(&uptime);
return (uint64_t)uptime.tv_sec * USEC_PER_SEC + (uint64_t)uptime.tv_nsec / NSEC_PER_USEC;
}
/*
* Task control
*/
/** OS-specific task control block extension */
typedef struct bcmos_sys_task
{
struct task_struct *t;
} bcmos_sys_task;
/** Memory pool control block */
struct bcmos_byte_pool
{
bcmos_byte_pool_parm parm; /**< Pool parameters */
uint32_t allocated; /**< Number of bytes allocated */
#ifdef BCMOS_MEM_DEBUG
uint32_t magic; /**< magic number */
#define BCMOS_BYTE_POOL_VALID (('b'<<24) | ('y' << 16) | ('p' << 8) | 'o')
#define BCMOS_BYTE_POOL_DELETED (('b'<<24) | ('y' << 16) | ('p' << 8) | '~')
#endif
};
/* Transport / network buffer service */
extern uint32_t bcmos_buf_default_headroom;
/*
* Network / transport buffer
*/
/* Data alignment. Should be a max lf L1, L2 cache line size */
#define BCMOS_BUF_DATA_ALIGNMENT 128
/* Encapsulated skb */
struct bcmos_buf
{
struct sk_buff skb;
};
/* Buffer list */
typedef struct sk_buff_head bcmos_buf_queue;
/* Allocate buffer */
static inline bcmos_buf *bcmos_buf_alloc(uint32_t size)
{
/* Allocate extra 2 * BCMOS_BUF_DATA_ALIGNMENT to make sure that neither data start nor end
* end up in the middle of cache line
*/
struct sk_buff *skb = dev_alloc_skb(size + BCMTR_BUF_EXTRA_HEADROOM + 2 * BCMOS_BUF_DATA_ALIGNMENT - 1);
if (!skb)
return NULL;
#if BCMTR_BUF_EXTRA_HEADROOM
skb_reserve(skb, BCMTR_BUF_EXTRA_HEADROOM);
#endif
if ((long)skb->data & (BCMOS_BUF_DATA_ALIGNMENT - 1))
{
skb_reserve(skb, BCMOS_BUF_DATA_ALIGNMENT - ((long)skb->data & (BCMOS_BUF_DATA_ALIGNMENT - 1)));
}
return (bcmos_buf *)skb;
}
/* Release buffer */
static inline void bcmos_buf_free(bcmos_buf *buf)
{
consume_skb(&buf->skb);
}
/* Get data length */
static inline uint32_t bcmos_buf_length(bcmos_buf *buf)
{
return buf->skb.len;
}
/* Set data length */
static inline bcmos_errno bcmos_buf_length_set(bcmos_buf *buf, uint32_t length)
{
if (unlikely(length > skb_tailroom(&buf->skb)))
{
BCMOS_TRACE_ERR("!!!%s: length=%u tailroom=%d\n",
__FUNCTION__, length, skb_tailroom(&buf->skb));
return BCM_ERR_OVERFLOW;
}
buf->skb.len = length;
return BCM_ERR_OK;
}
/* Get buffer data pointer. */
static inline uint8_t *bcmos_buf_data(bcmos_buf *buf)
{
return buf->skb.data;
}
/* Get buffer channel. */
static inline uint8_t bcmos_buf_channel(bcmos_buf *buf)
{
return buf->skb.cb[0];
}
/* Set buffer channel. */
static inline void bcmos_buf_channel_set(bcmos_buf *buf, uint8_t channel)
{
buf->skb.cb[0] = channel;
}
/** Initialize buffer queue
* \param[in] q Buffer queue
*/
static inline void bcmos_buf_queue_init(bcmos_buf_queue *q)
{
skb_queue_head_init(q);
}
/** Enqueue buffer
*
* Must be called under lock, e.g., q->lock
*
* \param[in] q Buffer queue
* \param[in] buf Buffer
*/
static inline void bcmos_buf_queue_put(bcmos_buf_queue *q, bcmos_buf *buf)
{
__skb_queue_tail(q, &buf->skb);
}
/* Check if buffer queue is empty
* \param[in] q Buffer queue
* \returns TRUE if the queue is empty
*/
static inline bcmos_bool bcmos_buf_queue_is_empty(bcmos_buf_queue *q)
{
return (bcmos_bool)skb_queue_empty(q);
}
/* Dequeue buffer
*
* Must be called under lock, e.g., q->lock
*
* Remove and return the 1st queued buffer.
* \param[in] q Buffer queue
* \returns the buffer pointer
*/
static inline bcmos_buf *bcmos_buf_queue_get(bcmos_buf_queue *q)
{
struct sk_buff *skb = __skb_dequeue(q);
return skb ? container_of(skb, bcmos_buf, skb) : NULL;
}
/* Peek into queue and return the 1st buffer without dequeing it
*
* Must be called under lock, e.g., q->lock
* \param[in] q Buffer queue
* \returns the buffer pointer
*/
static inline bcmos_buf *bcmos_buf_queue_peek(bcmos_buf_queue *q)
{
struct sk_buff *skb = skb_peek(q);
return skb ? container_of(skb, bcmos_buf, skb) : NULL;
}
/*
* dcache utilities
*/
/* Invalidate address area in data cache. Dirty cache lines content is discarded */
static inline void bcmos_dcache_inv(void *start, uint32_t size)
{
#if defined(CONFIG_MIPS)
dma_cache_inv((unsigned long)start, size);
#elif defined(CONFIG_PPC)
if (((unsigned long)start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1)))
flush_dcache_range((unsigned long)start, (unsigned long)start + size);
else
invalidate_dcache_range((unsigned long)start, (unsigned long)start + size);
#elif defined(CONFIG_UML)
/* Nothing to do */
#else
#error Please implement bcmos_dcache_inv()
#endif
}
/* Flush address area in data cache. Dirty cache lines are committed to memory */
static inline void bcmos_dcache_flush(void *start, uint32_t size)
{
#if defined(CONFIG_MIPS)
dma_cache_wback((unsigned long)start, size);
#elif defined(CONFIG_PPC)
clean_dcache_range((unsigned long)start, (unsigned long)start + size);
#elif defined(CONFIG_UML)
/* Nothing to do */
#else
#error Please implement bcmos_dcache_flush()
#endif
}
/*
* Interrupt service
*/
/* Connect system interrupt */
static inline int bcmos_int_connect(int irq, int cpu, int flags,
int (*isr)(int irq, void *priv), const char *name, void *priv)
{
return request_irq(irq, (irq_handler_t)isr, flags, name, priv);
}
/* Disconnect system interrupt */
static inline void bcmos_int_disconnect(int irq, void *priv)
{
free_irq(irq, priv);
}
/* Unmask IRQ */
static inline void bcmos_int_enable(int irq)
{
enable_irq(irq);
}
/* Mask IRQ */
static inline void bcmos_int_disable(int irq)
{
disable_irq(irq);
}
/* Check in-irq status */
static inline int is_irq_mode(void)
{
return in_interrupt();
}
/* Check if interrupts are disabled */
static inline int is_irq_disabled(void)
{
return irqs_disabled();
}
/* Convert virtual address to physical address */
static inline unsigned long bcmos_virt_to_phys(void *va)
{
return virt_to_phys(va);
}
/* write barrier */
static inline void bcmos_barrier(void)
{
smp_wmb();
}
static inline int bcmos_getchar(void)
{
return -1;
}
static inline void bcmos_putchar(int c)
{
}
#ifdef BCMOS_MSG_QUEUE_DOMAIN_SOCKET
#undef BCMOS_MSG_QUEUE_DOMAIN_SOCKET
#endif
#ifdef BCMOS_MSG_QUEUE_UDP_SOCKET
#undef BCMOS_MSG_QUEUE_UDP_SOCKET
#endif
/* 2nd part of OS-independent declarations */
#include "bcmos_common2.h"
#endif /* BCMOS_SYSTEM_H_ */