gxp: [Copybara Auto Merge] Merge branch 'zumapro-u' into 'android14-gs-pixel-6.1'

gxp: fix dma addr log format
Use %pad for logging dma_addr_t types.
(cherry picked from commit cdf65e426bcc4ced80f9fa9f7d91814bac90338f)
gxp: Correct the user buffer range check
`mapping->gcip_mapping->size` is the size of the whole mapping
i.e. http://screen/BvVGV7kqf5MurU3 and not the size after the
`mapping->gcip_mapping->device_address` till the mapping end
i.e. http://screen/BrWQpMSEiutkBZF.
Bug: 324353546
(cherry picked from commit b4601b79558319310cb95e7c9bad95cfda3ac6e9)
gxp: Balance vunmap with vmap in error scenario
- Balance the `gxp_mapping_vunmap()` if the firmware passes the valid
device IOVA with invalid size. Otherwise mapping reference will not
be correctly updated and hence mapping will not be released during
`gxp_release()`.
- Correct the device address to be printed in case of error.
Bug: 324353546 (repeat)
Test: Validated the debug dump functionality after passing the invalid
user buffer details.
(cherry picked from commit fc5dee4d5a725efa3304c74641c7265d35e2bf95)
gxp: Fix range check while searching for a mapping
While searching for a mapping, range check was spilling into the next
page, resulting in an invalid mapping to be returned. Adjusting the
range check to page boundary.
Bug: 324353546 (repeat)
(cherry picked from commit 0a5a9eddd0a4c9a86efe2476ee1bbf4ba5e34cb7)
gxp: don't include gsa_image_auth
Bug: 324001894
gxp: Rename GCIP_KCI_CODE_FIRMWARE_INFO
Bug: 297305291
gxp: update license strings
Bug: 323813772
gcip: Rename GCIP_KCI_CODE_FIRMWARE_INFO
Bug: 297305291 (repeat)
GCIP_HEADER_REV_ID: 52f781eda1f9c76e78fe2a480898970438fc0079
gcip: alloc-helper use kvmalloc_array
GCIP_MAIN_REV_ID: 2c2eacffb922958cd7e0a0f1f05ea7ecc2d1e023
gxp: schedule response work for DCI
Bug: 323464908
gxp: Pass KD version to MCU
Bug: 297305291 (repeat)
gcip: GCIP_HAS_VMA_FLAGS_API temporarily check kernel version 6.1.25
Bug: 298697777
GCIP_HEADER_REV_ID: 27c4ef93900a17c2c6b6569dca3ffd7208c980b9
gcip: remove unneeded version checks
Bug: 298697777 (repeat)
gcip: remove HAS_IOVAD_BEST_FIT_ALGO
gcip: add gcip_iommu_domain_map_sgt_to_iova
Bug: 321911434
gcip: add GCIP_MAP_FLAGS_DMA macros
Bug: 321911434 (repeat)
gcip: add gcip_iommu_(un)map
Bug: 321911434 (repeat)
GCIP_HEADER_REV_ID: 79b1b74bc78ffd0193152648172b353fdebcff1f
gxp: use extern for static global vars
gxp: use IS_GXP_TEST
gxp: Use -{ENOENT,EAGAIN} when UCI wait_event expires
Bug: 316486026
gxp: adopt new class_create interface
Bug: 321614734
gxp: utilize gcip_iommu_domain_map_sgt_to_iova
Bug: 321911434 (repeat)
gxp: change the lock mode in gxp_client_destroy
gxp: always use gcip_iommu_map
Bug: 321911434 (repeat)
gxp: replace gxp_iommu_(un)map with gcip
Bug: 321911434 (repeat)
gcip: Wrap TEST_TRIGGER_TIMEOUT_RACE with braces
gcip: drop unnecessary version check
Bug: 298697777 (repeat)
Bug: 320371986
gcip: use GCIP_HAS_IOVAD_BEST_FIT_ALGO
gcip: expose gcip_iommu_domain_map_sgt_to_iova
Bug: 321911434 (repeat)
gcip: iommu_map_sg considers GCIP_IOMMU_MAP_HAS_GFP
Bug: 321614734 (repeat)
gcip: add gcip_iommu_domain_granule()
Bug: 321911434 (repeat)
gcip: implement gcip_iommu_(un)map
Bug: 321911434 (repeat)
GCIP_MAIN_REV_ID: d5a15d25b227a266595faac327488d227f4fc686

Signed-off-by: Aurora zuma pro automerger <[email protected]>
GitOrigin-RevId: 2dfe9fa8703fbf12a192f725aef3f246002a893c
Change-Id: I6f21e346022b25b451ead1faff7c45e0d850fd55
diff --git a/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c b/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c
index 8478c3c..44cc3a9 100644
--- a/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c
+++ b/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c
@@ -9,7 +9,6 @@
 #include <linux/device.h>
 #include <linux/gfp.h>
 #include <linux/mm_types.h>
-#include <linux/overflow.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -42,8 +41,6 @@
 	void *mem;
 	struct page **pages;
 	size_t count;
-	size_t pages_bytes;
-	bool pages_use_vfree = false;
 	int ret;
 
 	if (!sh)
@@ -60,16 +57,7 @@
 		goto err_free_sh;
 	}
 
-	if (unlikely(check_mul_overflow(count, sizeof(*pages), &pages_bytes))) {
-		dev_err(dev, "GCIP alloc pages array request too large count=%zu", count);
-		goto err_free_mem;
-	}
-
-	pages = kmalloc(pages_bytes, gfp | __GFP_NOWARN);
-	if (!pages) {
-		pages = vmalloc(pages_bytes);
-		pages_use_vfree = true;
-	}
+	pages = kvmalloc_array(count, sizeof(*pages), gfp);
 	if (!pages)
 		goto err_free_mem;
 
@@ -84,12 +72,12 @@
 		goto err_free_pages;
 	}
 
-	pages_use_vfree ? vfree(pages) : kfree(pages);
+	kvfree(pages);
 	sh->mem = mem;
 	return &sh->sgt;
 
 err_free_pages:
-	pages_use_vfree ? vfree(pages) : kfree(pages);
+	kvfree(pages);
 err_free_mem:
 	vfree(mem);
 err_free_sh:
diff --git a/gcip-kernel-driver/drivers/gcip/gcip-iommu.c b/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
index 28a7fe3..3b893d6 100644
--- a/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
+++ b/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
@@ -27,7 +27,7 @@
 #include <gcip/gcip-iommu.h>
 #include <gcip/gcip-mem-pool.h>
 
-#if HAS_IOVAD_BEST_FIT_ALGO
+#if GCIP_HAS_IOVAD_BEST_FIT_ALGO
 #include <linux/dma-iommu.h>
 #endif
 
@@ -94,6 +94,13 @@
 	}
 }
 
+static inline size_t gcip_iommu_domain_granule(struct gcip_iommu_domain *domain)
+{
+	if (unlikely(domain->default_domain))
+		return PAGE_SIZE;
+	return domain->domain_pool->granule;
+}
+
 /*
  * Allocates an IOVA for the scatterlist and maps it to @domain.
  *
@@ -138,11 +145,12 @@
 	 * It will iterate each scatter list segment in order and map them to the IOMMU domain
 	 * as amount of the size of each segment successively.
 	 * Returns an error on failure or the total length of mapped segments on success.
-	 *
-	 * Note: Before Linux 5.15, its return type was `size_t` and it returned 0 on failure.
-	 *       To make it compatible with those old versions, we should cast the return value.
 	 */
-	map_size = (ssize_t)iommu_map_sg(domain->domain, iova, sgl, nents, prot);
+#if GCIP_IOMMU_MAP_HAS_GFP
+	map_size = iommu_map_sg(domain->domain, iova, sgl, nents, prot, GFP_KERNEL);
+#else
+	map_size = iommu_map_sg(domain->domain, iova, sgl, nents, prot);
+#endif
 	if (map_size < 0 || map_size < iova_len)
 		goto err_free_iova;
 
@@ -153,8 +161,8 @@
 	ret = 0;
 	sg = sgl;
 	while (iova_len) {
-		size_t segment_len =
-			min_t(size_t, iova_len, UINT_MAX & ~(domain->domain_pool->granule - 1));
+		size_t segment_len = min_t(size_t, iova_len,
+					   UINT_MAX & ~(gcip_iommu_domain_granule(domain) - 1));
 
 		sg_dma_address(sg) = iova;
 		sg_dma_len(sg) = segment_len;
@@ -205,7 +213,7 @@
 
 static inline unsigned long gcip_iommu_domain_shift(struct gcip_iommu_domain *domain)
 {
-	return __ffs(domain->domain_pool->granule);
+	return __ffs(gcip_iommu_domain_granule(domain));
 }
 
 static inline unsigned long gcip_iommu_domain_pfn(struct gcip_iommu_domain *domain, dma_addr_t iova)
@@ -215,7 +223,7 @@
 
 static inline size_t gcip_iommu_domain_align(struct gcip_iommu_domain *domain, size_t size)
 {
-	return ALIGN(size, domain->domain_pool->granule);
+	return ALIGN(size, gcip_iommu_domain_granule(domain));
 }
 
 static int iovad_initialize_domain(struct gcip_iommu_domain *domain)
@@ -233,11 +241,7 @@
 		reserve_iova(&domain->iova_space.iovad, pfn_lo, pfn_hi);
 	}
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
 	return iova_domain_init_rcaches(&domain->iova_space.iovad);
-#else
-	return 0;
-#endif
 }
 
 static void iovad_finalize_domain(struct gcip_iommu_domain *domain)
