Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 376704 Details for
Bug 510020
x11-drivers/nvidia-drivers-96.43.23: Patches for kernels >3.7
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
173.14.36-37-gentoo.patch
173.14.36-37-gentoo.patch (text/plain), 181.83 KB, created by
Roger
on 2014-05-11 05:42:35 UTC
(
hide
)
Description:
173.14.36-37-gentoo.patch
Filename:
MIME Type:
Creator:
Roger
Created:
2014-05-11 05:42:35 UTC
Size:
181.83 KB
patch
obsolete
>diff -urN usr.orig/src/nv/conftest.sh usr/src/nv/conftest.sh >--- usr.orig/src/nv/conftest.sh 2012-08-31 14:04:44.000000000 -0800 >+++ usr/src/nv/conftest.sh 2014-05-10 21:02:17.740161977 -0800 >@@ -128,6 +128,7 @@ > if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then > MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/asm-x86/mach-default" > MACH_CFLAGS="$MACH_CFLAGS -I$SOURCES/arch/x86/include/asm/mach-default" >+ MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/arch/x86/include/uapi" > fi > if [ "$XEN_PRESENT" != "0" ]; then > MACH_CFLAGS="-I$HEADERS/asm-$ARCH/mach-xen $MACH_CFLAGS" >@@ -137,16 +138,21 @@ > if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then > MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/asm-x86/mach-default" > MACH_CFLAGS="$MACH_CFLAGS -I$SOURCES/arch/x86/include/asm/mach-default" >+ MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/arch/x86/include/uapi" > fi > if [ "$XEN_PRESENT" != "0" ]; then > MACH_CFLAGS="-I$HEADERS/asm/mach-xen $MACH_CFLAGS" > fi > fi > >- CFLAGS="$BASE_CFLAGS $MACH_CFLAGS $OUTPUT_CFLAGS -I$HEADERS $AUTOCONF_CFLAGS" >+ CFLAGS="$BASE_CFLAGS $MACH_CFLAGS $OUTPUT_CFLAGS $AUTOCONF_CFLAGS" >+ CFLAGS="$CFLAGS -I$HEADERS -I$HEADERS/uapi -I$OUTPUT/include/generated/uapi" > > if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then >- CFLAGS="$CFLAGS -I$SOURCES/arch/x86/include -I$OUTPUT/arch/x86/include/generated" >+ CFLAGS="$CFLAGS -I$SOURCES/arch/x86/include" >+ CFLAGS="$CFLAGS -I$SOURCES/arch/x86/include/uapi" >+ CFLAGS="$CFLAGS -I$OUTPUT/arch/x86/include/generated" >+ CFLAGS="$CFLAGS -I$OUTPUT/arch/x86/include/generated/uapi" > fi > if [ -n "$BUILD_PARAMS" ]; then > CFLAGS="$CFLAGS -D$BUILD_PARAMS" >@@ -1407,7 +1413,8 @@ > FILE="linux/version.h" > SELECTED_MAKEFILE="" > >- if [ -f $HEADERS/$FILE -o -f $OUTPUT/include/$FILE ]; then >+ if [ -f $HEADERS/$FILE -o -f $OUTPUT/include/$FILE -o \ >+ -f $OUTPUT/include/generated/uapi/$FILE ]; then > # > # We are either looking at a configured kernel source > # tree or at headers shipped for a specific kernel. >diff -urN usr.orig/src/nv/conftest.sh.orig usr/src/nv/conftest.sh.orig >--- usr.orig/src/nv/conftest.sh.orig 1969-12-31 14:00:00.000000000 -1000 >+++ usr/src/nv/conftest.sh.orig 2012-08-31 14:04:44.000000000 -0800 >@@ -0,0 +1,1784 @@ >+#!/bin/sh >+ >+# make sure we are in the directory containing this script >+SCRIPTDIR=`dirname $0` >+cd $SCRIPTDIR >+PATH="${PATH}:/bin:/sbin" >+ >+# >+# HOSTCC vs. CC - if a conftest needs to build and execute a test >+# binary, like get_uname, then $HOSTCC needs to be used for this >+# conftest in order for the host/build system to be able to execute >+# it in X-compile environments. >+# In all other cases, $CC should be used to minimize the risk of >+# false failures due to conflicts with architecture specific header >+# files. >+# >+CC="$1" >+HOSTCC="$2" >+ISYSTEM=`$CC -print-file-name=include 2> /dev/null` >+SOURCES=$3 >+HEADERS=$SOURCES/include >+OUTPUT=$4 >+XEN_PRESENT=1 >+ >+test_xen() { >+ # >+ # Determine if the target kernel is a Xen kernel. It used to be >+ # sufficient to check for CONFIG_XEN, but the introduction of >+ # modular para-virtualization (CONFIG_PARAVIRT, etc.) and >+ # Xen guest support, it is no longer possible to determine the >+ # target environment at build time. Therefore, if both >+ # CONFIG_XEN and CONFIG_PARAVIRT are present, text_xen() treats >+ # the kernel as a stand-alone kernel. >+ # >+ OLD_FILE="linux/autoconf.h" >+ NEW_FILE="generated/autoconf.h" >+ >+ if [ -f $HEADERS/$NEW_FILE -o -f $OUTPUT/include/$NEW_FILE ]; then >+ FILE=$NEW_FILE >+ fi >+ if [ -f $HEADERS/$OLD_FILE -o -f $OUTPUT/include/$OLD_FILE ]; then >+ FILE=$OLD_FILE >+ fi >+ >+ if [ -n "$FILE" ]; then >+ # >+ # We are looking at a configured source tree; verify >+ # that it's not a Xen kernel. >+ # >+ echo "#include <$FILE> >+ #if defined(CONFIG_XEN) && !defined(CONFIG_PARAVIRT) >+ #error CONFIG_XEN defined! >+ #endif >+ " > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ XEN_PRESENT=0 >+ fi >+ else >+ CONFIG=$HEADERS/../.config >+ if [ -f $CONFIG ]; then >+ if [ -z "$(grep "^CONFIG_XEN=y" $CONFIG)" ]; then >+ XEN_PRESENT="0" >+ return >+ fi >+ if [ -n "$(grep "^CONFIG_PARAVIRT=y" $CONFIG)" ]; then >+ XEN_PRESENT="0" >+ fi >+ fi >+ fi >+} >+ >+test_headers() { >+ # >+ # Determine which header files (of a set that may or may not be >+ # present) are provided by the target kernel. >+ # >+ FILES="asm/system.h" >+ FILES="$FILES generated/autoconf.h" >+ FILES="$FILES generated/compile.h" >+ FILES="$FILES generated/utsrelease.h" >+ FILES="$FILES linux/kconfig.h" >+ FILES="$FILES linux/screen_info.h" >+ FILES="$FILES linux/semaphore.h" >+ >+ for FILE in $FILES; do >+ FILE_DEFINE=NV_`echo $FILE | tr '/.' '_' | tr 'a-z' 'A-Z'`_PRESENT >+ if [ -f $HEADERS/$FILE -o -f $OUTPUT/include/$FILE ]; then >+ echo "#define $FILE_DEFINE" >> conftest.h >+ else >+ echo "#undef $FILE_DEFINE" >> conftest.h >+ fi >+ done >+} >+ >+build_cflags() { >+ ARCH=`uname -m | sed -e 's/i.86/i386/'` >+ >+ BASE_CFLAGS="-O2 -D__KERNEL__ \ >+-DKBUILD_BASENAME=\"#conftest$$\" -DKBUILD_MODNAME=\"#conftest$$\" \ >+-nostdinc -isystem $ISYSTEM" >+ >+ if [ "$OUTPUT" != "$SOURCES" ]; then >+ OUTPUT_CFLAGS="-I$OUTPUT/include2 -I$OUTPUT/include" >+ if [ -f "$OUTPUT/include/generated/autoconf.h" ]; then >+ AUTOCONF_CFLAGS="-include $OUTPUT/include/generated/autoconf.h" >+ else >+ AUTOCONF_CFLAGS="-include $OUTPUT/include/linux/autoconf.h" >+ fi >+ else >+ if [ -f "$HEADERS/generated/autoconf.h" ]; then >+ AUTOCONF_CFLAGS="-include $HEADERS/generated/autoconf.h" >+ else >+ AUTOCONF_CFLAGS="-include $HEADERS/linux/autoconf.h" >+ fi >+ fi >+ >+ CFLAGS="$CFLAGS $OUTPUT_CFLAGS -I$HEADERS $AUTOCONF_CFLAGS" >+ >+ test_xen >+ >+ if [ "$OUTPUT" != "$SOURCES" ]; then >+ MACH_CFLAGS="-I$HEADERS/asm-$ARCH/mach-default" >+ if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then >+ MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/asm-x86/mach-default" >+ MACH_CFLAGS="$MACH_CFLAGS -I$SOURCES/arch/x86/include/asm/mach-default" >+ fi >+ if [ "$XEN_PRESENT" != "0" ]; then >+ MACH_CFLAGS="-I$HEADERS/asm-$ARCH/mach-xen $MACH_CFLAGS" >+ fi >+ else >+ MACH_CFLAGS="-I$HEADERS/asm/mach-default" >+ if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then >+ MACH_CFLAGS="$MACH_CFLAGS -I$HEADERS/asm-x86/mach-default" >+ MACH_CFLAGS="$MACH_CFLAGS -I$SOURCES/arch/x86/include/asm/mach-default" >+ fi >+ if [ "$XEN_PRESENT" != "0" ]; then >+ MACH_CFLAGS="-I$HEADERS/asm/mach-xen $MACH_CFLAGS" >+ fi >+ fi >+ >+ CFLAGS="$BASE_CFLAGS $MACH_CFLAGS $OUTPUT_CFLAGS -I$HEADERS $AUTOCONF_CFLAGS" >+ >+ if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]; then >+ CFLAGS="$CFLAGS -I$SOURCES/arch/x86/include -I$OUTPUT/arch/x86/include/generated" >+ fi >+ if [ -n "$BUILD_PARAMS" ]; then >+ CFLAGS="$CFLAGS -D$BUILD_PARAMS" >+ fi >+} >+ >+CONFTEST_PREAMBLE="#include \"conftest.h\" >+ #if defined(NV_LINUX_KCONFIG_H_PRESENT) >+ #include <linux/kconfig.h> >+ #endif >+ #if defined(NV_GENERATED_AUTOCONF_H_PRESENT) >+ #include <generated/autoconf.h> >+ #else >+ #include <linux/autoconf.h> >+ #endif >+ #if defined(CONFIG_XEN) && \ >+ defined(CONFIG_XEN_INTERFACE_VERSION) && !defined(__XEN_INTERFACE_VERSION__) >+ #define __XEN_INTERFACE_VERSION__ CONFIG_XEN_INTERFACE_VERSION >+ #endif" >+ >+compile_test() { >+ case "$1" in >+ remap_page_range) >+ # >+ # Determine if the remap_page_range() function is present >+ # and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/mm.h> >+ void conftest_remap_page_range(void) { >+ remap_page_range(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_REMAP_PAGE_RANGE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/mm.h> >+ int conftest_remap_page_range(void) { >+ pgprot_t pgprot = __pgprot(0); >+ return remap_page_range(NULL, 0L, 0L, 0L, pgprot); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_REMAP_PAGE_RANGE_PRESENT" >> conftest.h >+ echo "#define NV_REMAP_PAGE_RANGE_ARGUMENT_COUNT 5" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/mm.h> >+ int conftest_remap_page_range(void) { >+ pgprot_t pgprot = __pgprot(0); >+ return remap_page_range(0L, 0L, 0L, pgprot); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_REMAP_PAGE_RANGE_PRESENT" >> conftest.h >+ echo "#define NV_REMAP_PAGE_RANGE_ARGUMENT_COUNT 4" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#error remap_page_range() conftest failed!" >> conftest.h >+ return >+ fi >+ ;; >+ >+ set_pages_uc) >+ # >+ # Determine if the set_pages_uc() function is present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <asm/cacheflush.h> >+ void conftest_set_pages_uc(void) { >+ set_pages_uc(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_SET_PAGES_UC_PRESENT" >> conftest.h >+ return >+ else >+ echo "#ifdef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h >+ echo "#undef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h >+ echo "#endif" >> conftest.h >+ echo "#define NV_SET_PAGES_UC_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ change_page_attr) >+ # >+ # Determine if the change_page_attr() function is >+ # present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/version.h> >+ #include <linux/utsname.h> >+ #include <linux/mm.h> >+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) >+ #include <asm/cacheflush.h> >+ #endif >+ void conftest_change_page_attr(void) { >+ change_page_attr(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#ifndef NV_SET_PAGES_UC_PRESENT" >> conftest.h >+ echo "#define NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h >+ echo "#endif" >> conftest.h >+ return >+ fi >+ ;; >+ >+ pci_get_class) >+ # >+ # Determine if the pci_get_class() function is >+ # present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/pci.h> >+ void conftest_pci_get_class(void) { >+ pci_get_class(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_PCI_GET_CLASS_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_PCI_GET_CLASS_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ remap_pfn_range) >+ # >+ # Determine if the remap_pfn_range() function is >+ # present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/mm.h> >+ void conftest_remap_pfn_range(void) { >+ remap_pfn_range(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_REMAP_PFN_RANGE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_REMAP_PFN_RANGE_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ agp_backend_acquire) >+ # >+ # Determine if the agp_backend_acquire() function is >+ # present and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/agp_backend.h> >+ typedef struct agp_bridge_data agp_bridge_data; >+ agp_bridge_data *conftest_agp_backend_acquire(struct pci_dev *dev) { >+ return agp_backend_acquire(dev, 0L); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_AGP_BACKEND_ACQUIRE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/agp_backend.h> >+ typedef struct agp_bridge_data agp_bridge_data; >+ agp_bridge_data *conftest_agp_backend_acquire(struct pci_dev *dev) { >+ return agp_backend_acquire(dev); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_AGP_BACKEND_ACQUIRE_PRESENT" >> conftest.h >+ echo "#define NV_AGP_BACKEND_ACQUIRE_ARGUMENT_COUNT 1" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/agp_backend.h> >+ typedef struct agp_bridge_data agp_bridge_data; >+ agp_bridge_data *conftest_agp_backend_acquire(void) { >+ return agp_backend_acquire(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_AGP_BACKEND_ACQUIRE_PRESENT" >> conftest.h >+ echo "#define NV_AGP_BACKEND_ACQUIRE_ARGUMENT_COUNT 0" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#error agp_backend_acquire() conftest failed!" >> conftest.h >+ return >+ fi >+ ;; >+ >+ vmap) >+ # >+ # Determine if the vmap() function is present and how >+ # many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/vmalloc.h> >+ void conftest_vmap(void) { >+ vmap(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_VMAP_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/vmalloc.h> >+ void *conftest_vmap(struct page **pages, int count) { >+ return vmap(pages, count); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_VMAP_PRESENT" >> conftest.h >+ echo "#define NV_VMAP_ARGUMENT_COUNT 2" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/vmalloc.h> >+ #include <linux/mm.h> >+ void *conftest_vmap(struct page **pages, int count) { >+ return vmap(pages, count, 0, PAGE_KERNEL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_VMAP_PRESENT" >> conftest.h >+ echo "#define NV_VMAP_ARGUMENT_COUNT 4" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#error vmap() conftest failed!" >> conftest.h >+ return >+ fi >+ ;; >+ >+ i2c_adapter) >+ # >+ # Determine if the 'i2c_adapter' structure has inc_use() >+ # and client_register() members. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/i2c.h> >+ int conftest_i2c_adapter(void) { >+ return offsetof(struct i2c_adapter, inc_use); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_I2C_ADAPTER_HAS_INC_USE" >> conftest.h >+ rm -f conftest$$.o >+ else >+ echo "#undef NV_I2C_ADAPTER_HAS_INC_USE" >> conftest.h >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/i2c.h> >+ int conftest_i2c_adapter(void) { >+ return offsetof(struct i2c_adapter, client_register); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_I2C_ADAPTER_HAS_CLIENT_REGISTER" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#undef NV_I2C_ADAPTER_HAS_CLIENT_REGISTER" >> conftest.h >+ return >+ fi >+ ;; >+ >+ pm_message_t) >+ # >+ # Determine if the 'pm_message_t' data type is present >+ # and if it as an 'event' member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/pm.h> >+ void conftest_pm_message_t(pm_message_t state) { >+ pm_message_t *p = &state; >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_PM_MESSAGE_T_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ else >+ echo "#undef NV_PM_MESSAGE_T_PRESENT" >> conftest.h >+ echo "#undef NV_PM_MESSAGE_T_HAS_EVENT" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/pm.h> >+ int conftest_pm_message_t(void) { >+ return offsetof(pm_message_t, event); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_PM_MESSAGE_T_HAS_EVENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#undef NV_PM_MESSAGE_T_HAS_EVENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ pci_choose_state) >+ # >+ # Determine if the pci_choose_state() function is >+ # present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/pci.h> >+ void conftest_pci_choose_state(void) { >+ pci_choose_state(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_PCI_CHOOSE_STATE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_PCI_CHOOSE_STATE_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ vm_insert_page) >+ # >+ # Determine if the vm_insert_page() function is >+ # present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/mm.h> >+ void conftest_vm_insert_page(void) { >+ vm_insert_page(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_VM_INSERT_PAGE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_VM_INSERT_PAGE_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ irq_handler_t) >+ # >+ # Determine if the 'irq_handler_t' type is present and >+ # if it takes a 'struct ptregs *' argument. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/interrupt.h> >+ irq_handler_t conftest_isr; >+ " > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ ! -f conftest$$.o ]; then >+ echo "#undef NV_IRQ_HANDLER_T_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ rm -f conftest$$.o >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/interrupt.h> >+ irq_handler_t conftest_isr; >+ int conftest_irq_handler_t(int irq, void *arg) { >+ return conftest_isr(irq, arg); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_IRQ_HANDLER_T_PRESENT" >> conftest.h >+ echo "#define NV_IRQ_HANDLER_T_ARGUMENT_COUNT 2" >> conftest.h >+ rm -f conftest$$.o >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/interrupt.h> >+ irq_handler_t conftest_isr; >+ int conftest_irq_handler_t(int irq, void *arg, struct pt_regs *regs) { >+ return conftest_isr(irq, arg, regs); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_IRQ_HANDLER_T_PRESENT" >> conftest.h >+ echo "#define NV_IRQ_HANDLER_T_ARGUMENT_COUNT 3" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#error irq_handler_t() conftest failed!" >> conftest.h >+ return >+ fi >+ ;; >+ >+ acpi_device_ops) >+ # >+ # Determine if the 'acpi_device_ops' structure has >+ # a match() member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi_bus.h> >+ int conftest_acpi_device_ops(void) { >+ return offsetof(struct acpi_device_ops, match); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ACPI_DEVICE_OPS_HAS_MATCH" >> conftest.h >+ return >+ else >+ echo "#undef NV_ACPI_DEVICE_OPS_HAS_MATCH" >> conftest.h >+ return >+ fi >+ ;; >+ >+ acpi_device_id) >+ # >+ # Determine if the 'acpi_device_id' structure has >+ # a 'driver_data' member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi_drivers.h> >+ int conftest_acpi_device_id(void) { >+ return offsetof(struct acpi_device_id, driver_data); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_ACPI_DEVICE_ID_HAS_DRIVER_DATA" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#undef NV_ACPI_DEVICE_ID_HAS_DRIVER_DATA" >> conftest.h >+ return >+ fi >+ ;; >+ >+ acquire_console_sem) >+ # >+ # Determine if the acquire_console_sem() function >+ # is present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/console.h> >+ void conftest_acquire_console_sem(void) { >+ acquire_console_sem(NULL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_ACQUIRE_CONSOLE_SEM_PRESENT" >> conftest.h >+ return >+ else >+ echo "#define NV_ACQUIRE_CONSOLE_SEM_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ kmem_cache_create) >+ # >+ # Determine if the kmem_cache_create() function is >+ # present and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/slab.h> >+ void conftest_kmem_cache_create(void) { >+ kmem_cache_create(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_KMEM_CACHE_CREATE_PRESENT" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/slab.h> >+ void conftest_kmem_cache_create(void) { >+ kmem_cache_create(NULL, 0, 0, 0L, NULL, NULL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_KMEM_CACHE_CREATE_PRESENT" >> conftest.h >+ echo "#define NV_KMEM_CACHE_CREATE_ARGUMENT_COUNT 6 " >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/slab.h> >+ void conftest_kmem_cache_create(void) { >+ kmem_cache_create(NULL, 0, 0, 0L, NULL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_KMEM_CACHE_CREATE_PRESENT" >> conftest.h >+ echo "#define NV_KMEM_CACHE_CREATE_ARGUMENT_COUNT 5 " >> conftest.h >+ return >+ else >+ echo "#error kmem_cache_create() conftest failed!" >> conftest.h >+ fi >+ ;; >+ >+ smp_call_function) >+ # >+ # Determine if the smp_call_function() function is >+ # present and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_smp_call_function(void) { >+ #ifdef CONFIG_SMP >+ smp_call_function(); >+ #endif >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_SMP_CALL_FUNCTION_PRESENT" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_smp_call_function(void) { >+ smp_call_function(NULL, NULL, 0, 0); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_SMP_CALL_FUNCTION_PRESENT" >> conftest.h >+ echo "#define NV_SMP_CALL_FUNCTION_ARGUMENT_COUNT 4 " >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_smp_call_function(void) { >+ smp_call_function(NULL, NULL, 0); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_SMP_CALL_FUNCTION_PRESENT" >> conftest.h >+ echo "#define NV_SMP_CALL_FUNCTION_ARGUMENT_COUNT 3 " >> conftest.h >+ return >+ else >+ echo "#error smp_call_function() conftest failed!" >> conftest.h >+ fi >+ ;; >+ >+ on_each_cpu) >+ # >+ # Determine if the on_each_cpu() function is present >+ # and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_on_each_cpu(void) { >+ #ifdef CONFIG_SMP >+ on_each_cpu(); >+ #endif >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_ON_EACH_CPU_PRESENT" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_on_each_cpu(void) { >+ on_each_cpu(NULL, NULL, 0, 0); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ON_EACH_CPU_PRESENT" >> conftest.h >+ echo "#define NV_ON_EACH_CPU_ARGUMENT_COUNT 4 " >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/smp.h> >+ void conftest_on_each_cpu(void) { >+ on_each_cpu(NULL, NULL, 0); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ON_EACH_CPU_PRESENT" >> conftest.h >+ echo "#define NV_ON_EACH_CPU_ARGUMENT_COUNT 3 " >> conftest.h >+ return >+ else >+ echo "#error on_each_cpu() conftest failed!" >> conftest.h >+ fi >+ ;; >+ >+ acpi_evaluate_integer) >+ # >+ # Determine if the acpi_evaluate_integer() function is >+ # present and the type of its 'data' argument. >+ # >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi_bus.h> >+ acpi_status acpi_evaluate_integer(acpi_handle h, acpi_string s, >+ struct acpi_object_list *l, unsigned long long *d) { >+ return AE_OK; >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ACPI_EVALUATE_INTEGER_PRESENT" >> conftest.h >+ echo "typedef unsigned long long nv_acpi_integer_t;" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi_bus.h> >+ acpi_status acpi_evaluate_integer(acpi_handle h, acpi_string s, >+ struct acpi_object_list *l, unsigned long *d) { >+ return AE_OK; >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ACPI_EVALUATE_INTEGER_PRESENT" >> conftest.h >+ echo "typedef unsigned long nv_acpi_integer_t;" >> conftest.h >+ return >+ else >+ # >+ # We can't report a compile test failure here because >+ # this is a catch-all for both kernels that don't >+ # have acpi_evaluate_integer() and kernels that have >+ # broken header files that make it impossible to >+ # tell if the function is present. >+ # >+ echo "#undef NV_ACPI_EVALUATE_INTEGER_PRESENT" >> conftest.h >+ echo "typedef unsigned long nv_acpi_integer_t;" >> conftest.h >+ fi >+ ;; >+ >+ acpi_walk_namespace) >+ # >+ # Determine if the acpi_walk_namespace() function is present >+ # and how many arguments it takes. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi.h> >+ void conftest_acpi_walk_namespace(void) { >+ acpi_walk_namespace(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_ACPI_WALK_NAMESPACE_PRESENT" >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi.h> >+ void conftest_acpi_walk_namespace(void) { >+ acpi_walk_namespace(0, NULL, 0, NULL, NULL, NULL, NULL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ACPI_WALK_NAMESPACE_PRESENT" >> conftest.h >+ echo "#define NV_ACPI_WALK_NAMESPACE_ARGUMENT_COUNT 7 " >> conftest.h >+ return >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <acpi/acpi.h> >+ void conftest_acpi_walk_namespace(void) { >+ acpi_walk_namespace(0, NULL, 0, NULL, NULL, NULL); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#define NV_ACPI_WALK_NAMESPACE_PRESENT" >> conftest.h >+ echo "#define NV_ACPI_WALK_NAMESPACE_ARGUMENT_COUNT 6 " >> conftest.h >+ return >+ else >+ echo "#error acpi_walk_namespace() conftest failed!" >> conftest.h >+ fi >+ ;; >+ >+ ioremap_cache) >+ # >+ # Determine if the ioremap_cache() function is present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <asm/io.h> >+ void conftest_ioremap_cache(void) { >+ ioremap_cache(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_IOREMAP_CACHE_PRESENT" >> conftest.h >+ return >+ else >+ echo "#define NV_IOREMAP_CACHE_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ ioremap_wc) >+ # >+ # Determine if the ioremap_wc() function is present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <asm/io.h> >+ void conftest_ioremap_wc(void) { >+ ioremap_wc(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ rm -f conftest$$.o >+ echo "#undef NV_IOREMAP_WC_PRESENT" >> conftest.h >+ return >+ else >+ echo "#define NV_IOREMAP_WC_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ proc_dir_entry) >+ # >+ # Determine if the 'proc_dir_entry' structure has >+ # an 'owner' member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/proc_fs.h> >+ int conftest_proc_dir_entry(void) { >+ return offsetof(struct proc_dir_entry, owner); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_PROC_DIR_ENTRY_HAS_OWNER" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#undef NV_PROC_DIR_ENTRY_HAS_OWNER" >> conftest.h >+ return >+ fi >+ ;; >+ >+ agp_memory) >+ # >+ # Determine if the 'agp_memory' structure has >+ # a 'pages' member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/agp_backend.h> >+ int conftest_agp_memory(void) { >+ return offsetof(struct agp_memory, pages); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_AGP_MEMORY_HAS_PAGES" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#undef NV_AGP_MEMORY_HAS_PAGES" >> conftest.h >+ return >+ fi >+ ;; >+ >+ scatterlist) >+ # >+ # Determine if the 'scatterlist' structure has >+ # a 'page_link' member. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/scatterlist.h> >+ int conftest_scatterlist(void) { >+ return offsetof(struct scatterlist, page_link); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_SCATTERLIST_HAS_PAGE" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_SCATTERLIST_HAS_PAGE" >> conftest.h >+ return >+ fi >+ ;; >+ >+ file_operations) >+ # >+ # Determine if the 'file_operations' structure has >+ # 'ioctl', 'unlocked_ioctl' and 'compat_ioctl' fields. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/fs.h> >+ int conftest_file_operations(void) { >+ return offsetof(struct file_operations, ioctl); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_FILE_OPERATIONS_HAS_IOCTL" >> conftest.h >+ rm -f conftest$$.o >+ else >+ echo "#undef NV_FILE_OPERATIONS_HAS_IOCTL" >> conftest.h >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/fs.h> >+ int conftest_file_operations(void) { >+ return offsetof(struct file_operations, unlocked_ioctl); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_FILE_OPERATIONS_HAS_UNLOCKED_IOCTL" >> conftest.h >+ rm -f conftest$$.o >+ else >+ echo "#undef NV_FILE_OPERATIONS_HAS_UNLOCKED_IOCTL" >> conftest.h >+ fi >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/fs.h> >+ int conftest_file_operations(void) { >+ return offsetof(struct file_operations, compat_ioctl); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#define NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL" >> conftest.h >+ rm -f conftest$$.o >+ else >+ echo "#undef NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL" >> conftest.h >+ fi >+ ;; >+ >+ sg_init_table) >+ # >+ # Determine if the sg_init_table() function is present. >+ # >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/scatterlist.h> >+ void conftest_sg_init_table(struct scatterlist *sgl, >+ unsigned int nents) { >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ ! -f conftest$$.o ]; then >+ echo "#undef NV_SG_INIT_TABLE_PRESENT" >> conftest.h >+ return >+ >+ fi >+ rm -f conftest$$.o >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/types.h> >+ #include <linux/scatterlist.h> >+ void conftest_sg_init_table(struct scatterlist *sgl, >+ unsigned int nents) { >+ sg_init_table(); >+ }" > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ -f conftest$$.o ]; then >+ echo "#undef NV_SG_INIT_TABLE_PRESENT" >> conftest.h >+ rm -f conftest$$.o >+ return >+ else >+ echo "#define NV_SG_INIT_TABLE_PRESENT" >> conftest.h >+ return >+ fi >+ ;; >+ >+ esac >+} >+ >+build_cflags >+ >+case "$5" in >+ cc_sanity_check) >+ # >+ # Check if the selected compiler can create executables >+ # in the current environment. >+ # >+ VERBOSE=$6 >+ >+ echo "#include <stdio.h> >+ int main(int argc, char *argv[]) { >+ return 0; >+ }" > conftest$$.c >+ >+ $HOSTCC -o conftest$$ conftest$$.c > /dev/null 2>&1 >+ rm -f conftest$$.c >+ >+ if [ ! -x conftest$$ ]; then >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo ""; >+ fi >+ if [ "$CC" != "cc" ]; then >+ echo "The C compiler '$CC' does not appear to be able to" >+ echo "create executables. Please make sure you have " >+ echo "your Linux distribution's libc development package" >+ echo "installed and that '$CC' is a valid C compiler"; >+ echo "name." >+ else >+ echo "The C compiler '$CC' does not appear to be able to" >+ echo "create executables. Please make sure you have " >+ echo "your Linux distribution's gcc and libc development" >+ echo "packages installed." >+ fi >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo ""; >+ echo "*** Failed CC sanity check. Bailing out! ***"; >+ echo ""; >+ fi >+ exit 1 >+ else >+ rm conftest$$ >+ exit 0 >+ fi >+ ;; >+ >+ cc_version_check) >+ # >+ # Verify that the same compiler is used for the kernel and kernel >+ # module. >+ # >+ VERBOSE=$6 >+ >+ if [ -n "$IGNORE_CC_MISMATCH" -o -n "$SYSSRC" -o -n "$SYSINCLUDE" ]; then >+ # >+ # The user chose to disable the CC version test (which may or >+ # may not be wise) or is building the module for a kernel not >+ # currently running, which renders the test meaningless. >+ # >+ exit 0 >+ fi >+ >+ rm -f gcc-version-check >+ $CC gcc-version-check.c -o gcc-version-check > /dev/null 2>&1 >+ if [ ! -f gcc-version-check ]; then >+ if [ "$CC" != "cc" ]; then >+ MSG="Could not compile 'gcc-version-check.c'. Please be " >+ MSG="$MSG sure you have your Linux distribution's libc " >+ MSG="$MSG development package installed and that '$CC' " >+ MSG="$MSG is a valid C compiler name." >+ else >+ MSG="Could not compile 'gcc-version-check.c'. Please be " >+ MSG="$MSG sure you have your Linux distribution's gcc " >+ MSG="$MSG and libc development packages installed." >+ fi >+ RET=1 >+ else >+ PROC_VERSION="/proc/version" >+ if [ -f $PROC_VERSION ]; then >+ MSG=`./gcc-version-check "$(cat $PROC_VERSION)"` >+ RET=$? >+ else >+ MSG="$PROC_VERSION does not exist." >+ RET=1 >+ fi >+ rm -f gcc-version-check >+ fi >+ >+ if [ "$RET" != "0" ]; then >+ # >+ # The gcc version check failed >+ # >+ >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo ""; >+ echo "gcc-version-check failed:"; >+ echo ""; >+ echo "$MSG" | fmt -w 52 >+ echo ""; >+ echo "If you know what you are doing and want to override"; >+ echo "the gcc version check, you can do so by setting the"; >+ echo "IGNORE_CC_MISMATCH environment variable to \"1\"."; >+ echo ""; >+ echo "In any other case, set the CC environment variable"; >+ echo "to the name of the compiler that was used to compile"; >+ echo "the kernel."; >+ echo "" >+ echo "*** Failed CC version check. Bailing out! ***"; >+ echo ""; >+ else >+ echo "$MSG"; >+ fi >+ exit 1; >+ else >+ exit 0 >+ fi >+ ;; >+ >+ kernel_patch_level) >+ # >+ # Determine the kernel's major patch level; this is only done if we >+ # aren't told by KBUILD. >+ # >+ MAKEFILE=$HEADERS/../Makefile >+ >+ if [ -f $MAKEFILE ]; then >+ PATCHLEVEL=$(grep "^PATCHLEVEL =" $MAKEFILE | cut -d " " -f 3) >+ >+ if [ -z "$PATCHLEVEL" ]; then >+ exit 1 >+ else >+ echo $PATCHLEVEL >+ exit 0 >+ fi >+ fi >+ ;; >+ >+ suser_sanity_check) >+ # >+ # Determine the caller's user id to determine if we have sufficient >+ # privileges for the requested operation. >+ # >+ if [ $(id -ur) != 0 ]; then >+ echo ""; >+ echo "Please run \"make install\" as root."; >+ echo ""; >+ echo "*** Failed super-user sanity check. Bailing out! ***"; >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ rmmod_sanity_check) >+ # >+ # Make sure that any currently loaded NVIDIA kernel module can be >+ # unloaded. >+ # >+ MODULE="nvidia" >+ >+ if [ -n "$SYSSRC" -o -n "$SYSINCLUDE" ]; then >+ # >+ # Don't attempt to remove the kernel module if we're not >+ # building against the running kernel. >+ # >+ exit 0 >+ fi >+ >+ if lsmod | grep -wq $MODULE; then >+ rmmod $MODULE > /dev/null 2>&1 >+ fi >+ >+ if lsmod | grep -wq $MODULE; then >+ # >+ # The NVIDIA kernel module is still loaded, most likely because >+ # it is busy. >+ # >+ echo ""; >+ echo "Unable to remove existing NVIDIA kernel module."; >+ echo "Please be sure you have exited X before attempting"; >+ echo "to install the NVIDIA kernel module."; >+ echo ""; >+ echo "*** Failed rmmod sanity check. Bailing out! ***"; >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ select_makefile) >+ # >+ # Select which Makefile to use based on the version of the >+ # kernel we are building against: use the kbuild Makefile for >+ # 2.6 and newer kernels, and the old Makefile for kernels older >+ # than 2.6. >+ # >+ rm -f Makefile >+ RET=1 >+ VERBOSE=$6 >+ FILE="linux/version.h" >+ SELECTED_MAKEFILE="" >+ >+ if [ -f $HEADERS/$FILE -o -f $OUTPUT/include/$FILE ]; then >+ # >+ # We are either looking at a configured kernel source >+ # tree or at headers shipped for a specific kernel. >+ # Determine the kernel version using a compile check. >+ # >+ rm -f conftest.h >+ test_headers >+ >+ echo "$CONFTEST_PREAMBLE >+ #include <linux/version.h> >+ #include <linux/utsname.h> >+ #if defined(TEST_2_4) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) >+ #error \"!KERNEL_2_4\" >+ #endif >+ #if defined(TEST_2_6_OR_3) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) >+ #error \"!KERNEL_2_6_OR_3\" >+ #endif" > conftest$$.c >+ >+ $CC $CFLAGS -DTEST_2_6_OR_3 -c conftest$$.c > /dev/null 2>&1 >+ >+ if [ -f conftest$$.o ]; then >+ if [ -f Makefile.rmlite ]; then >+ SELECTED_MAKEFILE=Makefile.rmlite >+ else >+ SELECTED_MAKEFILE=Makefile.kbuild >+ fi >+ RET=0 >+ else >+ $CC $CFLAGS -DTEST_2_4 -c conftest$$.c > /dev/null 2>&1 >+ >+ if [ -f conftest$$.o ]; then >+ SELECTED_MAKEFILE=Makefile.nvidia >+ RET=0 >+ fi >+ fi >+ >+ rm -f conftest$$.c conftest$$.o >+ rm -f conftest.h >+ else >+ MAKEFILE=$HEADERS/../Makefile >+ CONFIG=$HEADERS/../.config >+ >+ if [ -f $MAKEFILE -a -f $CONFIG ]; then >+ # >+ # This source tree is not configured, but includes >+ # a Makefile and a .config file. If this is a 2.6 >+ # kernel older than 2.6.6, that's all we require to >+ # build the module. >+ # >+ PATCHLEVEL=$(grep "^PATCHLEVEL =" $MAKEFILE | cut -d " " -f 3) >+ SUBLEVEL=$(grep "^SUBLEVEL =" $MAKEFILE | cut -d " " -f 3) >+ >+ if [ -n "$PATCHLEVEL" -a $PATCHLEVEL -ge 6 \ >+ -a -n "$SUBLEVEL" -a $SUBLEVEL -le 5 ]; then >+ SELECTED_MAKEFILE=Makefile.kbuild >+ RET=0 >+ fi >+ fi >+ fi >+ >+ if [ "$RET" = "0" ]; then >+ ln -s $SELECTED_MAKEFILE Makefile >+ exit 0 >+ else >+ echo "If you are using a Linux 2.4 kernel, please make sure"; >+ echo "you either have configured kernel sources matching your"; >+ echo "kernel or the correct set of kernel headers installed"; >+ echo "on your system."; >+ echo ""; >+ echo "If you are using a Linux 2.6 kernel, please make sure"; >+ echo "you have configured kernel sources matching your kernel"; >+ echo "installed on your system. If you specified a separate"; >+ echo "output directory using either the \"KBUILD_OUTPUT\" or"; >+ echo "the \"O\" KBUILD parameter, make sure to specify this"; >+ echo "directory with the SYSOUT environment variable or with"; >+ echo "the equivalent nvidia-installer command line option."; >+ echo ""; >+ echo "Depending on where and how the kernel sources (or the"; >+ echo "kernel headers) were installed, you may need to specify"; >+ echo "their location with the SYSSRC environment variable or"; >+ echo "the equivalent nvidia-installer command line option."; >+ echo ""; >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo "*** Unable to determine the target kernel version. ***"; >+ echo ""; >+ fi >+ exit 1 >+ fi >+ ;; >+ >+ get_uname) >+ # >+ # Print UTS_RELEASE from the kernel sources, if the kernel header >+ # file ../linux/version.h or ../linux/utsrelease.h exists. If >+ # neither header file is found, but a Makefile is found, extract >+ # PATCHLEVEL and SUBLEVEL, and use them to build the kernel >+ # release name. >+ # >+ # If no source file is found, or if an error occurred, return the >+ # output of `uname -r`. >+ # >+ RET=1 >+ DIRS="generated linux" >+ FILE="" >+ >+ for DIR in $DIRS; do >+ if [ -f $HEADERS/$DIR/utsrelease.h ]; then >+ FILE="$HEADERS/$DIR/utsrelease.h" >+ break >+ elif [ -f $OUTPUT/include/$DIR/utsrelease.h ]; then >+ FILE="$OUTPUT/include/$DIR/utsrelease.h" >+ break >+ fi >+ done >+ >+ if [ -z "$FILE" ]; then >+ if [ -f $HEADERS/linux/version.h ]; then >+ FILE="$HEADERS/linux/version.h" >+ elif [ -f $OUTPUT/include/linux/version.h ]; then >+ FILE="$OUTPUT/include/linux/version.h" >+ fi >+ fi >+ >+ if [ -n "$FILE" ]; then >+ # >+ # We are either looking at a configured kernel source tree >+ # or at headers shipped for a specific kernel. Determine >+ # the kernel version using a CPP check. >+ # >+ VERSION=`echo "UTS_RELEASE" | $CC - -E -P -include $FILE 2>&1` >+ >+ if [ "$?" = "0" -a "VERSION" != "UTS_RELEASE" ]; then >+ echo "$VERSION" >+ RET=0 >+ fi >+ else >+ # >+ # If none of the kernel headers ar found, but a Makefile is, >+ # extract PATCHLEVEL and SUBLEVEL and use them to find >+ # the kernel version. >+ # >+ MAKEFILE=$HEADERS/../Makefile >+ >+ if [ -f $MAKEFILE ]; then >+ # >+ # This source tree is not configured, but includes >+ # the top-level Makefile. >+ # >+ PATCHLEVEL=$(grep "^PATCHLEVEL =" $MAKEFILE | cut -d " " -f 3) >+ SUBLEVEL=$(grep "^SUBLEVEL =" $MAKEFILE | cut -d " " -f 3) >+ >+ if [ -n "$PATCHLEVEL" -a -n "$SUBLEVEL" ]; then >+ echo 2.$PATCHLEVEL.$SUBLEVEL >+ RET=0 >+ fi >+ fi >+ fi >+ >+ if [ "$RET" != "0" ]; then >+ uname -r >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ rivafb_sanity_check) >+ # >+ # Check if the kernel was compiled with rivafb support. If so, then >+ # exit, since the driver no longer works with rivafb. >+ # >+ RET=1 >+ VERBOSE=$6 >+ OLD_FILE="linux/autoconf.h" >+ NEW_FILE="generated/autoconf.h" >+ >+ if [ -f $HEADERS/$NEW_FILE -o -f $OUTPUT/include/$NEW_FILE ]; then >+ FILE=$NEW_FILE >+ fi >+ if [ -f $HEADERS/$OLD_FILE -o -f $OUTPUT/include/$OLD_FILE ]; then >+ FILE=$OLD_FILE >+ fi >+ >+ if [ -n "$FILE" ]; then >+ # >+ # We are looking at a configured source tree; verify >+ # that its configuration doesn't include rivafb using >+ # a compile check. >+ # >+ rm -f conftest.h >+ test_headers >+ >+ echo "$CONFTEST_PREAMBLE >+ #ifdef CONFIG_FB_RIVA >+ #error CONFIG_FB_RIVA defined! >+ #endif >+ " > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ >+ if [ -f conftest$$.o ]; then >+ RET=0 >+ fi >+ >+ rm -f conftest$$.c conftest$$.o >+ rm -f conftest.h >+ else >+ CONFIG=$HEADERS/../.config >+ if [ -f $CONFIG ]; then >+ if [ -z "$(grep "^CONFIG_FB_RIVA=y" $CONFIG)" ]; then >+ RET=0 >+ fi >+ fi >+ fi >+ >+ if [ "$RET" != "0" ]; then >+ echo "Your kernel was configured to include rivafb support!"; >+ echo ""; >+ echo "The rivafb driver conflicts with the NVIDIA driver, please"; >+ echo "reconfigure your kernel and *disable* rivafb support, then"; >+ echo "try installing the NVIDIA kernel module again."; >+ echo ""; >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo "*** Failed rivafb sanity check. Bailing out! ***"; >+ echo ""; >+ fi >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ nvidiafb_sanity_check) >+ # >+ # Check if the kernel was compiled with nvidiafb support. If so, then >+ # exit, since the driver doesn't work with nvidiafb. >+ # >+ RET=1 >+ VERBOSE=$6 >+ OLD_FILE="linux/autoconf.h" >+ NEW_FILE="generated/autoconf.h" >+ >+ if [ -f $HEADERS/$NEW_FILE -o -f $OUTPUT/include/$NEW_FILE ]; then >+ FILE=$NEW_FILE >+ fi >+ if [ -f $HEADERS/$OLD_FILE -o -f $OUTPUT/include/$OLD_FILE ]; then >+ FILE=$OLD_FILE >+ fi >+ >+ if [ -n "$FILE" ]; then >+ # >+ # We are looking at a configured source tree; verify >+ # that its configuration doesn't include nvidiafb using >+ # a compile check. >+ # >+ rm -f conftest.h >+ test_headers >+ >+ echo "$CONFTEST_PREAMBLE >+ #ifdef CONFIG_FB_NVIDIA >+ #error CONFIG_FB_NVIDIA defined! >+ #endif >+ " > conftest$$.c >+ >+ $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 >+ >+ if [ -f conftest$$.o ]; then >+ RET=0 >+ fi >+ >+ rm -f conftest$$.c conftest$$.o >+ rm -f conftest.h >+ else >+ CONFIG=$HEADERS/../.config >+ if [ -f $CONFIG ]; then >+ if [ -z "$(grep "^CONFIG_FB_NVIDIA=y" $CONFIG)" ]; then >+ RET=0 >+ fi >+ fi >+ fi >+ >+ if [ "$RET" != "0" ]; then >+ echo "Your kernel was configured to include nvidiafb support!"; >+ echo ""; >+ echo "The nvidiafb driver conflicts with the NVIDIA driver, please"; >+ echo "reconfigure your kernel and *disable* nvidiafb support, then"; >+ echo "try installing the NVIDIA kernel module again."; >+ echo ""; >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo "*** Failed nvidiafb sanity check. Bailing out! ***"; >+ echo ""; >+ fi >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ xen_sanity_check) >+ # >+ # Check if the target kernel is a Xen kernel. If so, then exit, since >+ # the driver doesn't currently work with Xen. >+ # >+ VERBOSE=$6 >+ >+ if [ -n "$IGNORE_XEN_PRESENCE" ]; then >+ exit 0 >+ fi >+ >+ if [ "$XEN_PRESENT" != "0" ]; then >+ echo "The kernel you are installing for is a Xen kernel!"; >+ echo ""; >+ echo "The NVIDIA driver does not currently work on Xen kernels. If "; >+ echo "you are using a stock distribution kernel, please install "; >+ echo "a variant of this kernel without Xen support; if this is a "; >+ echo "custom kernel, please install a standard Linux kernel. Then "; >+ echo "try installing the NVIDIA kernel module again."; >+ echo ""; >+ if [ "$VERBOSE" = "full_output" ]; then >+ echo "*** Failed Xen sanity check. Bailing out! ***"; >+ echo ""; >+ fi >+ exit 1 >+ else >+ exit 0 >+ fi >+ ;; >+ >+ patch_check) >+ # >+ # Check for any "official" patches that may have been applied and >+ # construct a description table for reporting purposes. >+ # >+ PATCHES="" >+ >+ for PATCH in patch-*.h; do >+ if [ -f $PATCH ]; then >+ echo "#include \"$PATCH\"" >> patches.h >+ PATCHES="$PATCHES "`echo $PATCH | sed -s 's/patch-\(.*\)\.h/\1/'` >+ fi >+ done >+ >+ echo "static struct { >+ const char *short_description; >+ const char *description; >+ } __nv_patches[] = {" >> patches.h >+ for i in $PATCHES; do >+ echo "{ \"$i\", NV_PATCH_${i}_DESCRIPTION }," >> patches.h >+ done >+ echo "{ NULL, NULL } };" >> patches.h >+ >+ exit 0 >+ ;; >+ >+ compile_tests) >+ # >+ # Run a series of compile tests to determine the set of interfaces >+ # and features available in the target kernel. >+ # >+ shift 5 >+ >+ rm -f conftest.h >+ test_headers >+ >+ for i in $*; do compile_test $i; done >+ >+ if [ -n "$SHOW_COMPILE_TEST_RESULTS" -a -f conftest.h ]; then >+ cat conftest.h >+ fi >+ >+ exit 0 >+ ;; >+ >+esac >diff -urN usr.orig/src/nv/nv-linux.h usr/src/nv/nv-linux.h >--- usr.orig/src/nv/nv-linux.h 2012-08-31 14:04:44.000000000 -0800 >+++ usr/src/nv/nv-linux.h 2014-05-10 21:02:17.747162867 -0800 >@@ -64,6 +64,18 @@ > #include <linux/module.h> > #include <linux/kmod.h> > >+#include <linux/mm.h> >+ >+#if !defined(VM_RESERVED) >+#define VM_RESERVED 0x00000000 >+#endif >+#if !defined(VM_DONTEXPAND) >+#define VM_DONTEXPAND 0x00000000 >+#endif >+#if !defined(VM_DONTDUMP) >+#define VM_DONTDUMP 0x00000000 >+#endif >+ > #include <linux/init.h> /* module_init, module_exit */ > #include <linux/types.h> /* pic_t, size_t, __u32, etc */ > #include <linux/errno.h> /* error codes */ >diff -urN usr.orig/src/nv/nv.c usr/src/nv/nv.c >--- usr.orig/src/nv/nv.c 2012-08-31 14:04:44.000000000 -0800 >+++ usr/src/nv/nv.c 2014-05-10 21:02:17.745162613 -0800 >@@ -2348,9 +2348,8 @@ > NV_PRINT_AT(NV_DBG_MEMINFO, at); > nv_vm_list_page_count(&at->page_table[i], pages); > >- /* prevent the swapper from swapping it out */ >- /* mark the memory i/o so the buffers aren't dumped on core dumps */ > vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED); >+ vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP); > } > > NV_VMA_FILE(vma) = file; >diff -urN usr.orig/src/nv/nv.c.orig usr/src/nv/nv.c.orig >--- usr.orig/src/nv/nv.c.orig 1969-12-31 14:00:00.000000000 -1000 >+++ usr/src/nv/nv.c.orig 2012-08-31 14:04:44.000000000 -0800 >@@ -0,0 +1,4159 @@ >+/* _NVRM_COPYRIGHT_BEGIN_ >+ * >+ * Copyright 1999-2001 by NVIDIA Corporation. All rights reserved. All >+ * information contained herein is proprietary and confidential to NVIDIA >+ * Corporation. Any use, reproduction, or disclosure without the written >+ * permission of NVIDIA Corporation is prohibited. >+ * >+ * _NVRM_COPYRIGHT_END_ >+ */ >+ >+#include "nv-misc.h" >+#include "os-interface.h" >+#include "nv-linux.h" >+#include "nv_compiler.h" >+#include "os-agp.h" >+#include "nv-vm.h" >+ >+#if defined(MODULE_LICENSE) >+MODULE_LICENSE("NVIDIA"); >+#endif >+#if defined(MODULE_INFO) >+MODULE_INFO(supported, "external"); >+#endif >+ >+#ifdef MODULE_ALIAS_CHARDEV_MAJOR >+MODULE_ALIAS_CHARDEV_MAJOR(NV_MAJOR_DEVICE_NUMBER); >+#endif >+ >+#if defined(KERNEL_2_4) && (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) >+extern int i2c_add_adapter (struct i2c_adapter *) __attribute__ ((weak)); >+extern int i2c_del_adapter (struct i2c_adapter *) __attribute__ ((weak)); >+#endif >+ >+#include "patches.h" >+ >+/* >+ * our global state; one per device >+ */ >+ >+static U032 num_nv_devices = 0; >+static U032 num_probed_nv_devices = 0; >+ >+nv_linux_state_t nv_linux_devices[NV_MAX_DEVICES]; >+EXPORT_SYMBOL(nv_linux_devices); >+ >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+static struct pm_dev *apm_nv_dev[NV_MAX_DEVICES] = { 0 }; >+#endif >+ >+int nv_pat_mode = NV_PAT_MODE_DISABLED; >+ >+#if defined(NVCPU_X86) || defined(NVCPU_X86_64) >+NvU64 __nv_supported_pte_mask = ~_PAGE_NX; >+#endif >+ >+/* >+ * And one for the control device >+ */ >+ >+nv_linux_state_t nv_ctl_device = { { 0 } }; >+wait_queue_head_t nv_ctl_waitqueue; >+ >+#ifdef CONFIG_PROC_FS >+struct proc_dir_entry *proc_nvidia; >+struct proc_dir_entry *proc_nvidia_warnings; >+struct proc_dir_entry *proc_nvidia_patches; >+#endif >+ >+static const char *__README_warning = \ >+ "The NVIDIA graphics driver tries to detect potential problems\n" >+ "with the host system and warns about them using the system's\n" >+ "logging mechanisms. Important warning message are also logged\n" >+ "to dedicated text files in this directory.\n"; >+ >+static const char *__README_patches = \ >+ "The NVIDIA graphics driver's kernel interface files can be\n" >+ "patched to improve compatibility with new Linux kernels or to\n" >+ "fix bugs in these files. When applied, each official patch\n" >+ "provides a short text file with a short description of itself\n" >+ "in this directory.\n"; >+ >+#if defined(NV_SWIOTLB) >+static const char *__swiotlb_warning = \ >+ "You are probably using the kernel's SWIOTLB interface.\n\n" >+ "Be very careful with this interface, as it is easy to exhaust\n" >+ "its memory buffer, at which point it may panic the kernel.\n" >+ "Please increase the default size of this buffer by specifying\n" >+ "a larger buffer size with the \"swiotlb\" kernel parameter,\n" >+ "e.g.: \"swiotlb=16384\".\n"; >+#endif >+ >+#if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) >+static const char *__cpgattr_warning = \ >+ "Your Linux kernel has known problems in its implementation of\n" >+ "the change_page_attr() kernel interface.\n\n" >+ "The NVIDIA graphics driver will attempt to work around these\n" >+ "problems, but system stability may be adversely affected.\n" >+ "It is recommended that you update to Linux 2.6.11 (or a newer\n" >+ "Linux kernel release).\n"; >+ >+static const char *__cpgattr_warning_2 = \ >+ "Your Linux kernel's version and architecture indicate that it\n" >+ "may have an implementation of the change_page_attr() kernel\n" >+ "kernel interface known to have problems. The NVIDIA graphics\n" >+ "driver made an attempt to determine whether your kernel is\n" >+ "affected, but could not. It will assume the interface does not\n" >+ "work correctly and attempt to employ workarounds.\n" >+ "This may adversely affect system stability.\n" >+ "It is recommended that you update to Linux 2.6.11 (or a newer\n" >+ "Linux kernel release).\n"; >+#endif >+ >+static const char *__mmconfig_warning = \ >+ "Your current system configuration has known problems when\n" >+ "accessing PCI Configuration Space that can lead to accesses\n" >+ "to the PCI Configuration Space of the wrong PCI device. This\n" >+ "is known to cause instabilities with the NVIDIA graphics driver.\n\n" >+ "Please see the MMConfig section in the readme for more information\n" >+ "on how to work around this problem.\n"; >+ >+#if defined(NV_SG_MAP_BUFFERS) >+int nv_swiotlb = 0; >+#if defined(NV_NEED_REMAP_CHECK) >+unsigned int nv_remap_count; >+unsigned int nv_remap_limit; >+#endif >+#endif >+ >+int nv_update_memory_types = 1; >+static int nv_mmconfig_failure_detected = 0; >+ >+static void *nv_pte_t_cache = NULL; >+ >+// allow an easy way to convert all debug printfs related to events >+// back and forth between 'info' and 'errors' >+#if defined(NV_DBG_EVENTS) >+#define NV_DBG_EVENTINFO NV_DBG_ERRORS >+#else >+#define NV_DBG_EVENTINFO NV_DBG_INFO >+#endif >+ >+/*** >+ *** STATIC functions, only in this file >+ ***/ >+ >+/* nvos_ functions.. do not take a state device parameter */ >+static int nvos_post_vbios(void *, int); >+static void nvos_proc_create(void); >+static void nvos_proc_add_text_file(struct proc_dir_entry *, >+ const char *, const char *); >+static void nvos_proc_remove_all(struct proc_dir_entry *); >+static void nvos_proc_remove(void); >+static int nvos_count_devices(void); >+ >+static nv_alloc_t *nvos_create_alloc(struct pci_dev *, int); >+static int nvos_free_alloc(nv_alloc_t *); >+ >+/* nvl_ functions.. take a linux state device pointer */ >+static nv_alloc_t *nvl_find_alloc(nv_linux_state_t *, unsigned long, unsigned long); >+static int nvl_add_alloc(nv_linux_state_t *, nv_alloc_t *); >+static int nvl_remove_alloc(nv_linux_state_t *, nv_alloc_t *); >+ >+/* lock-related functions that should only be called from this file */ >+static void nv_lock_init_locks(nv_state_t *nv); >+ >+ >+/*** >+ *** EXPORTS to Linux Kernel >+ ***/ >+ >+/* nv_kern_* functions, driver interfaces called by the Linux kernel */ >+static void nv_kern_vma_open(struct vm_area_struct *); >+static void nv_kern_vma_release(struct vm_area_struct *); >+ >+int nv_kern_open(struct inode *, struct file *); >+int nv_kern_close(struct inode *, struct file *); >+int nv_kern_mmap(struct file *, struct vm_area_struct *); >+unsigned int nv_kern_poll(struct file *, poll_table *); >+int nv_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long); >+long nv_kern_unlocked_ioctl(struct file *, unsigned int, unsigned long); >+long nv_kern_compat_ioctl(struct file *, unsigned int, unsigned long); >+void nv_kern_isr_bh(unsigned long); >+#if !defined(NV_IRQ_HANDLER_T_PRESENT) || (NV_IRQ_HANDLER_T_ARGUMENT_COUNT == 3) >+irqreturn_t nv_kern_isr(int, void *, struct pt_regs *); >+#else >+irqreturn_t nv_kern_isr(int, void *); >+#endif >+void nv_kern_rc_timer(unsigned long); >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+static int nv_kern_apm_event(struct pm_dev *, pm_request_t, void *); >+#endif >+ >+static int nv_kern_read_cardinfo(char *, char **, off_t off, int, int *, void *); >+static int nv_kern_read_status(char *, char **, off_t off, int, int *, void *); >+static int nv_kern_read_registry(char *, char **, off_t off, int, int *, void *); >+static int nv_kern_read_agpinfo(char *, char **, off_t off, int, int *, void *); >+static int nv_kern_read_version(char *, char **, off_t off, int, int *, void *); >+static int nv_kern_read_text_file(char *, char **, off_t off, int, int *, void *); >+ >+int nv_kern_ctl_open(struct inode *, struct file *); >+int nv_kern_ctl_close(struct inode *, struct file *); >+unsigned int nv_kern_ctl_poll(struct file *, poll_table *); >+ >+int nv_kern_probe(struct pci_dev *, const struct pci_device_id *); >+ >+#if defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL) >+static int nv_kern_suspend(struct pci_dev *, pm_message_t); >+static int nv_kern_resume(struct pci_dev *); >+#endif >+ >+/*** >+ *** see nv.h for functions exported to other parts of resman >+ ***/ >+ >+static struct pci_device_id nv_pci_table[] = { >+ { >+ .vendor = PCI_VENDOR_ID_NVIDIA, >+ .device = PCI_ANY_ID, >+ .subvendor = PCI_ANY_ID, >+ .subdevice = PCI_ANY_ID, >+ .class = (PCI_CLASS_DISPLAY_VGA << 8), >+ .class_mask = ~0 >+ }, >+ { >+ .vendor = PCI_VENDOR_ID_NVIDIA, >+ .device = PCI_ANY_ID, >+ .subvendor = PCI_ANY_ID, >+ .subdevice = PCI_ANY_ID, >+ .class = (PCI_CLASS_DISPLAY_3D << 8), >+ .class_mask = ~0 >+ }, >+ { } >+}; >+ >+MODULE_DEVICE_TABLE(pci, nv_pci_table); >+ >+static struct pci_driver nv_pci_driver = { >+ .name = "nvidia", >+ .id_table = nv_pci_table, >+ .probe = nv_kern_probe, >+#if defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL) >+ .suspend = nv_kern_suspend, >+ .resume = nv_kern_resume, >+#endif >+}; >+ >+/* character driver entry points */ >+ >+static struct file_operations nv_fops = { >+ .owner = THIS_MODULE, >+ .poll = nv_kern_poll, >+#if defined(NV_FILE_OPERATIONS_HAS_IOCTL) >+ .ioctl = nv_kern_ioctl, >+#endif >+#if defined(NV_FILE_OPERATIONS_HAS_UNLOCKED_IOCTL) >+ .unlocked_ioctl = nv_kern_unlocked_ioctl, >+#endif >+#if defined(NVCPU_X86_64) && defined(NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL) >+ .compat_ioctl = nv_kern_compat_ioctl, >+#endif >+ .mmap = nv_kern_mmap, >+ .open = nv_kern_open, >+ .release = nv_kern_close, >+}; >+ >+// Our reserved major device number. >+int nv_major = NV_MAJOR_DEVICE_NUMBER; >+ >+// pull in the pointer to the NVID stamp from the binary module >+extern const char *pNVRM_ID; >+ >+#if defined(VM_CHECKER) >+/* kernel virtual memory usage/allocation information */ >+U032 vm_usage = 0; >+struct mem_track_t *vm_list = NULL; >+nv_spinlock_t vm_lock; >+#endif >+ >+#if defined(KM_CHECKER) >+/* kernel logical memory usage/allocation information */ >+U032 km_usage = 0; >+struct mem_track_t *km_list = NULL; >+nv_spinlock_t km_lock; >+#endif >+ >+ >+/*** >+ *** STATIC functions >+ ***/ >+ >+/* specify that this card needs it's vbios posted */ >+static int nvos_post_vbios(void *args, int size) >+{ >+ nv_ioctl_post_vbios_t *info; >+ U032 i; >+ >+ if (size != sizeof(nv_ioctl_post_vbios_t)) >+ return -EINVAL; >+ >+ info = args; >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ nv_state_t *nv = NV_STATE_PTR(&nv_linux_devices[i]); >+ if (nv->bus == info->bus && nv->slot == info->slot) >+ { >+ // we assume any device was already posted and rely on >+ // X to tell us which cards need posting. But if we've >+ // already manually posted a card, it doesn't need to >+ // be reposted again. >+ if (!(nv->flags & NV_FLAG_WAS_POSTED || nv->flags & NV_FLAG_OPEN)) >+ { >+ nv->flags |= NV_FLAG_NEEDS_POSTING; >+ } >+ } >+ } >+ >+ return 0; >+} >+ >+static >+nv_alloc_t *nvos_create_alloc( >+ struct pci_dev *dev, >+ int num_pages >+) >+{ >+ nv_alloc_t *at; >+ unsigned int pt_size, i; >+ >+ NV_KMALLOC(at, sizeof(nv_alloc_t)); >+ if (at == NULL) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to allocate alloc info\n"); >+ return NULL; >+ } >+ >+ memset(at, 0, sizeof(nv_alloc_t)); >+ >+ pt_size = num_pages * sizeof(nv_pte_t *); >+ if (os_alloc_mem((void **)&at->page_table, pt_size) != RM_OK) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to allocate page table\n"); >+ NV_KFREE(at, sizeof(nv_alloc_t)); >+ return NULL; >+ } >+ >+ memset(at->page_table, 0, pt_size); >+ at->num_pages = num_pages; >+ NV_ATOMIC_SET(at->usage_count, 0); >+ >+ for (i = 0; i < at->num_pages; i++) >+ { >+ NV_KMEM_CACHE_ALLOC(at->page_table[i], nv_pte_t_cache, nv_pte_t); >+ if (at->page_table[i] == NULL) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: failed to allocate page table entry\n"); >+ nvos_free_alloc(at); >+ return NULL; >+ } >+ memset(at->page_table[i], 0, sizeof(nv_pte_t)); >+ } >+ >+ at->pid = os_get_current_process(); >+ >+ return at; >+} >+ >+static >+int nvos_free_alloc( >+ nv_alloc_t *at >+) >+{ >+ unsigned int i; >+ >+ if (at == NULL) >+ return -1; >+ >+ if (NV_ATOMIC_READ(at->usage_count)) >+ return 1; >+ >+ for (i = 0; i < at->num_pages; i++) >+ { >+ if (at->page_table[i] != NULL) >+ NV_KMEM_CACHE_FREE(at->page_table[i], nv_pte_t, nv_pte_t_cache); >+ } >+ os_free_mem(at->page_table); >+ >+ NV_KFREE(at, sizeof(nv_alloc_t)); >+ >+ return 0; >+} >+ >+static u8 nvos_find_agp_capability(struct pci_dev *dev) >+{ >+ u16 status; >+ u8 cap_ptr, cap_id; >+ >+ pci_read_config_word(dev, PCI_STATUS, &status); >+ status &= PCI_STATUS_CAP_LIST; >+ if (!status) >+ return 0; >+ >+ switch (dev->hdr_type) { >+ case PCI_HEADER_TYPE_NORMAL: >+ case PCI_HEADER_TYPE_BRIDGE: >+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); >+ break; >+ default: >+ return 0; >+ } >+ >+ do { >+ cap_ptr &= 0xfc; >+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); >+ if (cap_id == PCI_CAP_ID_AGP) >+ return cap_ptr; >+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, &cap_ptr); >+ } while (cap_ptr && cap_id != 0xff); >+ >+ return 0; >+} >+ >+static u8 nvos_find_pci_express_capability(struct pci_dev *dev) >+{ >+ u16 status; >+ u8 cap_ptr, cap_id; >+ >+ pci_read_config_word(dev, PCI_STATUS, &status); >+ status &= PCI_STATUS_CAP_LIST; >+ if (!status) >+ return 0; >+ >+ switch (dev->hdr_type) { >+ case PCI_HEADER_TYPE_NORMAL: >+ case PCI_HEADER_TYPE_BRIDGE: >+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); >+ break; >+ default: >+ return 0; >+ } >+ >+ do { >+ cap_ptr &= 0xfc; >+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); >+ if (cap_id == PCI_CAP_ID_EXP) >+ return cap_ptr; >+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, &cap_ptr); >+ } while (cap_ptr && cap_id != 0xff); >+ >+ return 0; >+} >+ >+static struct pci_dev* nvos_get_agp_device_by_class(unsigned int class) >+{ >+ struct pci_dev *dev, *fdev; >+ u32 slot, func, fn; >+ >+ dev = NV_PCI_GET_CLASS(class << 8, NULL); >+ while (dev) { >+ slot = NV_PCI_SLOT_NUMBER(dev); >+ for (func = 0; func < 8; func++) { >+ fn = PCI_DEVFN(slot, func); >+ fdev = NV_PCI_GET_SLOT(NV_PCI_BUS_NUMBER(dev), fn); >+ if (!fdev) >+ continue; >+ if (nvos_find_agp_capability(fdev)) { >+ NV_PCI_DEV_PUT(dev); >+ return fdev; >+ } >+ NV_PCI_DEV_PUT(fdev); >+ } >+ dev = NV_PCI_GET_CLASS(class << 8, dev); >+ } >+ >+ return NULL; >+} >+ >+static struct pci_dev* nv_get_pci_device(nv_state_t *nv) >+{ >+ struct pci_dev *dev; >+ >+ dev = NV_PCI_GET_DEVICE(nv->vendor_id, nv->device_id, NULL); >+ while (dev) { >+ if (NV_PCI_SLOT_NUMBER(dev) == nv->slot >+ && NV_PCI_BUS_NUMBER(dev) == nv->bus) >+ return dev; >+ dev = NV_PCI_GET_DEVICE(nv->vendor_id, nv->device_id, dev); >+ } >+ >+ return NULL; >+} >+ >+static void nvos_proc_create(void) >+{ >+#ifdef CONFIG_PROC_FS >+ struct pci_dev *dev; >+ U032 j, i = 0; >+ char name[6]; >+ >+ struct proc_dir_entry *entry; >+ struct proc_dir_entry *proc_nvidia_agp, *proc_nvidia_cards; >+ >+ /* world readable directory */ >+ int d_flags = S_IFDIR | S_IRUGO | S_IXUGO; >+ >+ /* world readable file */ >+ int flags = S_IFREG | S_IRUGO; >+ >+ nv_state_t *nv; >+ nv_linux_state_t *nvl; >+ >+ proc_nvidia = create_proc_entry("driver/nvidia", d_flags, NULL); >+ if (!proc_nvidia) >+ goto failed; >+ >+ proc_nvidia_cards = create_proc_entry("cards", d_flags, proc_nvidia); >+ if (!proc_nvidia_cards) >+ goto failed; >+ >+ proc_nvidia_warnings = create_proc_entry("warnings", d_flags, proc_nvidia); >+ if (!proc_nvidia_warnings) >+ goto failed; >+ >+ proc_nvidia_patches = create_proc_entry("patches", d_flags, proc_nvidia); >+ if (!proc_nvidia_patches) >+ goto failed; >+ >+ /* >+ * Set the module owner to ensure that the reference >+ * count reflects accesses to the proc files. >+ */ >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ proc_nvidia->owner = THIS_MODULE; >+ proc_nvidia_cards->owner = THIS_MODULE; >+ proc_nvidia_warnings->owner = THIS_MODULE; >+ proc_nvidia_patches->owner = THIS_MODULE; >+#endif >+ >+ for (j = 0; j < num_nv_devices; j++) >+ { >+ nvl = &nv_linux_devices[j]; >+ nv = NV_STATE_PTR(nvl); >+ >+ dev = nv_get_pci_device(nv); >+ if (!dev) >+ break; >+ >+ sprintf(name, "%d", i++); >+ entry = create_proc_entry(name, flags, proc_nvidia_cards); >+ if (!entry) { >+ NV_PCI_DEV_PUT(dev); >+ goto failed; >+ } >+ >+ entry->data = nv; >+ entry->read_proc = nv_kern_read_cardinfo; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ >+ if (nvos_find_agp_capability(dev)) { >+ /* >+ * Create the /proc/driver/nvidia/agp/{status,host-bridge,card} >+ * entries now that we know there's AGP hardware. >+ */ >+ entry = create_proc_entry("agp", d_flags, proc_nvidia); >+ if (!entry) { >+ NV_PCI_DEV_PUT(dev); >+ goto failed; >+ } >+ >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ proc_nvidia_agp = entry; >+ >+ entry = create_proc_entry("status", flags, proc_nvidia_agp); >+ if (!entry) { >+ NV_PCI_DEV_PUT(dev); >+ goto failed; >+ } >+ >+ entry->data = nv; >+ entry->read_proc = nv_kern_read_status; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ >+ entry = create_proc_entry("host-bridge", flags, proc_nvidia_agp); >+ if (!entry) { >+ NV_PCI_DEV_PUT(dev); >+ goto failed; >+ } >+ >+ entry->data = NULL; >+ entry->read_proc = nv_kern_read_agpinfo; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ >+ entry = create_proc_entry("card", flags, proc_nvidia_agp); >+ if (!entry) { >+ NV_PCI_DEV_PUT(dev); >+ goto failed; >+ } >+ >+ entry->data = nv; >+ entry->read_proc = nv_kern_read_agpinfo; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ } >+ >+ NV_PCI_DEV_PUT(dev); >+ } >+ >+ entry = create_proc_entry("version", flags, proc_nvidia); >+ if (!entry) >+ goto failed; >+ >+ entry->read_proc = nv_kern_read_version; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ >+ entry = create_proc_entry("registry", flags, proc_nvidia); >+ if (!entry) >+ goto failed; >+ >+ entry->read_proc = nv_kern_read_registry; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+ >+ return; >+ >+failed: >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to create /proc entries!\n"); >+ nvos_proc_remove_all(proc_nvidia); >+#endif >+} >+ >+static void >+nvos_proc_add_text_file( >+ struct proc_dir_entry *parent, >+ const char *filename, >+ const char *text >+) >+{ >+#ifdef CONFIG_PROC_FS >+ struct proc_dir_entry *entry; >+ >+ /* world readable file */ >+ int flags = S_IFREG | S_IRUGO; >+ >+ entry = create_proc_entry(filename, flags, parent); >+ if (!entry) return; >+ >+ entry->data = (void *)text; >+ entry->read_proc = nv_kern_read_text_file; >+#if defined(NV_PROC_DIR_ENTRY_HAS_OWNER) >+ entry->owner = THIS_MODULE; >+#endif >+#endif >+} >+ >+#ifdef CONFIG_PROC_FS >+static void nvos_proc_remove_all(struct proc_dir_entry *entry) >+{ >+ while (entry) { >+ struct proc_dir_entry *next = entry->next; >+ if (entry->subdir) >+ nvos_proc_remove_all(entry->subdir); >+ remove_proc_entry(entry->name, entry->parent); >+ if (entry == proc_nvidia) >+ break; >+ entry = next; >+ } >+} >+#endif >+ >+static void nvos_proc_remove(void) >+{ >+#ifdef CONFIG_PROC_FS >+ nvos_proc_remove_all(proc_nvidia); >+#endif >+} >+ >+/* >+ * Given a physical address (within the AGP aperture, plain physical >+ * or 32-bit DMA'able within the IOMMU), find and return the 'at' that >+ * owns the address, then return it to the caller. >+ */ >+static nv_alloc_t *nvl_find_alloc( >+ nv_linux_state_t *nvl, >+ unsigned long address, >+ unsigned long flags >+) >+{ >+ nv_alloc_t *at; >+ >+ for (at = nvl->alloc_queue; at; at = at->next) >+ { >+ unsigned int i; >+ >+ // make sure this 'at' matches the flags the caller provided >+ // ie, don't mistake a pci allocation with an agp allocation >+ if (!(at->flags & flags)) >+ continue; >+ >+ // most mappings will be found based on the 'key' >+ if (address == ((unsigned long) at->key_mapping)) >+ return at; >+ >+ // if agp, allow the address to fall within this range >+ if (NV_ALLOC_MAPPING_AGP(at->flags) && >+ (address >= (unsigned long) at->key_mapping) && >+ (address + PAGE_SIZE <= (unsigned long) at->key_mapping + at->num_pages * PAGE_SIZE)) >+ return at; >+ >+ for (i = 0; i < at->num_pages; i++) >+ { >+ nv_pte_t *page_ptr = at->page_table[i]; >+ >+ if ((address >= page_ptr->phys_addr) && >+ ((address - page_ptr->phys_addr) < PAGE_SIZE)) >+ return at; >+ if ((address >= page_ptr->dma_addr) && >+ ((address - page_ptr->dma_addr) < PAGE_SIZE)) >+ return at; >+ } >+ } >+ >+ /* failure is not necessarily an error if the caller >+ was just probing an address */ >+ nv_printf(NV_DBG_INFO, "NVRM: could not find map for vm 0x%lx\n", address); >+ return NULL; >+} >+ >+static int nvl_add_alloc( >+ nv_linux_state_t *nvl, >+ nv_alloc_t *at >+) >+{ >+ down(&nvl->at_lock); >+ at->next = nvl->alloc_queue; >+ nvl->alloc_queue = at; >+ up(&nvl->at_lock); >+ return 0; >+} >+ >+static int nvl_remove_alloc( >+ nv_linux_state_t *nvl, >+ nv_alloc_t *at >+) >+{ >+ nv_alloc_t *tmp, *prev; >+ >+ if (nvl->alloc_queue == at) >+ { >+ nvl->alloc_queue = nvl->alloc_queue->next; >+ return 0; >+ } >+ >+ for (tmp = prev = nvl->alloc_queue; tmp; prev = tmp, tmp = tmp->next) >+ { >+ if (tmp == at) >+ { >+ prev->next = tmp->next; >+ return 0; >+ } >+ } >+ >+ return -1; >+} >+ >+static int __nv_enable_pat_support (void); >+static void __nv_disable_pat_support (void); >+ >+#if defined(NV_ENABLE_PAT_SUPPORT) >+/* >+ * Private PAT support for use by the NVIDIA driver. This is used on >+ * kernels that do not modify the PAT to include a write-combining >+ * entry. >+ */ >+static int __determine_pat_mode (void); >+static void __nv_setup_pat_entries (void *); >+static void __nv_restore_pat_entries (void *); >+ >+#define NV_READ_PAT_ENTRIES(pat1, pat2) rdmsr(0x277, (pat1), (pat2)) >+#define NV_WRITE_PAT_ENTRIES(pat1, pat2) wrmsr(0x277, (pat1), (pat2)) >+#define NV_PAT_ENTRY(pat, index) \ >+ (((pat) & (0xff << ((index)*8))) >> ((index)*8)) >+ >+static inline void __nv_disable_caches(unsigned long *cr4) >+{ >+ unsigned long cr0 = read_cr0(); >+ write_cr0(((cr0 & (0xdfffffff)) | 0x40000000)); >+ wbinvd(); >+ *cr4 = read_cr4(); >+ if (*cr4 & 0x80) write_cr4(*cr4 & ~0x80); >+ __flush_tlb(); >+} >+ >+static inline void __nv_enable_caches(unsigned long cr4) >+{ >+ unsigned long cr0 = read_cr0(); >+ wbinvd(); >+ __flush_tlb(); >+ write_cr0((cr0 & 0x9fffffff)); >+ if (cr4 & 0x80) write_cr4(cr4); >+} >+ >+static int __determine_pat_mode() >+{ >+ unsigned int pat1, pat2, i; >+ U008 PAT_WC_index; >+ >+ if (!test_bit(X86_FEATURE_PAT, >+ (volatile unsigned long *)&boot_cpu_data.x86_capability)) >+ { >+ if ((boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) || >+ (boot_cpu_data.cpuid_level < 1) || >+ ((cpuid_edx(1) & (1 << 16)) == 0) || >+ (boot_cpu_data.x86 != 6) || (boot_cpu_data.x86_model >= 15)) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: CPU does not support the PAT, falling back to MTRRs.\n"); >+ return NV_PAT_MODE_DISABLED; >+ } >+ } >+ >+ NV_READ_PAT_ENTRIES(pat1, pat2); >+ PAT_WC_index = 0xf; >+ >+ for (i = 0; i < 4; i++) >+ { >+ if (NV_PAT_ENTRY(pat1, i) == 0x01) >+ { >+ PAT_WC_index = i; >+ break; >+ } >+ >+ if (NV_PAT_ENTRY(pat2, i) == 0x01) >+ { >+ PAT_WC_index = (i + 4); >+ break; >+ } >+ } >+ >+ if (PAT_WC_index == 1) >+ return NV_PAT_MODE_KERNEL; >+ else if (PAT_WC_index != 0xf) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: PAT configuration unsupported, falling back to MTRRs.\n"); >+ return NV_PAT_MODE_DISABLED; >+ } >+ else >+ return NV_PAT_MODE_BUILTIN; >+} >+ >+static unsigned long orig_pat1, orig_pat2; >+ >+static void __nv_setup_pat_entries(void *info) >+{ >+ unsigned long pat1, pat2, cr4; >+ unsigned long eflags; >+ >+#if defined(CONFIG_HOTPLUG_CPU) >+ int cpu = (NvUPtr)info; >+ if ((cpu != 0) && (cpu != (int)smp_processor_id())) >+ return; >+#endif >+ >+ NV_SAVE_FLAGS(eflags); >+ NV_CLI(); >+ __nv_disable_caches(&cr4); >+ >+ NV_READ_PAT_ENTRIES(pat1, pat2); >+ >+ pat1 &= 0xffff00ff; >+ pat1 |= 0x00000100; >+ >+ NV_WRITE_PAT_ENTRIES(pat1, pat2); >+ >+ __nv_enable_caches(cr4); >+ NV_RESTORE_FLAGS(eflags); >+} >+ >+static void __nv_restore_pat_entries(void *info) >+{ >+ unsigned long cr4; >+ unsigned long eflags; >+ >+#if defined(CONFIG_HOTPLUG_CPU) >+ int cpu = (NvUPtr)info; >+ if ((cpu != 0) && (cpu != (int)smp_processor_id())) >+ return; >+#endif >+ >+ NV_SAVE_FLAGS(eflags); >+ NV_CLI(); >+ __nv_disable_caches(&cr4); >+ >+ NV_WRITE_PAT_ENTRIES(orig_pat1, orig_pat2); >+ >+ __nv_enable_caches(cr4); >+ NV_RESTORE_FLAGS(eflags); >+} >+#endif >+ >+static int __nv_enable_pat_support() >+{ >+#if defined(NV_ENABLE_PAT_SUPPORT) >+ unsigned long pat1, pat2; >+ >+ if (nv_pat_mode != NV_PAT_MODE_DISABLED) >+ return 1; >+ >+ nv_pat_mode = __determine_pat_mode(); >+ >+ switch (nv_pat_mode) >+ { >+ case NV_PAT_MODE_DISABLED: >+ /* avoid the PAT if unavailable/unusable */ >+ return 0; >+ case NV_PAT_MODE_KERNEL: >+ /* inherit the kernel's PAT layout */ >+ return 1; >+ case NV_PAT_MODE_BUILTIN: >+ /* use builtin code to modify the PAT layout */ >+ break; >+ } >+ >+ NV_READ_PAT_ENTRIES(orig_pat1, orig_pat2); >+ nv_printf(NV_DBG_SETUP, "saved orig pats as 0x%lx 0x%lx\n", orig_pat1, orig_pat2); >+ >+ if (nv_execute_on_all_cpus(__nv_setup_pat_entries, NULL) != 0) >+ { >+ nv_execute_on_all_cpus(__nv_restore_pat_entries, NULL); >+ return 0; >+ } >+ >+ NV_READ_PAT_ENTRIES(pat1, pat2); >+ nv_printf(NV_DBG_SETUP, "changed pats to 0x%lx 0x%lx\n", pat1, pat2); >+#endif >+ return 1; >+} >+ >+static void __nv_disable_pat_support() >+{ >+#if defined(NV_ENABLE_PAT_SUPPORT) >+ unsigned long pat1, pat2; >+ >+ if (nv_pat_mode != NV_PAT_MODE_BUILTIN) >+ return; >+ >+ if (nv_execute_on_all_cpus(__nv_restore_pat_entries, NULL) != 0) >+ return; >+ >+ nv_pat_mode = NV_PAT_MODE_DISABLED; >+ >+ NV_READ_PAT_ENTRIES(pat1, pat2); >+ nv_printf(NV_DBG_SETUP, "restored orig pats as 0x%lx 0x%lx\n", pat1, pat2); >+#endif >+} >+ >+#if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) >+/* >+ * nv_verify_cpa_interface() - determine if the change_page_attr() large page >+ * management accounting bug known to exist in early Linux/x86-64 kernels >+ * is present in this kernel. >+ * >+ * There's really no good way to determine if change_page_attr() is working >+ * correctly. We can't reliably use change_page_attr() on Linux/x86-64 2.6 >+ * kernels < 2.6.11: if we run into the accounting bug, the Linux kernel will >+ * trigger a BUG() if we attempt to restore the WB memory type of a page >+ * originally part of a large page. >+ * >+ * So if we can successfully allocate such a page, change its memory type to >+ * UC and check if the accounting was done correctly, we can determine if >+ * the change_page_attr() interface can be used safely. >+ * >+ * Return values: >+ * 0 - test passed, the change_page_attr() interface works >+ * 1 - test failed, the status is unclear >+ * -1 - test failed, the change_page_attr() interface is broken >+ */ >+ >+static inline pte_t *check_large_page(unsigned long vaddr) >+{ >+ pgd_t *pgd = NULL; >+ pmd_t *pmd = NULL; >+ >+ pgd = NV_PGD_OFFSET(vaddr, 1, NULL); >+ if (!NV_PGD_PRESENT(pgd)) >+ return NULL; >+ >+ pmd = NV_PMD_OFFSET(vaddr, pgd); >+ if (!pmd || pmd_none(*pmd)) >+ return NULL; >+ >+ if (!pmd_large(*pmd)) >+ return NULL; >+ >+ return (pte_t *) pmd; >+} >+ >+#define CPA_FIXED_MAX_ALLOCS 500 >+ >+int nv_verify_cpa_interface(void) >+{ >+ unsigned int i, size; >+ unsigned long large_page = 0; >+ unsigned long *vaddr_list; >+ size = sizeof(unsigned long) * CPA_FIXED_MAX_ALLOCS; >+ >+ NV_KMALLOC(vaddr_list, size); >+ if (!vaddr_list) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: nv_verify_cpa_interface: failed to allocate " >+ "page table\n"); >+ return 1; >+ } >+ >+ memset(vaddr_list, 0, size); >+ >+ /* try to track down an allocation from a 2M page. */ >+ for (i = 0; i < CPA_FIXED_MAX_ALLOCS; i++) >+ { >+ vaddr_list[i] = __get_free_page(GFP_KERNEL); >+ if (!vaddr_list[i]) >+ continue; >+ >+#if defined(_PAGE_NX) >+ if ((pgprot_val(PAGE_KERNEL) & _PAGE_NX) && >+ virt_to_phys((void *)vaddr_list[i]) < 0x400000) >+ continue; >+#endif >+ >+ if (check_large_page(vaddr_list[i]) != NULL) >+ { >+ large_page = vaddr_list[i]; >+ vaddr_list[i] = 0; >+ break; >+ } >+ } >+ >+ for (i = 0; i < CPA_FIXED_MAX_ALLOCS; i++) >+ { >+ if (vaddr_list[i]) >+ free_page(vaddr_list[i]); >+ } >+ NV_KFREE(vaddr_list, size); >+ >+ if (large_page) >+ { >+ struct page *page = virt_to_page(large_page); >+ struct page *kpte_page; >+ pte_t *kpte; >+ unsigned long kpte_val; >+ pgprot_t prot; >+ >+ // lookup a pointer to our pte >+ kpte = check_large_page(large_page); >+ kpte_val = pte_val(*kpte); >+ kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); >+ >+ prot = PAGE_KERNEL_NOCACHE; >+ pgprot_val(prot) &= __nv_supported_pte_mask; >+ >+ // this should split the large page >+ change_page_attr(page, 1, prot); >+ >+ // broken kernels may get confused after splitting the page and >+ // restore the page before returning to us. detect that case. >+ if (((pte_val(*kpte) & ~_PAGE_NX) == kpte_val) && >+ (pte_val(*kpte) & _PAGE_PSE)) >+ { >+ if ((pte_val(*kpte) & _PAGE_NX) && >+ (__nv_supported_pte_mask & _PAGE_NX) == 0) >+ clear_bit(_PAGE_BIT_NX, kpte); >+ // don't change the page back, as it's already been reverted >+ put_page(kpte_page); >+ free_page(large_page); >+ return -1; // yep, we're broken >+ } >+ >+ // ok, now see if our bookkeeping is broken >+ if (page_count(kpte_page) != 0) >+ return -1; // yep, we're broken >+ >+ prot = PAGE_KERNEL; >+ pgprot_val(prot) &= __nv_supported_pte_mask; >+ >+ // everything's ok! >+ change_page_attr(page, 1, prot); >+ free_page(large_page); >+ return 0; >+ } >+ >+ return 1; >+} >+#endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */ >+ >+/* >+ * nv_verify_page_mappings() - verify that the kernel mapping of the specified >+ * page matches the specified type. This is to help detect bugs in the Linux >+ * kernel's change_page_attr() interface, early. >+ * >+ * This function relies on the ability to perform kernel virtul address to PFN >+ * translations and therefore on 'init_mm'. Unfortunately, the latter is no >+ * longer exported in recent Linux/x86 2.6 kernels. The export was removed at >+ * roughtly the same time as the set_pages_{uc,wb}() change_page_attr() >+ * replacement interfaces were introduced; hopefully, it will be sufficient to >+ * check for their presence. >+ */ >+int nv_verify_page_mappings( >+ nv_pte_t *page_ptr, >+ unsigned int cachetype >+) >+{ >+#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) >+ unsigned long retval = -1; >+#if defined(NVCPU_X86) || defined(NVCPU_X86_64) >+ pgd_t *pgd = NULL; >+ pmd_t *pmd = NULL; >+ pte_t *pte = NULL; >+ unsigned int flags, expected; >+ unsigned long address; >+ static int count = 0; >+ >+ if (!nv_update_memory_types) >+ return 0; >+ >+ address = (unsigned long)__va(page_ptr->phys_addr); >+ >+ pgd = NV_PGD_OFFSET(address, 1, NULL); >+ if (!NV_PGD_PRESENT(pgd)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: pgd not present for addr 0x%lx\n", address); >+ goto failed; >+ } >+ >+ pmd = NV_PMD_OFFSET(address, pgd); >+ if (!pmd || pmd_none(*pmd)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: pmd not present for addr 0x%lx\n", address); >+ goto failed; >+ } >+ >+ // account for large pages >+ if (pmd_large(*pmd)) >+ { >+ pte = (pte_t *)pmd; >+ flags = pte_val(*pte) & ~(PAGE_MASK|_PAGE_PSE); >+ NV_PMD_UNMAP(pmd); >+ } >+ else >+ { >+ pte = NV_PTE_OFFSET(address, pmd); >+ if (!NV_PTE_PRESENT(pte)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: pte not present for addr 0x%lx\n", >+ address); >+ goto failed; >+ } >+ flags = NV_PTE_VALUE(pte) & ~(PAGE_MASK|_PAGE_PSE); >+ } >+ >+ switch (cachetype) >+ { >+ case NV_MEMORY_CACHED: >+ expected = pgprot_val(PAGE_KERNEL); >+ if ((flags & ~_PAGE_NX) == (expected & ~_PAGE_NX)) >+ retval = 0; >+ break; >+ default: >+ expected = pgprot_val(PAGE_KERNEL_NOCACHE); >+ if ((flags & ~(_PAGE_NX | _PAGE_PWT)) == (expected & ~(_PAGE_NX | _PAGE_PWT))) >+ retval = 0; >+ break; >+ } >+ >+ if (retval) >+ { >+ if (count < NV_MAX_RECURRING_WARNING_MESSAGES) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: bad caching on address 0x%lx: actual 0x%x != expected 0x%x\n", >+ address, flags, expected); >+ } >+ >+ if (count == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: please see the README section on " >+ "Cache Aliasing for more information\n"); >+ } >+ >+ count++; >+ } >+ >+failed: >+#endif /* defined(NVCPU_X86) || defined(NVCPU_X86_64) */ >+ return retval; >+#else >+ return 0; >+#endif >+} >+ >+#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) >+static int >+nv_kern_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) >+{ >+ unsigned int cpu = get_cpu(); >+ >+ switch (action) >+ { >+ case CPU_DOWN_FAILED: >+ case CPU_ONLINE: >+ if (cpu == (NvUPtr)hcpu) >+ __nv_setup_pat_entries(NULL); >+ else >+ NV_SMP_CALL_FUNCTION(__nv_setup_pat_entries, hcpu, 1); >+ break; >+ case CPU_DOWN_PREPARE: >+ if (cpu == (NvUPtr)hcpu) >+ __nv_restore_pat_entries(NULL); >+ else >+ NV_SMP_CALL_FUNCTION(__nv_restore_pat_entries, hcpu, 1); >+ break; >+ } >+ >+ put_cpu(); >+ >+ return NOTIFY_OK; >+} >+ >+static struct notifier_block nv_hotcpu_nfb = { >+ .notifier_call = nv_kern_cpu_callback, >+ .priority = 0 >+}; >+#endif >+ >+ >+/*** >+ *** EXPORTS to Linux Kernel >+ ***/ >+ >+static int __init nvidia_init_module(void) >+{ >+ int rc, disable_pat = 0; >+ U032 i, count, data; >+ nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device); >+ >+#if defined(VM_CHECKER) >+ NV_SPIN_LOCK_INIT(&vm_lock); >+#endif >+#if defined(KM_CHECKER) >+ NV_SPIN_LOCK_INIT(&km_lock); >+#endif >+ >+ count = nvos_count_devices(); >+ if (count == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter found!\n"); >+ return -ENODEV; >+ } >+ >+ if (!rm_init_rm()) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_rm() failed!\n"); >+ return -EIO; >+ } >+ >+ memset(nv_linux_devices, 0, sizeof(nv_linux_devices)); >+ >+ if (pci_register_driver(&nv_pci_driver) < 0) >+ { >+ pci_unregister_driver(&nv_pci_driver); // XXX ??? >+ rm_shutdown_rm(); >+ nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter found!\n"); >+ return -ENODEV; >+ } >+ >+ if (num_probed_nv_devices != count) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: The NVIDIA probe routine was not called for %d device(s).\n", >+ count - num_probed_nv_devices); >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: This can occur when a driver such as nouveau, rivafb,\n" >+ "NVRM: nvidiafb, or rivatv was loaded and obtained ownership of\n" >+ "NVRM: the NVIDIA device(s).\n"); >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: Try unloading the conflicting kernel module (and/or\n" >+ "NVRM: reconfigure your kernel without the conflicting\n" >+ "NVRM: driver(s)), then try loading the NVIDIA kernel module\n" >+ "NVRM: again.\n"); >+ } >+ >+ if (num_probed_nv_devices == 0) >+ { >+ pci_unregister_driver(&nv_pci_driver); >+ rm_shutdown_rm(); >+ nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter probed!\n"); >+ return -ENODEV; >+ } >+ >+ if (num_probed_nv_devices != num_nv_devices) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: The NVIDIA probe routine failed for %d device(s).\n", >+ num_probed_nv_devices - num_nv_devices); >+ } >+ >+ if (num_nv_devices == 0) >+ { >+ pci_unregister_driver(&nv_pci_driver); >+ rm_shutdown_rm(); >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: None of the NVIDIA graphics adapters were initialized!\n"); >+ return -ENODEV; >+ } >+ >+ nv_printf(NV_DBG_ERRORS, "NVRM: loading %s", pNVRM_ID); >+ if (__nv_patches[0].short_description != NULL) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ " (applied patches: %s", __nv_patches[0].short_description); >+ for (i = 1; __nv_patches[i].short_description; i++) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ ",%s", __nv_patches[i].short_description); >+ } >+ nv_printf(NV_DBG_ERRORS, ")"); >+ } >+ nv_printf(NV_DBG_ERRORS, "\n"); >+ >+ rc = register_chrdev(nv_major, "nvidia", &nv_fops); >+ if (rc < 0) >+ { >+ pci_unregister_driver(&nv_pci_driver); >+ rm_shutdown_rm(); >+ nv_printf(NV_DBG_ERRORS, "NVRM: register_chrdev() failed!\n"); >+ return rc; >+ } >+ >+ /* instantiate tasklets */ >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ /* >+ * We keep one tasklet per card to avoid latency issues with more >+ * than one device; no two instances of a single tasklet are ever >+ * executed concurrently. >+ */ >+ NV_ATOMIC_SET(nv_linux_devices[i].tasklet.count, 1); >+ } >+ >+ // init the nvidia control device >+ { >+ nv_state_t *nv_ctl = NV_STATE_PTR(&nv_ctl_device); >+ nv_ctl->os_state = (void *) &nv_ctl_device; >+ nv_lock_init_locks(nv_ctl); >+ } >+ >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ apm_nv_dev[i] = pm_register(PM_PCI_DEV, PM_SYS_VGA, nv_kern_apm_event); >+ } >+#endif >+ >+ NV_KMEM_CACHE_CREATE(nv_pte_t_cache, "nv_pte_t", nv_pte_t); >+ if (nv_pte_t_cache == NULL) >+ { >+ rc = -ENOMEM; >+ nv_printf(NV_DBG_ERRORS, "NVRM: pte cache allocation failed\n"); >+ goto failed; >+ } >+ >+#if defined(NV_SG_MAP_BUFFERS) && defined(NV_NEED_REMAP_CHECK) >+ rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "RemapLimit", &nv_remap_limit); >+ >+ // allow an override, but use default if no override >+ if (nv_remap_limit == 0) >+ nv_remap_limit = NV_REMAP_LIMIT_DEFAULT; >+ >+ nv_remap_count = 0; >+#endif >+ >+#if defined(NVCPU_X86_64) || (defined(NVCPU_X86) && defined(CONFIG_X86_PAE)) >+ if (boot_cpu_has(X86_FEATURE_NX)) >+ { >+ U032 __eax, __edx; >+ rdmsr(MSR_EFER, __eax, __edx); >+ if ((__eax & EFER_NX) != 0) >+ __nv_supported_pte_mask |= _PAGE_NX; >+ } >+ if (_PAGE_NX != ((NvU64)1<<63)) >+ { >+ /* >+ * Make sure we don't strip software no-execute >+ * bits from PAGE_KERNEL(_NOCACHE) before calling >+ * change_page_attr(). >+ */ >+ __nv_supported_pte_mask |= _PAGE_NX; >+ } >+#endif >+ >+ /* create /proc/driver/nvidia */ >+ nvos_proc_create(); >+ >+ /* >+ * Give users an opportunity to disable the driver's use of >+ * the change_page_attr() and set_pages_{uc,wb}() kernel >+ * interfaces. >+ */ >+ rc = rm_read_registry_dword(nv, "NVreg", "UpdateMemoryTypes", &data); >+ if ((rc == 0) && ((int)data != ~0)) >+ { >+ nv_update_memory_types = data; >+ } >+#if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) >+ /* >+ * Unless we explicitely detect that the change_page_attr() >+ * inteface is fixed, disable usage of the interface on >+ * this kernel. Notify the user of this problem using the >+ * driver's /proc warnings interface (read by the installer >+ * and the bug report script). >+ */ >+ else >+ { >+ rc = nv_verify_cpa_interface(); >+ if (rc < 0) >+ { >+ nv_prints(NV_DBG_ERRORS, __cpgattr_warning); >+ nvos_proc_add_text_file(proc_nvidia_warnings, "change_page_attr", >+ __cpgattr_warning); >+ nv_update_memory_types = 0; >+ } >+ else if (rc != 0) >+ { >+ nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2); >+ nvos_proc_add_text_file(proc_nvidia_warnings, "change_page_attr", >+ __cpgattr_warning_2); >+ nv_update_memory_types = 0; >+ } >+ } >+#endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */ >+ >+#if defined(NVCPU_X86_64) && defined(CONFIG_IA32_EMULATION) && \ >+ !defined(NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL) >+ rm_register_ioctl_conversions(); >+#endif >+ >+ nvos_proc_add_text_file(proc_nvidia_warnings, "README", __README_warning); >+ >+ for (i = 0; __nv_patches[i].short_description; i++) >+ { >+ nvos_proc_add_text_file(proc_nvidia_patches, >+ __nv_patches[i].short_description, __nv_patches[i].description); >+ } >+ >+ nvos_proc_add_text_file(proc_nvidia_patches, "README", __README_patches); >+ >+ rc = rm_read_registry_dword(nv, >+ "NVreg", "UsePageAttributeTable", &data); >+ if ((rc == 0) && ((int)data != ~0)) >+ { >+ disable_pat = (data == 0); >+ } >+ >+ if (!disable_pat) >+ { >+ __nv_enable_pat_support(); >+#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) >+ if (nv_pat_mode == NV_PAT_MODE_BUILTIN) >+ { >+ if (register_hotcpu_notifier(&nv_hotcpu_nfb) != 0) >+ { >+ __nv_disable_pat_support(); >+ rc = -EIO; >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: CPU hotplug notifier registration failed!\n"); >+ goto failed; >+ } >+ } >+#endif >+ } >+ else >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: builtin PAT support disabled, falling back to MTRRs.\n"); >+ } >+ >+#if (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) && defined(KERNEL_2_4) >+ // attempt to load the i2c modules for linux kernel >+ // check to see if this is possible >+ if((!i2c_add_adapter) || (!i2c_del_adapter)) >+ { >+ // attempt to load the module >+ request_module("i2c-core"); >+ >+ // recheck for valid addresses >+ if((!i2c_add_adapter) || (!i2c_del_adapter)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: Your Linux 2.4 kernel was configured to include modular\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: support for the Linux/i2c infrastructure, but the NVIDIA\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: Linux graphics driver was unable to locate and load the\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: i2c-core.o kernel module.\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: \n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: If you wish to take advantage of the NVIDIA driver's i2c\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: support feature, please make sure the Linux/i2c kernel\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: modules are installed correctly.\n"); >+ } >+ } >+#endif >+ >+ return 0; >+ >+failed: >+ if (nv_pte_t_cache != NULL) >+ NV_KMEM_CACHE_DESTROY(nv_pte_t_cache); >+ >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+ for (i = 0; i < num_nv_devices; i++) >+ if (apm_nv_dev[i] != NULL) pm_unregister(apm_nv_dev[i]); >+#endif >+ >+ unregister_chrdev(nv_major, "nvidia"); >+ >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ if (nv_linux_devices[i].dev) >+ { >+ struct pci_dev *dev = nv_linux_devices[i].dev; >+ release_mem_region(NV_PCI_RESOURCE_START(dev, NV_GPU_BAR_INDEX_REGS), >+ NV_PCI_RESOURCE_SIZE(dev, NV_GPU_BAR_INDEX_REGS)); >+ NV_PCI_DISABLE_DEVICE(dev); >+ } >+ } >+ >+ pci_unregister_driver(&nv_pci_driver); >+ rm_shutdown_rm(); >+ >+ return rc; >+} >+ >+static void __exit nvidia_exit_module(void) >+{ >+ U032 i; >+ nv_linux_state_t *nvl; >+ nv_state_t *nv; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nvidia_exit_module\n"); >+ >+ unregister_chrdev(nv_major, "nvidia"); >+ >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ struct pci_dev *dev; >+ nvl = &nv_linux_devices[i]; >+ >+ if ((dev = nvl->dev) != NULL) >+ { >+ rm_i2c_remove_adapters(NV_STATE_PTR(nvl)); >+ >+ rm_free_private_state(NV_STATE_PTR(nvl)); >+ release_mem_region(NV_PCI_RESOURCE_START(dev, NV_GPU_BAR_INDEX_REGS), >+ NV_PCI_RESOURCE_SIZE(dev, NV_GPU_BAR_INDEX_REGS)); >+ NV_PCI_DISABLE_DEVICE(dev); >+ } >+ } >+ >+ pci_unregister_driver(&nv_pci_driver); >+ >+ /* remove /proc/driver/nvidia */ >+ nvos_proc_remove(); >+ >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ if (apm_nv_dev[i] != NULL) pm_unregister(apm_nv_dev[i]); >+ } >+#endif >+ >+ /* >+ * Make sure we freed up all the mappings. The kernel should >+ * do this automatically before calling close. >+ */ >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ nvl = &nv_linux_devices[i]; >+ nv = NV_STATE_PTR(nvl); >+ >+ if (nvl->alloc_queue) >+ { >+ nv_alloc_t *at = nvl->alloc_queue, *next; >+ while (at) >+ { >+ NV_PRINT_AT(NV_DBG_ERRORS, at); >+ /* nv_free_pages() will free this 'at' */ >+ next = at->next; >+ nv_free_pages(nv, at->num_pages, >+ NV_ALLOC_MAPPING_AGP(at->flags), >+ NV_ALLOC_MAPPING_CONTIG(at->flags), >+ NV_ALLOC_MAPPING(at->flags), >+ (void *)at); >+ at = next; >+ } >+ } >+ } >+ >+ // Shutdown the resource manager >+ rm_shutdown_rm(); >+ >+#if defined(NVCPU_X86_64) && defined(CONFIG_IA32_EMULATION) && \ >+ !defined(NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL) >+ rm_unregister_ioctl_conversions(); >+#endif >+ >+ if (nv_pat_mode == NV_PAT_MODE_BUILTIN) >+ { >+ __nv_disable_pat_support(); >+#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) >+ unregister_hotcpu_notifier(&nv_hotcpu_nfb); >+#endif >+ } >+ >+#if defined(NV_ENABLE_MEM_TRACKING) >+#if defined(VM_CHECKER) >+ if (vm_usage != 0) >+ { >+ nv_list_mem("VM", vm_list); >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: final VM memory usage: 0x%x bytes\n", vm_usage); >+ } >+#endif >+#if defined(KM_CHECKER) >+ if (km_usage != 0) >+ { >+ nv_list_mem("KM", km_list); >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: final KM memory usage: 0x%x bytes\n", km_usage); >+ } >+#endif >+#if defined(NV_SG_MAP_BUFFERS) && defined(NV_NEED_REMAP_CHECK) >+ if (nv_remap_count != 0) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: final SG memory usage: 0x%x bytes\n", nv_remap_count); >+ } >+#endif >+#endif /* NV_ENABLE_MEM_TRACKING */ >+ >+ NV_KMEM_CACHE_DESTROY(nv_pte_t_cache); >+} >+ >+module_init(nvidia_init_module); >+module_exit(nvidia_exit_module); >+ >+ >+/* >+ * The 'struct vm_operations' open() callback is called by the Linux >+ * kernel when the parent VMA is split or copied, close() when the >+ * current VMA is about to be deleted. >+ * >+ * We implement these callbacks to keep track of the number of user >+ * mappings of system memory allocations. This was motivated by a >+ * subtle interaction problem between the driver and the kernel with >+ * respect to the bookkeeping of pages marked reserved and later >+ * mapped with mmap(). >+ * >+ * Traditionally, the Linux kernel ignored reserved pages, such that >+ * when they were mapped via mmap(), the integrity of their usage >+ * counts depended on the reserved bit being set for as long as user >+ * mappings existed. >+ * >+ * Since we mark system memory pages allocated for DMA reserved and >+ * typically map them with mmap(), we need to ensure they remain >+ * reserved until the last mapping has been torn down. This worked >+ * correctly in most cases, but in a few, the RM API called into the >+ * RM to free memory before calling munmap() to unmap it. >+ * >+ * In the past, we allowed nv_free_pages() to remove the 'at' from >+ * the parent device's allocation list in this case, but didn't >+ * release the underlying pages until the last user mapping had been >+ * destroyed: >+ * >+ * In nv_kern_vma_release(), we freed any resources associated with >+ * the allocation (IOMMU/SWIOTLB mappings, etc.) and cleared the >+ * underlying pages' reserved bits, but didn't free them. The kernel >+ * was expected to do this. >+ * >+ * This worked in practise, but made dangerous assumptions about the >+ * kernel's behavior and could fail in some cases. We now handle >+ * this case differently (see below). >+ */ >+static void >+nv_kern_vma_open(struct vm_area_struct *vma) >+{ >+ NV_PRINT_VMA(NV_DBG_MEMINFO, vma); >+ >+ if (NV_VMA_PRIVATE(vma)) >+ { >+ nv_alloc_t *at = (nv_alloc_t *) NV_VMA_PRIVATE(vma); >+ NV_ATOMIC_INC(at->usage_count); >+ >+ if (!NV_ALLOC_MAPPING_AGP(at->flags)) >+ { >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ nv_vm_list_page_count(at->page_table, at->num_pages); >+ } >+ } >+} >+ >+/* >+ * (see above for additional information) >+ * >+ * If the 'at' usage count drops to zero with the updated logic, the >+ * VMA's file pointer is saved; nv_kern_close() uses it to find >+ * these allocations when the parent file descriptor is closed. This >+ * will typically happen when the process exits. >+ * >+ * Since this is technically a workaround to handle possible fallout >+ * from misbehaving clients, we addtionally print a warning. >+ */ >+static void >+nv_kern_vma_release(struct vm_area_struct *vma) >+{ >+ NV_PRINT_VMA(NV_DBG_MEMINFO, vma); >+ >+ if (NV_VMA_PRIVATE(vma)) >+ { >+ nv_alloc_t *at = (nv_alloc_t *) NV_VMA_PRIVATE(vma); >+ >+ if (NV_ATOMIC_DEC_AND_TEST(at->usage_count)) >+ { >+ static int count = 0; >+ if ((at->pid == os_get_current_process()) && >+ (count++ < NV_MAX_RECURRING_WARNING_MESSAGES)) >+ { >+ nv_printf(NV_DBG_MEMINFO, >+ "NVRM: VM: nv_kern_vma_release: late unmap, comm: %s, 0x%p\n", >+ current->comm, at); >+ } >+ at->file = NV_VMA_FILE(vma); >+ } >+ >+ if (!NV_ALLOC_MAPPING_AGP(at->flags)) >+ { >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ nv_vm_list_page_count(at->page_table, at->num_pages); >+ } >+ } >+} >+ >+#if !defined(NV_VM_INSERT_PAGE_PRESENT) >+static >+struct page *nv_kern_vma_nopage( >+ struct vm_area_struct *vma, >+ unsigned long address, >+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) >+ int *type >+#else >+ int write_access >+#endif >+) >+{ >+ struct page *page; >+ >+ page = pfn_to_page(vma->vm_pgoff); >+ get_page(page); >+ >+ return page; >+} >+#endif >+ >+struct vm_operations_struct nv_vm_ops = { >+ .open = nv_kern_vma_open, >+ .close = nv_kern_vma_release, /* "close" */ >+#if !defined(NV_VM_INSERT_PAGE_PRESENT) >+ .nopage = nv_kern_vma_nopage, >+#endif >+}; >+ >+static nv_file_private_t * >+nv_alloc_file_private(void) >+{ >+ nv_file_private_t *nvfp; >+ >+ NV_KMALLOC(nvfp, sizeof(nv_file_private_t)); >+ if (!nvfp) >+ return NULL; >+ >+ memset(nvfp, 0, sizeof(nv_file_private_t)); >+ >+ init_waitqueue_head(&nvfp->waitqueue); >+ NV_SPIN_LOCK_INIT(&nvfp->fp_lock); >+ >+ return nvfp; >+} >+ >+static void >+nv_free_file_private(nv_file_private_t *nvfp) >+{ >+ nvidia_event_t *nvet; >+ >+ if (nvfp == NULL) >+ return; >+ >+ for (nvet = nvfp->event_head; nvet != NULL; nvet = nvfp->event_head) >+ { >+ nvfp->event_head = nvfp->event_head->next; >+ NV_KFREE(nvet, sizeof(nvidia_event_t)); >+ } >+ NV_KFREE(nvfp, sizeof(nv_file_private_t)); >+} >+ >+ >+/* >+** nv_kern_open >+** >+** nv driver open entry point. Sessions are created here. >+*/ >+int nv_kern_open( >+ struct inode *inode, >+ struct file *file >+) >+{ >+ nv_state_t *nv = NULL; >+ nv_linux_state_t *nvl = NULL; >+ U032 devnum; >+ int rc = 0, status; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_open...\n"); >+ >+ FILE_PRIVATE(file) = nv_alloc_file_private(); >+ if (FILE_PRIVATE(file) == NULL) >+ return -ENOMEM; >+ >+ /* for control device, just jump to its open routine */ >+ /* after setting up the private data */ >+ if (NV_IS_CONTROL_DEVICE(inode)) >+ return nv_kern_ctl_open(inode, file); >+ >+ /* what device are we talking about? */ >+ devnum = NV_DEVICE_NUMBER(inode); >+ if (devnum >= num_nv_devices) >+ { >+ nv_free_file_private(FILE_PRIVATE(file)); >+ FILE_PRIVATE(file) = NULL; >+ return -ENODEV; >+ } >+ >+ nvl = &nv_linux_devices[devnum]; >+ nv = NV_STATE_PTR(nvl); >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_open on device %d\n", devnum); >+ down(&nvl->ldata_lock); >+ >+ nv_verify_pci_config(nv); >+ >+ NVL_FROM_FILEP(file) = nvl; >+ >+ /* >+ * map the memory and allocate isr on first open >+ */ >+ >+ if ( ! (nv->flags & NV_FLAG_OPEN)) >+ { >+ if (nv->device_id == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: open of nonexistent device %d\n", >+ devnum); >+ rc = -ENXIO; >+ goto failed; >+ } >+ >+ status = request_irq(nv->interrupt_line, nv_kern_isr, IRQF_SHARED, >+ "nvidia", (void *)nvl); >+ if (status != 0) >+ { >+ if ( nv->interrupt_line && (status == -EBUSY) ) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: Tried to get irq %d, but another driver", >+ (unsigned int) nv->interrupt_line); >+ nv_printf(NV_DBG_ERRORS, "NVRM: has it and is not sharing it.\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: you may want to verify that an audio driver"); >+ nv_printf(NV_DBG_ERRORS, " isn't using the irq\n"); >+ } >+ nv_printf(NV_DBG_ERRORS, "NVRM: isr request failed 0x%x\n", status); >+ rc = -EIO; >+ goto failed; >+ } >+ >+ if ( ! rm_init_adapter(nv)) >+ { >+ free_irq(nv->interrupt_line, (void *) nvl); >+ nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_adapter(%d) failed\n", devnum); >+ rc = -EIO; >+ goto failed; >+ } >+ >+ nvl->tasklet.func = nv_kern_isr_bh; >+ nvl->tasklet.data = (unsigned long) nv; >+ tasklet_enable(&nvl->tasklet); >+ >+ nv->flags |= NV_FLAG_OPEN; >+ } >+ >+ NV_ATOMIC_INC(nvl->usage_count); >+ >+ failed: >+ up(&nvl->ldata_lock); >+ >+ if ((rc) && FILE_PRIVATE(file)) >+ { >+ nv_free_file_private(FILE_PRIVATE(file)); >+ FILE_PRIVATE(file) = NULL; >+ } >+ >+ return rc; >+} >+ >+ >+/* >+** nv_kern_close >+** >+** Master driver close entry point. >+*/ >+ >+int nv_kern_close( >+ struct inode *inode, >+ struct file *file >+) >+{ >+ nv_linux_state_t *nvl = NVL_FROM_FILEP(file); >+ nv_state_t *nv = NV_STATE_PTR(nvl); >+ >+ nv_verify_pci_config(nv); >+ >+ /* for control device, just jump to its open routine */ >+ /* after setting up the private data */ >+ if (NV_IS_CONTROL_DEVICE(inode)) >+ return nv_kern_ctl_close(inode, file); >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_close on device %d\n", >+ NV_DEVICE_NUMBER(inode)); >+ >+ rm_free_unused_clients(nv, (void *)file); >+ >+ down(&nvl->at_lock); >+ if (nvl->alloc_queue != NULL) >+ { >+ nv_alloc_t *at = nvl->alloc_queue, *next; >+ while (at != NULL) >+ { >+ /* nv_free_pages() will free this 'at' */ >+ next = at->next; >+ if ((NV_ATOMIC_READ(at->usage_count) == 0) && (at->file == file)) >+ { >+ NV_ATOMIC_INC(at->usage_count); >+ up(&nvl->at_lock); >+ if (at->pid == os_get_current_process()) >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ nv_free_pages(nv, at->num_pages, >+ NV_ALLOC_MAPPING_AGP(at->flags), >+ NV_ALLOC_MAPPING_CONTIG(at->flags), >+ NV_ALLOC_MAPPING(at->flags), >+ (void *)at); >+ down(&nvl->at_lock); >+ next = nvl->alloc_queue; /* start over */ >+ } >+ at = next; >+ } >+ } >+ up(&nvl->at_lock); >+ >+ down(&nvl->ldata_lock); >+ if (NV_ATOMIC_DEC_AND_TEST(nvl->usage_count)) >+ { >+ /* >+ * The usage count for this device has dropped to zero, it can be shut >+ * down safely; disable its interrupts. >+ */ >+ rm_disable_adapter(nv); >+ >+ /* >+ * Disable this device's tasklet to make sure that no bottom half will >+ * run with undefined device state. >+ */ >+ tasklet_disable(&nvl->tasklet); >+ >+ /* >+ * Free the IRQ, which may block until all pending interrupt processing >+ * has completed. >+ */ >+ free_irq(nv->interrupt_line, (void *) nvl); >+ >+ rm_shutdown_adapter(nv); >+ >+ /* >+ * Make sure we free all memory tied to this device. Memory freed here >+ * has been leaked by the core RM, warn accordingly. >+ */ >+ if (nvl->alloc_queue) >+ { >+ nv_alloc_t *at = nvl->alloc_queue, *next; >+ while (at) >+ { >+ NV_PRINT_AT(NV_DBG_ERRORS, at); >+ /* nv_free_pages() will free this 'at' */ >+ next = at->next; >+ nv_free_pages(nv, at->num_pages, >+ NV_ALLOC_MAPPING_AGP(at->flags), >+ NV_ALLOC_MAPPING_CONTIG(at->flags), >+ NV_ALLOC_MAPPING(at->flags), >+ (void *)at); >+ at = next; >+ } >+ } >+ >+ /* leave INIT flag alone so we don't reinit every time */ >+ nv->flags &= ~NV_FLAG_OPEN; >+ } >+ up(&nvl->ldata_lock); >+ >+ if (FILE_PRIVATE(file)) >+ { >+ nv_free_file_private(FILE_PRIVATE(file)); >+ FILE_PRIVATE(file) = NULL; >+ } >+ >+ return 0; >+} >+ >+int nv_encode_caching( >+ pgprot_t *prot, >+ unsigned int cache_type, >+ unsigned int memory_type >+) >+{ >+ pgprot_t tmp = __pgprot(0); >+ >+ if (prot == NULL) prot = &tmp; >+ >+ // allow setting or refusal of specific caching types >+ switch (cache_type) >+ { >+ case NV_MEMORY_UNCACHED_WEAK: >+ *prot = pgprot_noncached_weak(*prot); >+ break; >+ case NV_MEMORY_UNCACHED: >+ *prot = pgprot_noncached(*prot); >+ break; >+#if defined(NVCPU_X86) || defined(NVCPU_X86_64) >+ case NV_MEMORY_WRITECOMBINED: >+#if defined(NV_ENABLE_PAT_SUPPORT) >+ if ((nv_pat_mode != NV_PAT_MODE_DISABLED) && >+ (memory_type != NV_MEMORY_TYPE_REGISTERS)) >+ { >+ pgprot_val(*prot) &= ~(_PAGE_PSE | _PAGE_PCD | _PAGE_PWT); >+ *prot = __pgprot(pgprot_val(*prot) | _PAGE_PWT); >+ break; >+ } >+#endif >+ /* >+ * If PAT support is unavailable and the memory space isn't >+ * NV_MEMORY_TYPE_AGP, we need to return an error code to >+ * the caller, but do not print a warning message. >+ * >+ * In the case of AGP memory, we will have attempted to add >+ * a WC MTRR for the AGP aperture and aborted the AGP >+ * initialization if this failed, so we can safely return >+ * success here. >+ * >+ * For frame buffer memory, callers are expected to use the >+ * UC- memory type if we report WC as unsupported, which >+ * translates to the effective memory type WC if a WC MTRR >+ * exists or else UC. >+ */ >+ if (memory_type == NV_MEMORY_TYPE_AGP) >+ break; >+ return 1; >+#endif >+ case NV_MEMORY_CACHED: >+ /* >+ * RAM is cached on Linux by default, we can assume there's >+ * nothing to be done here. This is not the case for the >+ * other memory spaces: as commented on above, we will have >+ * added a WC MTRR for the AGP aperture (or else aborted >+ * AGP initialization), and we will have made an attempt to >+ * add a WC MTRR for the frame buffer. >+ * >+ * If a WC MTRR is present, we can't satisfy the WB mapping >+ * attempt here, since the achievable effective memory >+ * types in that case are WC and UC, if not it's typically >+ * UC (MTRRdefType is UC); we could only satisfy WB mapping >+ * requests with a WB MTRR. >+ */ >+ if (memory_type == NV_MEMORY_TYPE_SYSTEM) >+ break; >+ default: >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: VM: memory type %d not supported for memory space %d!\n", >+ cache_type, memory_type); >+ return 1; >+ } >+ return 0; >+} >+ >+int nv_kern_mmap( >+ struct file *file, >+ struct vm_area_struct *vma >+) >+{ >+ unsigned int pages; >+ nv_alloc_t *at; >+ nv_linux_state_t *nvl = NVL_FROM_FILEP(file); >+ nv_state_t *nv = NV_STATE_PTR(nvl); >+ >+ if (nv->flags & NV_FLAG_CONTROL) >+ return -ENODEV; >+ >+ NV_PRINT_VMA(NV_DBG_MEMINFO, vma); >+ >+ nv_verify_pci_config(nv); >+ >+ // be a bit paranoid for now >+ if ( NV_MASK_OFFSET(vma->vm_start) || >+ NV_MASK_OFFSET(vma->vm_end)) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: bad mmap range: %lx - %lx\n", >+ vma->vm_start, vma->vm_end); >+ return -EINVAL; >+ } >+ >+ pages = NV_VMA_SIZE(vma) >> PAGE_SHIFT; >+ NV_VMA_PRIVATE(vma) = NULL; >+ >+ vma->vm_ops = &nv_vm_ops; >+ >+#if defined(NVCPU_X86) >+ if (vma->vm_pgoff & ~0xfffff) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: bad mmap offset: %lx\n", vma->vm_pgoff); >+ return -EINVAL; >+ } >+#endif >+ >+ /* NV reg space */ >+ if (IS_REG_OFFSET(nv, NV_VMA_OFFSET(vma), NV_VMA_SIZE(vma))) >+ { >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_MEMORY_UNCACHED, >+ NV_MEMORY_TYPE_REGISTERS)) >+ { >+ return -ENXIO; >+ } >+ >+ if (NV_REMAP_PAGE_RANGE(vma->vm_start, >+ NV_VMA_OFFSET(vma), >+ NV_VMA_SIZE(vma), >+ vma->vm_page_prot)) >+ return -EAGAIN; >+ >+ /* mark it as IO so that we don't dump it on core dump */ >+ vma->vm_flags |= VM_IO; >+ } >+ >+ /* NV fb space */ >+ else if (IS_FB_OFFSET(nv, NV_VMA_OFFSET(vma), NV_VMA_SIZE(vma))) >+ { >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_MEMORY_WRITECOMBINED, >+ NV_MEMORY_TYPE_FRAMEBUFFER)) >+ { >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_MEMORY_UNCACHED_WEAK, >+ NV_MEMORY_TYPE_FRAMEBUFFER)) >+ { >+ return -ENXIO; >+ } >+ } >+ >+ if (NV_REMAP_PAGE_RANGE(vma->vm_start, >+ NV_VMA_OFFSET(vma), >+ NV_VMA_SIZE(vma), >+ vma->vm_page_prot)) >+ return -EAGAIN; >+ >+ // mark it as IO so that we don't dump it on core dump >+ vma->vm_flags |= VM_IO; >+ } >+ >+ /* NV bc space */ >+ else if (IS_BC_OFFSET(nv, NV_VMA_OFFSET(vma), NV_VMA_SIZE(vma))) >+ { >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_MEMORY_WRITECOMBINED, >+ NV_MEMORY_TYPE_FRAMEBUFFER)) >+ return -ENXIO; >+ >+ if (NV_REMAP_PAGE_RANGE(vma->vm_start, >+ NV_VMA_OFFSET(vma), >+ NV_VMA_SIZE(vma), >+ vma->vm_page_prot)) >+ return -EAGAIN; >+ >+ // mark it as IO so that we don't dump it on core dump >+ vma->vm_flags |= VM_IO; >+ } >+ >+ /* AGP allocator */ >+ else if (IS_AGP_OFFSET(nv, NV_VMA_OFFSET(vma), NV_VMA_SIZE(vma))) >+ { >+ unsigned int i; >+ >+ down(&nvl->at_lock); >+ at = nvl_find_alloc(nvl, NV_VMA_OFFSET(vma), NV_ALLOC_TYPE_AGP); >+ >+ if (at == NULL) >+ { >+ static int count = 0; >+ if (count++ < NV_MAX_RECURRING_WARNING_MESSAGES) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: nv_kern_mmap: invalid offset: 0x%08x @ 0x%016llx (AGP)\n", >+ NV_VMA_SIZE(vma), NV_VMA_OFFSET(vma)); >+ } >+ up(&nvl->at_lock); >+ return -EINVAL; >+ } >+ >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_MEMORY_WRITECOMBINED, >+ NV_MEMORY_TYPE_AGP)) >+ { >+ up(&nvl->at_lock); >+ return -ENXIO; >+ } >+ >+ NV_VMA_PRIVATE(vma) = at; >+ NV_ATOMIC_INC(at->usage_count); >+ up(&nvl->at_lock); >+ >+ if (NV_REMAP_PAGE_RANGE(vma->vm_start, >+ NV_VMA_OFFSET(vma), >+ NV_VMA_SIZE(vma), >+ vma->vm_page_prot)) >+ { >+ NV_ATOMIC_DEC(at->usage_count); >+ return -EAGAIN; >+ } >+ >+ i = (NV_VMA_OFFSET(vma) - (NvUPtr)at->key_mapping) >> PAGE_SHIFT; >+ >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ nv_vm_list_page_count(&at->page_table[i], pages); >+ >+ // mark it as IO so that we don't dump it on core dump >+ vma->vm_flags |= VM_IO; >+ } >+ >+ /* Magic allocator */ >+ else // if (NV_VMA_OFFSET(vma) == NV_MMAP_ALLOCATION_OFFSET) >+ { >+ unsigned long start = 0; >+ unsigned int i, j; >+ >+ down(&nvl->at_lock); >+ at = nvl_find_alloc(nvl, NV_VMA_OFFSET(vma), NV_ALLOC_TYPE_PCI); >+ >+ if (at == NULL) >+ { >+ static int count = 0; >+ up(&nvl->at_lock); >+ if (count++ < NV_MAX_RECURRING_WARNING_MESSAGES) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: nv_kern_mmap: invalid offset: 0x%08x @ 0x%016llx (PCI)\n", >+ NV_VMA_SIZE(vma), NV_VMA_OFFSET(vma)); >+ } >+ return -EINVAL; >+ } >+ >+ for (i = 0; i < at->num_pages; i++) >+ { >+ if ((NV_VMA_OFFSET(vma) == at->page_table[i]->phys_addr) >+ || (NV_VMA_OFFSET(vma) == at->page_table[i]->dma_addr)) >+ break; >+ } >+ >+ if (i == at->num_pages) /* sanity check */ >+ { >+ up(&nvl->at_lock); >+ return -EINVAL; >+ } >+ >+ if ((i + pages) > at->num_pages) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: requested mapping exceeds allocation's boundary!\n"); >+ up(&nvl->at_lock); >+ return -EINVAL; >+ } >+ >+ if (nv_encode_caching(&vma->vm_page_prot, >+ NV_ALLOC_MAPPING(at->flags), >+ NV_MEMORY_TYPE_SYSTEM)) >+ { >+ up(&nvl->at_lock); >+ return -ENXIO; >+ } >+ >+ NV_VMA_PRIVATE(vma) = at; >+ NV_ATOMIC_INC(at->usage_count); >+ up(&nvl->at_lock); >+ >+ nv_printf(NV_DBG_INFO, >+ "NVRM: remapping %d system pages, index %d, for 'at' 0x%p\n", pages, i, at); >+ >+ start = vma->vm_start; >+ for (j = i; j < (i + pages); j++) >+ { >+ nv_verify_page_mappings(at->page_table[j], NV_ALLOC_MAPPING(at->flags)); >+#if defined(NV_VM_INSERT_PAGE_PRESENT) >+ if (NV_VM_INSERT_PAGE(vma, start, >+ NV_GET_PAGE_STRUCT(at->page_table[j]->phys_addr))) >+#else >+ if (NV_REMAP_PAGE_RANGE(start, at->page_table[j]->phys_addr, >+ PAGE_SIZE, vma->vm_page_prot)) >+#endif >+ { >+ NV_ATOMIC_DEC(at->usage_count); >+ return -EAGAIN; >+ } >+ start += PAGE_SIZE; >+ } >+ >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ nv_vm_list_page_count(&at->page_table[i], pages); >+ >+ /* prevent the swapper from swapping it out */ >+ /* mark the memory i/o so the buffers aren't dumped on core dumps */ >+ vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED); >+ } >+ >+ NV_VMA_FILE(vma) = file; >+ >+ return 0; >+} >+ >+unsigned int nv_kern_poll( >+ struct file *file, >+ poll_table *wait >+) >+{ >+ unsigned int mask = 0; >+ nv_file_private_t *nvfp; >+ nv_linux_state_t *nvl; >+ unsigned long eflags; >+ >+ nvl = NVL_FROM_FILEP(file); >+ >+ if (NV_IS_CONTROL_DEVICE(file->f_dentry->d_inode)) >+ return nv_kern_ctl_poll(file, wait); >+ >+ nvfp = NV_GET_NVFP(file); >+ >+ if ( !(file->f_flags & O_NONBLOCK)) >+ { >+ // add us to the list >+ poll_wait(file, &nvfp->waitqueue, wait); >+ } >+ >+ NV_SPIN_LOCK_IRQSAVE(&nvfp->fp_lock, eflags); >+ >+ // wake the user on any event >+ if (nvfp->event_head != NULL) >+ { >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: Hey, an event occured!\n"); >+ // trigger the client, when they grab the event, >+ // we'll decrement the event count >+ mask |= (POLLPRI|POLLIN); >+ } >+ >+ NV_SPIN_UNLOCK_IRQRESTORE(&nvfp->fp_lock, eflags); >+ >+ return mask; >+} >+ >+#define NV_CTL_DEVICE_ONLY(nv) \ >+{ \ >+ if (((nv)->flags & NV_FLAG_CONTROL) == 0) \ >+ { \ >+ status = -EINVAL; \ >+ goto done; \ >+ } \ >+} >+ >+int nv_kern_ioctl( >+ struct inode *inode, >+ struct file *file, >+ unsigned int cmd, >+ unsigned long i_arg) >+{ >+ RM_STATUS rmStatus; >+ int status = 0; >+ nv_linux_state_t *nvl; >+ nv_state_t *nv; >+ void *arg = (void *) i_arg; >+ void *arg_copy; >+ int arg_size; >+ >+ nvl = NVL_FROM_FILEP(file); >+ nv = NV_STATE_PTR(nvl); >+ >+ nv_printf(NV_DBG_INFO, "NVRM: ioctl(0x%x, 0x%x, 0x%x)\n", >+ _IOC_NR(cmd), (unsigned int) i_arg, _IOC_SIZE(cmd)); >+ >+ nv_verify_pci_config(nv); >+ >+ arg_size = _IOC_SIZE(cmd); >+ NV_KMALLOC(arg_copy, arg_size); >+ if (arg_copy == NULL) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to allocate ioctl memory\n"); >+ return -ENOMEM; >+ } >+ >+ if (copy_from_user(arg_copy, arg, arg_size)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to copy in ioctl data\n"); >+ NV_KFREE(arg_copy, arg_size); >+ return -ENOMEM; >+ } >+ >+ switch (_IOC_NR(cmd)) >+ { >+ /* pass out info about the card */ >+ case NV_ESC_CARD_INFO: >+ { >+ nv_ioctl_card_info_t *ci; >+ nv_linux_state_t *tnvl; >+ nv_ioctl_rm_api_old_version_t *rm_api; >+ U032 i; >+ >+ NV_CTL_DEVICE_ONLY(nv); >+ >+ if (arg_size < (sizeof(*ci) * num_nv_devices)) >+ { >+ status = -EINVAL; >+ goto done; >+ } >+ >+ /* the first element of card info passed from the client will have >+ * the rm_api_version_magic value to show that the client is new >+ * enough to support versioning. If the client is too old to >+ * support versioning, our mmap interfaces are probably different >+ * enough to cause serious damage. >+ * just copy in the one dword to check. >+ */ >+ rm_api = arg_copy; >+ switch (rm_api->magic) >+ { >+ case NV_RM_API_OLD_VERSION_MAGIC_REQ: >+ case NV_RM_API_OLD_VERSION_MAGIC_LAX_REQ: >+ case NV_RM_API_OLD_VERSION_MAGIC_OVERRIDE_REQ: >+ /* the client is using the old major-minor-patch >+ * API version check; reject it. >+ */ >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: API mismatch: the client has the version %d.%d-%d, but\n" >+ "NVRM: this kernel module has the version %s. Please\n" >+ "NVRM: make sure that this kernel module and all NVIDIA driver\n" >+ "NVRM: components have the same version.\n", >+ rm_api->major, rm_api->minor, rm_api->patch, >+ NV_VERSION_STRING); >+ status = -EINVAL; >+ goto done; >+ >+ case NV_RM_API_OLD_VERSION_MAGIC_IGNORE: >+ /* the client is telling us to ignore the old >+ * version scheme; it will do a version check via >+ * NV_ESC_CHECK_VERSION_STR >+ */ >+ break; >+ default: >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: client does not support versioning!!\n"); >+ status = -EINVAL; >+ goto done; >+ } >+ >+ ci = arg_copy; >+ memset(ci, 0, arg_size); >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ nv_state_t *tnv; >+ tnvl = &nv_linux_devices[i]; >+ tnv = NV_STATE_PTR(tnvl); >+ if (tnv->device_id) >+ { >+ ci->flags = NV_IOCTL_CARD_INFO_FLAG_PRESENT; >+ ci->bus = tnv->bus; >+ ci->slot = tnv->slot; >+ ci->vendor_id = tnv->vendor_id; >+ ci->device_id = tnv->device_id; >+ ci->interrupt_line = tnv->interrupt_line; >+ ci->reg_address = tnv->regs->address; >+ ci->reg_size = tnv->regs->size; >+ ci->fb_address = tnv->fb->address; >+ ci->fb_size = tnv->fb->size; >+ ci++; >+ } >+ } >+ break; >+ } >+ >+ /* set a card to be posted */ >+ case NV_ESC_POST_VBIOS: >+ { >+ NV_CTL_DEVICE_ONLY(nv); >+ >+ status = nvos_post_vbios(arg_copy, arg_size); >+ break; >+ } >+ >+ case NV_ESC_CHECK_VERSION_STR: >+ { >+ NV_CTL_DEVICE_ONLY(nv); >+ >+ rmStatus = rm_perform_version_check(arg_copy, arg_size); >+ status = ((rmStatus == RM_OK) ? 0 : -EINVAL); >+ break; >+ } >+ >+ default: >+ rmStatus = rm_ioctl(nv, file, _IOC_NR(cmd), arg_copy, arg_size); >+ status = ((rmStatus == RM_OK) ? 0 : -EINVAL); >+ break; >+ } >+ >+ done: >+ if (copy_to_user(arg, arg_copy, arg_size)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: failed to copyout ioctl data\n"); >+ status = -EFAULT; >+ } >+ NV_KFREE(arg_copy, arg_size); >+ return status; >+} >+ >+long nv_kern_unlocked_ioctl( >+ struct file *file, >+ unsigned int cmd, >+ unsigned long i_arg >+) >+{ >+ return nv_kern_ioctl(file->f_dentry->d_inode, file, cmd, i_arg); >+} >+ >+long nv_kern_compat_ioctl( >+ struct file *file, >+ unsigned int cmd, >+ unsigned long i_arg >+) >+{ >+ return nv_kern_ioctl(file->f_dentry->d_inode, file, cmd, i_arg); >+} >+ >+/* >+ * driver receives an interrupt >+ * if someone waiting, then hand it off. >+ */ >+irqreturn_t nv_kern_isr( >+ int irq, >+ void *arg >+#if !defined(NV_IRQ_HANDLER_T_PRESENT) || (NV_IRQ_HANDLER_T_ARGUMENT_COUNT == 3) >+ ,struct pt_regs *regs >+#endif >+) >+{ >+ nv_linux_state_t *nvl = (void *) arg; >+ nv_state_t *nv = NV_STATE_PTR(nvl); >+ U032 need_to_run_bottom_half = 0; >+ BOOL ret; >+ >+ nv_verify_pci_config(nv); >+ >+ ret = rm_isr(nv, &need_to_run_bottom_half); >+ if (need_to_run_bottom_half) >+ { >+ tasklet_schedule(&nvl->tasklet); >+ } >+ >+ return IRQ_RETVAL(ret); >+} >+ >+void nv_kern_isr_bh( >+ unsigned long data >+) >+{ >+ nv_state_t *nv = (nv_state_t *) data; >+ /* >+ * XXX: This level of indirection is necessary to work around >+ * problems with Linux kernels using a non-standard calling >+ * convention, i.e. Arjan van de Ven's/RedHat's 2.6.0 kernels. >+ */ >+ nv_verify_pci_config(nv); >+ rm_isr_bh(nv); >+} >+ >+void nv_kern_rc_timer( >+ unsigned long data >+) >+{ >+ nv_linux_state_t *nvl = (nv_linux_state_t *) data; >+ nv_state_t *nv = NV_STATE_PTR(nvl); >+ >+ // nv_printf(NV_DBG_INFO, "NVRM: rc timer\n"); >+ >+ nv_verify_pci_config(nv); >+ rm_run_rc_callback(nv); >+ mod_timer(&nvl->rc_timer, jiffies + HZ); /* set another timeout in 1 second */ >+} >+ >+#if defined(NV_PM_SUPPORT_OLD_STYLE_APM) >+/* kernel calls us with a power management event */ >+static int >+nv_kern_apm_event( >+ struct pm_dev *dev, >+ pm_request_t rqst, >+ void *data >+) >+{ >+ nv_state_t *nv; >+ nv_linux_state_t *lnv; >+ U032 devnum; >+ int status = RM_OK; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_apm_event: %d (0x%p)\n", rqst, data); >+ >+ for (devnum = 0; devnum < num_nv_devices; devnum++) >+ { >+ if (apm_nv_dev[devnum] == dev) >+ { >+ break; >+ } >+ } >+ >+ if (devnum == num_nv_devices) >+ { >+ nv_printf(NV_DBG_WARNINGS, "NVRM: APM: invalid device!\n"); >+ return 1; >+ } >+ >+ lnv = &nv_linux_devices[devnum]; >+ nv = NV_STATE_PTR(lnv); >+ >+ nv_verify_pci_config(nv); >+ >+ switch (rqst) >+ { >+ case PM_RESUME: >+ nv_printf(NV_DBG_INFO, "NVRM: APM: received resume event\n"); >+ __nv_enable_pat_support(); >+ status = rm_power_management(nv, 0, NV_PM_APM_RESUME); >+ break; >+ >+ case PM_SUSPEND: >+ nv_printf(NV_DBG_INFO, "NVRM: APM: received suspend event\n"); >+ status = rm_power_management(nv, 0, NV_PM_APM_SUSPEND); >+ __nv_disable_pat_support(); >+ break; >+ >+ // 2.4 kernels sent a PM_SAVE_STATE request when powering down via >+ // ACPI. just ignore it and return success so the power down works >+ case PM_SAVE_STATE: >+ status = RM_OK; >+ break; >+ >+ default: >+ nv_printf(NV_DBG_WARNINGS, "NVRM: APM: unsupported event: %d\n", rqst); >+ return 1; >+ } >+ >+ if (status != RM_OK) >+ nv_printf(NV_DBG_ERRORS, "NVRM: APM: failed event: %d\n", rqst); >+ >+ return status; >+} >+#endif /* defined(NV_PM_SUPPORT_OLD_STYLE_APM) */ >+ >+/* >+** nv_kern_ctl_open >+** >+** nv control driver open entry point. Sessions are created here. >+*/ >+int nv_kern_ctl_open( >+ struct inode *inode, >+ struct file *file >+) >+{ >+ nv_state_t *nv; >+ nv_linux_state_t *nvl; >+ int rc = 0; >+ >+ nvl = &nv_ctl_device; >+ nv = (nv_state_t *) nvl; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_ctl_open\n"); >+ >+ down(&nvl->ldata_lock); >+ >+ /* save the nv away in file->private_data */ >+ NVL_FROM_FILEP(file) = nvl; >+ >+ if (NV_ATOMIC_READ(nvl->usage_count) == 0) >+ { >+ init_waitqueue_head(&nv_ctl_waitqueue); >+ } >+ >+ nv->flags |= NV_FLAG_OPEN + NV_FLAG_CONTROL; >+ >+ /* turn off the hotkey occurred bit */ >+ nv->flags &= ~NV_FLAG_HOTKEY_OCCURRED; >+ >+ NV_ATOMIC_INC(nvl->usage_count); >+ up(&nvl->ldata_lock); >+ >+ return rc; >+} >+ >+ >+/* >+** nv_kern_ctl_close >+*/ >+int nv_kern_ctl_close( >+ struct inode *inode, >+ struct file *file >+) >+{ >+ nv_linux_state_t *nvl = NVL_FROM_FILEP(file); >+ nv_state_t *nv = NV_STATE_PTR(nvl); >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_kern_ctl_close\n"); >+ >+ down(&nvl->ldata_lock); >+ if (NV_ATOMIC_DEC_AND_TEST(nvl->usage_count)) >+ { >+ nv->flags &= ~(NV_FLAG_OPEN | NV_FLAG_HOTKEY_OCCURRED); >+ } >+ up(&nvl->ldata_lock); >+ >+ rm_free_unused_clients(nv, (void *)file); >+ >+ if (FILE_PRIVATE(file)) >+ { >+ nv_free_file_private(FILE_PRIVATE(file)); >+ FILE_PRIVATE(file) = NULL; >+ } >+ >+ return 0; >+} >+ >+ >+/* >+ * nv_kern_ctl_poll() - add the process to the wait queue >+ */ >+ >+unsigned int nv_kern_ctl_poll( >+ struct file *file, >+ poll_table *wait >+) >+{ >+ nv_linux_state_t *nvl; >+ nv_state_t *nv; >+ unsigned int ret = 0; >+ >+ nvl = NVL_FROM_FILEP(file); >+ nv = NV_STATE_PTR(nvl); >+ >+ if ( !(file->f_flags & O_NONBLOCK) ) >+ { >+ poll_wait(file, &nv_ctl_waitqueue, wait); >+ } >+ >+ nv_lock_rm(nv); >+ if (nv->flags & NV_FLAG_HOTKEY_OCCURRED) >+ { >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: a hotkey event has occurred\n"); >+ nv->flags &= ~NV_FLAG_HOTKEY_OCCURRED; >+ ret = POLLIN | POLLRDNORM; >+ } >+ nv_unlock_rm(nv); >+ >+ return ret; >+} >+ >+ >+ >+ >+/* >+ * nv_set_hotkey_occurred_flag() - set the hotkey flag and wake up anybody >+ * waiting on the wait queue >+ */ >+ >+void NV_API_CALL nv_set_hotkey_occurred_flag(void) >+{ >+ nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device); >+ >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: setting the hotkey occurred flag!\n"); >+ >+ nv_lock_rm(nv); >+ nv_ctl_device.nv_state.flags |= NV_FLAG_HOTKEY_OCCURRED; >+ nv_unlock_rm(nv); >+ >+ wake_up_interruptible(&nv_ctl_waitqueue); >+} >+ >+void NV_API_CALL nv_set_dma_address_size( >+ nv_state_t *nv, >+ U032 phys_addr_bits >+) >+{ >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+#ifdef NV_SWIOTLB >+ if (swiotlb && !nv_swiotlb && phys_addr_bits<=32) >+ { >+ nv_prints(NV_DBG_ERRORS, __swiotlb_warning); >+ nvos_proc_add_text_file(proc_nvidia_warnings, "swiotlb", >+ __swiotlb_warning); >+ nv_swiotlb = 1; >+ } >+#endif >+ >+ nvl->dev->dma_mask = (((u64)1) << phys_addr_bits) - 1; >+} >+ >+static int >+nv_kern_read_cardinfo(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ struct pci_dev *dev; >+ char *type, *fmt, tmpstr[NV_DEVICE_NAME_LENGTH]; >+ int len = 0, status; >+ U032 vbios_rev1, vbios_rev2, vbios_rev3, vbios_rev4, vbios_rev5; >+ >+ nv_state_t *nv; >+ nv = (nv_state_t *) data; >+ *eof = 1; >+ >+ dev = nv_get_pci_device(nv); >+ if (!dev) >+ return 0; >+ >+ if (rm_get_device_name(nv, dev->device, NV_DEVICE_NAME_LENGTH, >+ tmpstr) != RM_OK) { >+ strcpy (tmpstr, "Unknown"); >+ } >+ >+ len += sprintf(page+len, "Model: \t\t %s\n", tmpstr); >+ len += sprintf(page+len, "IRQ: \t\t %d\n", nv->interrupt_line); >+ >+ status = rm_get_vbios_version(nv, &vbios_rev1, &vbios_rev2, >+ &vbios_rev3, &vbios_rev4, &vbios_rev5); >+ >+ if (status < 0) { >+ /* before rm_init_adapter */ >+ len += sprintf(page+len, "Video BIOS: \t ??.??.??.??.??\n"); >+ } else { >+ fmt = "Video BIOS: \t %02x.%02x.%02x.%02x.%02x\n"; >+ len += sprintf(page+len, fmt, vbios_rev1, vbios_rev2, vbios_rev3, >+ vbios_rev4, vbios_rev5); >+ } >+ >+ if (nvos_find_agp_capability(dev)) type = "AGP"; >+ else if (nvos_find_pci_express_capability(dev)) type = "PCI-E"; >+ else type = "PCI"; >+ len += sprintf(page+len, "Card Type: \t %s\n", type); >+ >+ // Report the number of bits set in dev->dma_mask >+ len += sprintf(page+len, "DMA Size: \t %d bits\n", >+ nv_count_bits(dev->dma_mask)); >+ len += sprintf(page+len, "DMA Mask: \t 0x%llx\n", dev->dma_mask); >+ >+ NV_PCI_DEV_PUT(dev); >+ return len; >+} >+ >+static int >+nv_kern_read_version(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ int len = 0; >+ *eof = 1; >+ >+ len += sprintf(page+len, "NVRM version: %s\n", pNVRM_ID); >+ len += sprintf(page+len, "GCC version: %s\n", NV_COMPILER); >+ >+ return len; >+} >+ >+static int >+nv_kern_read_agpinfo(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ struct pci_dev *dev; >+ char *fw, *sba; >+ u8 cap_ptr; >+ u32 status, command, agp_rate; >+ int len = 0; >+ >+ nv_state_t *nv; >+ nv = (nv_state_t *) data; >+ *eof = 1; >+ >+ if (nv) { >+ dev = nv_get_pci_device(nv); >+ if (!dev) >+ return 0; >+ } else { >+ dev = nvos_get_agp_device_by_class(PCI_CLASS_BRIDGE_HOST); >+ if (!dev) >+ return 0; >+ >+ len += sprintf(page+len, "Host Bridge: \t "); >+ >+#if defined(CONFIG_PCI_NAMES) >+ len += sprintf(page+len, "%s\n", NV_PCI_DEVICE_NAME(dev)); >+#else >+ len += sprintf(page+len, "PCI device %04x:%04x\n", >+ dev->vendor, dev->device); >+#endif >+ } >+ >+ /* what can this AGP device do? */ >+ cap_ptr = nvos_find_agp_capability(dev); >+ >+ pci_read_config_dword(dev, cap_ptr + 4, &status); >+ pci_read_config_dword(dev, cap_ptr + 8, &command); >+ >+ fw = (status & 0x00000010) ? "Supported" : "Not Supported"; >+ sba = (status & 0x00000200) ? "Supported" : "Not Supported"; >+ >+ len += sprintf(page+len, "Fast Writes: \t %s\n", fw); >+ len += sprintf(page+len, "SBA: \t\t %s\n", sba); >+ >+ agp_rate = status & 0x7; >+ if (status & 0x8) // agp 3.0 >+ agp_rate <<= 2; >+ >+ len += sprintf(page+len, "AGP Rates: \t %s%s%s%s\n", >+ (agp_rate & 0x00000008) ? "8x " : "", >+ (agp_rate & 0x00000004) ? "4x " : "", >+ (agp_rate & 0x00000002) ? "2x " : "", >+ (agp_rate & 0x00000001) ? "1x " : ""); >+ >+ len += sprintf(page+len, "Registers: \t 0x%08x:0x%08x\n", status, command); >+ >+ NV_PCI_DEV_PUT(dev); >+ return len; >+} >+ >+static int >+nv_kern_read_status(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ struct pci_dev *dev; >+ char *fw, *sba, *drv; >+ int len = 0; >+ u8 cap_ptr; >+ u32 scratch; >+ u32 status, command, agp_rate; >+ >+ nv_state_t *nv; >+ nv = (nv_state_t *) data; >+ *eof = 1; >+ >+ dev = nvos_get_agp_device_by_class(PCI_CLASS_BRIDGE_HOST); >+ if (!dev) >+ return 0; >+ cap_ptr = nvos_find_agp_capability(dev); >+ >+ pci_read_config_dword(dev, cap_ptr + 4, &status); >+ pci_read_config_dword(dev, cap_ptr + 8, &command); >+ NV_PCI_DEV_PUT(dev); >+ >+ dev = nvos_get_agp_device_by_class(PCI_CLASS_DISPLAY_VGA); >+ if (!dev) >+ return 0; >+ cap_ptr = nvos_find_agp_capability(dev); >+ >+ pci_read_config_dword(dev, cap_ptr + 4, &scratch); >+ status &= scratch; >+ pci_read_config_dword(dev, cap_ptr + 8, &scratch); >+ command &= scratch; >+ >+ if (NV_AGP_ENABLED(nv) && (command & 0x100)) { >+ len += sprintf(page+len, "Status: \t Enabled\n"); >+ >+ drv = NV_OSAGP_ENABLED(nv) ? "AGPGART" : "NVIDIA"; >+ len += sprintf(page+len, "Driver: \t %s\n", drv); >+ >+ // mask off agp rate. >+ // If this is agp 3.0, we need to shift the value >+ agp_rate = command & 0x7; >+ if (status & 0x8) // agp 3.0 >+ agp_rate <<= 2; >+ >+ len += sprintf(page+len, "AGP Rate: \t %dx\n", agp_rate); >+ >+ fw = (command & 0x00000010) ? "Enabled" : "Disabled"; >+ len += sprintf(page+len, "Fast Writes: \t %s\n", fw); >+ >+ sba = (command & 0x00000200) ? "Enabled" : "Disabled"; >+ len += sprintf(page+len, "SBA: \t\t %s\n", sba); >+ } else { >+ int agp_config = 0; >+ >+ len += sprintf(page+len, "Status: \t Disabled\n\n"); >+ >+ /* >+ * If we find AGP is disabled, but the RM registry indicates it >+ * was requested, direct the user to the kernel log (we, or even >+ * the kernel may have printed a warning/an error message). >+ * >+ * Note that the "XNvAGP" registry key reflects the user request >+ * and overrides the RM "NvAGP" key, if present. >+ */ >+ rm_read_registry_dword(nv, "NVreg", "NvAGP", &agp_config); >+ rm_read_registry_dword(nv, "NVreg", "XNvAGP", &agp_config); >+ >+ if (agp_config != NVOS_AGP_CONFIG_DISABLE_AGP && NV_AGP_FAILED(nv)) { >+ len += sprintf(page+len, >+ "AGP initialization failed, please check the ouput \n" >+ "of the 'dmesg' command and/or your system log file \n" >+ "for additional information on this problem. \n"); >+ } >+ } >+ >+ NV_PCI_DEV_PUT(dev); >+ return len; >+} >+ >+extern nv_parm_t nv_parms[]; >+extern char *NVreg_RegistryDwords; >+ >+static int >+nv_kern_read_registry(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ unsigned int i, len = 0; >+ nv_parm_t *entry; >+ *eof = 1; >+ >+ for (i = 0; (entry = &nv_parms[i])->name != NULL; i++) >+ len += sprintf(page+len, "%s: %u\n", entry->name, *entry->data); >+ >+ len += sprintf(page+len, "RegistryDwords: \"%s\"\n", >+ (NVreg_RegistryDwords != NULL) ? NVreg_RegistryDwords : ""); >+ >+ return len; >+} >+ >+static int >+nv_kern_read_text_file(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ *eof = 1; >+ return sprintf(page, "%s", (char *)data); >+} >+ >+/*** >+ *** EXPORTS to rest of resman >+ ***/ >+ >+/* >+ * Given a physical address, find the associated 'at', track down >+ * the actual page within the allocation and return a kernel virtual >+ * mapping to it. Make sure to save the page offset if the address >+ * isn't aligned. >+ * >+ * If the requested mapping spans more than one page, then determine >+ * the individual pages and create a mapping with vmap(). >+ */ >+void* NV_API_CALL nv_alloc_kernel_mapping( >+ nv_state_t *nv, >+ NvU64 address, >+ U032 size, >+ void **priv_data >+) >+{ >+ nv_alloc_t *at; >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ U032 i, offset; >+ >+ down(&nvl->at_lock); >+ at = nvl_find_alloc(nvl, address, NV_ALLOC_TYPE_PCI); >+ if (at != NULL) >+ { >+ offset = address & ~PAGE_MASK; >+ address &= PAGE_MASK; >+ >+ for (i = 0; i < at->num_pages; i++) >+ { >+ if ((address == at->page_table[i]->phys_addr) >+ || (address == at->page_table[i]->dma_addr)) >+ break; >+ } >+ >+ if (i == at->num_pages) /* not found */ >+ { >+ up(&nvl->at_lock); >+ return NULL; >+ } >+ } >+ else >+ { >+ at = nvl_find_alloc(nvl, address, NV_ALLOC_TYPE_AGP); >+ if (at != NULL) >+ { >+ offset = address - (unsigned long) at->key_mapping; >+ i = offset >> PAGE_SHIFT; >+ offset = address & ~PAGE_MASK; >+ >+ if (at->page_table[i]->virt_addr == 0) >+ { >+ up(&nvl->at_lock); >+ return NULL; >+ } >+ } >+ else >+ { >+ up(&nvl->at_lock); >+ return NULL; /* not found */ >+ } >+ } >+ up(&nvl->at_lock); >+ >+ if ((size + offset) <= PAGE_SIZE) >+ { >+ *priv_data = NULL; >+ return (void *)(at->page_table[i]->virt_addr + offset); >+ } >+ else >+ { >+#if defined(NV_VMAP_PRESENT) >+ U032 j, page_count; >+ unsigned long virt_addr; >+ struct page **pages; >+ >+ size += offset; /* adjust mapping size */ >+ page_count = (size >> PAGE_SHIFT) + ((size & ~PAGE_MASK) ? 1 : 0); >+ >+ if ((i + page_count) > at->num_pages) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: requested mapping exceeds allocation's boundary!\n"); >+ return NULL; >+ } >+ >+ NV_KMALLOC(pages, sizeof(struct page *) * page_count); >+ if (pages == NULL) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: failed to allocate vmap() page descriptor table!\n"); >+ return NULL; >+ } >+ >+ for (j = 0; j < page_count; j++) >+ pages[j] = NV_GET_PAGE_STRUCT(at->page_table[i+j]->phys_addr); >+ >+ NV_VMAP(virt_addr, pages, page_count, NV_ALLOC_MAPPING_CACHED(at->flags)); >+ NV_KFREE(pages, sizeof(struct page *) * page_count); >+ if (virt_addr == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: vmap() failed to map pages!\n"); >+ return NULL; >+ } >+ >+ *priv_data = (void *)(unsigned long)page_count; >+ return (void *)(virt_addr + offset); >+#else >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: This version of the Linux kernel does not provide the vmap()\n" >+ "NVRM: kernel interface. If you see this message, please update\n" >+ "NVRM: your kernel to Linux 2.4.22 or install a distribution kernel\n" >+ "NVRM: that supports the vmap() kernel interface.\n"); >+#endif >+ } >+ >+ return NULL; >+} >+ >+int NV_API_CALL nv_free_kernel_mapping( >+ nv_state_t *nv, >+ void *address, >+ void *priv_data >+) >+{ >+#if defined(NV_VMAP_PRESENT) >+ unsigned long virt_addr; >+ U032 page_count; >+ >+ virt_addr = (unsigned long)address & PAGE_MASK; >+ >+ if (virt_addr >= VMALLOC_START && virt_addr < VMALLOC_END) >+ { >+ page_count = (unsigned long)priv_data; >+ if (page_count == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: nv_free_kernel_mapping(): invalid page count!\n"); >+ return RM_ERROR; >+ } >+ >+ NV_VUNMAP(virt_addr, page_count); >+ } >+#endif >+ return RM_OK; >+} >+ >+ >+/* virtual address to physical page address */ >+NvU64 nv_get_phys_address( >+ NvU64 address, >+ BOOL kern >+) >+{ >+#if defined(NV_SET_PAGES_UC_PRESENT) >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: can't translate address in nv_get_phys_address()!\n"); >+#else >+ struct mm_struct *mm; >+ pgd_t *pgd = NULL; >+ pmd_t *pmd = NULL; >+ pte_t *pte = NULL; >+ NvU64 retval; >+ >+ if (!kern) >+ { >+ mm = current->mm; >+ down_read(&mm->mmap_sem); >+ } >+ else >+ mm = NULL; >+ >+ pgd = NV_PGD_OFFSET(address, kern, mm); >+ if (!NV_PGD_PRESENT(pgd)) >+ goto failed; >+ >+ pmd = NV_PMD_OFFSET(address, pgd); >+ if (!NV_PMD_PRESENT(pmd)) >+ goto failed; >+ >+ pte = NV_PTE_OFFSET(address, pmd); >+ if (!NV_PTE_PRESENT(pte)) >+ goto failed; >+ >+ retval = ((NV_PTE_VALUE(pte) & PAGE_MASK) | NV_MASK_OFFSET(address)); >+ >+#if defined(NVCPU_X86_64) && defined(_PAGE_NX) >+ // mask out the non-executable page bit for the true physical address >+ retval &= ~_PAGE_NX; >+#endif >+ >+ if (!kern) >+ up_read(&mm->mmap_sem); >+ return retval; >+ >+failed: >+ if (!kern) >+ up_read(&mm->mmap_sem); >+#endif >+ return 0; >+} >+ >+NvU64 NV_API_CALL nv_get_kern_phys_address(NvU64 address) >+{ >+ /* make sure this address is a kernel virtual address */ >+#if defined(DEBUG) && !defined(CONFIG_X86_4G) >+ if (address < PAGE_OFFSET) >+ { >+ nv_printf(NV_DBG_WARNINGS, >+ "NVRM: user address passed to get_kern_phys_address: 0x%llx!\n", >+ address); >+ return 0; >+ } >+#endif >+ >+ /* direct-mapped kernel address */ >+ if ((address > PAGE_OFFSET) && (address < VMALLOC_START)) >+ return __pa(address); >+ >+ return nv_get_phys_address(address, TRUE); >+} >+ >+NvU64 NV_API_CALL nv_get_kern_user_address(NvU64 address) >+{ >+ /* make sure this address is not a kernel virtual address */ >+#if defined(DEBUG) && !defined(CONFIG_X86_4G) >+ if (address >= PAGE_OFFSET) >+ { >+ nv_printf(NV_DBG_WARNINGS, >+ "NVRM: kernel address passed to get_user_phys_address: 0x%llx!\n", >+ address); >+ return 0; >+ } >+#endif >+ >+ return nv_get_phys_address(address, FALSE); >+} >+ >+ >+/* allocate memory for DMA push buffers */ >+int NV_API_CALL nv_alloc_pages( >+ nv_state_t *nv, >+ U032 page_count, >+ U032 agp_memory, >+ U032 contiguous, >+ U032 cache_type, >+ NvU64 *pte_array, >+ void **priv_data >+) >+{ >+ nv_alloc_t *at; >+ RM_STATUS rm_status = 0; >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ U032 i; >+ >+ nv_printf(NV_DBG_MEMINFO, "NVRM: VM: nv_alloc_pages: %d pages\n", page_count); >+ nv_printf(NV_DBG_MEMINFO, "NVRM: VM: agp %d contig %d cache_type %d\n", >+ agp_memory, contiguous, cache_type); >+ >+ /* if we can't support this caching, bail before we do any work */ >+ if (nv_encode_caching(NULL, cache_type, >+ agp_memory ? NV_MEMORY_TYPE_AGP : NV_MEMORY_TYPE_SYSTEM)) >+ return RM_ERROR; >+ >+ page_count = RM_PAGES_TO_OS_PAGES(page_count); >+ at = nvos_create_alloc(nvl->dev, page_count); >+ if (at == NULL) >+ return RM_ERROR; >+ >+ at->flags = nv_alloc_init_flags(cache_type, agp_memory, contiguous); >+ at->nv = nv; >+ >+ if (agp_memory) >+ { >+ U032 offset; >+ >+ if (!NV_AGP_ENABLED(nv)) >+ goto failed; >+ >+ /* allocate agp-able memory */ >+ if (NV_OSAGP_ENABLED(nv)) >+ { >+ /* agpgart will allocate all of the underlying memory */ >+ rm_status = KernAllocAGPPages(nv, page_count, priv_data, &offset); >+ if (rm_status) >+ goto failed; >+ >+ KernLoadAGPPages(nv, at, *priv_data); >+ } else { >+ rm_status = rm_alloc_agp_pages(nv, page_count, priv_data, &offset); >+ if (rm_status) >+ goto failed; >+ } >+ >+ at->priv_data = *priv_data; >+ nvl_add_alloc(nvl, at); >+ >+ pte_array[0] = (nv->agp.address + (offset << PAGE_SHIFT)); >+ at->key_mapping = (void *)(NvUPtr)pte_array[0]; >+ } >+ else >+ { >+ if (nv_vm_malloc_pages(nv, at)) >+ goto failed; >+ >+ /* >+ * must be page-aligned or mmap will fail >+ * so use the first page, which is page-aligned. this way, our >+ * allocated page table does not need to be page-aligned >+ */ >+ for (i = 0; i < ((contiguous) ? 1 : page_count); i++) >+ pte_array[i] = at->page_table[i]->dma_addr; >+ >+ at->key_mapping = (void *)at->page_table[0]->phys_addr; >+ nvl_add_alloc(nvl, at); >+ } >+ >+ *priv_data = at; >+ NV_ATOMIC_INC(at->usage_count); >+ >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ >+ return RM_OK; >+ >+failed: >+ nvos_free_alloc(at); >+ >+ return -1; >+} >+ >+int NV_API_CALL nv_free_pages( >+ nv_state_t *nv, >+ U032 page_count, >+ U032 agp_memory, >+ U032 contiguous, >+ U032 cache_type, >+ void *priv_data >+) >+{ >+ int rmStatus = 0; >+ nv_alloc_t *at = priv_data; >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+ page_count = RM_PAGES_TO_OS_PAGES(page_count); >+ nv_printf(NV_DBG_MEMINFO, "NVRM: VM: nv_free_pages: 0x%p 0x%x\n", >+ at->key_mapping, page_count); >+ >+ /* only lock ldata while removing 'at' from the list */ >+ down(&nvl->at_lock); >+ >+ NV_PRINT_AT(NV_DBG_MEMINFO, at); >+ >+ /* >+ * If the 'at' usage count doesn't drop to zero here, not all of >+ * the user mappings have been torn down in time - we can't >+ * safely free the memory. We report success back to the RM, but >+ * defer the actual free until later. >+ * >+ * This is described in greater detail in the comments above the >+ * nv_kern_vma_(open|release)() callbacks above. >+ */ >+ if (!NV_ATOMIC_DEC_AND_TEST(at->usage_count)) >+ { >+ up(&nvl->at_lock); >+ return 0; >+ } >+ >+ nvl_remove_alloc(nvl, at); >+ up(&nvl->at_lock); >+ >+ if (agp_memory) >+ { >+ if (!NV_AGP_ENABLED(nv)) >+ return -1; >+ >+ if (NV_OSAGP_ENABLED(nv)) >+ { >+ rmStatus = KernFreeAGPPages(nv, at->priv_data); >+ } else { >+ rmStatus = rm_free_agp_pages(nv, at->priv_data); >+ } >+ } else >+ nv_vm_free_pages(nv, at); >+ >+ nvos_free_alloc(at); >+ >+ return rmStatus; >+} >+ >+NvU64 NV_API_CALL nv_dma_to_mmap_token( >+ nv_state_t *nv, >+ NvU64 address >+) >+{ >+ return address; >+} >+ >+static void nv_lock_init_locks >+( >+ nv_state_t *nv >+) >+{ >+ nv_linux_state_t *nvl; >+ nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+ NV_SPIN_LOCK_INIT(&nvl->rm_lock); >+ >+ NV_INIT_MUTEX(&nvl->ldata_lock); >+ NV_INIT_MUTEX(&nvl->at_lock); >+ >+ NV_ATOMIC_SET(nvl->usage_count, 0); >+ >+ nvl->rm_lock_cpu = -1; >+ nvl->rm_lock_count = 0; >+} >+ >+void NV_API_CALL nv_lock_rm( >+ nv_state_t *nv >+) >+{ >+ nv_linux_state_t *nvl; >+ int cpu; >+ >+ nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ cpu = get_cpu(); >+ >+ if (nvl->rm_lock_cpu == cpu) >+ { >+ nvl->rm_lock_count++; >+ put_cpu(); >+ return; >+ } >+ >+ put_cpu(); >+ NV_SPIN_UNLOCK_WAIT(&nvl->rm_lock); >+ NV_SPIN_LOCK_IRQ(&nvl->rm_lock); >+ >+ nvl->rm_lock_cpu = smp_processor_id(); >+ nvl->rm_lock_count = 1; >+} >+ >+void NV_API_CALL nv_unlock_rm( >+ nv_state_t *nv >+) >+{ >+ nv_linux_state_t *nvl; >+ nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+ if (--nvl->rm_lock_count) >+ return; >+ >+ nvl->rm_lock_cpu = -1; >+ NV_SPIN_UNLOCK_IRQ(&nvl->rm_lock); >+} >+ >+/* >+** post the event >+*/ >+ >+void NV_API_CALL nv_post_event( >+ nv_state_t *nv, >+ nv_event_t *event, >+ U032 handle, >+ U032 index >+) >+{ >+ struct file *file = (struct file *) event->file; >+ nv_file_private_t *nvfp = NV_GET_NVFP(file); >+ unsigned long eflags; >+ nvidia_event_t *nvet; >+ >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: posting event on 0x%x:0x%x\n", >+ event, nvfp); >+ >+ NV_KMALLOC_ATOMIC(nvet, sizeof(nvidia_event_t)); >+ >+ if (nvet == NULL) >+ return; >+ >+ NV_SPIN_LOCK_IRQSAVE(&nvfp->fp_lock, eflags); >+ >+ // Insert the event struct in the queue >+ if (nvfp->event_tail != NULL) >+ nvfp->event_tail->next = nvet; >+ if (nvfp->event_head == NULL) >+ nvfp->event_head = nvet; >+ nvfp->event_tail = nvet; >+ nvet->next = NULL; >+ >+ // copy the event into the queue >+ nvet->event = *event; >+ >+ // set the handle for this event >+ nvet->event.hObject = handle; >+ nvet->event.index = index; >+ >+ wake_up_interruptible(&nvfp->waitqueue); >+ NV_SPIN_UNLOCK_IRQRESTORE(&nvfp->fp_lock, eflags); >+} >+ >+int NV_API_CALL nv_get_event( >+ nv_state_t *nv, >+ void *void_file, >+ nv_event_t *event, >+ U032 *more_events >+) >+{ >+ struct file *file = (struct file *) void_file; >+ nv_file_private_t *nvfp = NV_GET_NVFP(file); >+ nvidia_event_t *nvet; >+ unsigned long eflags; >+ >+ NV_SPIN_LOCK_IRQSAVE(&nvfp->fp_lock, eflags); >+ if (nvfp->event_head == NULL) >+ { >+ NV_SPIN_UNLOCK_IRQRESTORE(&nvfp->fp_lock, eflags); >+ return -1; >+ } >+ >+ nvet = nvfp->event_head; >+ >+ *event = nvet->event; >+ >+ if (nvfp->event_tail == nvet) >+ nvfp->event_tail = NULL; >+ nvfp->event_head = nvet->next; >+ >+ NV_KFREE(nvet, sizeof(nvidia_event_t)); >+ >+ if (more_events) >+ *more_events = (nvfp->event_head != NULL); >+ >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: returning event: 0x%x\n", event); >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: hParent: 0x%x\n", event->hParent); >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: hObject: 0x%x\n", event->hObject); >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: file: 0x%p\n", event->file); >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: fd: %d\n", event->fd); >+ if (more_events) >+ nv_printf(NV_DBG_EVENTINFO, "NVRM: more events: %d\n", *more_events); >+ >+ NV_SPIN_UNLOCK_IRQRESTORE(&nvfp->fp_lock, eflags); >+ >+ return 0; >+} >+ >+ >+int NV_API_CALL nv_agp_init( >+ nv_state_t *nv, >+ void **phys_start, >+ void *agp_limit, >+ U032 config /* passed in from XF86Config file */ >+) >+{ >+ U032 status = 1; >+ static int old_error = 0; >+ >+ if (NV_AGP_ENABLED(nv)) >+ return -1; >+ >+ if (config == NVOS_AGP_CONFIG_DISABLE_AGP) >+ { >+ nv->agp_config = NVOS_AGP_CONFIG_DISABLE_AGP; >+ nv->agp_status = NV_AGP_STATUS_DISABLED; >+ return 0; >+ } >+ >+ nv_printf(NV_DBG_SETUP, "NVRM: nv_agp_init\n"); >+ >+ nv->agp_config = NVOS_AGP_CONFIG_DISABLE_AGP; >+ nv->agp_status = NV_AGP_STATUS_FAILED; >+ >+ if (config & NVOS_AGP_CONFIG_OSAGP) >+ { >+ status = KernInitAGP(nv, phys_start, agp_limit); >+ >+ /* if enabling agpgart was successfull, register it, >+ * and check about overrides >+ */ >+ if (status == 0) >+ { >+ nv->agp_config = NVOS_AGP_CONFIG_OSAGP; >+ nv->agp_status = NV_AGP_STATUS_ENABLED; >+ >+ /* make sure we apply our overrides in this case */ >+ rm_update_agp_config(nv); >+ } >+ >+ if (status == 1 && !(config & NVOS_AGP_CONFIG_NVAGP) && !old_error) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: unable to initialize the Linux AGPGART driver, please \n" >+ "NVRM: verify you configured your kernel to include support \n" >+ "NVRM: for AGPGART (either statically linked, or as a kernel \n" >+ "NVRM: module). Please also make sure you selected support \n" >+ "NVRM: for your AGP chipset. \n"); >+#if !defined(KERNEL_2_4) >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: \n" >+ "NVRM: note that as of Linux 2.6 AGPGART, all chipset/vendor \n" >+ "NVRM: drivers are split into independent modules; make sure \n" >+ "NVRM: the correct one is loaded for your chipset. \n"); >+#endif >+ old_error = 1; >+ } >+ >+ /* if agpgart is loaded, but we failed to initialize it, >+ * we'd better not attempt nvagp, or we're likely to lock >+ * the machine. >+ */ >+ if (status < 0) >+ return status; >+ } >+ >+ /* we're either explicitly not using agpgart, >+ * or trying to use agpgart failed >+ * make sure the user did not specify "use agpgart only" >+ */ >+ if ( (!NV_AGP_ENABLED(nv)) && (config & NVOS_AGP_CONFIG_NVAGP) ) >+ { >+ /* make sure the user does not have agpgart loaded */ >+#if defined(KERNEL_2_4) >+ if (inter_module_get("drm_agp")) >+ { >+ inter_module_put("drm_agp"); >+ nv_printf(NV_DBG_WARNINGS, "NVRM: not using NVAGP, AGPGART is loaded!\n"); >+ return status; >+ } >+#elif defined(AGPGART) >+#if (NV_AGP_BACKEND_ACQUIRE_ARGUMENT_COUNT == 1) >+ if (!list_empty(&agp_bridges)) >+ { >+ nv_printf(NV_DBG_WARNINGS, >+ "NVRM: not using NVAGP, an AGPGART backend is loaded!\n"); >+ return status; >+ } >+#else >+ int error; >+ /* >+ * We can only safely use NvAGP when no backend has been >+ * registered with the AGPGART frontend. This condition >+ * is only met when the acquire function returns -EINVAL. >+ * >+ * Other return codes indicate that a backend is present >+ * and was either acquired, busy or else unavailable. >+ */ >+ if ((error = agp_backend_acquire()) != -EINVAL) >+ { >+ if (!error) agp_backend_release(); >+ nv_printf(NV_DBG_WARNINGS, >+ "NVRM: not using NVAGP, an AGPGART backend is loaded!\n"); >+ return status; >+ } >+#endif >+#endif /* AGPGART */ >+#if defined(CONFIG_X86_64) && defined(CONFIG_GART_IOMMU) >+ nv_printf(NV_DBG_WARNINGS, >+ "NVRM: not using NVAGP, kernel was compiled with GART_IOMMU support!!\n"); >+#else >+ status = rm_init_agp(nv); >+ if (status == RM_OK) >+ { >+ nv->agp_config = NVOS_AGP_CONFIG_NVAGP; >+ nv->agp_status = NV_AGP_STATUS_ENABLED; >+ } >+#endif >+ } >+ >+ if (NV_AGP_ENABLED(nv)) >+ old_error = 0; /* report new errors */ >+ >+ return status; >+} >+ >+int NV_API_CALL nv_agp_teardown( >+ nv_state_t *nv >+) >+{ >+ U032 status = 1; >+ >+ nv_printf(NV_DBG_SETUP, "NVRM: nv_agp_teardown\n"); >+ >+ /* little sanity check won't hurt */ >+ if (!NV_AGP_ENABLED(nv)) >+ return -1; >+ >+ if (NV_OSAGP_ENABLED(nv)) >+ status = KernTeardownAGP(nv); >+ else if (NV_NVAGP_ENABLED(nv)) >+ status = rm_teardown_agp(nv); >+ >+ nv->agp_config = NVOS_AGP_CONFIG_DISABLE_AGP; >+ nv->agp_status = NV_AGP_STATUS_DISABLED; >+ >+ return status; >+} >+ >+int NV_API_CALL nv_int10h_call( >+ nv_state_t *nv, >+ U032 *eax, >+ U032 *ebx, >+ U032 *ecx, >+ U032 *edx, >+ void *buffer >+) >+{ >+ return -1; >+} >+ >+/* set a timer to go off every second */ >+int NV_API_CALL nv_start_rc_timer( >+ nv_state_t *nv >+) >+{ >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+ if (nv->rc_timer_enabled) >+ return -1; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: initializing rc timer\n"); >+ init_timer(&nvl->rc_timer); >+ nvl->rc_timer.function = nv_kern_rc_timer; >+ nvl->rc_timer.data = (unsigned long) nv; >+ nv->rc_timer_enabled = 1; >+ mod_timer(&nvl->rc_timer, jiffies + HZ); /* set our timeout for 1 second */ >+ nv_printf(NV_DBG_INFO, "NVRM: rc timer initialized\n"); >+ >+ return 0; >+} >+ >+int NV_API_CALL nv_stop_rc_timer( >+ nv_state_t *nv >+) >+{ >+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); >+ >+ if (!nv->rc_timer_enabled) >+ return -1; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: stopping rc timer\n"); >+ nv->rc_timer_enabled = 0; >+ del_timer_sync(&nvl->rc_timer); >+ nv_printf(NV_DBG_INFO, "NVRM: rc timer stopped\n"); >+ >+ return 0; >+} >+ >+/* make sure the pci_driver called probe for all of our devices. >+ * we've seen cases where rivafb claims the device first and our driver >+ * doesn't get called. >+ */ >+static int >+nvos_count_devices(void) >+{ >+ struct pci_dev *dev; >+ int count = 0; >+ >+ dev = NV_PCI_GET_CLASS(PCI_CLASS_DISPLAY_VGA << 8, NULL); >+ while (dev) >+ { >+ if ((dev->vendor == 0x10de) && (dev->device >= 0x20) && >+ !rm_is_legacy_device(dev->device, TRUE)) >+ count++; >+ dev = NV_PCI_GET_CLASS(PCI_CLASS_DISPLAY_VGA << 8, dev); >+ } >+ >+ dev = NV_PCI_GET_CLASS(PCI_CLASS_DISPLAY_3D << 8, NULL); >+ while (dev) >+ { >+ if ((dev->vendor == 0x10de) && (dev->device >= 0x20) && >+ !rm_is_legacy_device(dev->device, TRUE)) >+ count++; >+ dev = NV_PCI_GET_CLASS(PCI_CLASS_DISPLAY_3D << 8, dev); >+ } >+ >+ return count; >+} >+ >+/* find nvidia devices and set initial state */ >+int >+nv_kern_probe >+( >+ struct pci_dev *dev, >+ const struct pci_device_id *id_table >+) >+{ >+ nv_state_t *nv; >+ nv_linux_state_t *nvl; >+ unsigned int i, j; >+ >+ nv_printf(NV_DBG_SETUP, "NVRM: probing 0x%x 0x%x, class 0x%x\n", >+ dev->vendor, dev->device, dev->class); >+ >+ if ((dev->vendor != 0x10de) || (dev->device < 0x20) || >+ ((dev->class != (PCI_CLASS_DISPLAY_VGA << 8)) && >+ (dev->class != (PCI_CLASS_DISPLAY_3D << 8))) || >+ rm_is_legacy_device(dev->device, FALSE)) >+ { >+ return -1; >+ } >+ >+ num_probed_nv_devices++; >+ >+ if (num_nv_devices == NV_MAX_DEVICES) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: maximum device number (%d) exceeded!\n", >+ (NV_MAX_DEVICES - 1)); >+ return -1; >+ } >+ >+ if (pci_enable_device(dev) != 0) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: pci_enable_device failed, aborting\n"); >+ return -1; >+ } >+ >+ if (dev->irq == 0) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: Can't find an IRQ for your NVIDIA card!\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: Please check your BIOS settings.\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: [Plug & Play OS] should be set to NO\n"); >+ nv_printf(NV_DBG_ERRORS, "NVRM: [Assign IRQ to VGA] should be set to YES \n"); >+ return -1; >+ } >+ >+ // we won't always have a bar 3 >+ for (i = 0; i < (NV_GPU_NUM_BARS - 1); i++) >+ { >+ if (NV_PCI_RESOURCE_VALID(dev, i)) >+ continue; >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: This PCI I/O region assigned to your NVIDIA device is invalid:\n" >+ "NVRM: BAR%d is %dM @ 0x%08x (PCI:%04x:%02x.%x)\n", i, >+ NV_PCI_RESOURCE_SIZE(dev, i) >> 20, NV_PCI_RESOURCE_START(dev, i), >+ NV_PCI_BUS_NUMBER(dev), NV_PCI_SLOT_NUMBER(dev), PCI_FUNC(dev->devfn)); >+ if (NV_PCI_RESOURCE_FLAGS(dev, i) & PCI_BASE_ADDRESS_MEM_TYPE_64) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: This is a 64-bit BAR, which some Linux kernels are known to\n" >+ "NVRM: ignore or handle incorrectly. Please see the README section\n" >+ "NVRM: on 64-bit BARs for more information.\n"); >+ } >+ else >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: The system BIOS may have misconfigured your graphics card.\n"); >+ } >+ return -1; >+ } >+ >+ // request ownership of our bars >+ // keeps other drivers from banging our registers. >+ // only do this for registers, as vesafb requests our framebuffer and will >+ // keep us from working properly >+ if (!request_mem_region(NV_PCI_RESOURCE_START(dev, NV_GPU_BAR_INDEX_REGS), >+ NV_PCI_RESOURCE_SIZE(dev, NV_GPU_BAR_INDEX_REGS), "nvidia")) >+ { >+ nv_printf(NV_DBG_ERRORS, >+ "NVRM: request_mem_region failed for %dM @ 0x%08x. This can\n" >+ "NVRM: occur when a driver such as rivatv is loaded and claims\n" >+ "NVRM: ownership of the device's registers.\n", >+ NV_PCI_RESOURCE_SIZE(dev, NV_GPU_BAR_INDEX_REGS) >> 20, >+ NV_PCI_RESOURCE_START(dev, NV_GPU_BAR_INDEX_REGS)); >+ return -1; >+ } >+ pci_set_master(dev); >+ >+ /* initialize bus-dependent config state */ >+ nvl = &nv_linux_devices[num_nv_devices]; >+ nv = NV_STATE_PTR(nvl); >+ >+ pci_set_drvdata(dev, (void *)nvl); >+ >+ /* default to 32-bit PCI bus address space */ >+ dev->dma_mask = 0xffffffffULL; >+ >+ nvl->dev = dev; >+ nv->vendor_id = dev->vendor; >+ nv->device_id = dev->device; >+ nv->os_state = (void *) nvl; >+ nv->bus = NV_PCI_BUS_NUMBER(dev); >+ nv->slot = NV_PCI_SLOT_NUMBER(dev); >+ nv->handle = dev; >+ >+ nv_lock_init_locks(nv); >+ >+ for (i = 0, j = 0; i < NVRM_PCICFG_NUM_BARS && j < NV_GPU_NUM_BARS; i++) >+ { >+ if ((NV_PCI_RESOURCE_VALID(dev, i)) && >+ (NV_PCI_RESOURCE_FLAGS(dev, i) & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) >+ { >+ nv->bars[j].address = NV_PCI_RESOURCE_START(dev, i); >+ nv->bars[j].size = NV_PCI_RESOURCE_SIZE(dev, i); >+ nv->bars[j].offset = NVRM_PCICFG_BAR_OFFSET(i); >+ j++; >+ } >+ } >+ nv->regs = &nv->bars[NV_GPU_BAR_INDEX_REGS]; >+ nv->fb = &nv->bars[NV_GPU_BAR_INDEX_FB]; >+ >+ nv->interrupt_line = dev->irq; >+ >+#if defined(CONFIG_VGA_ARB) >+#if defined(VGA_DEFAULT_DEVICE) >+ vga_tryget(VGA_DEFAULT_DEVICE, VGA_RSRC_LEGACY_MASK); >+#endif >+ vga_set_legacy_decoding(dev, VGA_RSRC_NONE); >+#endif >+ >+ if (!rm_init_private_state(nv)) >+ { >+ nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_private_state() failed!\n"); >+ goto err_zero_dev; >+ } >+ >+ nv_printf(NV_DBG_INFO, "NVRM: %02x:%02x.%x %04x:%04x - 0x%08x [size=%dM]\n", >+ nv->bus, nv->slot, PCI_FUNC(dev->devfn), >+ nv->vendor_id, nv->device_id, nv->regs->address, >+ nv->regs->size / (1024 * 1024)); >+ nv_printf(NV_DBG_INFO, "NVRM: %02x:%02x.%x %04x:%04x - 0x%08x [size=%dM]\n", >+ nv->bus, nv->slot, PCI_FUNC(dev->devfn), >+ nv->vendor_id, nv->device_id, nv->fb->address, >+ nv->fb->size / (1024 * 1024)); >+ >+ num_nv_devices++; >+ >+ return 0; >+ >+err_zero_dev: >+ rm_free_private_state(nv); >+ os_mem_set(nvl, 0, sizeof(nv_linux_state_t)); >+ release_mem_region(NV_PCI_RESOURCE_START(dev, NV_GPU_BAR_INDEX_REGS), >+ NV_PCI_RESOURCE_SIZE(dev, NV_GPU_BAR_INDEX_REGS)); >+ NV_PCI_DISABLE_DEVICE(dev); >+ return -1; >+} >+ >+int NV_API_CALL nv_no_incoherent_mappings(void) >+{ >+#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || defined(NV_SET_PAGES_UC_PRESENT) >+ return (nv_update_memory_types); >+#else >+ return 0; >+#endif >+} >+ >+#if defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL) >+ >+static int >+nv_power_management( >+ struct pci_dev *dev, >+ u32 state >+) >+{ >+ nv_state_t *nv; >+ nv_linux_state_t *lnv = NULL; >+ int status = RM_OK; >+ >+ nv_printf(NV_DBG_INFO, "NVRM: nv_power_management: %d\n", state); >+ lnv = pci_get_drvdata(dev); >+ >+ if ((!lnv) || (lnv->dev != dev)) >+ { >+ nv_printf(NV_DBG_WARNINGS, "NVRM: PM: invalid device!\n"); >+ return -1; >+ } >+ >+ nv = NV_STATE_PTR(lnv); >+ >+ nv_verify_pci_config(nv); >+ >+ switch (state) >+ { >+#if defined(NV_PM_SUPPORT_NEW_STYLE_APM) >+ case PCI_D3hot: >+ nv_printf(NV_DBG_INFO, "NVRM: APM: received suspend event\n"); >+ status = rm_power_management(nv, 0, NV_PM_APM_SUSPEND); >+ __nv_disable_pat_support(); >+ break; >+ >+ case PCI_D0: >+ nv_printf(NV_DBG_INFO, "NVRM: APM: received resume event\n"); >+ __nv_enable_pat_support(); >+ status = rm_power_management(nv, 0, NV_PM_APM_RESUME); >+ break; >+ >+#else /* end of NV_PM_SUPPORT_NEW_STYLE_APM */ >+ case PCI_D3hot: >+ nv_printf(NV_DBG_INFO, "NVRM: ACPI: received suspend event\n"); >+ status = rm_power_management(nv, 0, NV_PM_ACPI_STANDBY); >+ __nv_disable_pat_support(); >+ break; >+ >+ case PCI_D0: >+ nv_printf(NV_DBG_INFO, "NVRM: ACPI: received resume event\n"); >+ __nv_enable_pat_support(); >+ status = rm_power_management(nv, 0, NV_PM_ACPI_RESUME); >+ break; >+ >+#endif /* End of NV_PM_SUPPORT_NEW_STYLE_APM */ >+ >+ default: >+ nv_printf(NV_DBG_WARNINGS, "NVRM: PM: unsupported event: %d\n", state); >+ return -1; >+ } >+ >+ if (status != RM_OK) >+ nv_printf(NV_DBG_ERRORS, "NVRM: PM: failed event: %d\n", state); >+ >+ return status; >+} >+ >+static int nv_kern_suspend( >+ struct pci_dev *dev, >+ pm_message_t state >+) >+{ >+ int power_state = -1; >+ >+#if !defined(NV_PM_MESSAGE_T_PRESENT) >+ power_state = state; >+#elif defined(NV_PCI_CHOOSE_STATE_PRESENT) >+ power_state = pci_choose_state(dev, state); >+#endif >+ >+ return nv_power_management(dev, power_state); >+} >+ >+static int nv_kern_resume( >+ struct pci_dev *dev >+) >+{ >+ return nv_power_management(dev, PCI_D0); >+} >+ >+#endif /* defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL) */ >+ >+void* NV_API_CALL nv_get_adapter_state( >+ U016 bus, >+ U016 slot >+) >+{ >+ unsigned int i; >+ >+ for (i = 0; i < num_nv_devices; i++) >+ { >+ nv_state_t *nv = NV_STATE_PTR(&nv_linux_devices[i]); >+ if (nv->bus == bus && nv->slot == slot) >+ return (void *) nv; >+ } >+ >+ return NULL; >+} >+ >+void NV_API_CALL nv_verify_pci_config( >+ nv_state_t *nv >+) >+{ >+ BOOL check_the_bars; >+ >+ check_the_bars = (!nv_mmconfig_failure_detected && NV_MAY_SLEEP()); >+ rm_check_pci_config_space(nv, check_the_bars, &nv_mmconfig_failure_detected); >+ >+ if (nv_mmconfig_failure_detected) >+ { >+ if (NV_MAY_SLEEP()) >+ { >+ nvos_proc_add_text_file(proc_nvidia_warnings, "mmconfig", >+ __mmconfig_warning); >+ } >+ nv_prints(NV_DBG_ERRORS, __mmconfig_warning); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 510020
: 376704 |
376706