diff --git a/Makefile b/Makefile
index 182163b..4a3ce10 100644
--- a/Makefile
+++ b/Makefile
@@ -77,8 +77,11 @@ include dist-files.mk
 include $(COMMON_UTILS_DIR)/src.mk
 SRC += $(addprefix $(COMMON_UTILS_DIR)/,$(COMMON_UTILS_SRC))
 
-# rpcgen generates code that emits unused variable warnings
+# rpcgen generates code that emits unused variable warnings and suspicious
+# function type casts
 $(call BUILD_OBJECT_LIST,$(RPC_SRC)): CFLAGS += -Wno-unused-variable
+suppress_cast_func_type_warning := $(call TEST_CC_ARG,-Wno-cast-function-type)
+$(call BUILD_OBJECT_LIST,$(RPC_SRC)): CFLAGS += $(suppress_cast_func_type_warning)
 
 OBJS = $(call BUILD_OBJECT_LIST,$(SRC))
 
diff --git a/common-utils/msg.c b/common-utils/msg.c
index 8a78530..70772a2 100644
--- a/common-utils/msg.c
+++ b/common-utils/msg.c
@@ -113,7 +113,7 @@ do {                                               \
     NV_VSNPRINTF(buf, fmt);                        \
     format(stream, prefix, buf, whitespace);       \
     free (buf);                                    \
-} while(0)
+} while (0)
 
 
 /*
diff --git a/common-utils/nvgetopt.c b/common-utils/nvgetopt.c
index 286aee8..5ae3a14 100644
--- a/common-utils/nvgetopt.c
+++ b/common-utils/nvgetopt.c
@@ -189,7 +189,7 @@ int nvgetopt(int argc,
                     if (a[0] == '-') a++;
                     if (a[0] == '+') a++;
 
-                    while(a[0]) { a[0] = a[1]; a++; }
+                    while (a[0]) { a[0] = a[1]; a++; }
 
                     /*
                      * decrement argv_index so that we process this
diff --git a/common-utils/nvpci-utils.c b/common-utils/nvpci-utils.c
new file mode 100644
index 0000000..62946d2
--- /dev/null
+++ b/common-utils/nvpci-utils.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "nvpci-utils.h"
+
+/*
+ * libpciaccess stores the device class in bits 16-23, subclass in 8-15, and
+ * interface in bits 0-7 of dev->device_class.  We care only about the class
+ * and subclass.
+ */
+const uint32_t PCI_CLASS_DISPLAY_VGA = 0x30000;
+const uint32_t PCI_CLASS_SUBCLASS_MASK = 0xffff00;
+
+/*
+ * nvpci_find_gpu_by_vendor() - use libpciaccess to find all VGA and 3D PCI
+ * devices matching the passed-in vendor_id (which may be set to PCI_MATCH_ANY).
+ * The caller is responsible for calling pci_system_init() before using this
+ * function, and pci_system_cleanup() when libpciaccess is no longer needed.
+ */
+struct pci_device_iterator *nvpci_find_gpu_by_vendor(uint32_t vendor_id)
+{
+    const struct pci_id_match match = {
+        .vendor_id = vendor_id,
+        .device_id = PCI_MATCH_ANY,
+        .subvendor_id = PCI_MATCH_ANY,
+        .subdevice_id = PCI_MATCH_ANY,
+        .device_class = PCI_CLASS_DISPLAY_VGA,
+        /*
+         * Ignore bit 1 of the subclass, to allow both 0x30000 (VGA controller)
+         * and 0x30200 (3D controller).
+         */
+        .device_class_mask = PCI_CLASS_SUBCLASS_MASK & ~0x200,
+    };
+
+    return pci_id_match_iterator_create(&match);
+}
+
+/*
+ * nvpci_dev_is_vga() - test whether the passed-in struct pci_device* has the
+ * VGA device class 0x0300 (and not 3D class 0x0302).
+ */
+int nvpci_dev_is_vga(struct pci_device *dev)
+{
+    return (dev->device_class & PCI_CLASS_SUBCLASS_MASK) ==
+           PCI_CLASS_DISPLAY_VGA;
+}
diff --git a/common-utils/nvpci-utils.h b/common-utils/nvpci-utils.h
new file mode 100644
index 0000000..9813e90
--- /dev/null
+++ b/common-utils/nvpci-utils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __NVPCI_UTILS_H__
+#define __NVPCI_UTILS_H__
+
+#include <pciaccess.h>
+
+#define NV_PCI_VENDOR_ID 0x10de
+
+struct pci_device_iterator *nvpci_find_gpu_by_vendor(uint32_t vendor_id);
+int nvpci_dev_is_vga(struct pci_device *dev);
+
+#endif /* __NVPCI_UTILS_H__ */
diff --git a/common-utils/src.mk b/common-utils/src.mk
index 6dbed7a..bb1e1d3 100644
--- a/common-utils/src.mk
+++ b/common-utils/src.mk
@@ -1,5 +1,8 @@
 # makefile fragment included by nvidia-xconfig, nvidia-settings, and nvidia-installer
 