@@ -247,9 +251,9 @@
 
 static void iovad_enable_best_fit_algo(struct gcip_iommu_domain *domain)
 {
-#if HAS_IOVAD_BEST_FIT_ALGO
+#if GCIP_HAS_IOVAD_BEST_FIT_ALGO
 	domain->iova_space.iovad.best_fit = true;
-#endif /* HAS_IOVAD_BEST_FIT_ALGO */
+#endif /* GCIP_HAS_IOVAD_BEST_FIT_ALGO */
 }
 
 static dma_addr_t iovad_alloc_iova_space(struct gcip_iommu_domain *domain, size_t size,
@@ -261,19 +265,6 @@
 						  domain->domain_pool->last_daddr;
 
 	size = size >> shift;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)
-	/*
-	 * alloc_iova_fast() makes use of a cache of recently freed IOVA pages which does not
-	 * behave correctly for non-power-of-two amounts of pages. Round up the number of
-	 * pages being allocated to ensure it's a safe number of pages.
-	 *
-	 * This rounding is done automatically as of 5.17
-	 */
-	if (size < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
-		size = roundup_pow_of_two(size);
-#endif
-
 	iova_pfn = alloc_iova_fast(&domain->iova_space.iovad, size, iova_ceiling >> shift, true);
 	return (dma_addr_t)iova_pfn << shift;
 }
@@ -435,9 +426,9 @@
 }
 
 /* Maps @sgt to @iova. If @iova is 0, this function allocates an IOVA space internally. */
-static unsigned int gcip_iommu_domain_map_sgt_to_iova(struct gcip_iommu_domain *domain,
-						      struct sg_table *sgt, dma_addr_t iova,
-						      u64 *gcip_map_flags)
+unsigned int gcip_iommu_domain_map_sgt_to_iova(struct gcip_iommu_domain *domain,
+					       struct sg_table *sgt, dma_addr_t iova,
+					       u64 *gcip_map_flags)
 {
 	struct scatterlist *sgl = sgt->sgl;
 	uint orig_nents = sgt->orig_nents;
@@ -478,6 +469,12 @@
 	return gcip_iommu_domain_unmap_sgt_free_iova(domain, sgt, true, gcip_map_flags);
 }
 
+void gcip_iommu_domain_unmap_sgt_from_iova(struct gcip_iommu_domain *domain, struct sg_table *sgt,
+					   u64 gcip_map_flags)
+{
+	gcip_iommu_domain_unmap_sgt_free_iova(domain, sgt, false, gcip_map_flags);
+}
+
 /**
  * gcip_iommu_mapping_unmap_dma_buf() - Unmaps the dma buf mapping.
  * @mapping: The pointer of the mapping instance to be unmapped.
@@ -713,7 +710,7 @@
 
 void gcip_iommu_domain_pool_enable_best_fit_algo(struct gcip_iommu_domain_pool *pool)
 {
-	if (pool->domain_type == GCIP_IOMMU_DOMAIN_TYPE_IOVAD && !HAS_IOVAD_BEST_FIT_ALGO) {
+	if (pool->domain_type == GCIP_IOMMU_DOMAIN_TYPE_IOVAD && !GCIP_HAS_IOVAD_BEST_FIT_ALGO) {
 		dev_warn(pool->dev, "This env doesn't support best-fit algorithm with IOVAD");
 		pool->best_fit = false;
 	} else {
@@ -959,11 +956,7 @@
 	unsigned int gup_flags;
 
 	mmap_read_lock(current->mm);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 1)
-	vma = find_extend_vma(current->mm, host_addr & PAGE_MASK);
-#else
 	vma = vma_lookup(current->mm, host_addr & PAGE_MASK);
-#endif
 	mmap_read_unlock(current->mm);
 
 	if (!vma) {
@@ -1364,3 +1357,28 @@
 {
 	domain->ops->free_iova_space(domain, iova, gcip_iommu_domain_align(domain, size));
 }
+
+int gcip_iommu_map(struct gcip_iommu_domain *domain, dma_addr_t iova, phys_addr_t paddr,
+		   size_t size, u64 gcip_map_flags)
+{
+	enum dma_data_direction dir = GCIP_MAP_FLAGS_GET_DMA_DIRECTION(gcip_map_flags);
+	bool coherent = GCIP_MAP_FLAGS_GET_DMA_COHERENT(gcip_map_flags);
+	unsigned long attrs = GCIP_MAP_FLAGS_GET_DMA_ATTR(gcip_map_flags);
+	int prot = dma_info_to_prot(dir, coherent, attrs);
+
+#if GCIP_IOMMU_MAP_HAS_GFP
+	return iommu_map(domain->domain, iova, paddr, size, prot, GFP_KERNEL);
+#else
+	return iommu_map(domain->domain, iova, paddr, size, prot);
+#endif /* GCIP_IOMMU_MAP_HAS_GFP */
+}
+
+/* Reverts gcip_iommu_map(). */
+void gcip_iommu_unmap(struct gcip_iommu_domain *domain, dma_addr_t iova, size_t size)
+{
+	size_t unmapped = iommu_unmap(domain->domain, iova, size);
+
+	if (unlikely(unmapped != size))
+		dev_warn(domain->dev, "Unmapping IOVA %pad, size (%#zx) only unmapped %#zx", &iova,
+			 size, unmapped);
+}
diff --git a/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c b/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
index e5d755f..24849c9 100644
--- a/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
+++ b/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
@@ -255,12 +255,13 @@
 		memcpy(cur->async_resp->resp, resp, mailbox->resp_elem_size);
 		list_del(&cur->list);
 		awaiter = cur->awaiter;
-		if (awaiter)
+		if (awaiter) {
 			/*
 			 * The timedout handler will be fired, but pended by waiting for acquiring
 			 * the wait_list_lock.
 			 */
 			TEST_TRIGGER_TIMEOUT_RACE(awaiter);
+		}
 		kfree(cur);
 		break;
 	}
diff --git a/gcip-kernel-driver/drivers/gcip/gcip-thermal.c b/gcip-kernel-driver/drivers/gcip/gcip-thermal.c
index 85c89b2..f5f6ca4 100644
--- a/gcip-kernel-driver/drivers/gcip/gcip-thermal.c
+++ b/gcip-kernel-driver/drivers/gcip/gcip-thermal.c
@@ -176,7 +176,7 @@
 };
 
 /* This API was removed, but Android still uses it to update thermal request. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) && GCIP_IS_GKI
+#if GCIP_IS_GKI
 void thermal_cdev_update(struct thermal_cooling_device *cdev);
 #endif
 
@@ -186,7 +186,7 @@
 
 	cdev->updated = false;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) || GCIP_IS_GKI
+#if GCIP_IS_GKI
 	thermal_cdev_update(cdev);
 #elif IS_ENABLED(CONFIG_THERMAL)
 	dev_err_once(thermal->dev, "Thermal update not implemented");
diff --git a/gcip-kernel-driver/drivers/gcip/iif/iif-fence.c b/gcip-kernel-driver/drivers/gcip/iif/iif-fence.c
index b6d7c74..94333fa 100644
--- a/gcip-kernel-driver/drivers/gcip/iif/iif-fence.c
+++ b/gcip-kernel-driver/drivers/gcip/iif/iif-fence.c
@@ -8,6 +8,7 @@
 #define pr_fmt(fmt) "iif: " fmt
 
 #include <linux/atomic.h>
+#include <linux/container_of.h>
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -16,10 +17,6 @@
 #include <linux/types.h>
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
-#include <linux/container_of.h>
-#endif
-
 #include <gcip/iif/iif-fence-table.h>
 #include <gcip/iif/iif-fence.h>
 #include <gcip/iif/iif-manager.h>
diff --git a/gcip-kernel-driver/drivers/gcip/iif/iif-manager.c b/gcip-kernel-driver/drivers/gcip/iif/iif-manager.c
index d4676dd..253c36f 100644
--- a/gcip-kernel-driver/drivers/gcip/iif/iif-manager.c
+++ b/gcip-kernel-driver/drivers/gcip/iif/iif-manager.c
@@ -5,16 +5,13 @@
  * Copyright (C) 2023 Google LLC
  */
 
+#include <linux/container_of.h>
 #include <linux/idr.h>
 #include <linux/kref.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
-#include <linux/container_of.h>
-#endif
-
 #include <gcip/iif/iif-fence-table.h>
 #include <gcip/iif/iif-manager.h>
 
diff --git a/gcip-kernel-driver/include/gcip/gcip-config.h b/gcip-kernel-driver/include/gcip/gcip-config.h
index 176babc..be1716c 100644
--- a/gcip-kernel-driver/include/gcip/gcip-config.h
+++ b/gcip-kernel-driver/include/gcip/gcip-config.h
@@ -10,27 +10,26 @@
 
 #include <linux/version.h>
 
-#define GCIP_IS_GKI (IS_ENABLED(CONFIG_ANDROID) || IS_ENABLED(CONFIG_ANDROID_VENDOR_HOOKS))
+#define GCIP_IS_GKI IS_ENABLED(CONFIG_ANDROID_VENDOR_HOOKS)
 
 /* Macros to check the availability of features and APIs */
 
-#define GCIP_HAS_VMA_FLAGS_API                                                                     \
-	((LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 25) && GCIP_IS_GKI) ||                        \
-	 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0))
+/* TODO(b/298697777): temporarily check 6.1.25 until previous kernel version no longer in use. */
+#define GCIP_HAS_VMA_FLAGS_API                                                                \
+	((GCIP_IS_GKI && LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 25)) ||                   \
+	 (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)))
 
