Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Unified Diff: arch/arm/mach-tegra/nv/nvos/nvos.c

Issue 3256004: [ARM] tegra: add nvos/nvrm/nvmap drivers (Closed) Base URL: ssh://git@gitrw.chromium.org/kernel.git
Patch Set: remove ap15 headers Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/Makefile ('k') | arch/arm/mach-tegra/nv/nvos/nvos_exports.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: arch/arm/mach-tegra/nv/nvos/nvos.c
diff --git a/arch/arm/mach-tegra/nv/nvos/nvos.c b/arch/arm/mach-tegra/nv/nvos/nvos.c
new file mode 100644
index 0000000000000000000000000000000000000000..16bc55cbb1ec1dabfcbc89977b15da64a5278239
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvos/nvos.c
@@ -0,0 +1,1657 @@
+/*
+ * Copyright (c) 2008-2009 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "nvos.h"
+#include "nvos_trace.h"
+#include "nvutil.h"
+#include "nverror.h"
+#include "nvassert.h"
+#include "nvbootargs.h"
+#include "nvio.h"
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/div64.h>
+#include <asm/setup.h>
+#include <asm/cacheflush.h>
+#include <mach/irqs.h>
+#include <linux/freezer.h>
+#include <linux/slab.h>
+
+#if NVOS_TRACE || NV_DEBUG
+#undef NvOsAlloc
+#undef NvOsFree
+#undef NvOsRealloc
+#undef NvOsSharedMemAlloc
+#undef NvOsSharedMemMap
+#undef NvOsSharedMemUnmap
+#undef NvOsSharedMemFree
+#undef NvOsMutexCreate
+#undef NvOsExecAlloc
+#undef NvOsExecFree
+#undef NvOsPageAlloc
+#undef NvOsPageLock
+#undef NvOsPageFree
+#undef NvOsPageMap
+#undef NvOsPageMapIntoPtr
+#undef NvOsPageUnmap
+#undef NvOsPageAddress
+#undef NvOsIntrMutexCreate
+#undef NvOsIntrMutexLock
+#undef NvOsIntrMutexUnlock
+#undef NvOsIntrMutexDestroy
+#undef NvOsInterruptRegister
+#undef NvOsInterruptUnregister
+#undef NvOsInterruptEnable
+#undef NvOsInterruptDone
+#undef NvOsPhysicalMemMapIntoCaller
+#undef NvOsMutexLock
+#undef NvOsMutexUnlock
+#undef NvOsMutexDestroy
+#undef NvOsPhysicalMemMap
+#undef NvOsPhysicalMemUnmap
+#undef NvOsSemaphoreCreate
+#undef NvOsSemaphoreWait
+#undef NvOsSemaphoreWaitTimeout
+#undef NvOsSemaphoreSignal
+#undef NvOsSemaphoreDestroy
+#undef NvOsSemaphoreClone
+#undef NvOsSemaphoreUnmarshal
+#undef NvOsThreadCreate
+#undef NvOsInterruptPriorityThreadCreate
+#undef NvOsThreadJoin
+#undef NvOsThreadYield
+#endif
+
+#define KTHREAD_IRQ_PRIO (MAX_RT_PRIO>>1)
+
+#define NVOS_MAX_SYSTEM_IRQS NR_IRQS
+
+#define NVOS_IRQ_IS_ENABLED 0x1
+
+/* NVOS_IRQ_IS_ flags are mutually exclusive.
+ * IS_TASKLET executes the handler in a tasklet (used for kernel drivers)
+ * IS_KERNEL_THREAD executes in a kernel thread (used for kernel GPIOs)
+ * IS_USER simply signals an NvOs semaphore (used for user-mode interrupts)
+ *
+ * Currently the choice is based on the IRQ number and if the requester is
+ * an IOCTL. Later this can be modified to be exposed in the public APIs.
+ *
+ * If no flag is set, the IRQ is handled in the interrupt handler itself.
+ */
+
+#define NVOS_IRQ_TYPE_SHIFT 1
+#define NVOS_IRQ_TYPE_MASK (0x3 << NVOS_IRQ_TYPE_SHIFT)
+
+#define NVOS_IRQ_IS_IRQ (0)
+#define NVOS_IRQ_IS_TASKLET (0x1 << NVOS_IRQ_TYPE_SHIFT)
+#define NVOS_IRQ_IS_KERNEL_THREAD (0x2 << NVOS_IRQ_TYPE_SHIFT)
+#define NVOS_IRQ_IS_USER (0x3 << NVOS_IRQ_TYPE_SHIFT)
+
+static DEFINE_SPINLOCK(gs_NvOsSpinLock);
+
+typedef struct NvOsIrqHandlerRec
+{
+ union
+ {
+ NvOsInterruptHandler pHandler;
+ NvOsSemaphoreHandle pSem;
+ };
+ NvU32 Irq;
+ char IrqName[16];
+ struct semaphore sem;
+ struct task_struct *task;
+ struct tasklet_struct Tasklet;
+} NvOsIrqHandler;
+
+typedef struct NvOsInterruptBlockRec
+{
+ void *pArg;
+ NvU32 Flags;
+ NvU32 NumIrqs;
+ NvU32 Shutdown;
+ NvOsIrqHandler IrqList[1];
+} NvOsInterruptBlock;
+
+#define INTBLOCK_SIZE(NUMIRQS) \
+ (sizeof(NvOsInterruptBlock) + ((NUMIRQS)-1)*sizeof(NvOsIrqHandler))
+
+static NvOsInterruptBlock *s_pIrqList[NVOS_MAX_SYSTEM_IRQS] = { NULL };
+
+static NvBootArgs s_BootArgs = { {0}, {0}, {0}, {0}, {0}, {0}, {{0}} };
+
+/* The tasklet "data" parameter is a munging of the s_pIrqList index
+ * (just the IRQ number), and the InterruptBlock's IrqList index, to
+ * make interrupt handler lookups O(n)
+ */
+static void NvOsTaskletWrapper(
+ unsigned long data)
+{
+ NvOsInterruptBlock *pBlock = s_pIrqList[(data&0xffff)];
+ if (pBlock)
+ (*pBlock->IrqList[data>>16].pHandler)(pBlock->pArg);
+}
+
+/* The thread "pdata" parameter is a munging of the s_pIrqList index
+ * (just the IRQ number), and the InterruptBlock's IrqList index, to
+ * make interrupt handler lookups O(n)
+ */
+static int NvOsInterruptThreadWrapper(
+ void *pdata)
+{
+ unsigned long data = (unsigned long)pdata;
+ NvOsInterruptBlock *pBlock = s_pIrqList[(data&0xffff)];
+
+ if (!pBlock)
+ {
+ return 0;
+ }
+ while (!pBlock->Shutdown)
+ {
+ int t;
+
+ /* Is the timeout large enough? */
+ t = down_interruptible(&pBlock->IrqList[data>>16].sem);
+
+ if (pBlock->Shutdown)
+ break;
+
+ if (t)
+ continue;
+
+ (*pBlock->IrqList[data>>16].pHandler)(pBlock->pArg);
+ }
+
+ return 0;
+}
+
+static irqreturn_t NvOsIrqWrapper(
+ int irq,
+ void *dev_id)
+{
+ unsigned long data = (unsigned long)dev_id;
+ NvOsInterruptBlock *pBlock = s_pIrqList[irq];
+
+ disable_irq_nosync(irq);
+ switch (pBlock->Flags & NVOS_IRQ_TYPE_MASK)
+ {
+ case NVOS_IRQ_IS_TASKLET:
+ tasklet_schedule(&pBlock->IrqList[data].Tasklet);
+ break;
+ case NVOS_IRQ_IS_KERNEL_THREAD:
+ up(&(pBlock->IrqList[data].sem));
+ break;
+ case NVOS_IRQ_IS_USER:
+ NvOsSemaphoreSignal(pBlock->IrqList[data].pSem);
+ break;
+ case NVOS_IRQ_IS_IRQ:
+ (*pBlock->IrqList[data].pHandler)(pBlock->pArg);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+NvError NvOsFprintf(NvOsFileHandle stream, const char *format, ...)
+{
+ return NvError_NotImplemented;
+}
+
+NvS32 NvOsSnprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ va_start( ap, format );
+ return vsnprintf( str, size, format, ap );
+ va_end( ap );
+}
+
+NvError NvOsVfprintf(NvOsFileHandle stream, const char *format, va_list ap)
+{
+ return NvError_NotImplemented;
+}
+
+NvS32 NvOsVsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ return vsnprintf( str, size, format, ap );
+}
+
+void NvOsDebugPrintf(const char *format, ...)
+{
+ va_list ap;
+ va_start( ap, format );
+ vprintk( format, ap );
+ va_end( ap );
+}
+
+void
+NvOsDebugVprintf( const char *format, va_list ap )
+{
+ vprintk( format, ap );
+}
+
+NvS32 NvOsDebugNprintf(const char *format, ...)
+{
+ NvS32 r;
+ va_list ap;
+ va_start( ap, format );
+ r = vprintk( format, ap );
+ va_end( ap );
+ return r;
+}
+
+
+NvError NvOsGetOsInformation(NvOsOsInfo *pOsInfo)
+{
+ if (pOsInfo)
+ {
+ NvOsMemset(pOsInfo, 0, sizeof(NvOsOsInfo));
+ pOsInfo->OsType = NvOsOs_Linux;
+ }
+ else
+ {
+ return NvError_BadParameter;
+ }
+ return NvError_Success;
+}
+
+void NvOsStrncpy(char *dest, const char *src, size_t size)
+{
+ strncpy( dest, src, size );
+}
+
+NvOsCodePage NvOsStrGetSystemCodePage(void)
+{
+ return (NvOsCodePage)0;
+}
+
+size_t NvOsStrlen(const char *s)
+{
+ return strlen(s);
+}
+
+int NvOsStrcmp(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+int NvOsStrncmp(const char *s1, const char *s2, size_t size)
+{
+ return strncmp(s1, s2, size);
+}
+
+void NvOsMemcpy(void *dest, const void *src, size_t size)
+{
+ memcpy(dest, src, size);
+}
+
+int NvOsMemcmp(const void *s1, const void *s2, size_t size)
+{
+ return memcmp(s1, s2, size);
+}
+
+void NvOsMemset(void *s, NvU8 c, size_t size)
+{
+ memset(s, c, size);
+}
+
+void NvOsMemmove(void *dest, const void *src, size_t size)
+{
+ memmove(dest, src, size);
+}
+
+NvError NvOsCopyIn(void *pDst, const void *pSrc, size_t Bytes)
+{
+ if (!Bytes)
+ return NvSuccess;
+
+ if( access_ok( VERIFY_READ, pSrc, Bytes ) )
+ {
+ __copy_from_user(pDst, pSrc, Bytes);
+ return NvSuccess;
+ }
+
+ return NvError_InvalidAddress;
+}
+
+NvError NvOsCopyOut(void *pDst, const void *pSrc, size_t Bytes)
+{
+ if (!Bytes)
+ return NvSuccess;
+
+ if( access_ok( VERIFY_WRITE, pDst, Bytes ) )
+ {
+ __copy_to_user(pDst, pSrc, Bytes);
+ return NvSuccess;
+ }
+
+ return NvError_InvalidAddress;
+}
+
+NvError NvOsFopen(const char *path, NvU32 flags, NvOsFileHandle *file)
+{
+ return NvError_NotImplemented;
+}
+
+void NvOsFclose(NvOsFileHandle stream)
+{
+}
+
+NvError NvOsFwrite(NvOsFileHandle stream, const void *ptr, size_t size)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFread(
+ NvOsFileHandle stream,
+ void *ptr,
+ size_t size,
+ size_t *bytes)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFreadTimeout(
+ NvOsFileHandle stream,
+ void *ptr,
+ size_t size,
+ size_t *bytes,
+ NvU32 timeout_msec)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFgetc(NvOsFileHandle stream, NvU8 *c)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFseek(NvOsFileHandle file, NvS64 offset, NvOsSeekEnum whence)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFtell(NvOsFileHandle file, NvU64 *position)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsStat(const char *filename, NvOsStatType *stat)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFstat(NvOsFileHandle file, NvOsStatType *stat)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFflush(NvOsFileHandle stream)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsFsync(NvOsFileHandle stream)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsIoctl(
+ NvOsFileHandle hFile,
+ NvU32 IoctlCode,
+ void *pBuffer,
+ NvU32 InBufferSize,
+ NvU32 InOutBufferSize,
+ NvU32 OutBufferSize)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsOpendir(const char *path, NvOsDirHandle *dir)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsReaddir(NvOsDirHandle dir, char *name, size_t size)
+{
+ return NvError_NotImplemented;
+}
+
+void NvOsClosedir(NvOsDirHandle dir)
+{
+}
+
+const NvOsFileHooks *NvOsSetFileHooks(NvOsFileHooks *newHooks)
+{
+ return 0;
+}
+
+NvError NvOsGetConfigU32(const char *name, NvU32 *value)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsGetConfigString(const char *name, char *value, NvU32 size)
+{
+ return NvError_NotImplemented;
+}
+
+void *NvOsAlloc(size_t size)
+{
+ size_t AllocSize = size + sizeof(size_t);
+ size_t* ptr = NULL;
+ ptr = vmalloc(AllocSize);
+ if (!ptr)
+ return ptr;
+ *ptr = size;
+ ptr++;
+ return (ptr);
+}
+
+void *NvOsRealloc(void *ptr, size_t size)
+{
+ size_t* NewPtr = NULL;
+ size_t OldSize = 0;
+ size_t SmallerSize = 0;
+
+ if( !ptr )
+ {
+ return NvOsAlloc(size);
+ }
+ if (!size)
+ {
+ NvOsFree(ptr);
+ return NULL;
+ }
+
+ // Get the size of the memory allocated for ptr.
+ NewPtr = (size_t*)ptr;
+ NewPtr--;
+ OldSize = *NewPtr;
+ if (size == OldSize)
+ return ptr;
+ SmallerSize = (OldSize > size) ? size : OldSize;
+
+ NewPtr = NvOsAlloc(size);
+ if(!NewPtr)
+ return NULL;
+ NvOsMemcpy(NewPtr, ptr, SmallerSize);
+ NvOsFree(ptr);
+ return NewPtr;
+}
+
+void NvOsFree(void *ptr)
+{
+ size_t* AllocPtr = NULL;
+ if (ptr)
+ {
+ AllocPtr = (size_t*)ptr;
+ AllocPtr--;
+ }
+ else
+ return;
+ vfree(AllocPtr);
+}
+
+void *NvOsExecAlloc(size_t size)
+{
+ return vmalloc_exec( size );
+}
+
+NvError NvOsSharedMemAlloc(
+ const char *key,
+ size_t size,
+ NvOsSharedMemHandle *descriptor)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsSharedMemMap(
+ NvOsSharedMemHandle descriptor,
+ size_t offset,
+ size_t size,
+ void **ptr)
+{
+ return NvError_NotImplemented;
+}
+
+
+void NvOsSharedMemUnmap(void *ptr, size_t size)
+{
+}
+
+void NvOsSharedMemFree(NvOsSharedMemHandle descriptor)
+{
+}
+
+NvError NvOsPhysicalMemMap(
+ NvOsPhysAddr phys,
+ size_t size,
+ NvOsMemAttribute attrib,
+ NvU32 flags,
+ void **ptr)
+{
+ /* For apertures in the static kernel mapping, just return the
+ * static VA rather than creating a new mapping
+ * FIXME: Eventually, the static phyiscal apertures should be
+ * registered with NvOs when mapped, since they could be
+ * chip-dependent
+ */
+#define aperture_comp_map(_name, _pa, _len) \
+ if ((phys >= (NvOsPhysAddr)(_pa)) && \
+ ((NvOsPhysAddr)(phys+size)<=(NvOsPhysAddr)((_pa)+(_len)))) { \
+ *ptr = (void *)tegra_munge_pa(phys); \
+ return NvSuccess; \
+ }
+
+ tegra_apertures(aperture_comp_map);
+
+ if (attrib == NvOsMemAttribute_WriteCombined)
+ {
+ *ptr = ioremap_wc(phys, size);
+ }
+ else if (attrib == NvOsMemAttribute_WriteBack)
+ {
+ *ptr = ioremap_cached(phys, size);
+ }
+ else
+ {
+ *ptr = ioremap_nocache(phys, size);
+ }
+
+ if (*ptr == 0)
+ return NvError_InsufficientMemory;
+
+ return NvSuccess;
+}
+
+NvError NvOsPhysicalMemMapIntoCaller(
+ void *pCallerPtr,
+ NvOsPhysAddr phys,
+ size_t size,
+ NvOsMemAttribute attrib,
+ NvU32 flags)
+{
+ return NvError_NotImplemented;
+}
+
+void NvOsPhysicalMemUnmap(void *ptr, size_t size)
+{
+ NvUPtr va = (NvUPtr)ptr;
+
+ /* No unmapping required for statically mapped I/O space */
+#define aperture_comp_unmap(_name, _pa, _len) \
+ if ((tegra_munge_pa((_pa)) <= va) && \
+ (tegra_munge_pa((_pa))+(_len) >= (va+size))) \
+ return;
+
+
+ tegra_apertures(aperture_comp_unmap);
+ iounmap(ptr);
+}
+
+NvError NvOsLibraryLoad(const char *name, NvOsLibraryHandle *library)
+{
+ return NvError_NotImplemented;
+}
+
+void* NvOsLibraryGetSymbol(NvOsLibraryHandle library, const char *symbol)
+{
+ return 0;
+}
+
+void NvOsLibraryUnload(NvOsLibraryHandle library)
+{
+}
+
+void NvOsSleepMS(NvU32 msec)
+{
+ msleep( msec );
+}
+
+void NvOsWaitUS(NvU32 usec)
+{
+ udelay( usec );
+}
+
+typedef struct NvOsMutexRec
+{
+ struct mutex mutex;
+ volatile NvU32 count;
+ volatile struct thread_info *owner;
+} NvOsMutex;
+
+/**
+ * nvos mutexes are recursive.
+ */
+NvError NvOsMutexCreate(NvOsMutexHandle *mutex)
+{
+ NvOsMutex *m;
+
+ m = kzalloc( sizeof(NvOsMutex), GFP_KERNEL );
+ if( !m )
+ return NvError_InsufficientMemory;
+
+ mutex_init( &m->mutex );
+ m->count = 0;
+ m->owner = 0;
+
+ *mutex = m;
+ return NvSuccess;
+}
+
+void NvOsMutexLock(NvOsMutexHandle mutex)
+{
+ struct task_struct *task = current;
+ struct thread_info *info = task_thread_info(task);
+ int ret;
+
+ NV_ASSERT( mutex );
+
+ /* if we own the lock, increment the count and bail out */
+ if( mutex->owner == info )
+ {
+ mutex->count++;
+ return;
+ }
+
+ /* lock as normal, then setup the recursive stuff */
+ do
+ {
+ /* FIXME: interruptible mutexes may not be necessary, since this
+ * implementation is only used by the kernel tasks. */
+ ret = mutex_lock_interruptible( &mutex->mutex );
+ // If a signal arrives while the task is sleeping,
+ // re-schedule it and attempt to reacquire the mutex
+ if (ret && !try_to_freeze())
+ schedule();
+ } while (ret);
+ mutex->owner = info;
+ mutex->count = 1;
+}
+
+void NvOsMutexUnlock(NvOsMutexHandle mutex)
+{
+ NV_ASSERT( mutex );
+
+ mutex->count--;
+ if( mutex->count == 0 )
+ {
+ /* prevent the same thread from unlocking, then doing a recursive
+ * lock (skip mutex_lock).
+ */
+ mutex->owner = 0;
+
+ mutex_unlock( &mutex->mutex );
+ }
+}
+
+void NvOsMutexDestroy(NvOsMutexHandle mutex)
+{
+
+ if( !mutex )
+ return;
+ kfree( mutex );
+}
+
+typedef struct NvOsIntrMutexRec
+{
+ spinlock_t lock;
+ unsigned long flags;
+} NvOsIntrMutex;
+
+NvError NvOsIntrMutexCreate(NvOsIntrMutexHandle *mutex)
+{
+ NvOsIntrMutex *m;
+
+ m = kzalloc( sizeof(NvOsIntrMutex), GFP_KERNEL );
+ if( !m )
+ return NvError_InsufficientMemory;
+
+ spin_lock_init( &m->lock );
+ *mutex = m;
+ return NvSuccess;
+}
+
+void NvOsIntrMutexLock(NvOsIntrMutexHandle mutex)
+{
+ NV_ASSERT( mutex );
+ spin_lock_irqsave( &mutex->lock, mutex->flags );
+}
+
+void NvOsIntrMutexUnlock(NvOsIntrMutexHandle mutex)
+{
+ NV_ASSERT( mutex );
+ spin_unlock_irqrestore( &mutex->lock, mutex->flags );
+}
+
+void NvOsIntrMutexDestroy(NvOsIntrMutexHandle mutex)
+{
+ if (mutex)
+ kfree(mutex);
+}
+
+typedef struct NvOsSpinMutexRec
+{
+ spinlock_t lock;
+} NvOsSpinMutex;
+
+NvError NvOsSpinMutexCreate(NvOsSpinMutexHandle *mutex)
+{
+ NvOsSpinMutex *m;
+
+ m = kzalloc( sizeof(NvOsSpinMutex), GFP_KERNEL );
+ if( !m )
+ return NvError_InsufficientMemory;
+
+ spin_lock_init( &m->lock );
+ *mutex = m;
+ return NvSuccess;
+}
+
+void NvOsSpinMutexLock(NvOsSpinMutexHandle mutex)
+{
+ NV_ASSERT( mutex );
+ spin_lock( &mutex->lock );
+}
+
+void NvOsSpinMutexUnlock(NvOsSpinMutexHandle mutex)
+{
+ NV_ASSERT( mutex );
+ spin_unlock( &mutex->lock );
+}
+
+void NvOsSpinMutexDestroy(NvOsSpinMutexHandle mutex)
+{
+ if (mutex)
+ kfree(mutex);
+}
+
+typedef struct NvOsSemaphoreRec
+{
+ struct semaphore sem;
+ atomic_t refcount;
+} NvOsSemaphore;
+
+NvError NvOsSemaphoreCreate(
+ NvOsSemaphoreHandle *semaphore,
+ NvU32 value)
+{
+ NvOsSemaphore *s;
+
+ s = kzalloc( sizeof(NvOsSemaphore), GFP_KERNEL );
+ if( !s )
+ return NvError_InsufficientMemory;
+
+ sema_init( &s->sem, value );
+ atomic_set( &s->refcount, 1 );
+
+ *semaphore = s;
+
+ return NvSuccess;
+}
+
+NvError NvOsSemaphoreClone(
+ NvOsSemaphoreHandle orig,
+ NvOsSemaphoreHandle *semaphore)
+{
+ NV_ASSERT( orig );
+ NV_ASSERT( semaphore );
+
+ atomic_inc( &orig->refcount );
+ *semaphore = orig;
+
+ return NvSuccess;
+}
+
+NvError NvOsSemaphoreUnmarshal(
+ NvOsSemaphoreHandle hClientSema,
+ NvOsSemaphoreHandle *phDriverSema)
+{
+ NV_ASSERT( hClientSema );
+ NV_ASSERT( phDriverSema );
+
+ atomic_inc( &hClientSema->refcount );
+ *phDriverSema = hClientSema;
+
+ return NvSuccess;
+}
+
+int NvOsSemaphoreWaitInterruptible(NvOsSemaphoreHandle semaphore);
+int NvOsSemaphoreWaitInterruptible(NvOsSemaphoreHandle semaphore)
+{
+ NV_ASSERT(semaphore);
+
+ return down_interruptible(&semaphore->sem);
+}
+
+void NvOsSemaphoreWait(NvOsSemaphoreHandle semaphore)
+{
+ int ret;
+
+ NV_ASSERT(semaphore);
+
+ do
+ {
+ /* FIXME: We should split the implementation into two parts -
+ * one for semaphore that were created by users ioctl'ing into
+ * the nvos device (which need down_interruptible), and others that
+ * are created and used by the kernel drivers, which do not */
+ ret = down_interruptible(&semaphore->sem);
+ /* The kernel doesn't reschedule tasks
+ * that have pending signals. If a signal
+ * is pending, forcibly reschedule the task.
+ */
+ if (ret && !try_to_freeze())
+ schedule();
+ } while (ret);
+}
+
+NvError NvOsSemaphoreWaitTimeout(
+ NvOsSemaphoreHandle semaphore,
+ NvU32 msec)
+{
+ int t;
+
+ NV_ASSERT( semaphore );
+
+ if (!semaphore)
+ return NvError_Timeout;
+
+ if (msec==NV_WAIT_INFINITE)
+ {
+ NvOsSemaphoreWait(semaphore);
+ return NvSuccess;
+ }
+ else if (msec==0)
+ {
+ t = down_trylock(&semaphore->sem);
+ if (!t)
+ return NvSuccess;
+ else
+ return NvError_Timeout;
+ }
+
+ /* FIXME: The kernel doesn't provide an interruptible timed
+ * semaphore wait, which would be preferable for our the ioctl'd
+ * NvOs sempahores. */
+ t = down_timeout(&semaphore->sem, (long)msecs_to_jiffies( msec ));
+
+ if (t == -ETIME)
+ return NvError_Timeout;
+ else if (!t)
+ return NvSuccess;
+
+ return NvError_AccessDenied;
+}
+
+void NvOsSemaphoreSignal(NvOsSemaphoreHandle semaphore)
+{
+ NV_ASSERT( semaphore );
+
+ up( &semaphore->sem );
+}
+
+void NvOsSemaphoreDestroy(NvOsSemaphoreHandle semaphore)
+{
+ if (!semaphore)
+ return;
+
+ if( atomic_dec_return( &semaphore->refcount ) == 0 )
+ kfree( semaphore );
+}
+
+NvError NvOsThreadMode(int coop)
+{
+ return NvError_NotImplemented;
+}
+
+typedef struct NvOsThreadRec
+{
+ struct task_struct *task;
+ NvOsThreadFunction func;
+ void *arg;
+} NvOsThread;
+
+static int thread_wrapper( void *arg )
+{
+ NvOsThread *t = (NvOsThread *)arg;
+ t->func(t->arg);
+ return 0;
+}
+
+static NvError NvOsThreadCreateInternal(
+ NvOsThreadFunction function,
+ void *args,
+ NvOsThreadHandle *thread,
+ NvBool elevatedPriority)
+{
+ NvError e;
+ NvOsThread *t = 0;
+ static NvU32 NvOsKernelThreadIndex = 0;
+ struct sched_param sched;
+ int scheduler;
+ NvU32 ThreadId;
+
+ t = kzalloc( sizeof(NvOsThread), GFP_KERNEL );
+ if( !t )
+ {
+ return NvError_InsufficientMemory;
+ }
+
+ t->func = function;
+ t->arg = args;
+
+ ThreadId = (NvU32)NvOsAtomicExchangeAdd32((NvS32*)&NvOsKernelThreadIndex,1);
+ t->task =
+ kthread_create(thread_wrapper, t, "NvOsKernelThread/%d", ThreadId);
+
+ if(IS_ERR(t->task))
+ {
+ e = NvError_InsufficientMemory;
+ goto fail;
+ }
+
+ if (elevatedPriority)
+ {
+ scheduler = SCHED_FIFO;
+ sched.sched_priority = KTHREAD_IRQ_PRIO+1;
+ }
+ else
+ {
+ scheduler = SCHED_NORMAL;
+ sched.sched_priority = 0;
+ }
+
+ if (sched_setscheduler_nocheck( t->task, scheduler, &sched ) < 0)
+ NvOsDebugPrintf("Failed to set task priority to %d\n",
+ sched.sched_priority);
+
+ *thread = t;
+ wake_up_process( t->task );
+ e = NvSuccess;
+ goto clean;
+
+fail:
+ kfree( t );
+
+clean:
+ return e;
+}
+
+
+NvError NvOsInterruptPriorityThreadCreate(
+ NvOsThreadFunction function,
+ void *args,
+ NvOsThreadHandle *thread)
+{
+ return NvOsThreadCreateInternal(function, args, thread, NV_TRUE);
+}
+
+NvError NvOsThreadCreate(
+ NvOsThreadFunction function,
+ void *args,
+ NvOsThreadHandle *thread)
+{
+ return NvOsThreadCreateInternal(function, args, thread, NV_FALSE);
+}
+
+NvError NvOsThreadSetLowPriority(void)
+{
+ struct sched_param sched;
+ struct task_struct *curr;
+
+ curr = get_current();
+ sched.sched_priority = 0;
+
+ if (unlikely(!curr))
+ return NvError_NotInitialized;
+
+ if (sched_setscheduler_nocheck( curr, SCHED_IDLE, &sched )<0)
+ {
+ NvOsDebugPrintf("Failed to set low priority for thread %p\n", curr);
+ return NvError_NotSupported;
+ }
+
+ return NvSuccess;
+}
+
+void NvOsThreadJoin(NvOsThreadHandle thread)
+{
+ if (!thread)
+ return;
+
+ (void)kthread_stop(thread->task);
+ kfree(thread);
+}
+
+void NvOsThreadYield(void)
+{
+ schedule();
+}
+
+NvS32 NvOsAtomicCompareExchange32(
+ NvS32 *pTarget,
+ NvS32 OldValue,
+ NvS32 NewValue)
+{
+ return atomic_cmpxchg( (atomic_t *)pTarget, OldValue, NewValue );
+}
+
+NvS32 NvOsAtomicExchange32(NvS32 *pTarget, NvS32 Value)
+{
+ return atomic_xchg( (atomic_t *)pTarget, Value );
+}
+
+NvS32 NvOsAtomicExchangeAdd32(NvS32 *pTarget, NvS32 Value)
+{
+ NvS32 new;
+ new = atomic_add_return( Value, (atomic_t *)pTarget );
+ return new + (-Value);
+}
+
+NvU32 NvOsTlsAlloc(void)
+{
+ return 0;
+}
+
+void NvOsTlsFree(NvU32 TlsIndex)
+{
+}
+
+void *NvOsTlsGet(NvU32 TlsIndex)
+{
+ return 0;
+}
+
+void NvOsTlsSet(NvU32 TlsIndex, void *Value)
+{
+}
+
+NvU32 NvOsGetTimeMS(void)
+{
+ struct timespec ts;
+ s64 nsec;
+ getnstimeofday(&ts);
+ nsec = timespec_to_ns(&ts);
+ do_div(nsec, 1000000);
+ return (NvU32)nsec;
+}
+
+NvU64 NvOsGetTimeUS(void)
+{
+ struct timespec ts;
+ s64 nsec;
+ getnstimeofday(&ts);
+ nsec = timespec_to_ns(&ts);
+ do_div(nsec, 1000);
+ return (NvU32)nsec;
+}
+
+void NvOsDataCacheWritebackRange(
+ void *start,
+ NvU32 length)
+{
+ dmac_map_area(start, length, DMA_TO_DEVICE);
+}
+
+void NvOsDataCacheWritebackInvalidateRange(
+ void *start,
+ NvU32 length)
+{
+ dmac_flush_range(start, (NvU8*)start+length);
+}
+
+void NvOsInstrCacheInvalidate(void)
+{
+}
+
+void NvOsInstrCacheInvalidateRange(
+ void *start,
+ NvU32 length)
+{
+ __cpuc_coherent_kern_range((unsigned long)start,
+ (unsigned long)start+length);
+}
+
+void NvOsFlushWriteCombineBuffer( void )
+{
+ dsb();
+ outer_sync();
+}
+
+NvError NvOsInterruptRegisterInternal(
+ NvU32 IrqListSize,
+ const NvU32 *pIrqList,
+ const void *pList,
+ void* context,
+ NvOsInterruptHandle *handle,
+ NvBool InterruptEnable,
+ NvBool IsUser)
+{
+ const NvOsSemaphoreHandle *pSemList = NULL;
+ const NvOsInterruptHandler *pFnList = NULL;
+ NvError e = NvSuccess;
+ NvOsInterruptBlock *pNewBlock;
+ NvU32 i;
+
+ if (!IrqListSize)
+ return NvError_BadValue;
+
+ if (IsUser)
+ pSemList = (const NvOsSemaphoreHandle *)pList;
+ else
+ pFnList = (const NvOsInterruptHandler *)pList;
+
+ *handle = (NvOsInterruptHandle) 0;
+ pNewBlock = (NvOsInterruptBlock *)NvOsAlloc(INTBLOCK_SIZE(IrqListSize));
+ if (!pNewBlock)
+ return NvError_InsufficientMemory;
+
+ NvOsMemset(pNewBlock, 0, INTBLOCK_SIZE(IrqListSize));
+
+ pNewBlock->pArg = context;
+ pNewBlock->NumIrqs = IrqListSize;
+ pNewBlock->Shutdown = 0;
+ for (i=0; i<IrqListSize; i++)
+ {
+ if (pIrqList[i] >= NVOS_MAX_SYSTEM_IRQS)
+ {
+ BUG();
+ e = NvError_InsufficientMemory;
+ goto clean_fail;
+ }
+
+ if (NvOsAtomicCompareExchange32((NvS32*)&s_pIrqList[pIrqList[i]], 0,
+ (NvS32)pNewBlock)!=0)
+ {
+ e = NvError_AlreadyAllocated;
+ goto clean_fail;
+ }
+ snprintf(pNewBlock->IrqList[i].IrqName,
+ sizeof(pNewBlock->IrqList[i].IrqName),
+ "NvOsIrq%s%04d", (IsUser)?"User":"Kern", pIrqList[i]);
+
+ pNewBlock->IrqList[i].Irq = pIrqList[i];
+
+ /* HACK use threads for GPIO and tasklets for all other interrupts. */
+ if (IsUser)
+ {
+ pNewBlock->IrqList[i].pSem = pSemList[i];
+ pNewBlock->Flags |= NVOS_IRQ_IS_USER;
+ }
+ else
+ {
+ pNewBlock->IrqList[i].pHandler = pFnList[i];
+ if (pIrqList[i] >= INT_GPIO_BASE)
+ pNewBlock->Flags |= NVOS_IRQ_IS_KERNEL_THREAD;
+ else
+ pNewBlock->Flags |= NVOS_IRQ_IS_TASKLET;
+ }
+
+ if ((pNewBlock->Flags & NVOS_IRQ_TYPE_MASK)==NVOS_IRQ_IS_KERNEL_THREAD)
+ {
+ struct sched_param p;
+ p.sched_priority = KTHREAD_IRQ_PRIO;
+ sema_init(&(pNewBlock->IrqList[i].sem), 0);
+ pNewBlock->IrqList[i].task =
+ kthread_create(NvOsInterruptThreadWrapper,
+ (void *)((pIrqList[i]&0xffff) | ((i&0xffff)<<16)),
+ pNewBlock->IrqList[i].IrqName);
+ if (sched_setscheduler(pNewBlock->IrqList[i].task,
+ SCHED_FIFO, &p)<0)
+ NvOsDebugPrintf("Failed to elevate priority for IRQ %u\n",
+ pIrqList[i]);
+ wake_up_process( pNewBlock->IrqList[i].task );
+ }
+
+ if ((pNewBlock->Flags & NVOS_IRQ_TYPE_MASK)==NVOS_IRQ_IS_TASKLET)
+ {
+ tasklet_init(&pNewBlock->IrqList[i].Tasklet, NvOsTaskletWrapper,
+ (pIrqList[i]&0xffff) | ((i&0xffff)<<16));
+ }
+
+ /* NvOs specifies that the interrupt handler is responsible for
+ * re-enabling the interrupt. This is not the standard behavior
+ * for Linux IRQs, so only interrupts which are installed through
+ * NvOs will have the no-auto-enable flag specified
+ */
+ set_irq_flags(pIrqList[i], IRQF_VALID | IRQF_NOAUTOEN);
+
+ if (request_irq(pIrqList[i], NvOsIrqWrapper,
+ 0, pNewBlock->IrqList[i].IrqName, (void*)i)!=0)
+ {
+ e = NvError_ResourceError;
+ goto clean_fail;
+ }
+ }
+ *handle = (NvOsInterruptHandle)pNewBlock;
+ if (InterruptEnable)
+ {
+ pNewBlock->Flags |= NVOS_IRQ_IS_ENABLED;
+ i = 0;
+ }
+ for ( ; i<IrqListSize; i++)
+ enable_irq(pIrqList[i]);
+
+ return NvSuccess;
+
+ clean_fail:
+ while (i)
+ {
+ --i;
+ if ((pNewBlock->Flags & NVOS_IRQ_TYPE_MASK)==NVOS_IRQ_IS_KERNEL_THREAD)
+ {
+ up(&pNewBlock->IrqList[i].sem);
+ (void)kthread_stop(pNewBlock->IrqList[i].task);
+ }
+ if ((pNewBlock->Flags & NVOS_IRQ_TYPE_MASK) == NVOS_IRQ_IS_TASKLET)
+ {
+ tasklet_kill(&pNewBlock->IrqList[i].Tasklet);
+ }
+ free_irq(pIrqList[i], (void*)i);
+ set_irq_flags(pIrqList[i], IRQF_VALID);
+ NvOsAtomicCompareExchange32((NvS32*)&s_pIrqList[pIrqList[i]],
+ (NvS32)pNewBlock, 0);
+ }
+ *handle = NULL;
+ NvOsFree(pNewBlock);
+
+ return e;
+}
+
+NvError NvOsInterruptRegister(
+ NvU32 IrqListSize,
+ const NvU32 *pIrqList,
+ const NvOsInterruptHandler *pIrqHandlerList,
+ void *context,
+ NvOsInterruptHandle *handle,
+ NvBool InterruptEnable)
+{
+ return NvOsInterruptRegisterInternal(IrqListSize, pIrqList,
+ (const void*)pIrqHandlerList, context, handle,
+ InterruptEnable, NV_FALSE);
+}
+
+void NvOsInterruptUnregister(NvOsInterruptHandle handle)
+{
+ NvOsInterruptBlock *pBlock = (NvOsInterruptBlock *)handle;
+ NvU32 i;
+
+ if (!pBlock)
+ return;
+
+ pBlock->Shutdown = 1;
+
+ for (i=0; i<pBlock->NumIrqs; i++)
+ {
+ free_irq(pBlock->IrqList[i].Irq, (void*)i);
+ NvOsAtomicCompareExchange32(
+ (NvS32*)&s_pIrqList[pBlock->IrqList[i].Irq], (NvS32)pBlock, 0);
+
+ if ((pBlock->Flags & NVOS_IRQ_TYPE_MASK) == NVOS_IRQ_IS_KERNEL_THREAD)
+ {
+ up(&pBlock->IrqList[i].sem);
+ (void)kthread_stop(pBlock->IrqList[i].task);
+ }
+ if ((pBlock->Flags & NVOS_IRQ_TYPE_MASK) == NVOS_IRQ_IS_TASKLET)
+ {
+ tasklet_kill(&pBlock->IrqList[i].Tasklet);
+ }
+ set_irq_flags(pBlock->IrqList[i].Irq, IRQF_VALID);
+ }
+
+ NvOsFree(pBlock);
+}
+
+NvError NvOsInterruptEnable(NvOsInterruptHandle handle)
+{
+ NvOsInterruptBlock *pBlock = (NvOsInterruptBlock *)handle;
+ NvU32 i;
+
+ if (pBlock == NULL)
+ BUG();
+
+ if (!(pBlock->Flags & NVOS_IRQ_IS_ENABLED))
+ {
+ pBlock->Flags |= NVOS_IRQ_IS_ENABLED;
+ for (i=0; i<pBlock->NumIrqs; i++)
+ enable_irq(pBlock->IrqList[i].Irq);
+ }
+
+ return NvSuccess;
+}
+
+void NvOsInterruptDone(NvOsInterruptHandle handle)
+{
+ NvOsInterruptBlock *pBlock = (NvOsInterruptBlock *)handle;
+ NvU32 i;
+
+ if (pBlock == NULL)
+ BUG();
+
+ for (i=0; i<pBlock->NumIrqs; i++)
+ enable_irq(pBlock->IrqList[i].Irq);
+}
+
+void NvOsInterruptMask(NvOsInterruptHandle handle, NvBool mask)
+{
+ NvOsInterruptBlock *pBlock = (NvOsInterruptBlock *)handle;
+ NvU32 i;
+
+ if (pBlock == NULL)
+ BUG();
+
+ if (mask)
+ {
+ for (i=0; i<pBlock->NumIrqs; i++)
+ disable_irq(pBlock->IrqList[i].Irq);
+ }
+ else
+ {
+ for (i=0; i<pBlock->NumIrqs; i++)
+ enable_irq(pBlock->IrqList[i].Irq);
+ }
+}
+
+void NvOsProfileApertureSizes(NvU32 *apertures, NvU32 *sizes)
+{
+}
+
+void NvOsProfileStart(void **apertures)
+{
+}
+
+void NvOsProfileStop(void **apertures)
+{
+}
+
+NvError NvOsProfileWrite(
+ NvOsFileHandle file, NvU32 index,
+ void *aperture)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsBootArgSet(NvU32 key, void *arg, NvU32 size)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsBootArgGet(NvU32 key, void *arg, NvU32 size)
+{
+ const void *src;
+ NvU32 size_src;
+
+ if (key>=NvBootArgKey_PreservedMemHandle_0 &&
+ key<NvBootArgKey_PreservedMemHandle_Num)
+ {
+ int Index = key - NvBootArgKey_PreservedMemHandle_0;
+
+ src = &s_BootArgs.MemHandleArgs[Index];
+ size_src = sizeof(NvBootArgsPreservedMemHandle);
+ }
+ else
+ {
+ switch (key)
+ {
+ case NvBootArgKey_ChipShmoo:
+ src = &s_BootArgs.ChipShmooArgs;
+ size_src = sizeof(NvBootArgsChipShmoo);
+ break;
+ case NvBootArgKey_Framebuffer:
+ src = &s_BootArgs.FramebufferArgs;
+ size_src = sizeof(NvBootArgsFramebuffer);
+ break;
+ case NvBootArgKey_Display:
+ src = &s_BootArgs.DisplayArgs;
+ size_src = sizeof(NvBootArgsDisplay);
+ break;
+ case NvBootArgKey_Rm:
+ src = &s_BootArgs.RmArgs;
+ size_src = sizeof(NvBootArgsRm);
+ break;
+ case NvBootArgKey_ChipShmooPhys:
+ src = &s_BootArgs.ChipShmooPhysArgs;
+ size_src = sizeof(NvBootArgsChipShmooPhys);
+ break;
+ case NvBootArgKey_WarmBoot:
+ src = &s_BootArgs.WarmbootArgs;
+ size_src = sizeof(NvBootArgsWarmboot);
+ break;
+ default:
+ src = NULL;
+ size_src = 0;
+ break;
+ }
+ }
+
+ if (!arg || !src || (size_src!=size))
+ return NvError_BadParameter;
+
+ NvOsMemcpy(arg, src, size_src);
+ return NvSuccess;
+}
+
+/** nvassert functions */
+
+void NvOsBreakPoint(const char* file, NvU32 line, const char* condition)
+{
+ printk( "assert: %s:%d: %s\n", file, line, (condition) ? condition : " " );
+ dump_stack();
+}
+
+/** trace functions */
+
+void NvOsTraceLogPrintf( const char *format, ... )
+{
+
+}
+
+void NvOsTraceLogStart(void)
+{
+}
+
+void NvOsTraceLogEnd(void)
+{
+}
+
+/* resource tracking */
+
+#if NV_DEBUG
+void *NvOsAllocLeak( size_t size, const char *f, int l )
+{
+ return NvOsAlloc( size );
+}
+
+void *NvOsReallocLeak( void *ptr, size_t size, const char *f, int l )
+{
+ return NvOsRealloc( ptr, size );
+}
+
+void NvOsFreeLeak( void *ptr, const char *f, int l )
+{
+ NvOsFree( ptr );
+}
+#endif
+
+void NvOsGetProcessInfo(char* buf, NvU32 len)
+{
+ NvOsSnprintf(buf,len, "(kernel pid=%d)", current->pid);
+}
+
+#if (NVOS_TRACE || NV_DEBUG)
+void NvOsSetResourceAllocFileLine(void* userptr, const char* file, int line)
+{
+}
+#endif
+
+#ifdef GHACK
+
+static int __init parse_tegra_tag(const struct tag *tag)
+{
+ const struct tag_nvidia_tegra *nvtag = &tag->u.tegra;
+
+ if (nvtag->bootarg_key >= NvBootArgKey_PreservedMemHandle_0 &&
+ nvtag->bootarg_key < NvBootArgKey_PreservedMemHandle_Num)
+ {
+ int Index = nvtag->bootarg_key - NvBootArgKey_PreservedMemHandle_0;
+ NvBootArgsPreservedMemHandle *dst = &s_BootArgs.MemHandleArgs[Index];
+ const NvBootArgsPreservedMemHandle *src =
+ (const NvBootArgsPreservedMemHandle *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsPreservedMemHandle))
+ printk("Unexpected preserved memory handle tag length!\n");
+ else
+ *dst = *src;
+ return 0;
+ }
+
+ switch (nvtag->bootarg_key)
+ {
+ case NvBootArgKey_ChipShmoo:
+ {
+ NvBootArgsChipShmoo *dst = &s_BootArgs.ChipShmooArgs;
+ const NvBootArgsChipShmoo *src =
+ (const NvBootArgsChipShmoo *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsChipShmoo))
+ printk("Unexpected shmoo tag length!\n");
+ else
+ {
+ printk("Shmoo tag with %u handle\n",
+ src->MemHandleKey);
+ *dst = *src;
+ }
+ return 0;
+ }
+ case NvBootArgKey_Display:
+ {
+ NvBootArgsDisplay *dst = &s_BootArgs.DisplayArgs;
+ const NvBootArgsDisplay *src =
+ (const NvBootArgsDisplay *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsDisplay))
+ printk("Unexpected display tag length!\n");
+ else
+ *dst = *src;
+ return 0;
+ }
+ case NvBootArgKey_Framebuffer:
+ {
+ NvBootArgsFramebuffer *dst = &s_BootArgs.FramebufferArgs;
+ const NvBootArgsFramebuffer *src =
+ (const NvBootArgsFramebuffer *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsFramebuffer))
+ printk("Unexpected framebuffer tag length!\n");
+ else
+ {
+ printk("Framebuffer tag with %u handle\n",
+ src->MemHandleKey);
+ *dst = *src;
+ }
+ return 0;
+ }
+ case NvBootArgKey_Rm:
+ {
+ NvBootArgsRm *dst = &s_BootArgs.RmArgs;
+ const NvBootArgsRm *src =
+ (const NvBootArgsRm *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsRm))
+ printk("Unexpected RM tag length!\n");
+ else
+ *dst = *src;
+ return 0;
+ }
+ case NvBootArgKey_ChipShmooPhys:
+ {
+ NvBootArgsChipShmooPhys *dst = &s_BootArgs.ChipShmooPhysArgs;
+ const NvBootArgsChipShmooPhys *src =
+ (const NvBootArgsChipShmooPhys *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsChipShmooPhys))
+ printk("Unexpected phys shmoo tag length!\n");
+ else
+ {
+ printk("Phys shmoo tag with pointer 0x%X and length %u\n",
+ src->PhysShmooPtr, src->Size);
+ *dst = *src;
+ }
+ return 0;
+ }
+ case NvBootArgKey_WarmBoot:
+ {
+ NvBootArgsWarmboot *dst = &s_BootArgs.WarmbootArgs;
+ const NvBootArgsWarmboot *src =
+ (const NvBootArgsWarmboot *)nvtag->bootarg;
+
+ if (nvtag->bootarg_len != sizeof(NvBootArgsWarmboot))
+ printk("Unexpected warmboot tag length!\n");
+ else
+ {
+ printk("Found a warmboot tag!\n");
+ *dst = *src;
+ }
+ return 0;
+ }
+
+ default:
+ return 0;
+ }
+}
+__tagtable(ATAG_NVIDIA_TEGRA, parse_tegra_tag);
+
+void __init tegra_nvos_kernel_init(void);
+
+void __init tegra_nvos_kernel_init(void)
+{
+ spin_lock_init(&gs_NvOsSpinLock);
+}
+#endif
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/Makefile ('k') | arch/arm/mach-tegra/nv/nvos/nvos_exports.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698