+# the including makefile should set this if the relevant program uses pciaccess
+COMMON_UTILS_PCIACCESS ?=
+
 COMMON_UTILS_SRC        += nvgetopt.c
 COMMON_UTILS_SRC        += common-utils.c
 COMMON_UTILS_SRC        += msg.c
@@ -9,6 +12,16 @@ COMMON_UTILS_EXTRA_DIST += common-utils.h
 COMMON_UTILS_EXTRA_DIST += msg.h
 COMMON_UTILS_EXTRA_DIST += src.mk
 
+# only build nvpci-utils.c for programs that actually use libpciaccess, to
+# prevent other programs from needing to set the right CFLAGS/LDFLAGS for code
+# they won't use. Otherwise, just package it in the source tarball.
+ifneq ($(COMMON_UTILS_PCIACCESS),)
+    COMMON_UTILS_SRC        += nvpci-utils.c
+else
+    COMMON_UTILS_EXTRA_DIST += nvpci-utils.c
+endif
+COMMON_UTILS_EXTRA_DIST += nvpci-utils.h
+
 # gen-manpage-opts-helper.c is listed in EXTRA_DIST, rather than SRC,
 # because it is not compiled into the utilities themselves, but used
 # when building the utility's gen-manpage-opts
diff --git a/nv-ioctl-numa.h b/nv-ioctl-numa.h
index b051586..3fad820 100644
--- a/nv-ioctl-numa.h
+++ b/nv-ioctl-numa.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright (c) 2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -13,7 +14,7 @@
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
diff --git a/nv-ioctl-numbers.h b/nv-ioctl-numbers.h
index 14821b8..cb0b6a2 100644
--- a/nv-ioctl-numbers.h
+++ b/nv-ioctl-numbers.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * SPDX-License-Identifier: MIT
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -13,7 +14,7 @@
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
@@ -27,15 +28,16 @@
 /* NOTE: using an ioctl() number > 55 will overflow! */
 #define NV_IOCTL_MAGIC      'F'
 #define NV_IOCTL_BASE       200
-#define NV_ESC_CARD_INFO         (NV_IOCTL_BASE + 0)
-#define NV_ESC_REGISTER_FD       (NV_IOCTL_BASE + 1)
-#define NV_ESC_ALLOC_OS_EVENT    (NV_IOCTL_BASE + 6)
-#define NV_ESC_FREE_OS_EVENT     (NV_IOCTL_BASE + 7)
-#define NV_ESC_STATUS_CODE       (NV_IOCTL_BASE + 9)
-#define NV_ESC_CHECK_VERSION_STR (NV_IOCTL_BASE + 10)
-#define NV_ESC_IOCTL_XFER_CMD    (NV_IOCTL_BASE + 11)
-#define NV_ESC_ATTACH_GPUS_TO_FD (NV_IOCTL_BASE + 12)
-#define NV_ESC_QUERY_DEVICE_INTR (NV_IOCTL_BASE + 13)
-#define NV_ESC_SYS_PARAMS        (NV_IOCTL_BASE + 14)
+#define NV_ESC_CARD_INFO             (NV_IOCTL_BASE + 0)
+#define NV_ESC_REGISTER_FD           (NV_IOCTL_BASE + 1)
+#define NV_ESC_ALLOC_OS_EVENT        (NV_IOCTL_BASE + 6)
+#define NV_ESC_FREE_OS_EVENT         (NV_IOCTL_BASE + 7)
+#define NV_ESC_STATUS_CODE           (NV_IOCTL_BASE + 9)
+#define NV_ESC_CHECK_VERSION_STR     (NV_IOCTL_BASE + 10)
+#define NV_ESC_IOCTL_XFER_CMD        (NV_IOCTL_BASE + 11)
+#define NV_ESC_ATTACH_GPUS_TO_FD     (NV_IOCTL_BASE + 12)
+#define NV_ESC_QUERY_DEVICE_INTR     (NV_IOCTL_BASE + 13)
+#define NV_ESC_SYS_PARAMS            (NV_IOCTL_BASE + 14)
+#define NV_ESC_EXPORT_TO_DMABUF_FD   (NV_IOCTL_BASE + 17)
 
 #endif