-#define GCIP_HAS_IOMMU_PASID                                                                       \
-	((LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && GCIP_IS_GKI) ||                         \
-	 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
+#define GCIP_HAS_IOMMU_PASID (GCIP_IS_GKI || LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
 
-#define GCIP_HAS_AUX_DOMAINS (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 17, 0))
+#define GCIP_HAS_AUX_DOMAINS 0
 
 /*
  * TODO(b/277649169) Best fit IOVA allocator was removed in 6.1 GKI
  * The API needs to either be upstreamed, integrated into this driver, or disabled for 6.1
- * compatibility. For now, disable best-fit on all non-Android kernels and any GKI > 5.15.
+ * compatibility. For now, disable best-fit for IOVAD.
  */
-#define GCIP_HAS_IOVAD_BEST_FIT_ALGO                                                               \
-	(LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) &&                                          \
-	 (IS_ENABLED(CONFIG_GCIP_TEST) || GCIP_IS_GKI))
+#define GCIP_HAS_IOVAD_BEST_FIT_ALGO 0
+
+#define GCIP_IOMMU_MAP_HAS_GFP (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0))
 
 #endif /* __GCIP_CONFIG_H__ */
diff --git a/gcip-kernel-driver/include/gcip/gcip-iommu.h b/gcip-kernel-driver/include/gcip/gcip-iommu.h
index ca0e647..425691d 100644
--- a/gcip-kernel-driver/include/gcip/gcip-iommu.h
+++ b/gcip-kernel-driver/include/gcip/gcip-iommu.h
@@ -32,15 +32,6 @@
 #include <gcip/gcip-domain-pool.h>
 #include <gcip/gcip-mem-pool.h>
 
-/*
- * TODO(b/277649169) Best fit IOVA allocator was removed in 6.1 GKI
- * The API needs to either be upstreamed, integrated into this driver, or disabled for 6.1
- * compatibility. For now, disable best-fit on all non-Android kernels and any GKI > 5.15.
- */
-#define HAS_IOVAD_BEST_FIT_ALGO                           \
-	(LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) && \
-	 (IS_ENABLED(CONFIG_GCIP_TEST) || IS_ENABLED(CONFIG_ANDROID)))
-
 #if GCIP_HAS_IOMMU_PASID
 #include <linux/idr.h>
 #endif
@@ -71,6 +62,10 @@
 #define GCIP_MAP_FLAGS_RESTRICT_IOVA_TO_FLAGS(restrict) \
 	((u64)(restrict) << GCIP_MAP_FLAGS_RESTRICT_IOVA_OFFSET)
 
+/* Helper macros to easily create the mapping direction flags. */
+#define GCIP_MAP_FLAGS_DMA_RW GCIP_MAP_FLAGS_DMA_DIRECTION_TO_FLAGS(DMA_BIDIRECTIONAL)
+#define GCIP_MAP_FLAGS_DMA_RO GCIP_MAP_FLAGS_DMA_DIRECTION_TO_FLAGS(DMA_TO_DEVICE)
+
 /*
  * Bitfields of @gcip_map_flags:
  *   [1:0]   - DMA_DIRECTION:
@@ -379,6 +374,38 @@
 void gcip_iommu_domain_unmap_sgt(struct gcip_iommu_domain *domain, struct sg_table *sgt,
 				 u64 gcip_map_flags);
 
+/**
+ * gcip_iommu_domain_map_sgt_to_iova(): Maps the scatter-gather table with specified IOVA to the
+ *                                      target domain.
+ *
+ * @domain: The domain that the sgt will be mapped to.
+ * @sgt: The scatter-gather table to be mapped.
+ * @iova: The specified device address.
+ * @gcip_map_flags: The gcip flags used to map the @sgt.
+ *
+ * This function is almost identical to gcip_iommu_domain_map_sgt() except this function maps with
+ * the specified device address instead of allocating one internally.
+ *
+ * Note the used device address is NOT reserved by the domain, it's caller's responsibility to
+ * ensure @iova does not overlap with the domain's IOVA space.
+ *
+ * Return: The number of the entries that are mapped successfully.
+ */
+unsigned int gcip_iommu_domain_map_sgt_to_iova(struct gcip_iommu_domain *domain,
+					       struct sg_table *sgt, dma_addr_t iova,
+					       u64 *gcip_map_flags);
+/**
+ * gcip_iommu_domain_unmap_sgt_from_iova(): Reverts gcip_iommu_domain_map_sgt_to_iova().
+ * @domain: The domain that the sgt will be unmapped from.
+ * @sgt: The scatter-gather table to be unmapped.
+ * @gcip_map_flags: The gcip flags used to unmap @sgt.
+ *
+ * There is no @iova parameter because it is recorded in @sgt as done by
+ * gcip_iommu_domain_map_sgt_to_iova().
+ */
+void gcip_iommu_domain_unmap_sgt_from_iova(struct gcip_iommu_domain *domain, struct sg_table *sgt,
+					   u64 gcip_map_flags);
+
 /*
  * Returns a default GCIP IOMMU domain.
  *
@@ -512,4 +539,20 @@
 	mapping->data = data;
 }
 
+/**
+ * gcip_iommu_map() - Maps the desired mappings to the domain.
+ * @domain: The GCIP domain to be mapped to.
+ * @iova: The device address.
+ * @paddr: The target address to be mapped to.
+ * @size: Map size in bytes.
+ * @gcip_map_flags: Flags indicating mapping attributes, which can be encoded with
+ *                  gcip_iommu_encode_gcip_map_flags() or `GCIP_MAP_FLAGS_DMA_*_TO_FLAGS` macros.
+ *
+ * Return: 0 on success, otherwise a negative errno.
+ */
+int gcip_iommu_map(struct gcip_iommu_domain *domain, dma_addr_t iova, phys_addr_t paddr,
+		   size_t size, u64 gcip_map_flags);
+/* Reverts gcip_iommu_map(). */
+void gcip_iommu_unmap(struct gcip_iommu_domain *domain, dma_addr_t iova, size_t size);
+
 #endif /* __GCIP_IOMMU_H__ */
diff --git a/gcip-kernel-driver/include/gcip/gcip-kci.h b/gcip-kernel-driver/include/gcip/gcip-kci.h
index 8d9a741..c298a9d 100644
--- a/gcip-kernel-driver/include/gcip/gcip-kci.h
+++ b/gcip-kernel-driver/include/gcip/gcip-kci.h
@@ -73,7 +73,7 @@
 	GCIP_KCI_CODE_GET_DEBUG_DUMP = 8,
 	GCIP_KCI_CODE_OPEN_DEVICE = 9,
 	GCIP_KCI_CODE_CLOSE_DEVICE = 10,
-	GCIP_KCI_CODE_FIRMWARE_INFO = 11,
+	GCIP_KCI_CODE_EXCHANGE_INFO = 11,
 	/* TODO(b/271372136): remove v1 when v1 firmware no longer in use. */
 	GCIP_KCI_CODE_GET_USAGE_V1 = 12,
 	/* Backward compatible define, also update when v1 firmware no longer in use. */
diff --git a/gxp-bpm.c b/gxp-bpm.c
index 90cf0e9..5ccddcf 100644
--- a/gxp-bpm.c
+++ b/gxp-bpm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP bus performance monitor interface.
  *
diff --git a/gxp-bpm.h b/gxp-bpm.h
index 1281bce..3b3f37b 100644
--- a/gxp-bpm.h
+++ b/gxp-bpm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP bus performance monitor interface.
  *
diff --git a/gxp-client.c b/gxp-client.c
index 3b08a7f..a2a3dd0 100644
--- a/gxp-client.c
+++ b/gxp-client.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP client structure.
  *
@@ -138,7 +138,7 @@
 
 	cleanup_uci_cmd_work(client);
 
-	down_read(&client->semaphore);
+	down_write(&client->semaphore);
 
 	if (client->vd && client->vd->state != GXP_VD_OFF) {
 		down_write(&gxp->vd_semaphore);
@@ -179,7 +179,7 @@
 		client->vd = NULL;
 	}
 
-	up_read(&client->semaphore);
+	up_write(&client->semaphore);
 
 	/*
 	 * This part should be located outside of the @client->semaphore protection to prevent the
diff --git a/gxp-client.h b/gxp-client.h
index 2f5041e..3269491 100644
--- a/gxp-client.h
+++ b/gxp-client.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP client structure.
  *
diff --git a/gxp-common-platform.c b/gxp-common-platform.c
index ff5c2af..a2a5443 100644
--- a/gxp-common-platform.c
+++ b/gxp-common-platform.c
@@ -2132,7 +2132,11 @@
 {
 	int ret;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
 	gxp_class = class_create(THIS_MODULE, GXP_NAME);
+#else
+	gxp_class = class_create(GXP_NAME);
+#endif
 	if (IS_ERR(gxp_class)) {
 		pr_err(GXP_NAME " error creating gxp class: %ld\n",
 		       PTR_ERR(gxp_class));
diff --git a/gxp-dci.c b/gxp-dci.c
index 194bec6..5f658f8 100644
--- a/gxp-dci.c
+++ b/gxp-dci.c
@@ -110,7 +110,10 @@
 		resp_queue->lock, msecs_to_jiffies(MAILBOX_TIMEOUT));
 	if (timeout <= 0) {
 		spin_unlock_irq(&resp_queue->lock);
-		/* unusual case - this only happens when there is no command pushed */
+		/*
+		 * Unusual case - this only happens when there is no command pushed or a race with
+		 * gcip_mailbox_async_cmd_timeout_work.
+		 */
 		return timeout ? -ETIMEDOUT : timeout;
 	}
 	resp_ptr = list_first_entry(&resp_queue->dest_queue,
diff --git a/gxp-debug-dump.c b/gxp-debug-dump.c
index 74920b4..381438e 100644
--- a/gxp-debug-dump.c
+++ b/gxp-debug-dump.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP debug dump handler
  *
@@ -73,19 +73,19 @@
 	GXP_LPM_REGISTERS_IDX
 };
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 #include <gcip-unit/helper/test-sleep.h>
 #define TEST_SLEEP() test_sleep_may_sleep(1000)
 #else
 #define TEST_SLEEP()
