From f9d09670c9efb288f7feb8a0a7389d99a2439680 Mon Sep 17 00:00:00 2001 From: Rajat Goyal Date: Tue, 8 Apr 2025 09:08:21 +0000 Subject: [PATCH] BSA ACS Linux 6.13 Signed-off-by: Rajat Goyal Change-Id: Ibf1949058b3cfeab5edb19b0cac51665333ec633 --- kernel/src/0001-BSA-ACS-Linux-6.13.patch | 495 +++++++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100644 kernel/src/0001-BSA-ACS-Linux-6.13.patch diff --git a/kernel/src/0001-BSA-ACS-Linux-6.13.patch b/kernel/src/0001-BSA-ACS-Linux-6.13.patch new file mode 100644 index 0000000..ada9840 --- /dev/null +++ b/kernel/src/0001-BSA-ACS-Linux-6.13.patch @@ -0,0 +1,495 @@ +From a5efcd473c623d05e5f5a7cf4b079d334f5a43ea Mon Sep 17 00:00:00 2001 +From: Rajat Goyal +Date: Tue, 8 Apr 2025 08:35:29 +0000 +Subject: [PATCH] BSA ACS Linux 6.13 + +Signed-off-by: Rajat Goyal +Change-Id: I707c71d2b9affdc6b758ffe22d64be91db5fc7e3 +--- + drivers/ata/libahci.c | 3 + + drivers/ata/sata_sil24.c | 3 + + drivers/iommu/Makefile | 1 + + drivers/iommu/bsa-dma-iommu.c | 238 ++++++++++++++++++++++++++++++++++ + drivers/iommu/dma-iommu.c | 7 + + drivers/iommu/iommu.c | 3 + + drivers/irqchip/irq-gic-v3.c | 11 ++ + include/linux/bsa-iommu.h | 50 +++++++ + include/linux/irqdomain.h | 2 + + kernel/irq/irqdomain.c | 2 +- + mm/init-mm.c | 2 + + 11 files changed, 321 insertions(+), 1 deletion(-) + create mode 100644 drivers/iommu/bsa-dma-iommu.c + create mode 100644 include/linux/bsa-iommu.h + +diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c +index fdfa7b266218..c1c8a2daebcc 100644 +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -1647,6 +1647,8 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) + } + } + ++void bsa_scsi_sata_fill_dma_addr(struct scatterlist *sg); ++ + static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) + { + struct scatterlist *sg; +@@ -1656,6 +1658,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) + /* + * Next, the S/G list. + */ ++ bsa_scsi_sata_fill_dma_addr(qc->sg); + for_each_sg(qc->sg, sg, qc->n_elem, si) { + dma_addr_t addr = sg_dma_address(sg); + u32 sg_len = sg_dma_len(sg); +diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c +index 72c03cbdaff4..fff0f51b9bf2 100644 +--- a/drivers/ata/sata_sil24.c ++++ b/drivers/ata/sata_sil24.c +@@ -687,6 +687,8 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class, + return -EIO; + } + ++void bsa_scsi_sata_fill_dma_addr(struct scatterlist *sg); ++ + static int sil24_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) + { +@@ -773,6 +775,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, + struct sil24_sge *last_sge = NULL; + unsigned int si; + ++ bsa_scsi_sata_fill_dma_addr(qc->sg); + for_each_sg(qc->sg, sg, qc->n_elem, si) { + sge->addr = cpu_to_le64(sg_dma_address(sg)); + sge->cnt = cpu_to_le32(sg_dma_len(sg)); +diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile +index 5e5a83c6c2aa..3e984d4d385d 100644 +--- a/drivers/iommu/Makefile ++++ b/drivers/iommu/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_IOMMU_API) += iommu-traces.o + obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o + obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o + obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o ++obj-$(CONFIG_IOMMU_DMA) += bsa-dma-iommu.o + obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o + obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o + obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o +diff --git a/drivers/iommu/bsa-dma-iommu.c b/drivers/iommu/bsa-dma-iommu.c +new file mode 100644 +index 000000000000..c5ee940fb7ca +--- /dev/null ++++ b/drivers/iommu/bsa-dma-iommu.c +@@ -0,0 +1,238 @@ ++/* ++ * The IOMMU-API to BSA Architecture Compliance Suite glue layer. ++ * ++ * Copyright (C) 2021 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 "dma-iommu.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++bsa_iova_array g_bsa_iova_array[BSA_IOVA_DMA_ARRAY_LEN]; ++ ++struct iommu_domain *g_bsa_iommu_domain = NULL; ++ ++struct iova_domain *cookie_iovad_bsa(struct iommu_domain *domain); ++ ++/** ++ @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; ++} ++EXPORT_SYMBOL(bsa_iommu_dma_get_iova); ++ ++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); ++} ++EXPORT_SYMBOL(bsa_iommu_dev_start_monitor); ++ ++void ++bsa_iommu_dev_stop_monitor(struct device *dev) ++{ ++ g_bsa_iommu_domain = NULL; ++} ++EXPORT_SYMBOL(bsa_iommu_dev_stop_monitor); ++ ++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; ++ ++} ++EXPORT_SYMBOL(bsa_iommu_iova_get_addr); ++ ++/** ++ @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); ++} ++EXPORT_SYMBOL(bsa_dev_get_dma_attr); ++ ++/* 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; ++} ++EXPORT_SYMBOL(bsa_scsi_sata_get_dma_addr); ++ ++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)); ++} ++EXPORT_SYMBOL(bsa_scsi_sata_fill_dma_addr); +\ No newline at end of file +diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c +index 2a9fa0c8cc00..ae6904467a92 100644 +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -89,6 +89,13 @@ struct iommu_dma_cookie { + struct mutex mutex; + }; + ++struct iova_domain *cookie_iovad_bsa(struct iommu_domain *domain) ++{ ++ if (domain) ++ return &((struct iommu_dma_cookie *)domain->iova_cookie)->iovad; ++ return NULL; ++} ++ + static DEFINE_STATIC_KEY_FALSE(iommu_deferred_attach_enabled); + bool iommu_dma_forcedac __read_mostly; + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 599030e1e890..7b50771eb829 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -36,6 +36,7 @@ + + #include "dma-iommu.h" + #include "iommu-priv.h" ++#include + + static struct kset *iommu_group_kset; + static DEFINE_IDA(iommu_group_ida); +@@ -2443,6 +2444,8 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, + } + + pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); ++ if (bsa_is_domain_monitored(domain)) ++ bsa_iommu_iova_save_addr((dma_addr_t)iova, (unsigned int)size); + + while (size) { + size_t pgsize, count, mapped = 0; +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index 76dce0aac246..c5e63901c227 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -70,6 +70,9 @@ struct gic_chip_data { + struct partition_desc **ppi_descs; + }; + ++/* ACS GIC Patch */ ++struct irq_domain *acs_irq_domain = NULL; ++ + #define T241_CHIPS_MAX 4 + static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly; + static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum); +@@ -268,6 +271,14 @@ static enum gic_intid_range get_intid_range(struct irq_data *d) + return __get_intid_range(d->hwirq); + } + ++struct irq_domain* acs_get_irq_domain(void) ++{ ++ if (acs_irq_domain) ++ return acs_irq_domain; ++ return 0; ++} ++EXPORT_SYMBOL(acs_get_irq_domain); ++ + static inline bool gic_irq_in_rdist(struct irq_data *d) + { + switch (get_intid_range(d)) { +diff --git a/include/linux/bsa-iommu.h b/include/linux/bsa-iommu.h +new file mode 100644 +index 000000000000..81a516e5b2c9 +--- /dev/null ++++ b/include/linux/bsa-iommu.h +@@ -0,0 +1,50 @@ ++/* ++ * The IOMMU-API to BSA Architecture Compliance Suite glue layer. ++ * ++ * Copyright (C) 2021 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 ++ ++ ++#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); ++ ++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); ++ ++#endif ++#endif +\ No newline at end of file +diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h +index e432b6a12a32..f247ade690b2 100644 +--- a/include/linux/irqdomain.h ++++ b/include/linux/irqdomain.h +@@ -764,5 +764,7 @@ static inline struct irq_domain *irq_find_matching_fwnode( + return NULL; + } + #endif /* !CONFIG_IRQ_DOMAIN */ ++/* ACS GIC Patch */ ++struct irq_domain* acs_get_irq_domain(void); + + #endif /* _LINUX_IRQDOMAIN_H */ +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index ec6d8e72d980..315fb3443b37 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -1688,7 +1688,7 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, + + return ret; + } +-EXPORT_SYMBOL_GPL(__irq_domain_alloc_irqs); ++EXPORT_SYMBOL(__irq_domain_alloc_irqs); + + /* The irq_data was moved, fix the revmap to refer to the new location */ + static void irq_domain_fix_revmap(struct irq_data *d) +diff --git a/mm/init-mm.c b/mm/init-mm.c +index 24c809379274..6ab2e9e1e0ed 100644 +--- a/mm/init-mm.c ++++ b/mm/init-mm.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -46,6 +47,7 @@ struct mm_struct init_mm = { + .cpu_bitmap = CPU_BITS_NONE, + INIT_MM_CONTEXT(init_mm) + }; ++EXPORT_SYMBOL(init_mm); + + void setup_initial_init_mm(void *start_code, void *end_code, + void *end_data, void *brk) +-- +2.34.1 + -- GitLab