diff --git a/nvidia-numa.c b/nvidia-numa.c
index 0703806..afc8fe4 100644
--- a/nvidia-numa.c
+++ b/nvidia-numa.c
@@ -51,7 +51,8 @@
 #define MEMORY_PATH_FMT              "/sys/devices/system/memory"
 #define MEMORY_HARD_OFFLINE_PATH_FMT MEMORY_PATH_FMT "/hard_offline_page"
 #define MEMORY_PROBE_PATH_FMT        MEMORY_PATH_FMT "/probe"
-#define MEMBLK_DIR_PATH_FMT          MEMORY_PATH_FMT "/memory%d"
+#define MEMBLK_FILE_FMT              "memory%d"
+#define MEMBLK_DIR_PATH_FMT          MEMORY_PATH_FMT "/" MEMBLK_FILE_FMT
 #define MEMBLK_STATE_PATH_FMT        MEMBLK_DIR_PATH_FMT "/state"
 #define MEMBLK_VALID_ZONES_PATH_FMT  MEMBLK_DIR_PATH_FMT "/valid_zones"
 #define NID_PATH_FMT                 "/sys/devices/system/node/node%d"
@@ -328,102 +329,18 @@ inline int get_memblock_id_from_dirname(const char *dirname, uint32_t *block_id)
     return (sscanf(dirname, "memory%" PRIu32, block_id) == 1) ? 0 : -EINVAL;
 }
 
-/*
- * Looks through NUMA nodes, finding the upper and lower bounds, and returns
- * those. The assumption is that the nodes are physically contiguous, so that
- * the intervening nodes do not need to be explicitly returned.
- */
-static
-int gather_memblock_ids_for_node(uint32_t node_id, uint32_t *memblock_start_id,
-                                 uint32_t *memblock_end_id)
-{
-    DIR *dir_ptr;
-    int status = 0;
-    struct dirent *dir_entry;
-    char numa_file_path[BUF_SIZE];
-    uint32_t start_id = UINT32_MAX;
-    uint32_t end_id = 0;
-
-    sprintf(numa_file_path, NID_PATH_FMT, node_id);
-
-    dir_ptr = opendir(numa_file_path);
-    if (!dir_ptr) {
-        syslog(LOG_ERR, "NUMA: Failed to open directory %s: %s\n",
-               numa_file_path, strerror(errno));
-        return -errno;
-    }
-
-    /* Iterate through the node directory and get the memblock id */
-    while ((dir_entry = readdir(dir_ptr)) != NULL) {
-        uint32_t memblock_id = 0;
-
-        /* Skip entries that are not a memory node */
-        if (get_memblock_id_from_dirname(dir_entry->d_name, &memblock_id) < 0) {
-            continue;
-        }
-
-        if (memblock_id == 0) {
-            syslog(LOG_ERR,
-                   "NUMA: Failed to get memblock id while iterating through %s\n",
-                   numa_file_path);
-            goto cleanup;
-        }
-
-        SYSLOG_VERBOSE(LOG_DEBUG, "NUMA: Found memblock entry %"PRIu32"\n",
-                       memblock_id);
-
-        /* Record the smallest and largest assigned memblock IDs */
-        start_id = (start_id < memblock_id) ? start_id : memblock_id;
-        end_id = (end_id > memblock_id) ? end_id : memblock_id;
-    }
-
-    /*
-     * If the wrong directory was specified, readdir can return success,
-     * even though it never iterated any files in the directory. Make that case
-     * also an error, by verifying that start_id has been set.
-     */
-    if (start_id == UINT32_MAX) {
-        syslog(LOG_ERR, "NUMA: Failed to find any files in %s", numa_file_path);
-        status = -ENOENT;
-        goto cleanup;
-    }
-
-    *memblock_start_id = start_id;
-    *memblock_end_id = end_id;
-
-    SYSLOG_VERBOSE(LOG_DEBUG,
-                   "NUMA: Found memblock start id: %"PRIu32
-                   " and end id: %"PRIu32"\n",
-                   *memblock_start_id, *memblock_end_id);
-
-cleanup:
-    closedir(dir_ptr);
-    return status;
-}
-
 static