-#endif /* IS_ENABLED(CONFIG_GXP_TEST) */
+#endif /* IS_GXP_TEST */
 
 /* Whether or not the debug dump subsystem should be enabled. */
-#if !IS_ENABLED(CONFIG_GXP_TEST) && !GXP_ENABLE_DEBUG_DUMP
+#if !IS_GXP_TEST && !GXP_ENABLE_DEBUG_DUMP
 static int gxp_debug_dump_enable;
 #else
 static int gxp_debug_dump_enable = 1;
-#endif /* !IS_ENABLED(CONFIG_GXP_TEST) && !GXP_ENABLE_DEBUG_DUMP */
+#endif /* !IS_GXP_TEST && !GXP_ENABLE_DEBUG_DUMP */
 module_param_named(debug_dump_enable, gxp_debug_dump_enable, int, 0660);
 
 static void gxp_debug_dump_cache_invalidate(struct gxp_dev *gxp)
@@ -446,6 +446,7 @@
 		}
 
 		gxp_mapping_vunmap(mapping);
+		/* Release the reference acquired in `gxp_vd_mapping_search_in_range()` above. */
 		gxp_mapping_put(mapping);
 	}
 }
@@ -510,12 +511,15 @@
 			vaddr + daddr - (mapping->gcip_mapping->device_address & PAGE_MASK);
 
 		/* Check that the entire user buffer is mapped */
-		if ((user_buf_vaddrs[i] + user_buf->size) >
-		    (vaddr + mapping->gcip_mapping->size +
-		     (mapping->gcip_mapping->device_address & ~PAGE_MASK))) {
+		if ((user_buf_vaddrs[i] + user_buf->size) > (vaddr + mapping->gcip_mapping->size)) {
 			dev_warn(gxp->dev, "%pad user buffer requested with invalid size(%#x).\n",
 				 &daddr, user_buf->size);
 			user_buf->size = 0;
+			/*
+			 * Decrement the `mapping->vmap_count` incremented in gxp_mapping_vmap()
+			 * above.
+			 */
+			gxp_mapping_vunmap(mapping);
 			continue;
 		}
 
diff --git a/gxp-debug-dump.h b/gxp-debug-dump.h
index 7772b44..5bcec03 100644
--- a/gxp-debug-dump.h
+++ b/gxp-debug-dump.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP debug dump handler
  *
@@ -16,8 +16,7 @@
 #include "gxp-dma.h"
 #include "gxp-internal.h"
 
-#define HAS_COREDUMP                                                           \
-	(IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP))
+#define HAS_COREDUMP (IS_GXP_TEST || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP))
 
 #if HAS_COREDUMP
 #include <linux/platform_data/sscoredump.h>
diff --git a/gxp-dma-iommu.c b/gxp-dma-iommu.c
index fac5cb5..32c86f2 100644
--- a/gxp-dma-iommu.c
+++ b/gxp-dma-iommu.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP DMA implemented via IOMMU.
  *
@@ -76,33 +76,33 @@
 
 #define SYNC_BARRIERS_SIZE 0x100000
 
