# SPDX-License-Identifier: GPL-2.0-only
+config IOMMUFD_DRIVER_CORE
+       tristate
+       default (IOMMUFD_DRIVER || IOMMUFD) if IOMMUFD!=n
+
 config IOMMUFD
        tristate "IOMMU Userspace API"
        select INTERVAL_TREE
 
 
 obj-$(CONFIG_IOMMUFD) += iommufd.o
 obj-$(CONFIG_IOMMUFD_DRIVER) += iova_bitmap.o
+
+iommufd_driver-y := driver.o
+obj-$(CONFIG_IOMMUFD_DRIVER_CORE) += iommufd_driver.o
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES
+ */
+#include "iommufd_private.h"
+
+struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
+                                            size_t size,
+                                            enum iommufd_object_type type)
+{
+       struct iommufd_object *obj;
+       int rc;
+
+       obj = kzalloc(size, GFP_KERNEL_ACCOUNT);
+       if (!obj)
+               return ERR_PTR(-ENOMEM);
+       obj->type = type;
+       /* Starts out bias'd by 1 until it is removed from the xarray */
+       refcount_set(&obj->shortterm_users, 1);
+       refcount_set(&obj->users, 1);
+
+       /*
+        * Reserve an ID in the xarray but do not publish the pointer yet since
+        * the caller hasn't initialized it yet. Once the pointer is published
+        * in the xarray and visible to other threads we can't reliably destroy
+        * it anymore, so the caller must complete all errorable operations
+        * before calling iommufd_object_finalize().
+        */
+       rc = xa_alloc(&ictx->objects, &obj->id, XA_ZERO_ENTRY, xa_limit_31b,
+                     GFP_KERNEL_ACCOUNT);
+       if (rc)
+               goto out_free;
+       return obj;
+out_free:
+       kfree(obj);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_NS_GPL(_iommufd_object_alloc, IOMMUFD);
+
+MODULE_DESCRIPTION("iommufd code shared with builtin modules");
+MODULE_LICENSE("GPL");
 
        iommufd_object_remove(ictx, obj, obj->id, 0);
 }
 
-struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
-                                            size_t size,
-                                            enum iommufd_object_type type);
-
 #define __iommufd_object_alloc(ictx, ptr, type, obj)                           \
        container_of(_iommufd_object_alloc(                                    \
                             ictx,                                             \
 
 static const struct iommufd_object_ops iommufd_object_ops[];
 static struct miscdevice vfio_misc_dev;
 
-struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
-                                            size_t size,
-                                            enum iommufd_object_type type)
-{
-       struct iommufd_object *obj;
-       int rc;
-
-       obj = kzalloc(size, GFP_KERNEL_ACCOUNT);
-       if (!obj)
-               return ERR_PTR(-ENOMEM);
-       obj->type = type;
-       /* Starts out bias'd by 1 until it is removed from the xarray */
-       refcount_set(&obj->shortterm_users, 1);
-       refcount_set(&obj->users, 1);
-
-       /*
-        * Reserve an ID in the xarray but do not publish the pointer yet since
-        * the caller hasn't initialized it yet. Once the pointer is published
-        * in the xarray and visible to other threads we can't reliably destroy
-        * it anymore, so the caller must complete all errorable operations
-        * before calling iommufd_object_finalize().
-        */
-       rc = xa_alloc(&ictx->objects, &obj->id, XA_ZERO_ENTRY,
-                     xa_limit_31b, GFP_KERNEL_ACCOUNT);
-       if (rc)
-               goto out_free;
-       return obj;
-out_free:
-       kfree(obj);
-       return ERR_PTR(rc);
-}
-
 /*
  * Allow concurrent access to the object.
  *
 
        return -EOPNOTSUPP;
 }
 #endif /* CONFIG_IOMMUFD */
+
+#if IS_ENABLED(CONFIG_IOMMUFD_DRIVER_CORE)
+struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
+                                            size_t size,
+                                            enum iommufd_object_type type);
+#else /* !CONFIG_IOMMUFD_DRIVER_CORE */
+static inline struct iommufd_object *
+_iommufd_object_alloc(struct iommufd_ctx *ictx, size_t size,
+                     enum iommufd_object_type type)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+#endif /* CONFIG_IOMMUFD_DRIVER_CORE */
 #endif