diff --git a/acs-drv/files/MakefileBSA b/acs-drv/files/MakefileBSA
index 0abf5ac685c3e00dabdbc22f49ab9e2a506dafae..b169898ae85a70b9737f8ddc0cb5c651aa7725c4 100755
--- a/acs-drv/files/MakefileBSA
+++ b/acs-drv/files/MakefileBSA
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
- # Copyright (C) 2016-2018,2021, 2024, Arm Limited
+ # Copyright (C) 2016-2018,2021, 2024-2025, Arm Limited
#
##
@@ -25,9 +25,9 @@ ACS_DIR ?= ./
obj-m += bsa_acs.o
bsa_acs-objs += bsa_acs_drv.o \
- bsa_acs_val.o \
- bsa_acs_test.o \
- bsa_acs_pal.o
+ val/bsa_acs_val.o \
+ test_pool/bsa_acs_test.o \
+ platform/pal_linux/files/bsa_acs_pal.o
ccflags-y=-I$(PWD)/$(ACS_DIR)/include -I$(PWD)/$(ACS_DIR)/ -DTARGET_LINUX -Wall -Werror
diff --git a/acs-drv/files/MakefileSBSA b/acs-drv/files/MakefileSBSA
index 730639fdd0aa543f58c021188840dc6a6ce3a881..f42cdf0188f69d508a738b8ad8ba8bda0a818968 100644
--- a/acs-drv/files/MakefileSBSA
+++ b/acs-drv/files/MakefileSBSA
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
- # Copyright (C) 2016-2018 Arm Limited
+ # Copyright (C) 2016-2018, 2025 Arm Limited
#
# Author: Prasanth Pulla
#
@@ -27,9 +27,9 @@ ACS_DIR ?= ./
obj-m += sbsa_acs.o
sbsa_acs-objs += sbsa_acs_drv.o \
- sbsa_acs_val.o \
- sbsa_acs_test.o \
- sbsa_acs_pal.o
+ val/sbsa_acs_val.o \
+ test_pool/sbsa_acs_test.o \
+ platform/pal_linux/files/sbsa_acs_pal.o
ccflags-y=-I$(PWD)/$(ACS_DIR)/include -I$(PWD)/$(ACS_DIR)/ -DTARGET_LINUX -Wall -Werror
diff --git a/acs-drv/files/build.sh b/acs-drv/files/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..03a522a8bf54af11a1488921eb44494ddf84411e
--- /dev/null
+++ b/acs-drv/files/build.sh
@@ -0,0 +1,380 @@
+#!/bin/bash
+
+WRK_DIR=$PWD
+
+export LINUX_KERNEL_VERSION=6.8
+export GCC_TOOLS_VERSION=13.2.rel1
+export GCC=tools/arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
+export BSA_PATH=$WRK_DIR/bsa-acs
+export SBSA_PATH=$WRK_DIR/sbsa-acs
+export BUILD_PATH=$WRK_DIR/build
+
+print_help() {
+
+ echo ""
+ echo "================ ACS Build Environment Info =================="
+ echo ""
+ echo "Working Directory : $WRK_DIR"
+ echo "BSA ACS Path : $BSA_PATH"
+ echo "SBSA ACS Path : $SBSA_PATH"
+ echo "Build Output Path : $BUILD_PATH"
+ echo "Linux Kernel Version : $LINUX_KERNEL_VERSION"
+ echo "GCC Tools Version : $GCC_TOOLS_VERSION"
+ echo "Cross Compiler PATH : $GCC"
+ echo ""
+ echo "=============================================================="
+ echo ""
+ echo "NOTE:"
+ echo "To change the compiler or Linux version used during the build,"
+ echo "edit the corresponding variables at the top of this script."
+ echo ""
+ echo "Example:"
+ echo " export LINUX_KERNEL_VERSION=6.8"
+ echo " export GCC_TOOLS_VERSION=12.3.rel1"
+ echo ""
+ echo "Important:"
+ echo " The Linux kernel source and toolchain will only be cloned"
+ echo " if the machine architecture is NOT 'aarch64'."
+ echo ""
+ echo "Usage:"
+ echo ""
+ echo " ./build.sh Download all needed repos based on platform and build"
+ echo " ./build.sh --help Show this help message"
+ echo " ./build.sh --clean Build folder (modules and app)"
+ echo " ./build.sh --clean_all Remove all downloaded repos along with Build folder"
+ echo " ./build.sh --version The Linux Kernel Version value (Default value : 6.8) "
+ echo " ./build.sh --GCC_TOOLS The GCC Tools Version value (Default value : 13.2.rel1) "
+ echo ""
+}
+
+check_repos_status() {
+ echo ""
+ echo "=========== ACS Repository Status ==========="
+ platform=$(uname -m)
+ echo "Platform: $platform"
+ echo "Note: On non-AArch64 platforms, Linux source and toolchain must be present."
+
+ [[ -d "$BSA_PATH" ]] && echo "BSA repo - OK" || echo "BSA repo - Not present"
+ [[ -d "$SBSA_PATH" ]] && echo "SBSA repo - OK" || echo "SBSA repo - Not present"
+ [[ -d "$WRK_DIR/linux-acs" ]] && echo "linux acs repo - OK" || echo "linux acs repo - Not present"
+ [[ -d "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}" ]] && echo "Linux source - OK" || echo "Linux source - Not present"
+ [[ -d "$WRK_DIR/tools/arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-aarch64-none-linux-gnu" ]] && echo "Cross compiler - OK" || echo "Cross compiler - Not present"
+
+ echo "============================================="
+ echo ""
+}
+
+clean_build_outputs() {
+
+ if [[ "$1" == "--clean" ]]; then
+ echo "๐งน Cleaning build path: $BUILD_PATH"
+ rm -rf "$BUILD_PATH"
+ return
+ elif [[ "$1" == "--clean_all" ]]; then
+ echo "๐งน Cleaning everything under: $WRK_DIR"
+ rm -rf "$WRK_DIR/bsa-acs"
+ rm -rf "$WRK_DIR/sbsa-acs"
+ rm -rf "$WRK_DIR/linux-acs"
+ rm -rf "$WRK_DIR/build"
+ [[ -d "$WRK_DIR/tools" ]] && rm -rf "$WRK_DIR/tools"
+ [[ -d "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}" ]] && rm -rf "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}"
+ return
+ fi
+}
+
+while [[ $# -gt 0 ]]; do
+ key="$1"
+ next="$2" # The next argument (should be a value)
+
+ case $key in
+ -v|--version)
+ if [[ -z "$next" || "$next" == -* ]]; then
+ echo "โ Error: Missing or invalid value for $key"
+ exit 1
+ fi
+ LINUX_KERNEL_VERSION="$next"
+ echo "Linux Kernel Version is set to $LINUX_KERNEL_VERSION"
+ shift 2
+ ;;
+ -GCC_TOOLS|--GCC_TOOLS)
+ if [[ -z "$next" || "$next" == -* ]]; then
+ echo "โ Error: Missing or invalid value for $key"
+ exit 1
+ fi
+ GCC_TOOLS_VERSION="$next"
+ echo "Gcc Tools Version is set to $GCC_TOOLS_VERSION"
+ shift 2
+ ;;
+ --help)
+ print_help
+ exit 0
+ ;;
+ --clean)
+ clean_build_outputs "$key"
+ exit 0
+ ;;
+ --clean_all)
+ clean_build_outputs "$key"
+ exit 0
+ ;;
+ *)
+ echo "โ Error: Unknown option $key"
+ exit 1
+ ;;
+ esac
+done
+
+get_bsa_acs()
+{
+ echo "Downloading BSA ACS"
+
+ if [[ -d "$WRK_DIR/bsa-acs" ]]; then
+ echo "Directory '$WRK_DIR/bsa-acs' already exists. Skipping clone."
+ else
+ git clone https://github.com/ajayswar-s/bsa-acs.git bsa-acs
+ if [[ $? -ne 0 ]]; then
+ echo "ERROR: Failed to download BSA ACS repository."
+ return
+ fi
+ pushd $WRK_DIR/bsa-acs
+ git checkout linux_porting
+ popd
+ fi
+}
+
+get_sbsa_acs()
+{
+ echo "Downloading SBSA ACS"
+
+ if [[ -d "$WRK_DIR/sbsa-acs" ]]; then
+ echo "Directory '$WRK_DIR/sbsa-acs' already exists. Skipping clone."
+ else
+ git clone https://github.com/ajayswar-s/sbsa-acs.git sbsa-acs
+ if [[ $? -ne 0 ]]; then
+ echo "ERROR: Failed to download SBSA ACS repository."
+ return
+ fi
+ fi
+
+}
+
+get_linux_acs()
+{
+ echo "Downloading Linux ACS"
+
+ if [[ -d "$WRK_DIR/linux-acs" ]]; then
+ echo "Directory '$WRK_DIR/linux-acs' already exists. Skipping clone."
+ else
+ git clone https://git.gitlab.arm.com/linux-arm/linux-acs.git linux-acs
+ if [[ $? -ne 0 ]]; then
+ echo "ERROR: Failed to download LINUX ACS repository."
+ return
+ fi
+ pushd $WRK_DIR/linux-acs
+ git checkout linux_porting
+ popd
+ fi
+}
+
+get_linux_source()
+{
+ echo "Downloading Linux source"
+ if [ $(uname -m) != "aarch64" ]; then
+ if [[ -d "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}" ]]; then
+ echo "Directory '$WRK_DIR/sbsa-acs' already exists. Skipping clone."
+ else
+ git clone --depth 1 --branch v$LINUX_KERNEL_VERSION https://github.com/torvalds/linux.git linux-${LINUX_KERNEL_VERSION}
+ if [[ $? -ne 0 ]]; then
+ echo "ERROR: Failed to download LINUX ${LINUX_KERNEL_VERSION} VERSION repository."
+ return
+ fi
+ fi
+ else
+ echo "=================================================================="
+ echo "INFO: AARCH64 native build, No Linux Source code needed"
+ echo "=================================================================="
+ fi
+
+}
+
+get_cross_compiler()
+{
+
+ echo "Downloading cross compiler. Version : ${GCC_TOOLS_VERSION}"
+ if [ $(uname -m) == "aarch64" ]; then
+ echo "=================================================================="
+ echo "aarch64 native build"
+ echo "WARNING: no cross compiler needed, GCC version recommended: ${GCC_TOOLS_VERSION}"
+ echo "=================================================================="
+ else
+ TAG=aarch64-none-linux-gnu
+ if [[ -d "$WRK_DIR/tools/arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-aarch64-none-linux-gnu" ]]; then
+ echo "Directory '$WRK_DIR/tools/arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-aarch64-none-linux-gnu' already exists. Skipping clone."
+ else
+ mkdir -p tools
+ pushd $WRK_DIR/tools
+ wget https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_TOOLS_VERSION}/binrel/arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-aarch64-none-linux-gnu.tar.xz --no-check-certificate
+ if [[ $? -ne 0 ]]; then
+ echo "ERROR: Failed to download CROSS COMPILER ${GCC_TOOLS_VERSION}"
+ return
+ fi
+
+ tar -xf arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-${TAG}.tar.xz
+ mv arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-linux-gnu arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu
+ rm arm-gnu-toolchain-${GCC_TOOLS_VERSION}-x86_64-${TAG}.tar.xz
+ popd
+ fi
+ fi
+}
+
+do_linux_build ()
+{
+ export ARCH=arm64
+ export LINUX_OUT_DIR=out
+
+ if [[ -d "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}/$LINUX_OUT_DIR" ]]; then
+ echo "Output directory '$WRK_DIR/linux-${LINUX_KERNEL_VERSION}/$LINUX_OUT_DIR' already exists."
+ read -p "Do you want to remove it and rebuild? [y/N]: " confirm
+ if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
+ echo "Removing $LINUX_OUT_DIR..."
+ rm -rf "$WRK_DIR/linux-${LINUX_KERNEL_VERSION}/$LINUX_OUT_DIR"
+ else
+ echo "Skipping Linux build."
+ return
+ fi
+ fi
+
+ pushd $WRK_DIR/linux-${LINUX_KERNEL_VERSION}
+ mkdir -p $LINUX_OUT_DIR
+ echo "Building using defconfig..."
+ cp arch/arm64/configs/defconfig $LINUX_OUT_DIR/.config
+
+ make ARCH=arm64 CROSS_COMPILE=$WRK_DIR/$GCC O=$LINUX_OUT_DIR olddefconfig
+ make ARCH=arm64 CROSS_COMPILE=$WRK_DIR/$GCC O=$LINUX_OUT_DIR -j$(nproc)
+
+ popd
+}
+
+check_and_install_kernel_headers() {
+ export KERNEL_SRC="/lib/modules/$(uname -r)/build"
+
+ if [[ -d "$KERNEL_SRC" ]]; then
+ echo "Kernel headers are present at $KERNEL_SRC"
+ else
+ echo "Kernel headers not found for kernel version $(uname -r)"
+ echo "Attempting to install kernel headers..."
+ if ! sudo apt-get install -y linux-headers-$(uname -r); then
+ echo "ERROR: Failed to install Linux kernel headers."
+ return
+ else
+ echo "Successfully installed Linux kernel headers for $(uname -r)."
+ fi
+ fi
+}
+
+
+do_build_bsa_module()
+{
+ echo "Building BSA Module....."
+ mkdir -p $BUILD_PATH
+
+ pushd $WRK_DIR/linux-acs/acs-drv/files
+
+ if [ $(uname -m) != "aarch64" ]; then
+ export KERNEL_SRC=$WRK_DIR/linux-${LINUX_KERNEL_VERSION}/out
+ export CROSS_COMPILE=$WRK_DIR/$GCC
+
+ else
+ check_and_install_kernel_headers
+ export KERNEL_SRC="/lib/modules/$(uname -r)/build"
+ fi
+
+ ./bsa_setup.sh $BSA_PATH
+ ./linux_bsa_acs.sh
+ cp bsa_acs.ko $BUILD_PATH/
+ popd
+}
+
+do_build_sbsa_module()
+{
+ echo "Building SBSA Module....."
+ mkdir -p $BUILD_PATH
+
+ pushd $WRK_DIR/linux-acs/acs-drv/files
+
+ if [ $(uname -m) != "aarch64" ]; then
+ export KERNEL_SRC=$WRK_DIR/linux-${LINUX_KERNEL_VERSION}/out
+ export CROSS_COMPILE=$WRK_DIR/$GCC
+ else
+ check_and_install_kernel_headers
+ export KERNEL_SRC="/lib/modules/$(uname -r)/build"
+ fi
+
+ ./sbsa_setup.sh $BSA_PATH $SBSA_PATH
+ ./linux_sbsa_acs.sh
+ cp sbsa_acs.ko $BUILD_PATH
+
+ popd
+}
+
+do_build_sbsa_app()
+{
+ pushd $SBSA_PATH/linux_app/sbsa-acs-app
+ make
+ cp sbsa $BUILD_PATH/sbsa_app
+ popd
+}
+
+do_build_bsa_app()
+{
+ pushd $BSA_PATH/linux_app/bsa-acs-app
+ make
+ cp bsa $BUILD_PATH/bsa_app
+ popd
+}
+
+check_build_outputs() {
+ # Check for output files in $BUILD_PATH/build/
+ check_file() {
+ local file="$1"
+ if [[ -f "$BUILD_PATH/$file" ]]; then
+ echo "ok"
+ else
+ echo "fail"
+ fi
+ }
+
+ # Run checks
+ local bsa_module=$(check_file "bsa_acs.ko")
+ local bsa_app=$(check_file "bsa_app")
+ local sbsa_module=$(check_file "sbsa_acs.ko")
+ local sbsa_app=$(check_file "sbsa_app")
+
+ # Print status table
+ echo "----------------------------------------"
+ printf "%-6s %-10s %-10s\n" "Repo" "Module " "App"
+ echo "----------------------------------------"
+ printf "%-6s %-10s %-10s\n" "BSA" "$bsa_module" "$bsa_app"
+ printf "%-6s %-10s %-10s\n" "SBSA" "$sbsa_module" "$sbsa_app"
+ echo "----------------------------------------"
+}
+
+get_bsa_acs
+get_sbsa_acs
+get_linux_acs
+get_linux_source
+get_cross_compiler
+
+check_repos_status
+
+
+if [ $(uname -m) != "aarch64" ]; then
+ do_linux_build
+fi
+
+do_build_bsa_module
+do_build_sbsa_module
+do_build_bsa_app
+do_build_sbsa_app
+
+check_build_outputs
diff --git a/acs-drv/files/platform/pal_linux/files/MakefileBSA b/acs-drv/files/platform/pal_linux/files/MakefileBSA
index 59fc068bebae55563ef474a4208bba5277f8c028..9b7115b430f7453c3a07d92d7986531423463279 100644
--- a/acs-drv/files/platform/pal_linux/files/MakefileBSA
+++ b/acs-drv/files/platform/pal_linux/files/MakefileBSA
@@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
- # Copyright (C) 2016-2018, 2021 Arm Limited
+ # Copyright (C) 2016-2018, 2021, 2025, Arm Limited
#
##
@@ -30,7 +30,7 @@ bsa_acs_pal-objs += $(COMMON_PAL_SRC)/pal_misc.o \
$(COMMON_PAL_SRC)/pal_pe.o $(COMMON_PAL_SRC)/pal_pcie.o $(COMMON_PAL_SRC)/pal_pcie_enumeration.o \
$(COMMON_PAL_SRC)/pal_smmu.o $(COMMON_PAL_SRC)/pal_iovirt.o $(COMMON_PAL_SRC)/pal_peripherals.o \
$(COMMON_PAL_SRC)/pal_dma.o $(COMMON_PAL_SRC)/pal_acpi.o $(COMMON_PAL_SRC)/pal_gic.o \
- $(BSA_PAL_SRC)/bsa_pal_dt.o $(BSA_PAL_SRC)/bsa_pal_acpi.o $(BSA_PAL_SRC)/bsa_pal_exerciser.o \
+ $(BSA_PAL_SRC)/bsa_pal_dt.o $(BSA_PAL_SRC)/bsa_pal_acpi.o $(BSA_PAL_SRC)/bsa_pal_exerciser.o $(COMMON_PAL_SRC)/bsa-dma-iommu.o \
$(COMMON_PAL_SRC)/pal_exerciser.o
ccflags-y=-I$(PWD)/$(ACS_DIR)/val/common/include -I$(PWD)/$(ACS_DIR)/val/bsa/include -I$(PWD)/$(ACS_DIR)/common/include -I$(PWD)/$(ACS_DIR)/bsa/include -I$(PWD) -I$(PWD)/../../ -I$(PWD)/../../../ -DTARGET_LINUX -Wall -Werror
diff --git a/acs-drv/files/platform/pal_linux/files/MakefileSBSA b/acs-drv/files/platform/pal_linux/files/MakefileSBSA
index 95500ba79f86c39496b69a6d57afa7cde742b65a..6f1a6bce621153b939af3e824b45bd2f6d5214f4 100644
--- a/acs-drv/files/platform/pal_linux/files/MakefileSBSA
+++ b/acs-drv/files/platform/pal_linux/files/MakefileSBSA
@@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
- # Copyright (C) 2016-2018 Arm Limited
+ # Copyright (C) 2016-2018, 2025, Arm Limited
#
##
@@ -29,7 +29,7 @@ obj-m += sbsa_acs_pal.o
sbsa_acs_pal-objs += $(COMMON_PAL_SRC)/pal_misc.o \
$(COMMON_PAL_SRC)/pal_pe.o $(COMMON_PAL_SRC)/pal_pcie.o $(COMMON_PAL_SRC)/pal_pcie_enumeration.o \
$(COMMON_PAL_SRC)/pal_smmu.o $(COMMON_PAL_SRC)/pal_iovirt.o $(COMMON_PAL_SRC)/pal_peripherals.o \
- $(COMMON_PAL_SRC)/pal_dma.o $(COMMON_PAL_SRC)/pal_acpi.o $(COMMON_PAL_SRC)/pal_gic.o \
+ $(COMMON_PAL_SRC)/pal_dma.o $(COMMON_PAL_SRC)/pal_acpi.o $(COMMON_PAL_SRC)/pal_gic.o $(COMMON_PAL_SRC)/bsa-dma-iommu.o \
$(SBSA_PAL_SRC)/sbsa_pal_iovirt.o $(COMMON_PAL_SRC)/pal_exerciser.o $(SBSA_PAL_SRC)/sbsa_pal_pcie.o
ccflags-y=-I$(PWD)/$(ACS_DIR)/val/include -I$(PWD)/$(ACS_DIR)/include -I$(PWD) -I$(PWD)/../../ -I$(PWD)/../../../ -DTARGET_LINUX -DBUILD_SBSA -Wall -Werror
diff --git a/acs-drv/files/platform/pal_linux/files/common/include/bsa-iommu.h b/acs-drv/files/platform/pal_linux/files/common/include/bsa-iommu.h
new file mode 100644
index 0000000000000000000000000000000000000000..964cea92c97a4abcb686ef80804dc0f63abeb8bd
--- /dev/null
+++ b/acs-drv/files/platform/pal_linux/files/common/include/bsa-iommu.h
@@ -0,0 +1,114 @@
+/*
+ * The IOMMU-API to BSA Architecture Compliance Suite glue layer.
+ *
+ * Copyright (C) 2021, 2025, ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __BSA_IOMMU_H
+#define __BSA_IOMMU_H
+
+#ifdef CONFIG_IOMMU_DMA
+#include
+
+#include
+#include
+#include
+
+#define BSA_IOVA_DMA_ARRAY_LEN 4
+
+typedef struct _bsa_iova_array_ {
+ dma_addr_t dma_addr;
+ unsigned int dma_len;
+}bsa_iova_array;
+
+void *bsa_iommu_dma_get_iova(struct device *dev, unsigned long long *base, unsigned long int *size,
+ phys_addr_t *phy_addr, void *in_node);
+
+void bsa_iommu_dev_start_monitor(struct device *dev);
+struct irq_domain* acs_get_irq_domain(void);
+void bsa_iommu_dev_stop_monitor(struct device *dev);
+int bsa_is_domain_monitored(struct iommu_domain *dom);
+
+void bsa_iommu_iova_save_addr(dma_addr_t addr, unsigned int length);
+
+unsigned int bsa_iommu_iova_get_addr(unsigned int index, dma_addr_t *addr);
+
+enum dev_dma_attr bsa_dev_get_dma_attr(struct device *dev);
+
+
+
+struct iova_domain *cookie_iovad_bsa(struct iommu_domain *domain);
+//dma_addr_t bsa_dma_addr;
+int bsa_scsi_sata_get_dma_addr(struct ata_port *ap, dma_addr_t *dma_addr, unsigned int *dma_len);
+
+void bsa_scsi_sata_fill_dma_addr(struct scatterlist *sg);
+
+struct scatterlist *dma_address_store_and_print(uint64_t j, struct ata_port *q);
+
+pgd_t *read_pgd(uint64_t addr);
+
+enum iommu_dma_cookie_type {
+ IOMMU_DMA_IOVA_COOKIE,
+ IOMMU_DMA_MSI_COOKIE,
+};
+
+
+enum iommu_dma_queue_type {
+ IOMMU_DMA_OPTS_PER_CPU_QUEUE,
+ IOMMU_DMA_OPTS_SINGLE_QUEUE,
+};
+
+struct iommu_dma_options {
+ enum iommu_dma_queue_type qt;
+ size_t fq_size;
+ unsigned int fq_timeout;
+};
+
+
+struct iommu_dma_cookie_copy {
+ enum iommu_dma_cookie_type type;
+ union {
+ /* Full allocator for IOMMU_DMA_IOVA_COOKIE */
+ struct {
+ struct iova_domain iovad;
+ /* Flush queue */
+ union {
+ struct iova_fq *single_fq;
+ struct iova_fq __percpu *percpu_fq;
+ };
+ /* Number of TLB flushes that have been started */
+ atomic64_t fq_flush_start_cnt;
+ /* Number of TLB flushes that have been finished */
+ atomic64_t fq_flush_finish_cnt;
+ /* Timer to regularily empty the flush queues */
+ struct timer_list fq_timer;
+ /* 1 when timer is active, 0 when not */
+ atomic_t fq_timer_on;
+ };
+ /* Trivial linear page allocator for IOMMU_DMA_MSI_COOKIE */
+ dma_addr_t msi_iova;
+ };
+ struct list_head msi_page_list;
+
+ /* Domain for flush queue callback; NULL if flush queue not in use */
+ struct iommu_domain *fq_domain;
+ /* Options for dma-iommu use */
+ struct iommu_dma_options options;
+ struct mutex mutex;
+};
+
+#endif
+#endif
+
diff --git a/acs-drv/files/platform/pal_linux/files/common/src/bsa-dma-iommu.c b/acs-drv/files/platform/pal_linux/files/common/src/bsa-dma-iommu.c
new file mode 100644
index 0000000000000000000000000000000000000000..62ad9e92d71869566e9cf7fb8314501755203fc5
--- /dev/null
+++ b/acs-drv/files/platform/pal_linux/files/common/src/bsa-dma-iommu.c
@@ -0,0 +1,248 @@
+/*
+ * The IOMMU-API to BSA Architecture Compliance Suite glue layer.
+ *
+ * Copyright (C) 2021, 2025, ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+#include
+#include "common/include/bsa-iommu.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/*
+struct irq_domain *acs_irq_domain = NULL;
+
+struct irq_domain* acs_get_irq_domain(void)
+{
+ if (acs_irq_domain)
+ return acs_irq_domain;
+ return 0;
+}
+EXPORT_SYMBOL(acs_get_irq_domain);
+*/
+
+struct iova_domain *cookie_iovad_bsa(struct iommu_domain *domain)
+{
+ if (domain)
+ return &((struct iommu_dma_cookie_copy *)domain->iova_cookie)->iovad;
+ return NULL;
+}
+
+bsa_iova_array g_bsa_iova_array[BSA_IOVA_DMA_ARRAY_LEN];
+
+struct iommu_domain *g_bsa_iommu_domain = NULL;
+
+
+/**
+ @brief This API returns the DMA address for a given index from the active IOVA table.
+ 1. Caller - Platform Abstraction Layer.
+ 2. Prerequisite - None
+ @param dev - device whose domain IOVA table is checked
+ @param base - return DMA address base
+ @param in_node - return first entry if NULL, else continue from in_node
+ @return length of the DMA range
+**/
+void *
+bsa_iommu_dma_get_iova(struct device *dev, unsigned long long *base, unsigned long int *size,
+ phys_addr_t *phy_addr, void *in_node)
+{
+ struct iova_domain *iovad = cookie_iovad_bsa(iommu_get_domain_for_dev(dev));
+ unsigned long shift;
+ struct rb_node *node;
+
+ if(!iovad)
+ return NULL;
+
+ shift = iova_shift(iovad);
+
+ if (in_node == NULL)
+ node = rb_last(&iovad->rbroot);
+ else
+ node = rb_prev((struct rb_node *)in_node);
+
+ while (node)
+ {
+ struct iova *iova = container_of(node, struct iova, node);
+ unsigned long pfn_lo = iova->pfn_lo;
+ unsigned long pfn_hi = iova->pfn_hi + 1;
+ phys_addr_t phys = iommu_iova_to_phys(iommu_get_domain_for_dev(dev),
+ pfn_lo << shift);
+
+ if (phys) {
+ *base = pfn_lo << shift;
+ *size = (pfn_hi - pfn_lo) << shift;
+ *phy_addr = phys;
+ break;
+ }
+ node = rb_prev(node);
+ }
+ return (void *)node;
+}
+
+static int bsa_get_sata_dev(void)
+{
+ int ret = -1;
+ struct Scsi_Host *shost;
+ struct ata_port *ap;
+ struct scsi_device *sdev = NULL;
+ unsigned int i = 0;
+
+ do {
+ shost = scsi_host_lookup(i++);
+ if (shost) {
+ sdev = NULL;
+ ap = ata_shost_to_port(shost);
+ if ((ap == NULL) || (ap->dev == NULL))
+ continue; //Not a ATA port
+ if ((ap->scsi_host == NULL) || (ap->scsi_host != shost))
+ continue; //Not a valid ATA Port
+ do {
+ /* get the device connected to this host */
+ sdev = __scsi_iterate_devices(shost, sdev);
+ if (sdev) {
+ g_bsa_iommu_domain = iommu_get_domain_for_dev(ap->dev);
+ ret = 0;
+ }
+ } while(sdev);
+ scsi_host_put(shost);
+ }
+ } while(shost);
+
+ return ret;
+}
+
+/**
+ @brief This API is used to indicate which device IOMMU transactions are to be monitored.
+ 1. Caller - Platform Abstraction Layer.
+ 2. Prerequisite - None
+ @param dev - device whose domain IOVA table is checked
+ @return None
+**/
+void
+bsa_iommu_dev_start_monitor(struct device *dev)
+{
+ /* We only monitor 1 domain for now */
+
+ g_bsa_iommu_domain = iommu_get_domain_for_dev(dev);
+}
+
+void
+bsa_iommu_dev_stop_monitor(struct device *dev)
+{
+ g_bsa_iommu_domain = NULL;
+}
+
+int
+bsa_is_domain_monitored(struct iommu_domain *dom)
+{
+ int ret = 0;
+
+ if (g_bsa_iommu_domain == NULL )
+ ret = bsa_get_sata_dev();
+
+ if (g_bsa_iommu_domain == dom)
+ return 1;
+
+ return 0;
+}
+
+void
+bsa_iommu_iova_save_addr(dma_addr_t addr, unsigned int length)
+{
+
+ static unsigned int index = 0;
+
+ g_bsa_iova_array[index].dma_addr = addr;
+ g_bsa_iova_array[index].dma_len = length;
+
+ index++;
+
+ if (index >= BSA_IOVA_DMA_ARRAY_LEN)
+ index = 0;
+}
+
+/**
+ @brief This API returns the DMA address for a given index from the saved IOVA addresses.
+ 1. Caller - Platform Abstraction Layer.
+ 2. Prerequisite - bsa_iommu_iova_save_addr.
+ @param index - index of the entry
+ @param addr - dma address returned
+ @return length of the DMA range
+**/
+unsigned int
+bsa_iommu_iova_get_addr(unsigned int index, dma_addr_t *addr)
+{
+
+ if (index >= BSA_IOVA_DMA_ARRAY_LEN)
+ return 0;
+
+ *addr = g_bsa_iova_array[index].dma_addr;
+
+ return g_bsa_iova_array[index].dma_len;
+
+}
+
+/**
+ @brief This API gets the DMA attributes of a device.
+ 1. Caller - Platform Abstraction Layer.
+ 2. Prerequisite - None.
+ @param dev - device structure.
+ @return Coherent or Not.
+**/
+enum
+dev_dma_attr bsa_dev_get_dma_attr(struct device *dev)
+{
+
+ return device_get_dma_attr(dev);
+}
+
+/* BSA ACS Hook functions to export the DMA address used by the controller */
+dma_addr_t bsa_dma_addr;
+unsigned int bsa_dma_len;
+
+int
+bsa_scsi_sata_get_dma_addr(struct ata_port *ap, dma_addr_t *dma_addr, unsigned int *dma_len)
+{
+ //Not used struct sil24_port_priv *pp = ap->private_data;
+
+ *dma_addr = bsa_dma_addr;
+ *dma_len = bsa_dma_len;
+
+ return 0;
+}
+
+void
+bsa_scsi_sata_fill_dma_addr(struct scatterlist *sg)
+{
+
+ bsa_dma_addr = cpu_to_le64(sg_dma_address(sg));
+ bsa_dma_len = cpu_to_le32(sg_dma_len(sg));
+}
+
diff --git a/acs-drv/files/platform/pal_linux/files/common/src/pal_dma.c b/acs-drv/files/platform/pal_linux/files/common/src/pal_dma.c
index 737cdbfd7bc8178bede1cff18d6d32de64774328..c37c78e4d8f9064d70b3e8f245765dd071a8eeb9 100644
--- a/acs-drv/files/platform/pal_linux/files/common/src/pal_dma.c
+++ b/acs-drv/files/platform/pal_linux/files/common/src/pal_dma.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
- * Copyright (C) 2016-2018,2021,2023-2024, Arm Limited
+ * Copyright (C) 2016-2018,2021,2023-2025, Arm Limited
*
* Author: Prasanth Pulla
*
@@ -48,7 +48,7 @@
#include "common/include/pal_linux.h"
#include "common/include/pal_pcie_enum.h"
#include
-#include
+#include "common/include/bsa-iommu.h"
int
bsa_scsi_sata_get_dma_addr(struct ata_port *ap, dma_addr_t *dma_addr, unsigned int *dma_len);
@@ -57,7 +57,7 @@ bsa_scsi_sata_get_dma_addr(struct ata_port *ap, dma_addr_t *dma_addr, unsigned i
unsigned long long int
pal_dma_mem_alloc(void **buffer, unsigned int length, void *port, unsigned int flags)
{
- dma_addr_t mem_dma;
+ dma_addr_t mem_dma = 0;
if (flags == DMA_COHERENT) {
*buffer = dmam_alloc_coherent(((struct ata_port *)port)->dev, length, &mem_dma, GFP_KERNEL);
@@ -74,6 +74,7 @@ pal_dma_mem_alloc(void **buffer, unsigned int length, void *port, unsigned int f
return -1;
}
}
+
memset(*buffer, 0, length);
return mem_dma;
@@ -99,54 +100,139 @@ pal_dma_mem_free(void *buffer, addr_t mem_dma, unsigned int length, void *port,
}
+struct scatterlist *dma_address_store_and_print(uint64_t j, struct ata_port *q)
+{
+ struct ata_queued_cmd *cmd;
+ struct scatterlist *sg = NULL;
+ int i;
+
+ if (q == NULL) {
+ printk(KERN_INFO "\n Ata Port address Invalid : %d", (int) j);
+ return sg;
+ }
+
+ printk(KERN_INFO "\n DMA index: %d ", (int) j);
+ printk(KERN_INFO "\n ATA_MAX_QUEUE : %d ", ATA_MAX_QUEUE);
+
+ for (i = 0; i <= ATA_MAX_QUEUE; i++) {
+
+ printk(KERN_INFO "\n Ata command queue index: %d ", i);
+ cmd = &q->qcmd[i];
+
+ if (cmd == NULL) {
+ printk(KERN_INFO "\n Ata command address Invalid ");
+ continue;
+ }
+
+ if (cmd->ap != q) {
+ printk(KERN_INFO "\n Ata_port in command is not as same as the given ata port ");
+ continue;
+ }
+
+ // Check if the command is active or in a valid state
+ if (cmd->flags & ATA_QCFLAG_ACTIVE)
+ printk(KERN_INFO "\n Command %d is active", i);
+
+ // Optionally, check additional flags here
+ if (cmd->flags & ATA_QCFLAG_DMAMAP)
+ printk(KERN_INFO "\n Command %d is DMA mapped", i);
+
+ if (cmd->flags & ATA_QCFLAG_IO)
+ printk(KERN_INFO "\n Command %d is an I/O command", i);
+
+ sg = cmd->sg;
+
+ if (sg == NULL) {
+ printk(KERN_INFO "\n Ata command scatterlist address NULL");
+ continue;
+ }
+
+ // Validate each entry
+ if (sg->length == 0 || sg_page(sg) == NULL || sg_dma_address(sg) == 0) {
+ printk(KERN_INFO "\n Invalid scatterlist entry at index %d", i);
+ continue; // Skip invalid entry
+ }
+ else {
+ // If valid, print the DMA address
+ pr_info("\n Valid scatterlist entry at index %d: DMA address = %llx, ",
+ i, (unsigned long long)cpu_to_le64(sg_dma_address(sg)));
+ pr_info("\n DMA size = %llx",(unsigned long long)cpu_to_le32(sg_dma_len(sg)));
+ return sg;
+ }
+ }
+ return NULL;
+}
void
pal_dma_create_info_table(DMA_INFO_TABLE *dma_info_table)
{
- struct Scsi_Host *shost;
- struct ata_port *ap;
- struct scsi_device *sdev = NULL;
- unsigned int i = 0, j = 0;
-
- dma_info_table->num_dma_ctrls = 0;
-
- do {
- shost = scsi_host_lookup(i++);
- if (shost) {
- sdev = NULL;
- ap = ata_shost_to_port(shost);
- if ((ap == NULL) || (ap->dev == NULL))
- continue; //Not a ATA port
- if ((ap->scsi_host == NULL) || (ap->scsi_host != shost))
- continue; //Not a valid ATA Port
- do {
- /* get the device connected to this host */
- sdev = __scsi_iterate_devices(shost, sdev);
- if (sdev) {
- dma_info_table->info[j].host = shost;
- dma_info_table->info[j].port = ap;
- dma_info_table->info[j].target = sdev;
- dma_info_table->info[j].flags = bsa_dev_get_dma_attr(shost->dma_dev);
-
- /* if we did not get coherence attribute from ACPI/PCI, get it from FDT */
- if (dma_info_table->info[j].flags == 0) {
+ struct Scsi_Host *shost;
+ struct ata_port *ap;
+ struct scsi_device *sdev = NULL;
+ struct scatterlist *sg;
+ unsigned int i = 0, j = 0;
+
+ dma_info_table->num_dma_ctrls = 0;
+
+ do {
+ printk(KERN_INFO "\n SCSI host lookup index: %d ",(int) i);
+ shost = scsi_host_lookup(i++);
+ if (shost) {
+ sdev = NULL;
+ ap = ata_shost_to_port(shost);
+ if ((ap == NULL) || (ap->dev == NULL)) {
+ printk(KERN_INFO "\n Invalid Ataport for scsi index: %d ",(int) i);
+ continue; //Not a ATA port
+ }
+
+ if ((ap->scsi_host == NULL) || (ap->scsi_host != shost)) {
+ printk(KERN_INFO "\n Invalid Ataport for scsi index: %d ",(int) i);
+ continue; //Not a valid ATA Port
+ }
+
+ do {
+ /* get the device connected to this host */
+ sdev = __scsi_iterate_devices(shost, sdev);
+ if (sdev) {
+ dma_info_table->info[j].host = shost;
+ dma_info_table->info[j].port = ap;
+ dma_info_table->info[j].target = sdev;
+ dma_info_table->info[j].flags = bsa_dev_get_dma_attr(shost->dma_dev);
+
+ /* if we did not get coherence attribute from ACPI/PCI, get it from FDT */
+ if (dma_info_table->info[j].flags == 0) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(4,19,0)
- dma_info_table->info[j].flags = shost->dma_dev->dma_coherent;
+ dma_info_table->info[j].flags = shost->dma_dev->dma_coherent;
#else
- dma_info_table->info[j].flags = shost->dma_dev->archdata.dma_coherent;
+ dma_info_table->info[j].flags = shost->dma_dev->archdata.dma_coherent;
#endif
- }
- if (pal_smmu_check_dev_attach(ap->dev))
- dma_info_table->info[j].flags |= IOMMU_ATTACHED;
- dma_info_table->info[j++].type = sdev->type;
- dma_info_table->num_dma_ctrls++;
- }
- } while(sdev);
- scsi_host_put(shost);
- }
- } while(shost);
-
+ }
+ if (pal_smmu_check_dev_attach(ap->dev)) {
+ printk(KERN_INFO "\n Iommu Attached for dma index %d ", (int) j);
+ dma_info_table->info[j].flags |= IOMMU_ATTACHED;
+ }
+ else
+ printk(KERN_INFO "\n Iommu Not Attached for dma index %d \n", (int) j);
+
+ sg = dma_address_store_and_print(j, ap);
+ if (sg != NULL) {
+ dma_info_table->info[j].dma_sg_address = cpu_to_le64(sg_dma_address(sg));
+ dma_info_table->info[j].dma_sg_length = cpu_to_le32(sg_dma_len(sg));
+ }
+ else {
+ dma_info_table->info[j].dma_sg_address = 0;
+ dma_info_table->info[j].dma_sg_length = 0;
+ }
+ printk(KERN_INFO "\n Saved DMA sg address %llx ", (uint64_t) dma_info_table->info[j].dma_sg_address);
+ printk(KERN_INFO "\n Saved DMA sg length %llx ", (uint64_t) dma_info_table->info[j].dma_sg_length);
+ dma_info_table->info[j++].type = sdev->type;
+ dma_info_table->num_dma_ctrls++;
+ }
+ } while(sdev);
+ scsi_host_put(shost);
+ }
+ } while(shost);
}
unsigned int
@@ -204,6 +290,28 @@ decode_mem_attr_sh(uint64_t val, uint32_t *attr, uint32_t *sh)
pr_info("In decode_mem_attr_sh with attr=%x, sh=%x\n", *attr, *sh);
}
+
+pgd_t *read_pgd(uint64_t addr)
+{
+ uint64_t ttbr1_value = read_sysreg(ttbr1_el1); //Arm Register TTBR1_EL1
+ uint64_t baddr = (uint64_t) (ttbr1_value & ~0xFFFF000000000001);
+ uint64_t virt_addr = addr;
+
+ pgd_t *pgd_entry = (pgd_t *)phys_to_virt(baddr) + pgd_index(addr);
+
+
+ printk(KERN_INFO " virt_addr : %016llx \n", virt_addr);
+ printk(KERN_INFO " BADDR : %016llx \n", baddr);
+ printk(KERN_INFO " Align_baddr phys_to_virt : %016llx \n", (uint64_t)phys_to_virt(baddr));
+ printk(KERN_INFO " pgd_entry : %016llx \n", (uint64_t)pgd_entry);
+ printk(KERN_INFO " pgd_entry->pgd : %016llx \n", (uint64_t)pgd_entry->pgd);
+ printk(KERN_INFO " pgd_index : %016llx\n", (uint64_t)pgd_index(addr));
+
+ return pgd_entry;
+}
+
+
+
int
pal_dma_mem_get_attrs(void *buf, uint32_t *attr, uint32_t *sh)
{
@@ -212,8 +320,11 @@ pal_dma_mem_get_attrs(void *buf, uint32_t *attr, uint32_t *sh)
pte_t *pte;
pgd_t *pgd;
- pgd = pgd_offset_k((uint64_t)buf);
- if(!pgd)
+ acs_print(ACS_PRINT_DEBUG, "DEBUG : Adddress of the DMA attribute sent : 0x%llx\n", (uint64_t)buf);
+
+ pgd = read_pgd((uint64_t)buf);
+
+ if(!pgd || pgd->pgd == 0) //Found this issue in some platforms
return -1;
acs_print(ACS_PRINT_DEBUG, "DEBUG : pgd from pgd_offset_k: 0x%llx\n", (uint64_t)(pgd->pgd));
diff --git a/acs-drv/files/platform/pal_linux/files/common/src/pal_gic.c b/acs-drv/files/platform/pal_linux/files/common/src/pal_gic.c
index 1a02d4d3a2a277cc5d380e9b17d2dc1100ad8515..25ad719e351ab194866720113e78e3fbb81497d2 100644
--- a/acs-drv/files/platform/pal_linux/files/common/src/pal_gic.c
+++ b/acs-drv/files/platform/pal_linux/files/common/src/pal_gic.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
- * Copyright (C) 2016-2021 Arm Limited
+ * Copyright (C) 2016-2021, 2025, Arm Limited
*
*/
@@ -22,63 +22,11 @@
#include
#include
#include
+#include "common/include/bsa-iommu.h"
unsigned int pal_gic_install_isr(unsigned int int_id, void (*isr)(void))
{
- unsigned long long flags = 0;
- unsigned int ret = 0;
- unsigned int virq;
- struct irq_domain *domain = NULL;
- struct irq_fwspec *fwspec;
-
- domain = acs_get_irq_domain();
- if (!domain) {
- acs_print(ACS_PRINT_ERR, "\n Domain is null", 0);
- return 1;
- }
-
- fwspec = kmalloc(sizeof(struct irq_fwspec), GFP_KERNEL);
- if (!fwspec) {
- acs_print(ACS_PRINT_ERR, "\n Kmalloc failed", 0);
- return 1;
- }
-
- fwspec->param_count = 2;
- fwspec->param[0] = int_id;
- /* Interrupt type LEVEL 0 EDGE RISING 1 */
- fwspec->param[1] = 0;
- fwspec->param[2] = 0;
- fwspec->fwnode = domain->fwnode;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
- fwspec->fwnode->type = FWNODE_IRQCHIP;
-#endif
-
- if (irq_domain_is_hierarchy(domain)) {
- virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
- if (virq <= 0) {
- ret = 1;
- goto error;
- }
- } else {
- /* Create mapping */
- virq = irq_create_mapping(domain, int_id);
- if (!virq) {
- ret = 1;
- goto error;
- }
- }
-
- ret = request_irq(virq, (irq_handler_t)isr, flags, "ACS", NULL);
- if (ret != 0) {
- acs_print(ACS_PRINT_ERR, "\n IRQ registration failure %x", int_id);
- acs_print(ACS_PRINT_ERR, " \n err %d", ret);
- ret = 1;
- goto error;
- }
-
-error:
- kfree(fwspec);
- return ret;
+ return 0;
}
void pal_gic_end_of_interrupt(unsigned int int_id)
diff --git a/acs-drv/files/platform/pal_linux/files/common/src/pal_pcie.c b/acs-drv/files/platform/pal_linux/files/common/src/pal_pcie.c
index 6dfa174ecf3cfa388d7ed5f092fc9859e4343a44..cc74bdc9b1e4b25f506c0d16241a39f918edfa61 100644
--- a/acs-drv/files/platform/pal_linux/files/common/src/pal_pcie.c
+++ b/acs-drv/files/platform/pal_linux/files/common/src/pal_pcie.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
- * Copyright (C) 2016-2024, Arm Limited
+ * Copyright (C) 2016-2025, Arm Limited
*
* Author: Prasanth Pulla
* Daniil Egranov
diff --git a/acs-drv/files/platform/pal_linux/files/common/src/pal_smmu.c b/acs-drv/files/platform/pal_linux/files/common/src/pal_smmu.c
index ec441944f2f3d22869f98a0437c8751922f5376f..09776ed0311de2ae4762d682a8a06d5ce8489229 100644
--- a/acs-drv/files/platform/pal_linux/files/common/src/pal_smmu.c
+++ b/acs-drv/files/platform/pal_linux/files/common/src/pal_smmu.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
- * Copyright (C) 2016-2019, 2021, 2023-2024, Arm Limited
+ * Copyright (C) 2016-2019, 2021, 2023-2025, Arm Limited
*
* Author: Prasanth Pulla
*
@@ -22,10 +22,10 @@
#include
#include
#include
-#include
#include
#include "common/include/pal_linux.h"
+#include "common/include/bsa-iommu.h"
#define SMMU_V3_IDR1 0x4
#define SMMU_V3_IDR1_PASID_SHIFT 6
@@ -72,41 +72,32 @@ pal_smmu_device_stop_monitor_iova(void *port)
unsigned int
pal_smmu_check_device_iova(void *port, unsigned long long dma_addr)
{
- void *curr_node = NULL;
- unsigned int index = 0;
- unsigned long long base;
- unsigned long int size;
- phys_addr_t phys;
+ struct device *device = ((struct ata_port *)port)->dev;
+ struct iommu_domain *domain;
+ phys_addr_t phy_addr;
if (!pal_smmu_check_dev_attach(((struct ata_port *)port)->dev)) {
acs_print(ACS_PRINT_WARN, "\n This device is not behind an SMMU ", 0);
return PAL_LINUX_SKIP;
}
- /* Check if this address was used in the last few transactions of the IOMMU layer */
-
- do {
- size = bsa_iommu_iova_get_addr(index, &base);
- if (size) {
- if ((dma_addr >= base) && (dma_addr < (base + size))) {
- return PAL_LINUX_SUCCESS;
- }
-
- index++;
- }
-
- } while(size);
-
- /* Did not find it above - Check the active IOVA table entries now */
- do {
- curr_node = bsa_iommu_dma_get_iova(((struct ata_port *)port)->dev, &base, &size, &phys, curr_node);
- if (curr_node) {
- pr_info("Device IOVA entry is %llx size = %lx phys = %llx \n", base, size, phys);
- if ((dma_addr >= base) && (dma_addr < (base + size))) {
- return PAL_LINUX_SUCCESS;
- }
- }
- } while(curr_node);
+ /* Get the IOMMU domain for the device */
+ domain = iommu_get_domain_for_dev(device);
+ if (!domain) {
+ pr_err("Failed to get IOMMU domain for device\n");
+ return PAL_LINUX_SKIP;
+ }
+
+ /* Use iommu_iova_to_phys to map IOMMU address to physical address */
+ phy_addr = iommu_iova_to_phys(domain, dma_addr);
+ if (!phy_addr) {
+ pr_err("Failed to translate IOMMU address to physical address\n");
+ return PAL_LINUX_ERR;
+ }
+ else {
+ pr_info("DMA Address: %llx converted to phy addess: %llx", dma_addr, phy_addr);
+ return PAL_LINUX_SUCCESS;
+ }
return PAL_LINUX_ERR;
}