-static int gxp_map_csrs(struct gxp_dev *gxp, struct iommu_domain *domain,
+static int gxp_map_csrs(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
 			struct gxp_mapped_resource *regs)
 {
-	int ret = iommu_map(domain, GXP_IOVA_AURORA_TOP, gxp->regs.paddr,
-			    gxp->regs.size, IOMMU_READ | IOMMU_WRITE);
+	int ret = gcip_iommu_map(gdomain, GXP_IOVA_AURORA_TOP, gxp->regs.paddr, gxp->regs.size,
+				 GCIP_MAP_FLAGS_DMA_RW);
 	if (ret)
 		return ret;
 	/*
 	 * Firmware expects to access the sync barriers at a separate
 	 * address, lower than the rest of the AURORA_TOP registers.
 	 */
-	ret = iommu_map(domain, GXP_IOVA_SYNC_BARRIERS,
-			gxp->regs.paddr + GXP_IOVA_SYNC_BARRIERS,
-			SYNC_BARRIERS_SIZE, IOMMU_READ | IOMMU_WRITE);
+	ret = gcip_iommu_map(gdomain, GXP_IOVA_SYNC_BARRIERS,
+			     gxp->regs.paddr + GXP_IOVA_SYNC_BARRIERS, SYNC_BARRIERS_SIZE,
+			     GCIP_MAP_FLAGS_DMA_RW);
 	if (ret) {
-		iommu_unmap(domain, GXP_IOVA_AURORA_TOP, gxp->regs.size);
+		gcip_iommu_unmap(gdomain, GXP_IOVA_AURORA_TOP, gxp->regs.size);
 		return ret;
 	}
 
 	return 0;
 }
 
-static void gxp_unmap_csrs(struct gxp_dev *gxp, struct iommu_domain *domain,
+static void gxp_unmap_csrs(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
 			   struct gxp_mapped_resource *regs)
 {
-	iommu_unmap(domain, GXP_IOVA_SYNC_BARRIERS, SYNC_BARRIERS_SIZE);
-	iommu_unmap(domain, GXP_IOVA_AURORA_TOP, gxp->regs.size);
+	gcip_iommu_unmap(gdomain, GXP_IOVA_SYNC_BARRIERS, SYNC_BARRIERS_SIZE);
+	gcip_iommu_unmap(gdomain, GXP_IOVA_AURORA_TOP, gxp->regs.size);
 }
 
 #endif /* GXP_HAS_LAP */
@@ -123,18 +123,6 @@
 	return gdomain;
 }
 
-int gxp_iommu_map(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-		  unsigned long iova, phys_addr_t paddr, size_t size, int prot)
-{
-	return iommu_map(gdomain->domain, iova, paddr, size, prot);
-}
-
-void gxp_iommu_unmap(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-		     unsigned long iova, size_t size)
-{
-	iommu_unmap(gdomain->domain, iova, size);
-}
-
 int gxp_dma_init(struct gxp_dev *gxp)
 {
 	struct gxp_dma_iommu_manager *mgr;
@@ -217,28 +205,25 @@
 	gcip_iommu_domain_pool_detach_domain(gxp->domain_pool, gdomain);
 }
 
-int gxp_dma_map_core_resources(struct gxp_dev *gxp,
-			       struct gcip_iommu_domain *gdomain,
+int gxp_dma_map_core_resources(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
 			       uint core_list, u8 slice_index)
 {
 	int ret;
 	uint i;
-	struct iommu_domain *domain = gdomain->domain;
 
 	if (!gxp_is_direct_mode(gxp))
 		return 0;
 
-	ret = gxp_map_csrs(gxp, domain, &gxp->regs);
+	ret = gxp_map_csrs(gxp, gdomain, &gxp->regs);
 	if (ret)
 		goto err;
 
 	for (i = 0; i < GXP_NUM_CORES; i++) {
 		if (!(BIT(i) & core_list))
 			continue;
-		ret = iommu_map(domain, gxp->mbx[i].daddr,
-				gxp->mbx[i].paddr +
-					MAILBOX_DEVICE_INTERFACE_OFFSET,
-				gxp->mbx[i].size, IOMMU_READ | IOMMU_WRITE);
+		ret = gcip_iommu_map(gdomain, gxp->mbx[i].daddr,
+				     gxp->mbx[i].paddr + MAILBOX_DEVICE_INTERFACE_OFFSET,
+				     gxp->mbx[i].size, GCIP_MAP_FLAGS_DMA_RW);
 		if (ret)
 			goto err;
 	}
@@ -247,11 +232,9 @@
 		for (i = 0; i < GXP_NUM_CORES; i++) {
 			if (!(BIT(i) & core_list))
 				continue;
-			ret = iommu_map(
-				domain,
-				GXP_IOVA_EXT_TPU_MBX + i * EXT_TPU_MBX_SIZE,
-				gxp->tpu_dev.mbx_paddr + i * EXT_TPU_MBX_SIZE,
-				EXT_TPU_MBX_SIZE, IOMMU_READ | IOMMU_WRITE);
+			ret = gcip_iommu_map(gdomain, GXP_IOVA_EXT_TPU_MBX + i * EXT_TPU_MBX_SIZE,
+					     gxp->tpu_dev.mbx_paddr + i * EXT_TPU_MBX_SIZE,
+					     EXT_TPU_MBX_SIZE, GCIP_MAP_FLAGS_DMA_RW);
 			if (ret)
 				goto err;
 		}
@@ -268,12 +251,10 @@
 	return ret;
 }
 
-void gxp_dma_unmap_core_resources(struct gxp_dev *gxp,
-				  struct gcip_iommu_domain *gdomain,
+void gxp_dma_unmap_core_resources(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
 				  uint core_list)
 {
 	uint i;
-	struct iommu_domain *domain = gdomain->domain;
 
 	if (!gxp_is_direct_mode(gxp))
 		return;
@@ -283,17 +264,16 @@
 		for (i = 0; i < GXP_NUM_CORES; i++) {
 			if (!(BIT(i) & core_list))
 				continue;
-			iommu_unmap(domain,
-				    GXP_IOVA_EXT_TPU_MBX + i * EXT_TPU_MBX_SIZE,
-				    EXT_TPU_MBX_SIZE);
+			gcip_iommu_unmap(gdomain, GXP_IOVA_EXT_TPU_MBX + i * EXT_TPU_MBX_SIZE,
+					 EXT_TPU_MBX_SIZE);
 		}
 	}
 	for (i = 0; i < GXP_NUM_CORES; i++) {
 		if (!(BIT(i) & core_list))
 			continue;
-		iommu_unmap(domain, gxp->mbx[i].daddr, gxp->mbx[i].size);
+		gcip_iommu_unmap(gdomain, gxp->mbx[i].daddr, gxp->mbx[i].size);
 	}
-	gxp_unmap_csrs(gxp, domain, &gxp->regs);
+	gxp_unmap_csrs(gxp, gdomain, &gxp->regs);
 }
 
 static inline struct sg_table *alloc_sgt_for_buffer(void *ptr, size_t size,
@@ -375,7 +355,6 @@
 	int core;
 	int ret;
 	int i = 0;
-	struct iommu_domain *domain = gdomain->domain;
 
 	while (core_list) {
 		phys_addr_t cmdq_pa = mbx_info->mailboxes[i].cmdq_pa;
@@ -383,14 +362,14 @@
 
 		core = ffs(core_list) - 1;
 		queue_iova = GXP_IOVA_TPU_MBX_BUFFER(core);
-		ret = iommu_map(domain, queue_iova, cmdq_pa,
-				mbx_info->cmdq_size, IOMMU_WRITE);
+		ret = gcip_iommu_map(gdomain, queue_iova, cmdq_pa, mbx_info->cmdq_size,
+				     GCIP_MAP_FLAGS_DMA_RW);
 		if (ret)
 			goto error;
-		ret = iommu_map(domain, queue_iova + mbx_info->cmdq_size,
-				respq_pa, mbx_info->respq_size, IOMMU_READ);
+		ret = gcip_iommu_map(gdomain, queue_iova + mbx_info->cmdq_size, respq_pa,
+				     mbx_info->respq_size, GCIP_MAP_FLAGS_DMA_RO);
 		if (ret) {
-			iommu_unmap(domain, queue_iova, mbx_info->cmdq_size);
+			gcip_iommu_unmap(gdomain, queue_iova, mbx_info->cmdq_size);
 			goto error;
 		}
 		core_list &= ~BIT(core);
@@ -403,29 +382,25 @@
 		core = ffs(core_list) - 1;
 		core_list &= ~BIT(core);
 		queue_iova = GXP_IOVA_TPU_MBX_BUFFER(core);
-		iommu_unmap(domain, queue_iova, mbx_info->cmdq_size);
-		iommu_unmap(domain, queue_iova + mbx_info->cmdq_size,
-			    mbx_info->respq_size);
+		gcip_iommu_unmap(gdomain, queue_iova, mbx_info->cmdq_size);
+		gcip_iommu_unmap(gdomain, queue_iova + mbx_info->cmdq_size, mbx_info->respq_size);
 	}
 	return ret;
 }
 
-void gxp_dma_unmap_tpu_buffer(struct gxp_dev *gxp,
-			      struct gcip_iommu_domain *gdomain,
+void gxp_dma_unmap_tpu_buffer(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
 			      struct gxp_tpu_mbx_desc mbx_desc)
 {
 	uint core_list = mbx_desc.phys_core_list;
 	u64 queue_iova;
 	int core;
-	struct iommu_domain *domain = gdomain->domain;
 
 	while (core_list) {
 		core = ffs(core_list) - 1;
 		core_list &= ~BIT(core);
 		queue_iova = GXP_IOVA_TPU_MBX_BUFFER(core);
-		iommu_unmap(domain, queue_iova, mbx_desc.cmdq_size);
-		iommu_unmap(domain, queue_iova + mbx_desc.cmdq_size,
-			    mbx_desc.respq_size);
+		gcip_iommu_unmap(gdomain, queue_iova, mbx_desc.cmdq_size);
+		gcip_iommu_unmap(gdomain, queue_iova + mbx_desc.cmdq_size, mbx_desc.respq_size);
 	}
 }
 
@@ -439,15 +414,13 @@
 	struct gxp_dma_iommu_manager *mgr = container_of(
 		gxp->dma_mgr, struct gxp_dma_iommu_manager, dma_mgr);
 	struct sg_table *sgt;
-	ssize_t size_mapped;
+	unsigned int nents_mapped;
 	int ret = 0;
-	size_t size;
-	struct iommu_domain *domain = gdomain->domain;
+	u64 gcip_map_flags = GCIP_MAP_FLAGS_DMA_RW;
 
 	if (gdomain == gxp_iommu_get_domain_for_dev(gxp))
 		return 0;
 
-	size = buf->size;
 	sgt = alloc_sgt_for_buffer(buf->vaddr, buf->size,
 				   mgr->default_domain->domain, buf->dma_addr);
 	if (IS_ERR(sgt)) {
@@ -456,10 +429,10 @@
 		return PTR_ERR(sgt);
 	}
 
-	size_mapped = iommu_map_sg(domain, buf->dsp_addr, sgt->sgl, sgt->orig_nents,
-				   IOMMU_READ | IOMMU_WRITE);
-	if (size_mapped != size)
-		ret = size_mapped < 0 ? -EINVAL : (int)size_mapped;
+	nents_mapped =
+		gcip_iommu_domain_map_sgt_to_iova(gdomain, sgt, buf->dsp_addr, &gcip_map_flags);
+	if (!nents_mapped)
+		ret = -ENOSPC;
 
 	sg_free_table(sgt);
 	kfree(sgt);
@@ -518,8 +491,7 @@
 	if (gdomain == gxp_iommu_get_domain_for_dev(gxp))
 		return;
 
-	if (buf->size != iommu_unmap(gdomain->domain, buf->dsp_addr, buf->size))
-		dev_warn(gxp->dev, "Failed to unmap coherent buffer\n");
+	gcip_iommu_unmap(gdomain, buf->dsp_addr, buf->size);
 }
 
 void gxp_dma_free_coherent_buf(struct gxp_dev *gxp,
@@ -533,41 +505,6 @@
 	dma_free_coherent(gxp->dev, buf->size, buf->vaddr, buf->dma_addr);
 }
 
-int gxp_dma_map_iova_sgt(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-			 dma_addr_t iova, struct sg_table *sgt, int prot)
-{
-	ssize_t size_mapped;
-
-	size_mapped = (ssize_t)iommu_map_sg(gdomain->domain, iova, sgt->sgl,
-					    sgt->orig_nents, prot);
-	if (size_mapped <= 0) {
-		dev_err(gxp->dev, "map IOVA %pad to SG table failed: %d", &iova,
-			(int)size_mapped);
-		if (size_mapped == 0)
-			return -EINVAL;
-		return size_mapped;
-	}
-	dma_sync_sg_for_device(gxp->dev, sgt->sgl, sgt->orig_nents,
-			       DMA_BIDIRECTIONAL);
-
-	return 0;
-}
-
-void gxp_dma_unmap_iova_sgt(struct gxp_dev *gxp,
-			    struct gcip_iommu_domain *gdomain, dma_addr_t iova,
-			    struct sg_table *sgt)
-{
-	struct scatterlist *s;
-	int i;
-	size_t size = 0;
-
-	for_each_sg (sgt->sgl, s, sgt->orig_nents, i)
-		size += s->length;
-
-	if (!iommu_unmap(gdomain->domain, iova, size))
-		dev_warn(gxp->dev, "Failed to unmap sgt");
-}
-
 void gxp_dma_sync_sg_for_cpu(struct gxp_dev *gxp, struct scatterlist *sg,
 			     int nents, enum dma_data_direction direction)
 {
diff --git a/gxp-dma.h b/gxp-dma.h
index c3e8f10..019390b 100644
--- a/gxp-dma.h
+++ b/gxp-dma.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP DMA interface.
  *
@@ -43,24 +43,6 @@
 #endif
 
 /**
- * gxp_iommu_map() - Create mappings in iommu
- * @gxp: The GXP device
- * @gdomain: The IOMMU domain to create mappings in.
- *
- * Return: 0 on success or negative value indicating error
- */
-int gxp_iommu_map(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-		  unsigned long iova, phys_addr_t paddr, size_t size, int prot);
-
-/**
- * gxp_iommu_unmap() - Reverts mappings created by gxp_iommu_map()
- * @gxp: The GXP device
- * @gdomain: The IOMMU domain to revert mappings in.
- */
-void gxp_iommu_unmap(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-		     unsigned long iova, size_t size);
-
-/**
  * gxp_dma_init() - Initialize the GXP DMA subsystem
  * @gxp: The GXP device to initialize DMA for
  *
@@ -238,30 +220,6 @@
 			       struct gxp_coherent_buf *buf);
 
 /**
- * gxp_dma_map_iova_sgt() - Create a mapping for a scatter-gather list, with specific IOVA.
- * @gxp: The GXP device to map the scatter-gather list for
- * @gdomain: The IOMMU domain to be mapped
- * @iova: The IOVA to be mapped.
- * @sgt: The scatter-gather list table of the buffer to be mapped
- * @prot: The protection bits to be passed to IOMMU API
- *
- * Return: 0 on success. Negative errno otherwise.
- */
-int gxp_dma_map_iova_sgt(struct gxp_dev *gxp, struct gcip_iommu_domain *gdomain,
-			 dma_addr_t iova, struct sg_table *sgt, int prot);
-/**
- * gxp_dma_unmap_iova_sgt() - Revert gxp_dma_map_iova_sgt()
- * @gxp: The GXP device the scatter-gather list was mapped for
- * @gdomain: The IOMMU domain mapping was mapped on
- * @iova: The IOVA to be un-mapped.
- * @sgt: The scatter-gather list to unmap; The same one passed to
- *      `gxp_dma_map_iova_sgt()`
- */
-void gxp_dma_unmap_iova_sgt(struct gxp_dev *gxp,
-			    struct gcip_iommu_domain *gdomain, dma_addr_t iova,
-			    struct sg_table *sgt);
-
-/**
  * gxp_dma_sync_sg_for_cpu() - Sync sg list for reading by the  CPU
  * @gxp: The GXP device the mapping was created for
  * @sg: The mapped scatter-gather list to be synced
diff --git a/gxp-dmabuf.c b/gxp-dmabuf.c
index 3488530..c51cd0b 100644
--- a/gxp-dmabuf.c
+++ b/gxp-dmabuf.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Support for using dma-bufs.
  *
diff --git a/gxp-dmabuf.h b/gxp-dmabuf.h
index ff83bf5..8489a2a 100644
--- a/gxp-dmabuf.h
+++ b/gxp-dmabuf.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Support for using dma-bufs.
  *
diff --git a/gxp-domain-pool.c b/gxp-domain-pool.c
index 5f22ea7..62f1ba2 100644
--- a/gxp-domain-pool.c
+++ b/gxp-domain-pool.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP IOMMU domain allocator.
  *
diff --git a/gxp-domain-pool.h b/gxp-domain-pool.h
index dabf152..22fcc02 100644
--- a/gxp-domain-pool.h
+++ b/gxp-domain-pool.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * IOMMU domain allocator for gxp
  *
diff --git a/gxp-doorbell.c b/gxp-doorbell.c
index 491fb5b..588fc2a 100644
--- a/gxp-doorbell.c
+++ b/gxp-doorbell.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP doorbell interface.
  *
diff --git a/gxp-doorbell.h b/gxp-doorbell.h
index d2f167b..802661d 100644
--- a/gxp-doorbell.h
+++ b/gxp-doorbell.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP doorbell interface.
  *
diff --git a/gxp-eventfd.c b/gxp-eventfd.c
index ed0170f..978f1c6 100644
--- a/gxp-eventfd.c
+++ b/gxp-eventfd.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP eventfd
  *
diff --git a/gxp-eventfd.h b/gxp-eventfd.h
index 6a23200..a6360bd 100644
--- a/gxp-eventfd.h
+++ b/gxp-eventfd.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP eventfd
  *
diff --git a/gxp-firmware-data.c b/gxp-firmware-data.c
index 4426bb7..ed79a30 100644
--- a/gxp-firmware-data.c
+++ b/gxp-firmware-data.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP firmware data manager.
  *
diff --git a/gxp-firmware-data.h b/gxp-firmware-data.h
index 7a9dee5..028e610 100644
--- a/gxp-firmware-data.h
+++ b/gxp-firmware-data.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP firmware data manager.
  * A sub-module responsible for managing the resources/data regions shared
diff --git a/gxp-firmware.c b/gxp-firmware.c
index 3b767aa..f9049a0 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP firmware loader.
  *
@@ -9,7 +9,6 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/elf.h>
-#include <linux/gsa/gsa_image_auth.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
@@ -38,7 +37,13 @@
 #include "gxp-pm.h"
 #include "gxp-vd.h"
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if !GXP_HAS_MCU
+#include <linux/gsa/gsa_image_auth.h>
+#else
+#define gsa_authenticate_image(...) (0)
+#endif /* GXP_HAS_MCU */
+
+#if IS_GXP_TEST
 #include "unittests/factory/fake-gxp-firmware.h"
 #endif
 
@@ -368,7 +373,7 @@
 	 * space as an alive message
 	 */
 	ctr = 5000;
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 	fake_gxp_firmware_flush_work_all();
 	/*
 	 * As the fake firmware works are flushed, we don't have to busy-wait the response of
diff --git a/gxp-firmware.h b/gxp-firmware.h
index 4896ae2..40ee22b 100644
--- a/gxp-firmware.h
+++ b/gxp-firmware.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP firmware loader.
  *
diff --git a/gxp-host-device-structs.h b/gxp-host-device-structs.h
index 508d019..8fe8a78 100644
--- a/gxp-host-device-structs.h
+++ b/gxp-host-device-structs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP host-device interface structures.
  *
diff --git a/gxp-internal.h b/gxp-internal.h
index 84cd1d6..35c0993 100644
--- a/gxp-internal.h
+++ b/gxp-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP driver common internal definitions.
  *
diff --git a/gxp-kci.c b/gxp-kci.c
index 20cd2d9..722722e 100644
--- a/gxp-kci.c
+++ b/gxp-kci.c
@@ -35,6 +35,13 @@
 #define MBOX_CMD_QUEUE_NUM_ENTRIES 1024
 #define MBOX_RESP_QUEUE_NUM_ENTRIES 1024
 
+/*
+ * `flags` in `gcip_kci_dma_descriptor` struct is used to pass the gxp kernel driver major and
+ * minor version for the `GCIP_KCI_CODE_EXCHANGE_INFO` gcip_kci_code . First 16 bits of `flags`
+ * represent the major version and last 16 bits represent the minor version.
+ */
+#define GXP_INTERFACE_VERSION_MAJOR_SHIFT 16
+
 /* Callback functions for struct gcip_kci. */
 
 static u32 gxp_kci_get_cmd_queue_head(struct gcip_kci *kci)
@@ -396,10 +403,13 @@
 {
 	struct gxp_dev *gxp = gkci->gxp;
 	struct gcip_kci_command_element cmd = {
-		.code = GCIP_KCI_CODE_FIRMWARE_INFO,
+		.code = GCIP_KCI_CODE_EXCHANGE_INFO,
 		.dma = {
 			.address = 0,
 			.size = 0,
+			.flags =
+				(GXP_INTERFACE_VERSION_MAJOR << GXP_INTERFACE_VERSION_MAJOR_SHIFT) |
+				GXP_INTERFACE_VERSION_MINOR,
 		},
 	};
 	enum gcip_fw_flavor flavor = GCIP_FW_FLAVOR_UNKNOWN;
diff --git a/gxp-kci.h b/gxp-kci.h
index 5bfbcd5..4bf413f 100644
--- a/gxp-kci.h
+++ b/gxp-kci.h
@@ -27,7 +27,7 @@
 
 /* Timeout for KCI responses from the firmware (milliseconds) */
 #ifndef GXP_KCI_TIMEOUT
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 #define GXP_KCI_TIMEOUT (200) /* Fake firmware could respond in a short time. */
 #elif IS_ENABLED(CONFIG_GXP_IP_ZEBU)
 #define GXP_KCI_TIMEOUT (10000) /* 10 secs. */
diff --git a/gxp-lpm.c b/gxp-lpm.c
index 21abe4b..f3b7297 100644
--- a/gxp-lpm.c
+++ b/gxp-lpm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP local power management interface.
  *
diff --git a/gxp-lpm.h b/gxp-lpm.h
index 3c3f8b0..24054c0 100644
--- a/gxp-lpm.h
+++ b/gxp-lpm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP local power management interface.
  * Controlling Local Power Manager hardware.
diff --git a/gxp-mailbox-driver.c b/gxp-mailbox-driver.c
index d04a0a2..7257114 100644
--- a/gxp-mailbox-driver.c
+++ b/gxp-mailbox-driver.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP hardware-based mailbox driver implementation.
  *
diff --git a/gxp-mailbox-driver.h b/gxp-mailbox-driver.h
index 3865544..4349827 100644
--- a/gxp-mailbox-driver.h
+++ b/gxp-mailbox-driver.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP mailbox driver.
  *
diff --git a/gxp-mailbox-manager.c b/gxp-mailbox-manager.c
index bb74fcb..268c51f 100644
--- a/gxp-mailbox-manager.c
+++ b/gxp-mailbox-manager.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Mailbox manager abstracts the mailbox interfaces of user commands.
  *
diff --git a/gxp-mailbox-manager.h b/gxp-mailbox-manager.h
index 18658da..dc85477 100644
--- a/gxp-mailbox-manager.h
+++ b/gxp-mailbox-manager.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Mailbox manager abstracts the mailbox interfaces of user commands.
  *
diff --git a/gxp-mailbox.c b/gxp-mailbox.c
index cdbca66..5afd820 100644
--- a/gxp-mailbox.c
+++ b/gxp-mailbox.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP mailbox.
  *
@@ -53,7 +53,9 @@
 #if GXP_USE_LEGACY_MAILBOX
 	gxp_mailbox_consume_responses(mailbox);
 #else
-	if (mailbox->type == GXP_MBOX_TYPE_KCI)
+	if (gxp_is_direct_mode(mailbox->gxp))
+		gcip_mailbox_consume_responses_work(mailbox->mbx_impl.gcip_mbx);
+	else if (mailbox->type == GXP_MBOX_TYPE_KCI)
 		gxp_mcu_telemetry_irq_handler(((struct gxp_kci *)mailbox->data)->mcu);
 #endif
 }
@@ -65,16 +67,18 @@
  */
 static void gxp_mailbox_handle_irq(struct gxp_mailbox *mailbox)
 {
-#if !GXP_USE_LEGACY_MAILBOX
+	if (gxp_is_direct_mode(mailbox->gxp)) {
+		kthread_queue_work(&mailbox->response_worker, &mailbox->response_work);
+		return;
+	}
+#if GXP_HAS_MCU
 	if (mailbox->type == GXP_MBOX_TYPE_KCI) {
 		gcip_kci_handle_irq(mailbox->mbx_impl.gcip_kci);
 		kthread_queue_work(&mailbox->response_worker, &mailbox->response_work);
 	} else if (mailbox->type == GXP_MBOX_TYPE_GENERAL) {
 		gcip_mailbox_consume_responses_work(mailbox->mbx_impl.gcip_mbx);
 	}
-#else
-	kthread_queue_work(&mailbox->response_worker, &mailbox->response_work);
-#endif
+#endif /* GXP_HAS_MCU */
 }
 
 /* Priority level for realtime worker threads */
diff --git a/gxp-mailbox.h b/gxp-mailbox.h
index 2fb4162..7e3dd58 100644
--- a/gxp-mailbox.h
+++ b/gxp-mailbox.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP mailbox interface.
  *
diff --git a/gxp-mapping.c b/gxp-mapping.c
index 26af235..6d60d82 100644
--- a/gxp-mapping.c
+++ b/gxp-mapping.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Records the mapped device addresses.
  *
@@ -26,7 +26,7 @@
 
 #include <trace/events/gxp.h>
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 /* expose this variable to have unit tests set it dynamically */
 bool gxp_log_iova;
 #else
diff --git a/gxp-mapping.h b/gxp-mapping.h
index a426efe..751a0f9 100644
--- a/gxp-mapping.h
+++ b/gxp-mapping.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Records the mapped device addresses.
  *
@@ -20,7 +20,7 @@
 
 #include "gxp-internal.h"
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 /* expose this variable to have unit tests set it dynamically */
 extern bool gxp_log_iova;
 #endif
diff --git a/gxp-mb-notification.c b/gxp-mb-notification.c
index 77412f8..aa10849 100644
--- a/gxp-mb-notification.c
+++ b/gxp-mb-notification.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP notification implementation on top of the mailbox driver.
  *
diff --git a/gxp-mcu-firmware.c b/gxp-mcu-firmware.c
index 0a8ac9d..6d19080 100644
--- a/gxp-mcu-firmware.c
+++ b/gxp-mcu-firmware.c
@@ -19,6 +19,7 @@
 #include <gcip/gcip-common-image-header.h>
 #include <gcip/gcip-fault-injection.h>
 #include <gcip/gcip-image-config.h>
+#include <gcip/gcip-iommu.h>
 #include <gcip/gcip-pm.h>
 #include <gcip/gcip-thermal.h>
 
@@ -26,7 +27,6 @@
 #include "gxp-config.h"
 #include "gxp-core-telemetry.h"
 #include "gxp-debug-dump.h"
-#include "gxp-dma.h"
 #include "gxp-doorbell.h"
 #include "gxp-firmware-loader.h"
 #include "gxp-gsa.h"
@@ -745,16 +745,15 @@
 		return -EINVAL;
 	}
 
-	return gxp_iommu_map(gxp, gxp_iommu_get_domain_for_dev(gxp), daddr,
-			     paddr, size, IOMMU_READ | IOMMU_WRITE);
+	return gcip_iommu_map(gxp_iommu_get_domain_for_dev(gxp), daddr, paddr, size,
+			      GCIP_MAP_FLAGS_DMA_RW);
 }
 
-static void image_config_unmap(void *data, dma_addr_t daddr, size_t size,
-			       unsigned int flags)
+static void image_config_unmap(void *data, dma_addr_t daddr, size_t size, unsigned int flags)
 {
 	struct gxp_dev *gxp = data;
 
-	gxp_iommu_unmap(gxp, gxp_iommu_get_domain_for_dev(gxp), daddr, size);
+	gcip_iommu_unmap(gxp_iommu_get_domain_for_dev(gxp), daddr, size);
 }
 
 static void gxp_mcu_firmware_crash_handler_work(struct work_struct *work)
diff --git a/gxp-mcu-fs.c b/gxp-mcu-fs.c
index d6d8387..2c97e30 100644
--- a/gxp-mcu-fs.c
+++ b/gxp-mcu-fs.c
@@ -225,7 +225,7 @@
 	ret = gxp_uci_wait_async_response(
 		&client->vd->mailbox_resp_queues[UCI_RESOURCE_ID],
 		&ibuf.sequence_number, &ibuf.error_code, ibuf.opaque);
-	if (ret == -ENOENT)
+	if (ret == -ENOENT || ret == -EAGAIN)
 		goto out;
 
 	if (copy_to_user(argp, &ibuf, sizeof(ibuf)))
diff --git a/gxp-mcu-platform.c b/gxp-mcu-platform.c
index 4922b66..8e55dcd 100644
--- a/gxp-mcu-platform.c
+++ b/gxp-mcu-platform.c
@@ -23,7 +23,7 @@
 #include <soc/google/tpu-ext.h>
 #endif
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 char *gxp_work_mode_name = "mcu";
 #else
 static char *gxp_work_mode_name = "mcu";
diff --git a/gxp-mcu-platform.h b/gxp-mcu-platform.h
index e87a36b..6865310 100644
--- a/gxp-mcu-platform.h
+++ b/gxp-mcu-platform.h
@@ -13,7 +13,7 @@
 
 #define to_mcu_dev(gxp) container_of(gxp, struct gxp_mcu_dev, gxp)
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 /* expose this variable to have unit tests set it dynamically */
 extern char *gxp_work_mode_name;
 #endif
diff --git a/gxp-notification.h b/gxp-notification.h
index 6f43b70..ad4d00b 100644
--- a/gxp-notification.h
+++ b/gxp-notification.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP notification interface.
  *
diff --git a/gxp-pm.c b/gxp-pm.c
index 012b5c8..d294e02 100644
--- a/gxp-pm.c
+++ b/gxp-pm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP power management.
  *
@@ -39,6 +39,13 @@
 static bool gxp_slow_clk_on_idle = true;
 module_param_named(slow_clk, gxp_slow_clk_on_idle, bool, 0660);
 
+const uint aur_power_state2rate[] = {
+	AUR_OFF_RATE,	AUR_UUD_RATE,	   AUR_SUD_RATE,      AUR_UD_RATE,	AUR_NOM_RATE,
+	AUR_READY_RATE, AUR_UUD_PLUS_RATE, AUR_SUD_PLUS_RATE, AUR_UD_PLUS_RATE,
+};
+const struct gxp_power_states off_states = { AUR_OFF, AUR_MEM_UNDEFINED, false };
+const struct gxp_power_states uud_states = { AUR_UUD, AUR_MEM_UNDEFINED, false };
+
 /*
  * The order of this array decides the voting priority, should be increasing in
  * frequencies.
diff --git a/gxp-pm.h b/gxp-pm.h
index 7b678bf..27a1398 100644
--- a/gxp-pm.h
+++ b/gxp-pm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP power management.
  *
@@ -33,17 +33,7 @@
 	AUR_UD_PLUS = 8,
 };
 
-static const uint aur_power_state2rate[] = {
-	AUR_OFF_RATE,
-	AUR_UUD_RATE,
-	AUR_SUD_RATE,
-	AUR_UD_RATE,
-	AUR_NOM_RATE,
-	AUR_READY_RATE,
-	AUR_UUD_PLUS_RATE,
-	AUR_SUD_PLUS_RATE,
-	AUR_UD_PLUS_RATE,
-};
+extern const uint aur_power_state2rate[];
 
 enum aur_memory_power_state {
 	AUR_MEM_UNDEFINED = 0,
@@ -115,10 +105,8 @@
 	bool low_clkmux;
 };
 
-static const struct gxp_power_states off_states = { AUR_OFF, AUR_MEM_UNDEFINED,
-						    false };
-static const struct gxp_power_states uud_states = { AUR_UUD, AUR_MEM_UNDEFINED,
-						    false };
+extern const struct gxp_power_states off_states;
+extern const struct gxp_power_states uud_states;
 
 struct gxp_power_manager {
 	struct gxp_dev *gxp;
diff --git a/gxp-thermal.c b/gxp-thermal.c
index 8335280..9807b09 100644
--- a/gxp-thermal.c
+++ b/gxp-thermal.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Platform thermal driver for GXP.
  *
diff --git a/gxp-thermal.h b/gxp-thermal.h
index aa4fe3a..777815f 100644
--- a/gxp-thermal.h
+++ b/gxp-thermal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Platform thermal driver for GXP.
  *
diff --git a/gxp-uci.c b/gxp-uci.c
index 837de85..9ea2e43 100644
--- a/gxp-uci.c
+++ b/gxp-uci.c
@@ -24,7 +24,7 @@
 #include "gxp-vd.h"
 #include "gxp.h"
 
-#if IS_ENABLED(CONFIG_GXP_TEST)
+#if IS_GXP_TEST
 #include "unittests/factory/fake-gxp-mcu-firmware.h"
 
 #define TEST_FLUSH_FIRMWARE_WORK() fake_gxp_mcu_firmware_flush_work_all()
@@ -755,9 +755,22 @@
 		uci_resp_queue->waitq, !list_empty(&uci_resp_queue->dest_queue),
 		uci_resp_queue->lock, msecs_to_jiffies(MAILBOX_TIMEOUT));
 	if (timeout <= 0) {
+		*resp_seq = 0;
+		if (list_empty(&uci_resp_queue->wait_queue)) {
+			/* This only happens when there is no command pushed or signaled. */
+			*error_code = -ENOENT;
+			ret = -ENOENT;
+		} else {
+			/*
+			 * Might be a race with gcip_mailbox_async_cmd_timeout_work or the command
+			 * use a runtime specified timeout that is larger than MAILBOX_TIMEOUT.
+			 */
+			*error_code = -EAGAIN;
+			ret = -EAGAIN;
+		}
 		spin_unlock_irq(&uci_resp_queue->lock);