-int change_numa_node_state(uint32_t node_id, uint64_t region_gpu_size,
-                           uint64_t memblock_size, mem_state_t new_state)
+int change_numa_node_state(uint32_t node_id,
+                           uint64_t base_addr, 
+                           uint64_t region_gpu_size, 
+                           uint64_t memblock_size, 
+                           mem_state_t new_state)
 {
     uint32_t memblock_id;
     int status = 0, err_status = 0;
     uint64_t blocks_changed = 0;
-    uint32_t memblock_start_id = 0;
-    uint32_t memblock_end_id = 0;
-
-    status = gather_memblock_ids_for_node(node_id, &memblock_start_id,
-                                          &memblock_end_id);
-    if (status < 0) {
-        syslog(LOG_ERR, "NUMA: Failed to get all memblock ID's for node%d\n",
-               node_id);
-        return status;
-    }
-
-    if (memblock_start_id > memblock_end_id) {
-        syslog(LOG_ERR, "NUMA: Invalid memblock IDs were found for node%d\n",
-               node_id);
-        return -EINVAL;
-    }
+    uint32_t memblock_start_id = base_addr / memblock_size;
+    uint32_t memblock_end_id = (base_addr + region_gpu_size) / memblock_size - 1;
 
     SYSLOG_VERBOSE(LOG_DEBUG,
                    "NUMA: memblock ID range: %"PRIu32"-%"PRIu32
@@ -533,6 +450,14 @@ int probe_node_memory(uint64_t probe_base_addr, uint64_t region_gpu_size,
         return -EFAULT;
     }
 
+    if (access(MEMORY_PROBE_PATH_FMT, F_OK) != 0 && errno == ENOENT)
+        /*
+         * It is not an error when the 'probe' file is not found, since this
+         * situation is normal for systems where the driver handles probe of
+         * the NUMA memory.
+         */
+        goto done;
+
     for (start_addr = probe_base_addr;
          start_addr + memblock_size <= numa_end_addr;
          start_addr += memblock_size) {
@@ -619,6 +544,7 @@ int offline_memory(int fd)
     }
 
     status = change_numa_node_state(numa_info_params.nid,
+                                    numa_info_params.numa_mem_addr,
                                     numa_info_params.numa_mem_size,
                                     numa_info_params.memblock_size,
                                     NV_IOCTL_NUMA_STATUS_OFFLINE);
@@ -650,7 +576,7 @@ driver_fail:
 }
 
 #define MEMORY_AUTO_ONLINE_WARNING_FMT                                      \
-    "NUMA: %s state is online and the default zone is not movable (%s).\n"  \
+    "NUMA: " MEMBLK_FILE_FMT " state is online and the default zone is not movable (%s).\n"  \
     "This likely means that some non-NVIDIA software has auto-onlined\n"    \
     "the device memory before nvidia-persistenced could. Please check\n"    \
     "if the CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE kernel config option\n"    \
@@ -658,16 +584,22 @@ driver_fail:
     "/lib/udev/rules.d/."
 
 static
-int check_memory_auto_online(uint32_t node_id, NvCfgBool *auto_online_success)
+int check_memory_auto_online(uint32_t node_id, 
+                             uint64_t base_addr, 
+                             uint64_t region_gpu_size, 
+                             uint64_t memblock_size,
+                             NvCfgBool *auto_online_success)
 {
     DIR     *dir_ptr;
     int     status = 0;
-    struct  dirent *dir_entry;
     char    read_buf[BUF_SIZE];
     char    numa_file_path[BUF_SIZE];
     char    memory_file_path[BUF_SIZE];
     int     num_memory_node_in_dir = 0;
     int     num_memory_online_movable = 0;
+    uint32_t block_id;
+    uint32_t memblock_start_id = base_addr / memblock_size;
+    uint32_t memblock_end_id = (base_addr + region_gpu_size) / memblock_size - 1;
 
     *auto_online_success = NVCFG_FALSE;
 
@@ -680,14 +612,8 @@ int check_memory_auto_online(uint32_t node_id, NvCfgBool *auto_online_success)
         return -errno;
     }
 
-    /* Iterate through the node directory */
-    while ((dir_entry = readdir(dir_ptr)) != NULL) {
-        uint32_t block_id;
-
-        /* Skip entries that are not a memory node */
-        if (get_memblock_id_from_dirname(dir_entry->d_name, &block_id) < 0) {
-            continue;
-        }
+    /* Iterate through the blocks */
+    for (block_id = memblock_start_id; block_id <= memblock_end_id; block_id++) {
 
         num_memory_node_in_dir++;
 
@@ -697,7 +623,7 @@ int check_memory_auto_online(uint32_t node_id, NvCfgBool *auto_online_success)
                                        read_buf, sizeof(read_buf));
         if (status < 0) {
             syslog(LOG_ERR,
-                   "NUMA: Failed to read %s state\n", dir_entry->d_name);
+                   "NUMA: Failed to read " MEMBLK_FILE_FMT " state\n", block_id);
             goto cleanup;
         }
 
@@ -713,15 +639,15 @@ int check_memory_auto_online(uint32_t node_id, NvCfgBool *auto_online_success)
                                            read_buf, sizeof(read_buf));
             if (status < 0) {
                 syslog(LOG_ERR,
-                       "NUMA: Failed to read %s valid_zones\n",
-                       dir_entry->d_name);
+                       "NUMA: Failed to read " MEMBLK_FILE_FMT " valid_zones\n",
+                       block_id);
                 goto cleanup;
             }
 
             /* If memory was auto-onlined, check if valid_zones is Movable */
             if (strstr(read_buf, VALID_MOVABLE_STATE) != read_buf) {
                 syslog(LOG_NOTICE, MEMORY_AUTO_ONLINE_WARNING_FMT,
-                       dir_entry->d_name, read_buf);
+                       block_id, read_buf);
                 status = -ENOTSUP;
                 break;
             } else {
@@ -852,6 +778,9 @@ NvPdStatus nvNumaOnlineMemory(NvNumaDevice *numa_info)
 
     /* Check if probed memory has been auto-onlined */
     status = check_memory_auto_online(numa_info_params.nid,
+                                      numa_info_params.numa_mem_addr,
+                                      numa_info_params.numa_mem_size,
+                                      numa_info_params.memblock_size,
                                       &auto_online_success);
     if (status < 0) {
         if (status != -ENOTSUP) {
@@ -871,6 +800,7 @@ NvPdStatus nvNumaOnlineMemory(NvNumaDevice *numa_info)
     }
 
     status = change_numa_node_state(numa_info_params.nid,
+                                    numa_info_params.numa_mem_addr,
                                     numa_info_params.numa_mem_size,
                                     numa_info_params.memblock_size,
                                     NV_IOCTL_NUMA_STATUS_ONLINE);
diff --git a/utils.mk b/utils.mk
index e5ac3a2..ec2b51f 100644
--- a/utils.mk
+++ b/utils.mk
@@ -45,6 +45,9 @@ CXX_ONLY_CFLAGS       ?=
 LDFLAGS               ?=
 BIN_LDFLAGS           ?=
 
+STACK_USAGE_WARNING   ?=
+CFLAGS                += $(if $(STACK_USAGE_WARNING),-Wstack-usage=$(STACK_USAGE_WARNING))
+
 HOST_CC               ?= $(CC)
 HOST_LD               ?= $(LD)
 HOST_CFLAGS           ?= $(CFLAGS)
@@ -59,6 +62,10 @@ CFLAGS                += -Wno-unused-parameter
 HOST_CC_ONLY_CFLAGS   += -Wno-format-zero-length
 HOST_CFLAGS           += -Wno-unused-parameter
 
+# Treat warnings as errors, if requested
+WARNINGS_AS_ERRORS    ?=
+CFLAGS                += $(if $(WARNINGS_AS_ERRORS),-Werror)
+
 DEBUG                 ?=
 DEVELOP               ?=
 
@@ -100,7 +107,11 @@ CHMOD                 ?= chmod
 OBJCOPY               ?= objcopy
 XZ                    ?= xz
 WHOAMI                ?= whoami
-HOSTNAME              ?= hostname
+
+ifndef HOSTNAME
+  HOSTNAME             = $(shell hostname)
+endif
+
 
 NV_AUTO_DEPEND        ?= 1
 NV_VERBOSE            ?= 0
@@ -182,11 +193,13 @@ NV_QUIET_COMMAND_REMOVED_TARGET_PREFIX ?=
 
 NV_GENERATED_HEADERS ?=
 
+PCIACCESS_CFLAGS      ?=
+PCIACCESS_LDFLAGS     ?=
 
 ##############################################################################
 # This makefile uses the $(eval) builtin function, which was added in
 # GNU make 3.80.  Check that the current make version recognizes it.
-# Idea suggested by:  http://www.jgc.org/blog/cookbook-sample.pdf
+# Idea suggested by "The GNU Make Book" by John Graham-Cumming.
 ##############################################################################
 
 _eval_available :=
@@ -208,7 +221,7 @@ endif
 ##############################################################################
 
 TEST_CC_ARG = \
- $(shell $(CC) -c -x c /dev/null $(1) -o /dev/null > /dev/null 2>&1 && \
+ $(shell $(CC) -c -x c /dev/null -Werror $(1) -o /dev/null > /dev/null 2>&1 && \
    $(ECHO) $(1))
 
 
@@ -376,6 +389,7 @@ BUILD_OBJECT_LIST_WITH_DIR = \
 BUILD_OBJECT_LIST = \
   $(call BUILD_OBJECT_LIST_WITH_DIR,$(1),$(OUTPUTDIR))
 
+$(call BUILD_OBJECT_LIST,nvpci-utils.c): CFLAGS += $(PCIACCESS_CFLAGS)
 
 ##############################################################################
 # function to generate a list of dependency files from their
@@ -514,7 +528,7 @@ define GENERATE_NVIDSTRING
   # g_nvid_string.c depends on all objects except g_nvid_string.o, and version.mk
   $(NVIDSTRING): $$(filter-out $$(call BUILD_OBJECT_LIST,$$(NVIDSTRING)), $(3)) $$(VERSION_MK)
 	$(at_if_quiet)$$(MKDIR) $$(dir $$@)
-	$(at_if_quiet)$$(ECHO) "const char $(1)[] = \"nvidia id: NVIDIA $$(strip $(2)) for $$(TARGET_ARCH)  $$(NVIDIA_VERSION)  $$(NVIDSTRING_BUILD_TYPE_STRING)  (`$$(WHOAMI)`@`$$(HOSTNAME)`)  `$$(DATE)`\";" > $$@
+	$(at_if_quiet)$$(ECHO) "const char $(1)[] = \"nvidia id: NVIDIA $$(strip $(2)) for $$(TARGET_ARCH)  $$(NVIDIA_VERSION)  $$(NVIDSTRING_BUILD_TYPE_STRING)  (`$$(WHOAMI)`@$$(HOSTNAME))  `$$(DATE)`\";" > $$@
 	$(at_if_quiet)$$(ECHO) "const char *const p$$(strip $(1)) = $(1) + 11;" >> $$@;
 endef
 
diff --git a/version.mk b/version.mk
index b6c9f21..f3d1195 100644
--- a/version.mk
+++ b/version.mk
@@ -1,4 +1,4 @@
-NVIDIA_VERSION = 470.129.06
+NVIDIA_VERSION = 515.76
 
 # This file.
 VERSION_MK_FILE := $(lastword $(MAKEFILE_LIST))