-		/* unusual case - this only happens when there is no command pushed */
-		return -ENOENT;
+
+		return ret;
 	}
 	async_resp = list_first_entry(&uci_resp_queue->dest_queue,
 				      struct gxp_uci_async_response,
diff --git a/gxp-usage-stats.c b/gxp-usage-stats.c
index 4b859b3..44d6960 100644
--- a/gxp-usage-stats.c
+++ b/gxp-usage-stats.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * DSP usage stats
  *
diff --git a/gxp-usage-stats.h b/gxp-usage-stats.h
index 2f63557..edfbce4 100644
--- a/gxp-usage-stats.h
+++ b/gxp-usage-stats.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * DSP usage stats header
  *
diff --git a/gxp-vd.c b/gxp-vd.c
index aadb79b..2dd6959 100644
--- a/gxp-vd.c
+++ b/gxp-vd.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * GXP virtual device manager.
  *
@@ -17,6 +17,7 @@
 #include <gcip/gcip-alloc-helper.h>
 #include <gcip/gcip-image-config.h>
 #include <gcip/gcip-iommu-reserve.h>
+#include <gcip/gcip-iommu.h>
 
 #include "gxp-config.h"
 #include "gxp-core-telemetry.h"
@@ -84,7 +85,7 @@
 	struct sg_table *sgt;
 	size_t idx;
 	const size_t n_reg = ARRAY_SIZE(vd->ns_regions);
-	int ret;
+	u64 gcip_map_flags = GCIP_MAP_FLAGS_DMA_RW;
 
 	for (idx = 0; idx < n_reg; idx++) {
 		if (!vd->ns_regions[idx].sgt)
@@ -98,13 +99,10 @@
 	if (!sgt)
 		return -ENOMEM;
 
-	ret = gxp_dma_map_iova_sgt(gxp, vd->domain, daddr, sgt,
-				   IOMMU_READ | IOMMU_WRITE);
-	if (ret) {
-		dev_err(gxp->dev, "NS map %pad with size %#zx failed", &daddr,
-			size);
+	if (!gcip_iommu_domain_map_sgt_to_iova(vd->domain, sgt, daddr, &gcip_map_flags)) {
+		dev_err(gxp->dev, "NS map %pad with size %#zx failed", &daddr, size);
 		gcip_free_noncontiguous(sgt);
-		return ret;
+		return -EBUSY;
 	}
 	vd->ns_regions[idx].daddr = daddr;
 	vd->ns_regions[idx].sgt = sgt;
@@ -131,7 +129,7 @@
 	sgt = vd->ns_regions[idx].sgt;
 	vd->ns_regions[idx].sgt = NULL;
 	vd->ns_regions[idx].daddr = 0;
-	gxp_dma_unmap_iova_sgt(gxp, vd->domain, daddr, sgt);
+	gcip_iommu_domain_unmap_sgt_from_iova(vd->domain, sgt, GCIP_MAP_FLAGS_DMA_RW);
 	gcip_free_noncontiguous(sgt);
 }
 
@@ -143,10 +141,9 @@
 
 	if (!gxp->shared_buf.paddr)
 		return 0;
-	return gxp_iommu_map(gxp, vd->domain, gxp->shared_buf.daddr,
-			     gxp->shared_buf.paddr +
-				     shared_size * vd->slice_index,
-			     shared_size, IOMMU_READ | IOMMU_WRITE);
+	return gcip_iommu_map(vd->domain, gxp->shared_buf.daddr,
+			      gxp->shared_buf.paddr + shared_size * vd->slice_index, shared_size,
+			      GCIP_MAP_FLAGS_DMA_RW);
 }
 
 /* Reverts map_core_shared_buffer. */
@@ -157,26 +154,23 @@
 
 	if (!gxp->shared_buf.paddr)
 		return;
-	gxp_iommu_unmap(gxp, vd->domain, gxp->shared_buf.daddr, shared_size);
+	gcip_iommu_unmap(vd->domain, gxp->shared_buf.daddr, shared_size);
 }
 
 /* Maps @res->daddr to @res->paddr to @vd->domain. */
-static int map_resource(struct gxp_virtual_device *vd,
-			struct gxp_mapped_resource *res)
+static int map_resource(struct gxp_virtual_device *vd, struct gxp_mapped_resource *res)
 {
 	if (res->daddr == 0)
 		return 0;
-	return gxp_iommu_map(vd->gxp, vd->domain, res->daddr, res->paddr,
-			     res->size, IOMMU_READ | IOMMU_WRITE);
+	return gcip_iommu_map(vd->domain, res->daddr, res->paddr, res->size, GCIP_MAP_FLAGS_DMA_RW);
 }
 
 /* Reverts map_resource. */
-static void unmap_resource(struct gxp_virtual_device *vd,
-			   struct gxp_mapped_resource *res)
+static void unmap_resource(struct gxp_virtual_device *vd, struct gxp_mapped_resource *res)
 {
 	if (res->daddr == 0)
 		return;
-	gxp_iommu_unmap(vd->gxp, vd->domain, res->daddr, res->size);
+	gcip_iommu_unmap(vd->domain, res->daddr, res->size);
 }
 
 /*
@@ -197,15 +191,13 @@
 		dev_err(gxp->dev, "invalid system cfg size: %#llx", res->size);
 		return -EINVAL;
 	}
-	ret = gxp_iommu_map(gxp, vd->domain, res->daddr, res->paddr, ro_size,
-			    IOMMU_READ);
+	ret = gcip_iommu_map(vd->domain, res->daddr, res->paddr, ro_size, GCIP_MAP_FLAGS_DMA_RO);
 	if (ret)
 		return ret;
-	ret = gxp_iommu_map(gxp, vd->domain, res->daddr + ro_size,
-			    res->paddr + ro_size, res->size - ro_size,
-			    IOMMU_READ | IOMMU_WRITE);
+	ret = gcip_iommu_map(vd->domain, res->daddr + ro_size, res->paddr + ro_size,
+			     res->size - ro_size, GCIP_MAP_FLAGS_DMA_RW);
 	if (ret) {
-		gxp_iommu_unmap(gxp, vd->domain, res->daddr, ro_size);
+		gcip_iommu_unmap(vd->domain, res->daddr, ro_size);
 		return ret;
 	}
 	return 0;
@@ -427,15 +419,13 @@
 static int map_fw_image(struct gxp_dev *gxp, struct gxp_virtual_device *vd)
 {
 	/* Maps all FW regions together. */
-	return gxp_iommu_map(gxp, vd->domain, gxp->fwbufs[0].daddr,
-			     gxp->fwbufs[0].paddr,
-			     gxp->fwbufs[0].size * GXP_NUM_CORES, IOMMU_READ);
+	return gcip_iommu_map(vd->domain, gxp->fwbufs[0].daddr, gxp->fwbufs[0].paddr,
+			      gxp->fwbufs[0].size * GXP_NUM_CORES, GCIP_MAP_FLAGS_DMA_RO);
 }
 
 static void unmap_fw_image(struct gxp_dev *gxp, struct gxp_virtual_device *vd)
 {
-	gxp_iommu_unmap(gxp, vd->domain, gxp->fwbufs[0].daddr,
-			gxp->fwbufs[0].size * GXP_NUM_CORES);
+	gcip_iommu_unmap(vd->domain, gxp->fwbufs[0].daddr, gxp->fwbufs[0].size * GXP_NUM_CORES);
 }
 
 static int map_core_telemetry_buffers(struct gxp_dev *gxp,
@@ -1411,7 +1401,8 @@
 {
 	return ((device_address >= mapping->gcip_mapping->device_address) &&
 		(device_address <
-		 (mapping->gcip_mapping->device_address + mapping->gcip_mapping->size)));
+		((mapping->gcip_mapping->device_address & PAGE_MASK) +
+		mapping->gcip_mapping->size)));
 }
 
 static struct gxp_mapping *
diff --git a/gxp-vd.h b/gxp-vd.h
index 2fafa47..f49479d 100644
--- a/gxp-vd.h
+++ b/gxp-vd.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP virtual device manager.
  *
diff --git a/gxp.h b/gxp.h
index b0c224d..e4537b7 100644
--- a/gxp.h
+++ b/gxp.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * GXP kernel-userspace interface definitions.
  *
diff --git a/include/linux/gsa/gsa_image_auth.h b/include/linux/gsa/gsa_image_auth.h
deleted file mode 100644
index 149211c..0000000
--- a/include/linux/gsa/gsa_image_auth.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Fallback header for systems without GSA support.
- *
- * Copyright (C) 2022 Google, Inc.
- */
-
-#ifndef __LINUX_GSA_IMAGE_AUTH_H
-#define __LINUX_GSA_IMAGE_AUTH_H
-
-#include <linux/device.h>
-#include <linux/types.h>
-
-static inline int gsa_authenticate_image(struct device *gsa, dma_addr_t img_meta,
-					 phys_addr_t img_body)
-{
-	return 0;
-}
-
-#endif /* __LINUX_GSA_IMAGE_AUTH_H */