1946 lines
60 KiB
Diff
1946 lines
60 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:16 +0100
|
||
Subject: [PATCH 01/19] iommu: Introduce a union to struct iommu_resv_region
|
||
|
||
A union is introduced to struct iommu_resv_region to hold
|
||
any firmware specific data. This is in preparation to add
|
||
support for IORT RMR reserve regions and the union now holds
|
||
the RMR specific information.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
include/linux/iommu.h | 11 +++++++++++
|
||
1 file changed, 11 insertions(+)
|
||
|
||
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
|
||
index d2f3435e7d17..d5cfd0c6a217 100644
|
||
--- a/include/linux/iommu.h
|
||
+++ b/include/linux/iommu.h
|
||
@@ -126,6 +126,13 @@ enum iommu_resv_type {
|
||
IOMMU_RESV_SW_MSI,
|
||
};
|
||
|
||
+struct iommu_iort_rmr_data {
|
||
+#define IOMMU_RMR_REMAP_PERMITTED (1 << 0)
|
||
+ u32 flags;
|
||
+ u32 sid; /* Stream Id associated with RMR entry */
|
||
+ void *smmu; /* Associated IORT SMMU node pointer */
|
||
+};
|
||
+
|
||
/**
|
||
* struct iommu_resv_region - descriptor for a reserved memory region
|
||
* @list: Linked list pointers
|
||
@@ -133,6 +140,7 @@ enum iommu_resv_type {
|
||
* @length: Length of the region in bytes
|
||
* @prot: IOMMU Protection flags (READ/WRITE/...)
|
||
* @type: Type of the reserved region
|
||
+ * @rmr: ACPI IORT RMR specific data
|
||
*/
|
||
struct iommu_resv_region {
|
||
struct list_head list;
|
||
@@ -140,6 +148,9 @@ struct iommu_resv_region {
|
||
size_t length;
|
||
int prot;
|
||
enum iommu_resv_type type;
|
||
+ union {
|
||
+ struct iommu_iort_rmr_data rmr;
|
||
+ } fw_data;
|
||
};
|
||
|
||
/**
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:17 +0100
|
||
Subject: [PATCH 02/19] ACPI/IORT: Add support for RMR node parsing
|
||
|
||
Add support for parsing RMR node information from ACPI.
|
||
|
||
Find the associated streamid and smmu node info from the
|
||
RMR node and populate a linked list with RMR memory
|
||
descriptors.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/acpi/arm64/iort.c | 134 +++++++++++++++++++++++++++++++++++++-
|
||
1 file changed, 133 insertions(+), 1 deletion(-)
|
||
|
||
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
|
||
index f2f8f05662de..7df83d80819b 100644
|
||
--- a/drivers/acpi/arm64/iort.c
|
||
+++ b/drivers/acpi/arm64/iort.c
|
||
@@ -40,6 +40,8 @@ struct iort_fwnode {
|
||
static LIST_HEAD(iort_fwnode_list);
|
||
static DEFINE_SPINLOCK(iort_fwnode_lock);
|
||
|
||
+static LIST_HEAD(iort_rmr_list); /* list of RMR regions from ACPI */
|
||
+
|
||
/**
|
||
* iort_set_fwnode() - Create iort_fwnode and use it to register
|
||
* iommu data in the iort_fwnode_list
|
||
@@ -393,7 +395,8 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
|
||
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
|
||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
|
||
node->type == ACPI_IORT_NODE_SMMU_V3 ||
|
||
- node->type == ACPI_IORT_NODE_PMCG) {
|
||
+ node->type == ACPI_IORT_NODE_PMCG ||
|
||
+ node->type == ACPI_IORT_NODE_RMR) {
|
||
*id_out = map->output_base;
|
||
return parent;
|
||
}
|
||
@@ -1574,6 +1577,134 @@ static void __init iort_enable_acs(struct acpi_iort_node *iort_node)
|
||
#else
|
||
static inline void iort_enable_acs(struct acpi_iort_node *iort_node) { }
|
||
#endif
|
||
+static void iort_rmr_desc_check_overlap(struct acpi_iort_rmr_desc *desc, u32 count)
|
||
+{
|
||
+ int i, j;
|
||
+
|
||
+ for (i = 0; i < count; i++) {
|
||
+ u64 end, start = desc[i].base_address, length = desc[i].length;
|
||
+
|
||
+ end = start + length - 1;
|
||
+
|
||
+ /* Check for address overlap */
|
||
+ for (j = i + 1; j < count; j++) {
|
||
+ u64 e_start = desc[j].base_address;
|
||
+ u64 e_end = e_start + desc[j].length - 1;
|
||
+
|
||
+ if (start <= e_end && end >= e_start)
|
||
+ pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] overlaps, continue anyway\n",
|
||
+ start, end);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void __init iort_node_get_rmr_info(struct acpi_iort_node *iort_node)
|
||
+{
|
||
+ struct acpi_iort_node *smmu;
|
||
+ struct acpi_iort_rmr *rmr;
|
||
+ struct acpi_iort_rmr_desc *rmr_desc;
|
||
+ u32 map_count = iort_node->mapping_count;
|
||
+ u32 sid;
|
||
+ int i;
|
||
+
|
||
+ if (!iort_node->mapping_offset || map_count != 1) {
|
||
+ pr_err(FW_BUG "Invalid ID mapping, skipping RMR node %p\n",
|
||
+ iort_node);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Retrieve associated smmu and stream id */
|
||
+ smmu = iort_node_get_id(iort_node, &sid, 0);
|
||
+ if (!smmu) {
|
||
+ pr_err(FW_BUG "Invalid SMMU reference, skipping RMR node %p\n",
|
||
+ iort_node);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Retrieve RMR data */
|
||
+ rmr = (struct acpi_iort_rmr *)iort_node->node_data;
|
||
+ if (!rmr->rmr_offset || !rmr->rmr_count) {
|
||
+ pr_err(FW_BUG "Invalid RMR descriptor array, skipping RMR node %p\n",
|
||
+ iort_node);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ rmr_desc = ACPI_ADD_PTR(struct acpi_iort_rmr_desc, iort_node,
|
||
+ rmr->rmr_offset);
|
||
+
|
||
+ iort_rmr_desc_check_overlap(rmr_desc, rmr->rmr_count);
|
||
+
|
||
+ for (i = 0; i < rmr->rmr_count; i++, rmr_desc++) {
|
||
+ struct iommu_resv_region *region;
|
||
+ enum iommu_resv_type type;
|
||
+ int prot = IOMMU_READ | IOMMU_WRITE;
|
||
+ u64 addr = rmr_desc->base_address, size = rmr_desc->length;
|
||
+
|
||
+ if (!IS_ALIGNED(addr, SZ_64K) || !IS_ALIGNED(size, SZ_64K)) {
|
||
+ /* PAGE align base addr and size */
|
||
+ addr &= PAGE_MASK;
|
||
+ size = PAGE_ALIGN(size + offset_in_page(rmr_desc->base_address));
|
||
+
|
||
+ pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] not aligned to 64K, continue with [0x%llx - 0x%llx]\n",
|
||
+ rmr_desc->base_address,
|
||
+ rmr_desc->base_address + rmr_desc->length - 1,
|
||
+ addr, addr + size - 1);
|
||
+ }
|
||
+ if (rmr->flags & IOMMU_RMR_REMAP_PERMITTED) {
|
||
+ type = IOMMU_RESV_DIRECT_RELAXABLE;
|
||
+ /*
|
||
+ * Set IOMMU_CACHE as IOMMU_RESV_DIRECT_RELAXABLE is
|
||
+ * normally used for allocated system memory that is
|
||
+ * then used for device specific reserved regions.
|
||
+ */
|
||
+ prot |= IOMMU_CACHE;
|
||
+ } else {
|
||
+ type = IOMMU_RESV_DIRECT;
|
||
+ /*
|
||
+ * Set IOMMU_MMIO as IOMMU_RESV_DIRECT is normally used
|
||
+ * for device memory like MSI doorbell.
|
||
+ */
|
||
+ prot |= IOMMU_MMIO;
|
||
+ }
|
||
+
|
||
+ region = iommu_alloc_resv_region(addr, size, prot, type);
|
||
+ if (region) {
|
||
+ region->fw_data.rmr.flags = rmr->flags;
|
||
+ region->fw_data.rmr.sid = sid;
|
||
+ region->fw_data.rmr.smmu = smmu;
|
||
+ list_add_tail(®ion->list, &iort_rmr_list);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void __init iort_parse_rmr(void)
|
||
+{
|
||
+ struct acpi_iort_node *iort_node, *iort_end;
|
||
+ struct acpi_table_iort *iort;
|
||
+ int i;
|
||
+
|
||
+ if (iort_table->revision < 3)
|
||
+ return;
|
||
+
|
||
+ iort = (struct acpi_table_iort *)iort_table;
|
||
+
|
||
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
|
||
+ iort->node_offset);
|
||
+ iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
|
||
+ iort_table->length);
|
||
+
|
||
+ for (i = 0; i < iort->node_count; i++) {
|
||
+ if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
|
||
+ "IORT node pointer overflows, bad table!\n"))
|
||
+ return;
|
||
+
|
||
+ if (iort_node->type == ACPI_IORT_NODE_RMR)
|
||
+ iort_node_get_rmr_info(iort_node);
|
||
+
|
||
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
|
||
+ iort_node->length);
|
||
+ }
|
||
+}
|
||
|
||
static void __init iort_init_platform_devices(void)
|
||
{
|
||
@@ -1644,6 +1775,7 @@ void __init acpi_iort_init(void)
|
||
}
|
||
|
||
iort_init_platform_devices();
|
||
+ iort_parse_rmr();
|
||
}
|
||
|
||
#ifdef CONFIG_ZONE_DMA
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:18 +0100
|
||
Subject: [PATCH 03/19] iommu/dma: Introduce generic helper to retrieve RMR
|
||
info
|
||
|
||
Reserved Memory Regions(RMR) associated with an IOMMU can be
|
||
described through ACPI IORT tables in systems with devices
|
||
that require a unity mapping or bypass for those
|
||
regions.
|
||
|
||
Introduce a generic interface so that IOMMU drivers can retrieve
|
||
and set up necessary mappings.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/dma-iommu.c | 29 +++++++++++++++++++++++++++++
|
||
include/linux/dma-iommu.h | 13 +++++++++++++
|
||
2 files changed, 42 insertions(+)
|
||
|
||
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
|
||
index 48c6f7ff4aef..72d801a5a5f7 100644
|
||
--- a/drivers/iommu/dma-iommu.c
|
||
+++ b/drivers/iommu/dma-iommu.c
|
||
@@ -174,6 +174,35 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
|
||
}
|
||
EXPORT_SYMBOL(iommu_put_dma_cookie);
|
||
|
||
+/**
|
||
+ *
|
||
+ * iommu_dma_get_rmrs - Retrieve Reserved Memory Regions(RMRs) associated
|
||
+ * with a given IOMMU
|
||
+ * @iommu_fwnode: fwnode associated with IOMMU
|
||
+ * @list: RMR list to be populated
|
||
+ *
|
||
+ */
|
||
+int iommu_dma_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
+ struct list_head *list)
|
||
+{
|
||
+ return -EINVAL;
|
||
+}
|
||
+EXPORT_SYMBOL(iommu_dma_get_rmrs);
|
||
+
|
||
+/**
|
||
+ *
|
||
+ * iommu_dma_put_rmrs - Release Reserved Memory Regions(RMRs) associated
|
||
+ * with a given IOMMU
|
||
+ * @iommu_fwnode: fwnode associated with IOMMU
|
||
+ * @list: RMR list
|
||
+ *
|
||
+ */
|
||
+void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
+ struct list_head *list)
|
||
+{
|
||
+}
|
||
+EXPORT_SYMBOL(iommu_dma_put_rmrs);
|
||
+
|
||
/**
|
||
* iommu_dma_get_resv_regions - Reserved region driver helper
|
||
* @dev: Device from iommu_get_resv_regions()
|
||
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
|
||
index 24607dc3c2ac..7579c014e274 100644
|
||
--- a/include/linux/dma-iommu.h
|
||
+++ b/include/linux/dma-iommu.h
|
||
@@ -43,12 +43,16 @@ void iommu_dma_free_cpu_cached_iovas(unsigned int cpu,
|
||
|
||
extern bool iommu_dma_forcedac;
|
||
|
||
+int iommu_dma_get_rmrs(struct fwnode_handle *iommu, struct list_head *list);
|
||
+void iommu_dma_put_rmrs(struct fwnode_handle *iommu, struct list_head *list);
|
||
+
|
||
#else /* CONFIG_IOMMU_DMA */
|
||
|
||
struct iommu_domain;
|
||
struct msi_desc;
|
||
struct msi_msg;
|
||
struct device;
|
||
+struct fwnode_handle;
|
||
|
||
static inline void iommu_setup_dma_ops(struct device *dev, u64 dma_base,
|
||
u64 dma_limit)
|
||
@@ -89,5 +93,14 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he
|
||
{
|
||
}
|
||
|
||
+static int iommu_dma_get_rmrs(struct fwnode_handle *iommu, struct list_head *list)
|
||
+{
|
||
+ return -ENODEV;
|
||
+}
|
||
+
|
||
+static void iommu_dma_put_rmrs(struct fwnode_handle *iommu, struct list_head *list)
|
||
+{
|
||
+}
|
||
+
|
||
#endif /* CONFIG_IOMMU_DMA */
|
||
#endif /* __DMA_IOMMU_H */
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:19 +0100
|
||
Subject: [PATCH 04/19] ACPI/IORT: Add a helper to retrieve RMR memory regions
|
||
|
||
Add a helper function (iort_iommu_get_rmrs()) that retrieves RMR
|
||
memory descriptors associated with a given IOMMU. This will be used
|
||
by IOMMU drivers to setup necessary mappings.
|
||
|
||
Invoke it from the generic helper iommu_dma_get_rmrs().
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/acpi/arm64/iort.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||
drivers/iommu/dma-iommu.c | 4 ++++
|
||
include/linux/acpi_iort.h | 7 +++++++
|
||
3 files changed, 49 insertions(+)
|
||
|
||
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
|
||
index 7df83d80819b..66d200e577cb 100644
|
||
--- a/drivers/acpi/arm64/iort.c
|
||
+++ b/drivers/acpi/arm64/iort.c
|
||
@@ -809,6 +809,42 @@ static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
|
||
return NULL;
|
||
}
|
||
|
||
+/**
|
||
+ * iort_iommu_get_rmrs() - Helper to retrieve RMR info associated with IOMMU
|
||
+ * @iommu_fwnode: fwnode for the IOMMU
|
||
+ * @head: RMR list head to be populated
|
||
+ *
|
||
+ * Returns: 0 on success, <0 failure. Please note, we will keep the already
|
||
+ * allocated RMR reserve regions in case of a kmemdup()
|
||
+ * failure.
|
||
+ */
|
||
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
+ struct list_head *head)
|
||
+{
|
||
+ struct iommu_resv_region *e;
|
||
+ struct acpi_iort_node *iommu;
|
||
+ int rmrs = 0;
|
||
+
|
||
+ iommu = iort_get_iort_node(iommu_fwnode);
|
||
+ if (!iommu || list_empty(&iort_rmr_list))
|
||
+ return -ENODEV;
|
||
+
|
||
+ list_for_each_entry(e, &iort_rmr_list, list) {
|
||
+ struct iommu_resv_region *region;
|
||
+
|
||
+ if (e->fw_data.rmr.smmu != iommu)
|
||
+ continue;
|
||
+
|
||
+ region = kmemdup(e, sizeof(*region), GFP_KERNEL);
|
||
+ if (region) {
|
||
+ list_add_tail(®ion->list, head);
|
||
+ rmrs++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return (rmrs == 0) ? -ENODEV : 0;
|
||
+}
|
||
+
|
||
/**
|
||
* iort_iommu_msi_get_resv_regions - Reserved region driver helper
|
||
* @dev: Device from iommu_get_resv_regions()
|
||
@@ -1041,6 +1077,8 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
|
||
{ return 0; }
|
||
int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
|
||
{ return -ENODEV; }
|
||
+int iort_iommu_get_rmrs(struct fwnode_handle *fwnode, struct list_head *head)
|
||
+{ return -ENODEV; }
|
||
#endif
|
||
|
||
static int nc_dma_get_range(struct device *dev, u64 *size)
|
||
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
|
||
index 72d801a5a5f7..4e4d00a3adaf 100644
|
||
--- a/drivers/iommu/dma-iommu.c
|
||
+++ b/drivers/iommu/dma-iommu.c
|
||
@@ -185,6 +185,9 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
|
||
int iommu_dma_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
struct list_head *list)
|
||
{
|
||
+ if (!is_of_node(iommu_fwnode))
|
||
+ return iort_iommu_get_rmrs(iommu_fwnode, list);
|
||
+
|
||
return -EINVAL;
|
||
}
|
||
EXPORT_SYMBOL(iommu_dma_get_rmrs);
|
||
@@ -200,6 +203,7 @@ EXPORT_SYMBOL(iommu_dma_get_rmrs);
|
||
void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
struct list_head *list)
|
||
{
|
||
+ generic_iommu_put_resv_regions(iommu_fwnode->dev, list);
|
||
}
|
||
EXPORT_SYMBOL(iommu_dma_put_rmrs);
|
||
|
||
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
|
||
index f1f0842a2cb2..d8c030c103f5 100644
|
||
--- a/include/linux/acpi_iort.h
|
||
+++ b/include/linux/acpi_iort.h
|
||
@@ -38,6 +38,8 @@ int iort_dma_get_ranges(struct device *dev, u64 *size);
|
||
int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
|
||
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
|
||
phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
|
||
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
+ struct list_head *list);
|
||
#else
|
||
static inline void acpi_iort_init(void) { }
|
||
static inline u32 iort_msi_map_id(struct device *dev, u32 id)
|
||
@@ -57,6 +59,11 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
|
||
|
||
static inline phys_addr_t acpi_iort_dma_get_max_cpu_address(void)
|
||
{ return PHYS_ADDR_MAX; }
|
||
+
|
||
+static inline
|
||
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
+ struct list_head *list)
|
||
+{ return -ENODEV; }
|
||
#endif
|
||
|
||
#endif /* __ACPI_IORT_H__ */
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:20 +0100
|
||
Subject: [PATCH 05/19] iommu/arm-smmu-v3: Introduce strtab init helper
|
||
|
||
Introduce a helper to check the sid range and to init the l2 strtab
|
||
entries(bypass). This will be useful when we have to initialize the
|
||
l2 strtab with bypass for RMR SIDs.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 28 +++++++++++----------
|
||
1 file changed, 15 insertions(+), 13 deletions(-)
|
||
|
||
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
index 79edfdca6607..742c015c6616 100644
|
||
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
@@ -2530,6 +2530,19 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
|
||
return sid < limit;
|
||
}
|
||
|
||
+static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
|
||
+{
|
||
+ /* Check the SIDs are in range of the SMMU and our stream table */
|
||
+ if (!arm_smmu_sid_in_range(smmu, sid))
|
||
+ return -ERANGE;
|
||
+
|
||
+ /* Ensure l2 strtab is initialised */
|
||
+ if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
|
||
+ return arm_smmu_init_l2_strtab(smmu, sid);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
||
struct arm_smmu_master *master)
|
||
{
|
||
@@ -2553,20 +2566,9 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
||
new_stream->id = sid;
|
||
new_stream->master = master;
|
||
|
||
- /*
|
||
- * Check the SIDs are in range of the SMMU and our stream table
|
||
- */
|
||
- if (!arm_smmu_sid_in_range(smmu, sid)) {
|
||
- ret = -ERANGE;
|
||
+ ret = arm_smmu_init_sid_strtab(smmu, sid);
|
||
+ if (ret)
|
||
break;
|
||
- }
|
||
-
|
||
- /* Ensure l2 strtab is initialised */
|
||
- if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
|
||
- ret = arm_smmu_init_l2_strtab(smmu, sid);
|
||
- if (ret)
|
||
- break;
|
||
- }
|
||
|
||
/* Insert into SID tree */
|
||
new_node = &(smmu->streams.rb_node);
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:21 +0100
|
||
Subject: [PATCH 06/19] =?UTF-8?q?iommu/arm-smmu-v3:=20Refactor=C2=A0arm=5F?=
|
||
=?UTF-8?q?smmu=5Finit=5Fbypass=5Fstes()=20to=20force=20bypass?=
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
By default, disable_bypass flag is set and any dev without
|
||
an iommu domain installs STE with CFG_ABORT during
|
||
arm_smmu_init_bypass_stes(). Introduce a "force" flag and
|
||
move the STE update logic to arm_smmu_init_bypass_stes()
|
||
so that we can force it to install CFG_BYPASS STE for specific
|
||
SIDs.
|
||
|
||
This will be useful in follow-up patch to install bypass
|
||
for IORT RMR SIDs.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 17 +++++++++++++----
|
||
1 file changed, 13 insertions(+), 4 deletions(-)
|
||
|
||
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
index 742c015c6616..2c2e79034f4c 100644
|
||
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
@@ -1374,12 +1374,21 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
|
||
arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
|
||
}
|
||
|
||
-static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent)
|
||
+static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent, bool force)
|
||
{
|
||
unsigned int i;
|
||
+ u64 val = STRTAB_STE_0_V;
|
||
+
|
||
+ if (disable_bypass && !force)
|
||
+ val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT);
|
||
+ else
|
||
+ val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
|
||
|
||
for (i = 0; i < nent; ++i) {
|
||
- arm_smmu_write_strtab_ent(NULL, -1, strtab);
|
||
+ strtab[0] = cpu_to_le64(val);
|
||
+ strtab[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
|
||
+ STRTAB_STE_1_SHCFG_INCOMING));
|
||
+ strtab[2] = 0;
|
||
strtab += STRTAB_STE_DWORDS;
|
||
}
|
||
}
|
||
@@ -1407,7 +1416,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
|
||
return -ENOMEM;
|
||
}
|
||
|
||
- arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
|
||
+ arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT, false);
|
||
arm_smmu_write_strtab_l1_desc(strtab, desc);
|
||
return 0;
|
||
}
|
||
@@ -3054,7 +3063,7 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
|
||
reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
|
||
cfg->strtab_base_cfg = reg;
|
||
|
||
- arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents);
|
||
+ arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents, false);
|
||
return 0;
|
||
}
|
||
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:22 +0100
|
||
Subject: [PATCH 07/19] iommu/arm-smmu-v3: Get associated RMR info and install
|
||
bypass STE
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
Check if there is any RMR info associated with the devices behind
|
||
the SMMUv3 and if any, install bypass STEs for them. This is to
|
||
keep any ongoing traffic associated with these devices alive
|
||
when we enable/reset SMMUv3 during probe().
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 31 +++++++++++++++++++++
|
||
1 file changed, 31 insertions(+)
|
||
|
||
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
index 2c2e79034f4c..9b7753d66791 100644
|
||
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
||
@@ -3770,6 +3770,34 @@ static void __iomem *arm_smmu_ioremap(struct device *dev, resource_size_t start,
|
||
return devm_ioremap_resource(dev, &res);
|
||
}
|
||
|
||
+static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
|
||
+{
|
||
+ struct list_head rmr_list;
|
||
+ struct iommu_resv_region *e;
|
||
+ int ret;
|
||
+
|
||
+ INIT_LIST_HEAD(&rmr_list);
|
||
+ if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
|
||
+ return;
|
||
+
|
||
+ list_for_each_entry(e, &rmr_list, list) {
|
||
+ __le64 *step;
|
||
+ u32 sid = e->fw_data.rmr.sid;
|
||
+
|
||
+ ret = arm_smmu_init_sid_strtab(smmu, sid);
|
||
+ if (ret) {
|
||
+ dev_err(smmu->dev, "RMR SID(0x%x) bypass failed\n",
|
||
+ sid);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ step = arm_smmu_get_step_for_sid(smmu, sid);
|
||
+ arm_smmu_init_bypass_stes(step, 1, true);
|
||
+ }
|
||
+
|
||
+ iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
|
||
+}
|
||
+
|
||
static int arm_smmu_device_probe(struct platform_device *pdev)
|
||
{
|
||
int irq, ret;
|
||
@@ -3853,6 +3881,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
||
/* Record our private device structure */
|
||
platform_set_drvdata(pdev, smmu);
|
||
|
||
+ /* Check for RMRs and install bypass STEs if any */
|
||
+ arm_smmu_rmr_install_bypass_ste(smmu);
|
||
+
|
||
/* Reset the device */
|
||
ret = arm_smmu_device_reset(smmu, bypass);
|
||
if (ret)
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Jon Nettleton <jon@solid-run.com>
|
||
Date: Thu, 5 Aug 2021 09:07:23 +0100
|
||
Subject: [PATCH 08/19] iommu/arm-smmu: Get associated RMR info and install
|
||
bypass SMR
|
||
|
||
Check if there is any RMR info associated with the devices behind
|
||
the SMMU and if any, install bypass SMRs for them. This is to
|
||
keep any ongoing traffic associated with these devices alive
|
||
when we enable/reset SMMU during probe().
|
||
|
||
Signed-off-by: Jon Nettleton <jon@solid-run.com>
|
||
Signed-off-by: Steven Price <steven.price@arm.com>
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/arm/arm-smmu/arm-smmu.c | 48 +++++++++++++++++++++++++++
|
||
1 file changed, 48 insertions(+)
|
||
|
||
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
|
||
index 324e8f32962a..1d65dd243fee 100644
|
||
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
|
||
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
|
||
@@ -2066,6 +2066,50 @@ err_reset_platform_ops: __maybe_unused;
|
||
return err;
|
||
}
|
||
|
||
+static void arm_smmu_rmr_install_bypass_smr(struct arm_smmu_device *smmu)
|
||
+{
|
||
+ struct list_head rmr_list;
|
||
+ struct iommu_resv_region *e;
|
||
+ int i, cnt = 0;
|
||
+ u32 reg;
|
||
+
|
||
+ INIT_LIST_HEAD(&rmr_list);
|
||
+ if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
|
||
+ return;
|
||
+
|
||
+ /*
|
||
+ * Rather than trying to look at existing mappings that
|
||
+ * are setup by the firmware and then invalidate the ones
|
||
+ * that do no have matching RMR entries, just disable the
|
||
+ * SMMU until it gets enabled again in the reset routine.
|
||
+ */
|
||
+ reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
|
||
+ reg |= ARM_SMMU_sCR0_CLIENTPD;
|
||
+ arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
|
||
+
|
||
+ list_for_each_entry(e, &rmr_list, list) {
|
||
+ u32 sid = e->fw_data.rmr.sid;
|
||
+
|
||
+ i = arm_smmu_find_sme(smmu, sid, ~0);
|
||
+ if (i < 0)
|
||
+ continue;
|
||
+ if (smmu->s2crs[i].count == 0) {
|
||
+ smmu->smrs[i].id = sid;
|
||
+ smmu->smrs[i].mask = 0;
|
||
+ smmu->smrs[i].valid = true;
|
||
+ }
|
||
+ smmu->s2crs[i].count++;
|
||
+ smmu->s2crs[i].type = S2CR_TYPE_BYPASS;
|
||
+ smmu->s2crs[i].privcfg = S2CR_PRIVCFG_DEFAULT;
|
||
+
|
||
+ cnt++;
|
||
+ }
|
||
+
|
||
+ dev_notice(smmu->dev, "\tpreserved %d boot mapping%s\n", cnt,
|
||
+ cnt == 1 ? "" : "s");
|
||
+ iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
|
||
+}
|
||
+
|
||
static int arm_smmu_device_probe(struct platform_device *pdev)
|
||
{
|
||
struct resource *res;
|
||
@@ -2191,6 +2235,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
||
}
|
||
|
||
platform_set_drvdata(pdev, smmu);
|
||
+
|
||
+ /* Check for RMRs and install bypass SMRs if any */
|
||
+ arm_smmu_rmr_install_bypass_smr(smmu);
|
||
+
|
||
arm_smmu_device_reset(smmu);
|
||
arm_smmu_test_smr_masks(smmu);
|
||
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Thu, 5 Aug 2021 09:07:24 +0100
|
||
Subject: [PATCH 09/19] iommu/dma: Reserve any RMR regions associated with a
|
||
dev
|
||
|
||
Get ACPI IORT RMR regions associated with a dev reserved
|
||
so that there is a unity mapping for them in SMMU.
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/iommu/dma-iommu.c | 56 +++++++++++++++++++++++++++++++++++----
|
||
1 file changed, 51 insertions(+), 5 deletions(-)
|
||
|
||
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
|
||
index 4e4d00a3adaf..0014a70597ef 100644
|
||
--- a/drivers/iommu/dma-iommu.c
|
||
+++ b/drivers/iommu/dma-iommu.c
|
||
@@ -207,22 +207,68 @@ void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
}
|
||
EXPORT_SYMBOL(iommu_dma_put_rmrs);
|
||
|
||
+static bool iommu_dma_dev_has_rmr(struct iommu_fwspec *fwspec,
|
||
+ struct iommu_resv_region *e)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < fwspec->num_ids; i++) {
|
||
+ if (e->fw_data.rmr.sid == fwspec->ids[i])
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ return false;
|
||
+}
|
||
+
|
||
+static void iommu_dma_get_rmr_resv_regions(struct device *dev,
|
||
+ struct list_head *list)
|
||
+{
|
||
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||
+ struct list_head rmr_list;
|
||
+ struct iommu_resv_region *rmr, *tmp;
|
||
+
|
||
+ INIT_LIST_HEAD(&rmr_list);
|
||
+ if (iommu_dma_get_rmrs(fwspec->iommu_fwnode, &rmr_list))
|
||
+ return;
|
||
+
|
||
+ if (dev_is_pci(dev)) {
|
||
+ struct pci_dev *pdev = to_pci_dev(dev);
|
||
+ struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
|
||
+
|
||
+ if (!host->preserve_config)
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ list_for_each_entry_safe(rmr, tmp, &rmr_list, list) {
|
||
+ if (!iommu_dma_dev_has_rmr(fwspec, rmr))
|
||
+ continue;
|
||
+
|
||
+ /* Remove from iommu RMR list and add to dev resv_regions */
|
||
+ list_del_init(&rmr->list);
|
||
+ list_add_tail(&rmr->list, list);
|
||
+ }
|
||
+
|
||
+ iommu_dma_put_rmrs(fwspec->iommu_fwnode, &rmr_list);
|
||
+}
|
||
+
|
||
/**
|
||
* iommu_dma_get_resv_regions - Reserved region driver helper
|
||
* @dev: Device from iommu_get_resv_regions()
|
||
* @list: Reserved region list from iommu_get_resv_regions()
|
||
*
|
||
* IOMMU drivers can use this to implement their .get_resv_regions callback
|
||
- * for general non-IOMMU-specific reservations. Currently, this covers GICv3
|
||
- * ITS region reservation on ACPI based ARM platforms that may require HW MSI
|
||
- * reservation.
|
||
+ * for general non-IOMMU-specific reservations. Currently this covers,
|
||
+ * -GICv3 ITS region reservation on ACPI based ARM platforms that may
|
||
+ * require HW MSI reservation.
|
||
+ * -Any ACPI IORT RMR memory range reservations (IORT spec rev E.b)
|
||
*/
|
||
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
|
||
{
|
||
|
||
- if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode))
|
||
+ if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode)) {
|
||
iort_iommu_msi_get_resv_regions(dev, list);
|
||
-
|
||
+ iommu_dma_get_rmr_resv_regions(dev, list);
|
||
+ }
|
||
}
|
||
EXPORT_SYMBOL(iommu_dma_get_resv_regions);
|
||
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
Date: Fri, 17 Sep 2021 12:07:26 +0100
|
||
Subject: [PATCH 10/19] iommu/dma: Update RMR mem attributes
|
||
|
||
Since we dont have enough information from the IORT spec,
|
||
make use of ACPI table and EFI memory map to set the RMR
|
||
reserved region prot value.
|
||
|
||
[Not tested]
|
||
|
||
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
|
||
---
|
||
drivers/acpi/arm64/iort.c | 24 +++++++++++++-----------
|
||
drivers/iommu/dma-iommu.c | 1 +
|
||
include/linux/acpi_iort.h | 8 ++++++++
|
||
3 files changed, 22 insertions(+), 11 deletions(-)
|
||
|
||
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
|
||
index 66d200e577cb..c397c980a7f4 100644
|
||
--- a/drivers/acpi/arm64/iort.c
|
||
+++ b/drivers/acpi/arm64/iort.c
|
||
@@ -809,6 +809,16 @@ static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
|
||
return NULL;
|
||
}
|
||
|
||
+void iort_iommu_rmr_update_mem_attr(struct device *dev,
|
||
+ struct iommu_resv_region *rmr)
|
||
+{
|
||
+ if (device_get_dma_attr(dev) == DEV_DMA_COHERENT)
|
||
+ rmr->prot |= IOMMU_CACHE;
|
||
+
|
||
+ if (efi_mem_type(rmr->start) == EFI_MEMORY_MAPPED_IO)
|
||
+ rmr->prot |= IOMMU_MMIO;
|
||
+}
|
||
+
|
||
/**
|
||
* iort_iommu_get_rmrs() - Helper to retrieve RMR info associated with IOMMU
|
||
* @iommu_fwnode: fwnode for the IOMMU
|
||
@@ -1079,6 +1089,9 @@ int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
|
||
{ return -ENODEV; }
|
||
int iort_iommu_get_rmrs(struct fwnode_handle *fwnode, struct list_head *head)
|
||
{ return -ENODEV; }
|
||
+void iort_iommu_rmr_update_mem_attr(struct device *dev,
|
||
+ struct iommu_resv_region *rmr)
|
||
+{ }
|
||
#endif
|
||
|
||
static int nc_dma_get_range(struct device *dev, u64 *size)
|
||
@@ -1690,19 +1703,8 @@ static void __init iort_node_get_rmr_info(struct acpi_iort_node *iort_node)
|
||
}
|
||
if (rmr->flags & IOMMU_RMR_REMAP_PERMITTED) {
|
||
type = IOMMU_RESV_DIRECT_RELAXABLE;
|
||
- /*
|
||
- * Set IOMMU_CACHE as IOMMU_RESV_DIRECT_RELAXABLE is
|
||
- * normally used for allocated system memory that is
|
||
- * then used for device specific reserved regions.
|
||
- */
|
||
- prot |= IOMMU_CACHE;
|
||
} else {
|
||
type = IOMMU_RESV_DIRECT;
|
||
- /*
|
||
- * Set IOMMU_MMIO as IOMMU_RESV_DIRECT is normally used
|
||
- * for device memory like MSI doorbell.
|
||
- */
|
||
- prot |= IOMMU_MMIO;
|
||
}
|
||
|
||
region = iommu_alloc_resv_region(addr, size, prot, type);
|
||
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
|
||
index 0014a70597ef..2055151cfc3f 100644
|
||
--- a/drivers/iommu/dma-iommu.c
|
||
+++ b/drivers/iommu/dma-iommu.c
|
||
@@ -243,6 +243,7 @@ static void iommu_dma_get_rmr_resv_regions(struct device *dev,
|
||
if (!iommu_dma_dev_has_rmr(fwspec, rmr))
|
||
continue;
|
||
|
||
+ iort_iommu_rmr_update_mem_attr(dev, rmr);
|
||
/* Remove from iommu RMR list and add to dev resv_regions */
|
||
list_del_init(&rmr->list);
|
||
list_add_tail(&rmr->list, list);
|
||
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
|
||
index d8c030c103f5..f0a3882c26d4 100644
|
||
--- a/include/linux/acpi_iort.h
|
||
+++ b/include/linux/acpi_iort.h
|
||
@@ -10,6 +10,7 @@
|
||
#include <linux/acpi.h>
|
||
#include <linux/fwnode.h>
|
||
#include <linux/irqdomain.h>
|
||
+#include <linux/iommu.h>
|
||
|
||
#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
|
||
#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
|
||
@@ -40,6 +41,8 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
|
||
phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
|
||
int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
struct list_head *list);
|
||
+void iort_iommu_rmr_update_mem_attr(struct device *dev,
|
||
+ struct iommu_resv_region *rmr);
|
||
#else
|
||
static inline void acpi_iort_init(void) { }
|
||
static inline u32 iort_msi_map_id(struct device *dev, u32 id)
|
||
@@ -64,6 +67,11 @@ static inline
|
||
int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
|
||
struct list_head *list)
|
||
{ return -ENODEV; }
|
||
+
|
||
+static inline
|
||
+void iort_iommu_rmr_update_mem_attr(struct device *dev,
|
||
+ struct iommu_resv_region *rmr)
|
||
+{ }
|
||
#endif
|
||
|
||
#endif /* __ACPI_IORT_H__ */
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Makarand Pawagi <makarand.pawagi@nxp.com>
|
||
Date: Tue, 21 Apr 2020 11:25:53 +0530
|
||
Subject: [PATCH 11/19] soc: fsl: enable acpi support for Guts driver
|
||
|
||
ACPI support is added in the Guts driver
|
||
This is in accordance with the DSDT table added for Guts
|
||
|
||
Signed-off-by: Makarand Pawagi <makarand.pawagi@nxp.com>
|
||
---
|
||
drivers/soc/fsl/guts.c | 27 +++++++++++++++++++++------
|
||
1 file changed, 21 insertions(+), 6 deletions(-)
|
||
|
||
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
|
||
index 75eabfb916cb..b080721eace7 100644
|
||
--- a/drivers/soc/fsl/guts.c
|
||
+++ b/drivers/soc/fsl/guts.c
|
||
@@ -3,6 +3,7 @@
|
||
* Freescale QorIQ Platforms GUTS Driver
|
||
*
|
||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||
+ * Copyright 2020 NXP
|
||
*/
|
||
|
||
#include <linux/io.h>
|
||
@@ -149,7 +150,8 @@ static int fsl_guts_probe(struct platform_device *pdev)
|
||
if (!guts)
|
||
return -ENOMEM;
|
||
|
||
- guts->little_endian = of_property_read_bool(np, "little-endian");
|
||
+ guts->little_endian = fwnode_property_read_bool(pdev->dev.fwnode,
|
||
+ "little-endian");
|
||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
guts->regs = devm_ioremap_resource(dev, res);
|
||
@@ -157,17 +159,23 @@ static int fsl_guts_probe(struct platform_device *pdev)
|
||
return PTR_ERR(guts->regs);
|
||
|
||
/* Register soc device */
|
||
- root = of_find_node_by_path("/");
|
||
- if (of_property_read_string(root, "model", &machine))
|
||
- of_property_read_string_index(root, "compatible", 0, &machine);
|
||
+ if (dev_of_node(&pdev->dev)) {
|
||
+ root = of_find_node_by_path("/");
|
||
+ if (of_property_read_string(root, "model", &machine))
|
||
+ of_property_read_string_index(root,
|
||
+ "compatible", 0, &machine);
|
||
+ of_node_put(root);
|
||
+ } else {
|
||
+ fwnode_property_read_string(pdev->dev.fwnode,
|
||
+ "model", &machine);
|
||
+ }
|
||
+
|
||
if (machine) {
|
||
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
|
||
if (!soc_dev_attr.machine) {
|
||
- of_node_put(root);
|
||
return -ENOMEM;
|
||
}
|
||
}
|
||
- of_node_put(root);
|
||
|
||
svr = fsl_guts_get_svr();
|
||
soc_die = fsl_soc_die_match(svr, fsl_soc_die);
|
||
@@ -238,10 +246,17 @@ static const struct of_device_id fsl_guts_of_match[] = {
|
||
};
|
||
MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
|
||
|
||
+static const struct acpi_device_id fsl_guts_acpi_match[] = {
|
||
+ {"NXP0030", 0 },
|
||
+ { }
|
||
+};
|
||
+MODULE_DEVICE_TABLE(acpi, fsl_guts_acpi_match);
|
||
+
|
||
static struct platform_driver fsl_guts_driver = {
|
||
.driver = {
|
||
.name = "fsl-guts",
|
||
.of_match_table = fsl_guts_of_match,
|
||
+ .acpi_match_table = fsl_guts_acpi_match,
|
||
},
|
||
.probe = fsl_guts_probe,
|
||
.remove = fsl_guts_remove,
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
|
||
Date: Wed, 27 May 2020 21:35:11 +0530
|
||
Subject: [PATCH 12/19] mmc: sdhci-of-esdhc: Add ACPI support
|
||
|
||
This patch is to add acpi support in esdhc controller driver
|
||
|
||
Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
|
||
---
|
||
drivers/mmc/host/sdhci-of-esdhc.c | 62 +++++++++++++++++++------------
|
||
1 file changed, 39 insertions(+), 23 deletions(-)
|
||
|
||
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
|
||
index 0f3658b36513..c11544f6047b 100644
|
||
--- a/drivers/mmc/host/sdhci-of-esdhc.c
|
||
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
|
||
@@ -10,6 +10,7 @@
|
||
* Anton Vorontsov <avorontsov@ru.mvista.com>
|
||
*/
|
||
|
||
+#include <linux/acpi.h>
|
||
#include <linux/err.h>
|
||
#include <linux/io.h>
|
||
#include <linux/of.h>
|
||
@@ -73,6 +74,14 @@ static const struct of_device_id sdhci_esdhc_of_match[] = {
|
||
};
|
||
MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
|
||
|
||
+#ifdef CONFIG_ACPI
|
||
+static const struct acpi_device_id sdhci_esdhc_ids[] = {
|
||
+ {"NXP0003" },
|
||
+ { }
|
||
+};
|
||
+MODULE_DEVICE_TABLE(acpi, sdhci_esdhc_ids);
|
||
+#endif
|
||
+
|
||
struct sdhci_esdhc {
|
||
u8 vendor_ver;
|
||
u8 spec_ver;
|
||
@@ -1370,29 +1379,35 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
|
||
esdhc->clk_fixup = match->data;
|
||
np = pdev->dev.of_node;
|
||
|
||
- if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
|
||
- esdhc->quirk_delay_before_data_reset = true;
|
||
- esdhc->quirk_trans_complete_erratum = true;
|
||
- }
|
||
+ /* in case of device tree, get clock from framework */
|
||
+ if (np) {
|
||
+ if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
|
||
+ esdhc->quirk_delay_before_data_reset = true;
|
||
+ esdhc->quirk_trans_complete_erratum = true;
|
||
+ }
|
||
|
||
- clk = of_clk_get(np, 0);
|
||
- if (!IS_ERR(clk)) {
|
||
- /*
|
||
- * esdhc->peripheral_clock would be assigned with a value
|
||
- * which is eSDHC base clock when use periperal clock.
|
||
- * For some platforms, the clock value got by common clk
|
||
- * API is peripheral clock while the eSDHC base clock is
|
||
- * 1/2 peripheral clock.
|
||
- */
|
||
- if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
|
||
- of_device_is_compatible(np, "fsl,ls1028a-esdhc") ||
|
||
- of_device_is_compatible(np, "fsl,ls1088a-esdhc"))
|
||
- esdhc->peripheral_clock = clk_get_rate(clk) / 2;
|
||
- else
|
||
- esdhc->peripheral_clock = clk_get_rate(clk);
|
||
-
|
||
- clk_put(clk);
|
||
- }
|
||
+ clk = of_clk_get(np, 0);
|
||
+ if (!IS_ERR(clk)) {
|
||
+ /*
|
||
+ * esdhc->peripheral_clock would be assigned with a value
|
||
+ * which is eSDHC base clock when use periperal clock.
|
||
+ * For some platforms, the clock value got by common clk
|
||
+ * API is peripheral clock while the eSDHC base clock is
|
||
+ * 1/2 peripheral clock.
|
||
+ */
|
||
+ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
|
||
+ of_device_is_compatible(np, "fsl,ls1028a-esdhc") ||
|
||
+ of_device_is_compatible(np, "fsl,ls1088a-esdhc"))
|
||
+ esdhc->peripheral_clock = clk_get_rate(clk) / 2;
|
||
+ else
|
||
+ esdhc->peripheral_clock = clk_get_rate(clk);
|
||
+
|
||
+ clk_put(clk);
|
||
+ }
|
||
+ } else {
|
||
+ device_property_read_u32(&pdev->dev, "clock-frequency",
|
||
+ &esdhc->peripheral_clock);
|
||
+ }
|
||
|
||
esdhc_clock_enable(host, false);
|
||
val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
|
||
@@ -1425,7 +1440,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
|
||
|
||
np = pdev->dev.of_node;
|
||
|
||
- if (of_property_read_bool(np, "little-endian"))
|
||
+ if (device_property_read_bool(&pdev->dev, "little-endian"))
|
||
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata,
|
||
sizeof(struct sdhci_esdhc));
|
||
else
|
||
@@ -1510,6 +1525,7 @@ static struct platform_driver sdhci_esdhc_driver = {
|
||
.name = "sdhci-esdhc",
|
||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||
.of_match_table = sdhci_esdhc_of_match,
|
||
+ .acpi_match_table = sdhci_esdhc_ids,
|
||
.pm = &esdhc_of_dev_pm_ops,
|
||
},
|
||
.probe = sdhci_esdhc_probe,
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Meharbaan <meharbaan.ali@puresoftware.com>
|
||
Date: Tue, 28 Jul 2020 17:41:31 +0530
|
||
Subject: [PATCH 13/19] drivers/mmc/host/sdhci-of-esdhc : Fix DMA coherent
|
||
check in ACPI mode.
|
||
|
||
DMA-coherent check to set ESDHC_DMA_SNOOP mask was bypassed
|
||
when booted in ACPI mode. Now it also checks the acpi device and
|
||
its parents for _CCA property in the device, and sets the flag
|
||
accordingly.
|
||
|
||
Signed-off-by: Meharbaan <meharbaan.ali@puresoftware.com>
|
||
---
|
||
drivers/base/property.c | 38 +++++++++++++++++++++++++++++++
|
||
drivers/mmc/host/sdhci-of-esdhc.c | 7 ++++--
|
||
include/linux/property.h | 2 ++
|
||
3 files changed, 45 insertions(+), 2 deletions(-)
|
||
|
||
diff --git a/drivers/base/property.c b/drivers/base/property.c
|
||
index 735a23db1b5e..1125b79a9ca6 100644
|
||
--- a/drivers/base/property.c
|
||
+++ b/drivers/base/property.c
|
||
@@ -17,6 +17,7 @@
|
||
#include <linux/property.h>
|
||
#include <linux/etherdevice.h>
|
||
#include <linux/phy.h>
|
||
+#include <linux/platform_device.h>
|
||
|
||
struct fwnode_handle *dev_fwnode(struct device *dev)
|
||
{
|
||
@@ -915,6 +916,43 @@ enum dev_dma_attr device_get_dma_attr(struct device *dev)
|
||
}
|
||
EXPORT_SYMBOL_GPL(device_get_dma_attr);
|
||
|
||
+/**
|
||
+ * device_match_fw_node - Check if the device is the parent node.
|
||
+ * @dev: Pointer to the device.
|
||
+ * @parent_fwnode Pointer to the parent's firmware node.
|
||
+ *
|
||
+ * The function returns true if the device has no parent.
|
||
+ *
|
||
+ */
|
||
+static int device_match_fw_node(struct device *dev, const void *parent_fwnode)
|
||
+{
|
||
+ return dev->fwnode == parent_fwnode;
|
||
+}
|
||
+
|
||
+/**
|
||
+ * dev_dma_is_coherent - Check if the device or any of its parents has
|
||
+ * dma support enabled.
|
||
+ * @dev: Pointer to the device.
|
||
+ *
|
||
+ * The function gets the device pointer and check for device_dma_supported()
|
||
+ * on the device pointer passed and then recursively on its parent nodes.
|
||
+ */
|
||
+
|
||
+bool dev_dma_is_coherent(struct device *dev)
|
||
+{
|
||
+ struct fwnode_handle *parent_fwnode;
|
||
+
|
||
+ while (dev) {
|
||
+ if (device_dma_supported(dev))
|
||
+ return true;
|
||
+ parent_fwnode = fwnode_get_next_parent(dev->fwnode);
|
||
+ dev = bus_find_device(&platform_bus_type, NULL, parent_fwnode,
|
||
+ device_match_fw_node);
|
||
+ }
|
||
+ return false;
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(dev_dma_is_coherent);
|
||
+
|
||
/**
|
||
* fwnode_get_phy_mode - Get phy mode for given firmware node
|
||
* @fwnode: Pointer to the given node
|
||
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
|
||
index c11544f6047b..6e67bff51454 100644
|
||
--- a/drivers/mmc/host/sdhci-of-esdhc.c
|
||
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
|
||
@@ -545,8 +545,11 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
|
||
}
|
||
|
||
value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
|
||
-
|
||
- if (of_dma_is_coherent(dev->of_node))
|
||
+ /*
|
||
+ * of_dma_is_coherent() returns false in case of acpi hence
|
||
+ * dev_dma_is_coherent() is used along with it.
|
||
+ */
|
||
+ if (of_dma_is_coherent(dev->of_node) || dev_dma_is_coherent(dev))
|
||
value |= ESDHC_DMA_SNOOP;
|
||
else
|
||
value &= ~ESDHC_DMA_SNOOP;
|
||
diff --git a/include/linux/property.h b/include/linux/property.h
|
||
index 357513a977e5..a9009883ab9e 100644
|
||
--- a/include/linux/property.h
|
||
+++ b/include/linux/property.h
|
||
@@ -385,6 +385,8 @@ bool device_dma_supported(struct device *dev);
|
||
|
||
enum dev_dma_attr device_get_dma_attr(struct device *dev);
|
||
|
||
+bool dev_dma_is_coherent(struct device *dev);
|
||
+
|
||
const void *device_get_match_data(struct device *dev);
|
||
|
||
int device_get_phy_mode(struct device *dev);
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Jon Nettleton <jon@solid-run.com>
|
||
Date: Fri, 2 Jul 2021 07:28:21 -0400
|
||
Subject: [PATCH 14/19] ACPI: APD: Allow apd device to override fixed_clk_rate
|
||
|
||
Currently by default the apd drivers are always using the
|
||
fixed_clk_rate assigned in the matched acpi_device_desc.
|
||
This causes an issue on the LX2160a platform because the
|
||
NXP0001 settings do not match the platform and instead the
|
||
I2C bus is only running at 24000kHZ rather than the expect
|
||
100000. Instead of patching the source with more static numbers
|
||
that may or may not change instead add a check for the device
|
||
property "fixed-clock-rate" that can be added to the ACPI
|
||
tables to instruct the driver what rate to use.
|
||
|
||
I have chosen fixed-clock-rate because clock-frequency is already
|
||
used by I2C devices in acpi and device-tree to specify by bus
|
||
speed, and fixed-clock-rate matches the fixed_clk_rate used by the
|
||
apd_device_desc. If this device property is not set then the
|
||
default static values are used so this should cause no regressions.
|
||
|
||
Signed-off-by: Jon Nettleton <jon@solid-run.com>
|
||
---
|
||
drivers/acpi/acpi_apd.c | 13 +++++++++++--
|
||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||
|
||
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
|
||
index 6e02448d15d9..f79757c34a77 100644
|
||
--- a/drivers/acpi/acpi_apd.c
|
||
+++ b/drivers/acpi/acpi_apd.c
|
||
@@ -46,12 +46,21 @@ struct apd_private_data {
|
||
static int acpi_apd_setup(struct apd_private_data *pdata)
|
||
{
|
||
const struct apd_device_desc *dev_desc = pdata->dev_desc;
|
||
+ struct acpi_device *adev = pdata->adev;
|
||
+ const union acpi_object *obj;
|
||
+ unsigned int fixed_clk_rate;
|
||
struct clk *clk;
|
||
|
||
- if (dev_desc->fixed_clk_rate) {
|
||
+ if (!acpi_dev_get_property(adev, "uefi-clock-frequency", ACPI_TYPE_INTEGER, &obj)) {
|
||
+ fixed_clk_rate = obj->integer.value;
|
||
+ } else if (dev_desc->fixed_clk_rate) {
|
||
+ fixed_clk_rate = dev_desc->fixed_clk_rate;
|
||
+ }
|
||
+
|
||
+ if (fixed_clk_rate) {
|
||
clk = clk_register_fixed_rate(&pdata->adev->dev,
|
||
dev_name(&pdata->adev->dev),
|
||
- NULL, 0, dev_desc->fixed_clk_rate);
|
||
+ NULL, 0, fixed_clk_rate);
|
||
clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev));
|
||
pdata->clk = clk;
|
||
}
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||
Date: Tue, 24 Dec 2019 14:46:48 +0000
|
||
Subject: [PATCH 15/19] bus: fsl-mc: fix dprc object reading race
|
||
|
||
When modifying the objects attached to a DPRC, we may end up reading
|
||
the list of objects from the firmware while another thread is changing
|
||
changing the list. Since we read the objects via:
|
||
|
||
- Read the number of DPRC objects
|
||
- Iterate over this number of objects retrieving their details
|
||
|
||
and objects can be added in the middle of the list, this causes the
|
||
last few objects to unexpectedly disappear. The side effect of this
|
||
is if network interfaces are added after boot, they come and go. This
|
||
can result in already configured interfaces unexpectedly disappearing.
|
||
|
||
This has been easy to provoke with the restool interface added, and a
|
||
script which adds network interfaces one after each other; the kernel
|
||
rescanning runs asynchronously to restool.
|
||
|
||
NXP's approach to fixing this was to introduce a sysfs "attribute" in
|
||
their vendor tree, /sys/bus/fsl-mc/rescan, which userspace poked at to
|
||
request the kernel to rescan the DPRC object tree each time the
|
||
"restool" command completed (whether or not the tool changed anything.)
|
||
This has the effect of making the kernel's rescan synchronous with a
|
||
scripted restool, but still fails if we have multiple restools running
|
||
concurrently.
|
||
|
||
This patch takes a different approach:
|
||
- Read the number of DPRC objects
|
||
- Iterate over this number of objects retrieving their details
|
||
- Re-read the number of DPRC objects
|
||
- If the number of DPRC objects has changed while reading, repeat.
|
||
|
||
This solves the issue where network interfaces unexpectedly disappear
|
||
while adding others via ls-addni, because they've fallen off the end
|
||
of the object list.
|
||
|
||
This does *not* solve the issue that if an object is deleted while
|
||
another is added while we are reading the objects - that requires
|
||
firmware modification, or a more elaborate solution on the Linux side
|
||
(e.g., CRCing the object details and reading all objects at least
|
||
twice to check the CRC is stable.)
|
||
|
||
However, without firmware modification, this is probably the best way
|
||
to ensure that we read all the objects.
|
||
|
||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||
---
|
||
drivers/bus/fsl-mc/dprc-driver.c | 32 +++++++++++++++++++++++++++++---
|
||
1 file changed, 29 insertions(+), 3 deletions(-)
|
||
|
||
diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c
|
||
index 315e830b6ecd..2268869bf6ab 100644
|
||
--- a/drivers/bus/fsl-mc/dprc-driver.c
|
||
+++ b/drivers/bus/fsl-mc/dprc-driver.c
|
||
@@ -240,11 +240,11 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
|
||
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||
bool alloc_interrupts)
|
||
{
|
||
- int num_child_objects;
|
||
+ int num_child_objects, num_child_objects2;
|
||
int dprc_get_obj_failures;
|
||
int error;
|
||
- unsigned int irq_count = mc_bus_dev->obj_desc.irq_count;
|
||
- struct fsl_mc_obj_desc *child_obj_desc_array = NULL;
|
||
+ unsigned int irq_count;
|
||
+ struct fsl_mc_obj_desc *child_obj_desc_array;
|
||
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
|
||
|
||
error = dprc_get_obj_count(mc_bus_dev->mc_io,
|
||
@@ -257,6 +257,9 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||
return error;
|
||
}
|
||
|
||
+retry:
|
||
+ irq_count = mc_bus_dev->obj_desc.irq_count;
|
||
+ child_obj_desc_array = NULL;
|
||
if (num_child_objects != 0) {
|
||
int i;
|
||
|
||
@@ -315,6 +318,29 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||
}
|
||
}
|
||
|
||
+ error = dprc_get_obj_count(mc_bus_dev->mc_io,
|
||
+ 0,
|
||
+ mc_bus_dev->mc_handle,
|
||
+ &num_child_objects2);
|
||
+ if (error < 0) {
|
||
+ if (child_obj_desc_array)
|
||
+ devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
|
||
+ dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n",
|
||
+ error);
|
||
+ return error;
|
||
+ }
|
||
+
|
||
+ if (num_child_objects != num_child_objects2) {
|
||
+ /*
|
||
+ * Something changed while reading the number of objects.
|
||
+ * Retry reading the child object list.
|
||
+ */
|
||
+ if (child_obj_desc_array)
|
||
+ devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
|
||
+ num_child_objects = num_child_objects2;
|
||
+ goto retry;
|
||
+ }
|
||
+
|
||
/*
|
||
* Allocate IRQ's before binding the scanned devices with their
|
||
* respective drivers.
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||
Date: Fri, 24 Jan 2020 17:59:49 +0000
|
||
Subject: [PATCH 16/19] iommu: silence iommu group prints
|
||
|
||
On the LX2160A, there are lots (about 160) of IOMMU messages produced
|
||
during boot; this is excessive. Reduce the severity of these messages
|
||
to debug level.
|
||
|
||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||
---
|
||
drivers/iommu/iommu.c | 4 ++--
|
||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||
|
||
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
|
||
index 7f409e9eea4b..2dc9592ff309 100644
|
||
--- a/drivers/iommu/iommu.c
|
||
+++ b/drivers/iommu/iommu.c
|
||
@@ -905,7 +905,7 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
|
||
|
||
trace_add_device_to_group(group->id, dev);
|
||
|
||
- dev_info(dev, "Adding to iommu group %d\n", group->id);
|
||
+ dev_dbg(dev, "Adding to iommu group %d\n", group->id);
|
||
|
||
return 0;
|
||
|
||
@@ -942,7 +942,7 @@ void iommu_group_remove_device(struct device *dev)
|
||
if (!group)
|
||
return;
|
||
|
||
- dev_info(dev, "Removing from iommu group %d\n", group->id);
|
||
+ dev_dbg(dev, "Removing from iommu group %d\n", group->id);
|
||
|
||
/* Pre-notify listeners that a device is being removed. */
|
||
blocking_notifier_call_chain(&group->notifier,
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Diana Craciun <diana.craciun@oss.nxp.com>
|
||
Date: Wed, 22 Sep 2021 14:05:29 +0300
|
||
Subject: [PATCH 17/19] bus/fsl-mc: Add generic implementation for
|
||
open/reset/close commands
|
||
|
||
The open/reset/close commands format is similar for all objects.
|
||
Currently there are multiple implementations for these commands
|
||
scattered through various drivers. The code is cavsi-identical.
|
||
Create a generic implementation for the open/reset/close commands.
|
||
One of the consumer will be the VFIO driver which needs to
|
||
be able to reset a device.
|
||
|
||
Signed-off-by: Diana Craciun <diana.craciun@oss.nxp.com>
|
||
Reviewed-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
|
||
Link: https://lore.kernel.org/r/20210922110530.24736-1-diana.craciun@oss.nxp.com
|
||
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
||
---
|
||
drivers/bus/fsl-mc/Makefile | 3 +-
|
||
drivers/bus/fsl-mc/fsl-mc-private.h | 39 +++++++++--
|
||
drivers/bus/fsl-mc/obj-api.c | 103 ++++++++++++++++++++++++++++
|
||
include/linux/fsl/mc.h | 14 ++++
|
||
4 files changed, 154 insertions(+), 5 deletions(-)
|
||
create mode 100644 drivers/bus/fsl-mc/obj-api.c
|
||
|
||
diff --git a/drivers/bus/fsl-mc/Makefile b/drivers/bus/fsl-mc/Makefile
|
||
index 4ae292a30e53..892946245527 100644
|
||
--- a/drivers/bus/fsl-mc/Makefile
|
||
+++ b/drivers/bus/fsl-mc/Makefile
|
||
@@ -15,7 +15,8 @@ mc-bus-driver-objs := fsl-mc-bus.o \
|
||
dprc-driver.o \
|
||
fsl-mc-allocator.o \
|
||
fsl-mc-msi.o \
|
||
- dpmcp.o
|
||
+ dpmcp.o \
|
||
+ obj-api.o
|
||
|
||
# MC userspace support
|
||
obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
|
||
diff --git a/drivers/bus/fsl-mc/fsl-mc-private.h b/drivers/bus/fsl-mc/fsl-mc-private.h
|
||
index 1958fa065360..b3520ea1b9f4 100644
|
||
--- a/drivers/bus/fsl-mc/fsl-mc-private.h
|
||
+++ b/drivers/bus/fsl-mc/fsl-mc-private.h
|
||
@@ -48,7 +48,6 @@ struct dpmng_rsp_get_version {
|
||
|
||
/* DPMCP command IDs */
|
||
#define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800)
|
||
-#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b)
|
||
#define DPMCP_CMDID_RESET DPMCP_CMD(0x005)
|
||
|
||
struct dpmcp_cmd_open {
|
||
@@ -91,7 +90,6 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
|
||
|
||
/* DPRC command IDs */
|
||
#define DPRC_CMDID_CLOSE DPRC_CMD(0x800)
|
||
-#define DPRC_CMDID_OPEN DPRC_CMD(0x805)
|
||
#define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05)
|
||
|
||
#define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004)
|
||
@@ -453,7 +451,6 @@ int dprc_get_connection(struct fsl_mc_io *mc_io,
|
||
|
||
/* Command IDs */
|
||
#define DPBP_CMDID_CLOSE DPBP_CMD(0x800)
|
||
-#define DPBP_CMDID_OPEN DPBP_CMD(0x804)
|
||
|
||
#define DPBP_CMDID_ENABLE DPBP_CMD(0x002)
|
||
#define DPBP_CMDID_DISABLE DPBP_CMD(0x003)
|
||
@@ -492,7 +489,6 @@ struct dpbp_rsp_get_attributes {
|
||
|
||
/* Command IDs */
|
||
#define DPCON_CMDID_CLOSE DPCON_CMD(0x800)
|
||
-#define DPCON_CMDID_OPEN DPCON_CMD(0x808)
|
||
|
||
#define DPCON_CMDID_ENABLE DPCON_CMD(0x002)
|
||
#define DPCON_CMDID_DISABLE DPCON_CMD(0x003)
|
||
@@ -524,6 +520,41 @@ struct dpcon_cmd_set_notification {
|
||
__le64 user_ctx;
|
||
};
|
||
|
||
+/*
|
||
+ * Generic FSL MC API
|
||
+ */
|
||
+
|
||
+/* generic command versioning */
|
||
+#define OBJ_CMD_BASE_VERSION 1
|
||
+#define OBJ_CMD_ID_OFFSET 4
|
||
+
|
||
+#define OBJ_CMD(id) (((id) << OBJ_CMD_ID_OFFSET) | OBJ_CMD_BASE_VERSION)
|
||
+
|
||
+/* open command codes */
|
||
+#define DPRTC_CMDID_OPEN OBJ_CMD(0x810)
|
||
+#define DPNI_CMDID_OPEN OBJ_CMD(0x801)
|
||
+#define DPSW_CMDID_OPEN OBJ_CMD(0x802)
|
||
+#define DPIO_CMDID_OPEN OBJ_CMD(0x803)
|
||
+#define DPBP_CMDID_OPEN OBJ_CMD(0x804)
|
||
+#define DPRC_CMDID_OPEN OBJ_CMD(0x805)
|
||
+#define DPDMUX_CMDID_OPEN OBJ_CMD(0x806)
|
||
+#define DPCI_CMDID_OPEN OBJ_CMD(0x807)
|
||
+#define DPCON_CMDID_OPEN OBJ_CMD(0x808)
|
||
+#define DPSECI_CMDID_OPEN OBJ_CMD(0x809)
|
||
+#define DPAIOP_CMDID_OPEN OBJ_CMD(0x80a)
|
||
+#define DPMCP_CMDID_OPEN OBJ_CMD(0x80b)
|
||
+#define DPMAC_CMDID_OPEN OBJ_CMD(0x80c)
|
||
+#define DPDCEI_CMDID_OPEN OBJ_CMD(0x80d)
|
||
+#define DPDMAI_CMDID_OPEN OBJ_CMD(0x80e)
|
||
+#define DPDBG_CMDID_OPEN OBJ_CMD(0x80f)
|
||
+
|
||
+/* Generic object command IDs */
|
||
+#define OBJ_CMDID_CLOSE OBJ_CMD(0x800)
|
||
+#define OBJ_CMDID_RESET OBJ_CMD(0x005)
|
||
+
|
||
+struct fsl_mc_obj_cmd_open {
|
||
+ __le32 obj_id;
|
||
+};
|
||
|
||
/**
|
||
* struct fsl_mc_resource_pool - Pool of MC resources of a given
|
||
diff --git a/drivers/bus/fsl-mc/obj-api.c b/drivers/bus/fsl-mc/obj-api.c
|
||
new file mode 100644
|
||
index 000000000000..06c1dd84e38d
|
||
--- /dev/null
|
||
+++ b/drivers/bus/fsl-mc/obj-api.c
|
||
@@ -0,0 +1,103 @@
|
||
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||
+/*
|
||
+ * Copyright 2021 NXP
|
||
+ *
|
||
+ */
|
||
+#include <linux/kernel.h>
|
||
+#include <linux/fsl/mc.h>
|
||
+
|
||
+#include "fsl-mc-private.h"
|
||
+
|
||
+static int fsl_mc_get_open_cmd_id(const char *type)
|
||
+{
|
||
+ static const struct {
|
||
+ int cmd_id;
|
||
+ const char *type;
|
||
+ } dev_ids[] = {
|
||
+ { DPRTC_CMDID_OPEN, "dprtc" },
|
||
+ { DPRC_CMDID_OPEN, "dprc" },
|
||
+ { DPNI_CMDID_OPEN, "dpni" },
|
||
+ { DPIO_CMDID_OPEN, "dpio" },
|
||
+ { DPSW_CMDID_OPEN, "dpsw" },
|
||
+ { DPBP_CMDID_OPEN, "dpbp" },
|
||
+ { DPCON_CMDID_OPEN, "dpcon" },
|
||
+ { DPMCP_CMDID_OPEN, "dpmcp" },
|
||
+ { DPMAC_CMDID_OPEN, "dpmac" },
|
||
+ { DPSECI_CMDID_OPEN, "dpseci" },
|
||
+ { DPDMUX_CMDID_OPEN, "dpdmux" },
|
||
+ { DPDCEI_CMDID_OPEN, "dpdcei" },
|
||
+ { DPAIOP_CMDID_OPEN, "dpaiop" },
|
||
+ { DPCI_CMDID_OPEN, "dpci" },
|
||
+ { DPDMAI_CMDID_OPEN, "dpdmai" },
|
||
+ { DPDBG_CMDID_OPEN, "dpdbg" },
|
||
+ { 0, NULL }
|
||
+ };
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; dev_ids[i].type; i++)
|
||
+ if (!strcmp(dev_ids[i].type, type))
|
||
+ return dev_ids[i].cmd_id;
|
||
+
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+int fsl_mc_obj_open(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ int obj_id,
|
||
+ char *obj_type,
|
||
+ u16 *token)
|
||
+{
|
||
+ struct fsl_mc_command cmd = { 0 };
|
||
+ struct fsl_mc_obj_cmd_open *cmd_params;
|
||
+ int err = 0;
|
||
+ int cmd_id = fsl_mc_get_open_cmd_id(obj_type);
|
||
+
|
||
+ if (cmd_id == -1)
|
||
+ return -ENODEV;
|
||
+
|
||
+ /* prepare command */
|
||
+ cmd.header = mc_encode_cmd_header(cmd_id, cmd_flags, 0);
|
||
+ cmd_params = (struct fsl_mc_obj_cmd_open *)cmd.params;
|
||
+ cmd_params->obj_id = cpu_to_le32(obj_id);
|
||
+
|
||
+ /* send command to mc*/
|
||
+ err = mc_send_command(mc_io, &cmd);
|
||
+ if (err)
|
||
+ return err;
|
||
+
|
||
+ /* retrieve response parameters */
|
||
+ *token = mc_cmd_hdr_read_token(&cmd);
|
||
+
|
||
+ return err;
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(fsl_mc_obj_open);
|
||
+
|
||
+int fsl_mc_obj_close(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ u16 token)
|
||
+{
|
||
+ struct fsl_mc_command cmd = { 0 };
|
||
+
|
||
+ /* prepare command */
|
||
+ cmd.header = mc_encode_cmd_header(OBJ_CMDID_CLOSE, cmd_flags,
|
||
+ token);
|
||
+
|
||
+ /* send command to mc*/
|
||
+ return mc_send_command(mc_io, &cmd);
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(fsl_mc_obj_close);
|
||
+
|
||
+int fsl_mc_obj_reset(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ u16 token)
|
||
+{
|
||
+ struct fsl_mc_command cmd = { 0 };
|
||
+
|
||
+ /* prepare command */
|
||
+ cmd.header = mc_encode_cmd_header(OBJ_CMDID_RESET, cmd_flags,
|
||
+ token);
|
||
+
|
||
+ /* send command to mc*/
|
||
+ return mc_send_command(mc_io, &cmd);
|
||
+}
|
||
+EXPORT_SYMBOL_GPL(fsl_mc_obj_reset);
|
||
diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h
|
||
index 30ece3ae6df7..e026f6c48b49 100644
|
||
--- a/include/linux/fsl/mc.h
|
||
+++ b/include/linux/fsl/mc.h
|
||
@@ -620,6 +620,20 @@ int dpcon_reset(struct fsl_mc_io *mc_io,
|
||
u32 cmd_flags,
|
||
u16 token);
|
||
|
||
+int fsl_mc_obj_open(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ int obj_id,
|
||
+ char *obj_type,
|
||
+ u16 *token);
|
||
+
|
||
+int fsl_mc_obj_close(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ u16 token);
|
||
+
|
||
+int fsl_mc_obj_reset(struct fsl_mc_io *mc_io,
|
||
+ u32 cmd_flags,
|
||
+ u16 token);
|
||
+
|
||
/**
|
||
* struct dpcon_attr - Structure representing DPCON attributes
|
||
* @id: DPCON object ID
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Diana Craciun <diana.craciun@oss.nxp.com>
|
||
Date: Wed, 22 Sep 2021 14:05:30 +0300
|
||
Subject: [PATCH 18/19] vfio/fsl-mc: Add per device reset support
|
||
|
||
Currently when a fsl-mc device is reset, the entire DPRC container
|
||
is reset which is very inefficient because the devices within a
|
||
container will be reset multiple times.
|
||
Add support for individually resetting a device.
|
||
|
||
Signed-off-by: Diana Craciun <diana.craciun@oss.nxp.com>
|
||
Reviewed-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
|
||
Link: https://lore.kernel.org/r/20210922110530.24736-2-diana.craciun@oss.nxp.com
|
||
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
||
---
|
||
drivers/vfio/fsl-mc/vfio_fsl_mc.c | 45 ++++++++++++++++++++-----------
|
||
1 file changed, 30 insertions(+), 15 deletions(-)
|
||
|
||
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
|
||
index 0ead91bfa838..6d7b2d2571a2 100644
|
||
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
|
||
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
|
||
@@ -65,6 +65,34 @@ static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
|
||
kfree(vdev->regions);
|
||
}
|
||
|
||
+static int vfio_fsl_mc_reset_device(struct vfio_fsl_mc_device *vdev)
|
||
+{
|
||
+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
|
||
+ int ret = 0;
|
||
+
|
||
+ if (is_fsl_mc_bus_dprc(vdev->mc_dev)) {
|
||
+ return dprc_reset_container(mc_dev->mc_io, 0,
|
||
+ mc_dev->mc_handle,
|
||
+ mc_dev->obj_desc.id,
|
||
+ DPRC_RESET_OPTION_NON_RECURSIVE);
|
||
+ } else {
|
||
+ u16 token;
|
||
+
|
||
+ ret = fsl_mc_obj_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
|
||
+ mc_dev->obj_desc.type,
|
||
+ &token);
|
||
+ if (ret)
|
||
+ goto out;
|
||
+ ret = fsl_mc_obj_reset(mc_dev->mc_io, 0, token);
|
||
+ if (ret) {
|
||
+ fsl_mc_obj_close(mc_dev->mc_io, 0, token);
|
||
+ goto out;
|
||
+ }
|
||
+ ret = fsl_mc_obj_close(mc_dev->mc_io, 0, token);
|
||
+ }
|
||
+out:
|
||
+ return ret;
|
||
+}
|
||
|
||
static void vfio_fsl_mc_close_device(struct vfio_device *core_vdev)
|
||
{
|
||
@@ -78,9 +106,7 @@ static void vfio_fsl_mc_close_device(struct vfio_device *core_vdev)
|
||
vfio_fsl_mc_regions_cleanup(vdev);
|
||
|
||
/* reset the device before cleaning up the interrupts */
|
||
- ret = dprc_reset_container(mc_cont->mc_io, 0, mc_cont->mc_handle,
|
||
- mc_cont->obj_desc.id,
|
||
- DPRC_RESET_OPTION_NON_RECURSIVE);
|
||
+ ret = vfio_fsl_mc_reset_device(vdev);
|
||
|
||
if (WARN_ON(ret))
|
||
dev_warn(&mc_cont->dev,
|
||
@@ -203,18 +229,7 @@ static long vfio_fsl_mc_ioctl(struct vfio_device *core_vdev,
|
||
}
|
||
case VFIO_DEVICE_RESET:
|
||
{
|
||
- int ret;
|
||
- struct fsl_mc_device *mc_dev = vdev->mc_dev;
|
||
-
|
||
- /* reset is supported only for the DPRC */
|
||
- if (!is_fsl_mc_bus_dprc(mc_dev))
|
||
- return -ENOTTY;
|
||
-
|
||
- ret = dprc_reset_container(mc_dev->mc_io, 0,
|
||
- mc_dev->mc_handle,
|
||
- mc_dev->obj_desc.id,
|
||
- DPRC_RESET_OPTION_NON_RECURSIVE);
|
||
- return ret;
|
||
+ return vfio_fsl_mc_reset_device(vdev);
|
||
|
||
}
|
||
default:
|
||
--
|
||
2.18.4
|
||
|
||
|
||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Jon Nettleton <jon@solid-run.com>
|
||
Date: Mon, 20 Dec 2021 12:49:27 +0100
|
||
Subject: [PATCH 19/19] bus: fsl-mc: list more commands as accepted through the
|
||
ioctl
|
||
|
||
This adds the commands needed to use the DCE engine from
|
||
userspace. It includes the generic reset,enable,disable as
|
||
well as DPDCEI_* ioctls.
|
||
|
||
Signed-off-by: Jon Nettleton <jon@solid-run.com>
|
||
---
|
||
drivers/bus/fsl-mc/fsl-mc-uapi.c | 42 ++++++++++++++++++++++++++++++++
|
||
1 file changed, 42 insertions(+)
|
||
|
||
diff --git a/drivers/bus/fsl-mc/fsl-mc-uapi.c b/drivers/bus/fsl-mc/fsl-mc-uapi.c
|
||
index 9c4c1395fcdb..0b8733f0f189 100644
|
||
--- a/drivers/bus/fsl-mc/fsl-mc-uapi.c
|
||
+++ b/drivers/bus/fsl-mc/fsl-mc-uapi.c
|
||
@@ -61,6 +61,9 @@ enum fsl_mc_cmd_index {
|
||
DPNI_GET_STATISTICS,
|
||
DPNI_GET_LINK_STATE,
|
||
DPNI_GET_MAX_FRAME_LENGTH,
|
||
+ DPDCEI_CMDID_SET_RX_QUEUE,
|
||
+ DPDCEI_CMDID_GET_RX_QUEUE,
|
||
+ DPDCEI_CMDID_GET_TX_QUEUE,
|
||
DPSW_GET_TAILDROP,
|
||
DPSW_SET_TAILDROP,
|
||
DPSW_IF_GET_COUNTER,
|
||
@@ -71,6 +74,9 @@ enum fsl_mc_cmd_index {
|
||
GET_IRQ_MASK,
|
||
GET_IRQ_STATUS,
|
||
CLOSE,
|
||
+ RESET,
|
||
+ ENABLE,
|
||
+ DISABLE,
|
||
OPEN,
|
||
GET_API_VERSION,
|
||
DESTROY,
|
||
@@ -311,6 +317,24 @@ static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
|
||
.token = true,
|
||
.size = 10,
|
||
},
|
||
+ [DPDCEI_CMDID_SET_RX_QUEUE] = {
|
||
+ .cmdid_value = 0x1b00,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
+ [DPDCEI_CMDID_GET_RX_QUEUE] = {
|
||
+ .cmdid_value = 0x1b10,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
+ [DPDCEI_CMDID_GET_TX_QUEUE] = {
|
||
+ .cmdid_value = 0x1b20,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
[GET_ATTR] = {
|
||
.cmdid_value = 0x0040,
|
||
.cmdid_mask = 0xFFF0,
|
||
@@ -335,6 +359,24 @@ static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
|
||
.token = true,
|
||
.size = 8,
|
||
},
|
||
+ [RESET] = {
|
||
+ .cmdid_value = 0x0050,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
+ [ENABLE] = {
|
||
+ .cmdid_value = 0x0020,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
+ [DISABLE] = {
|
||
+ .cmdid_value = 0x0030,
|
||
+ .cmdid_mask = 0xFFF0,
|
||
+ .token = true,
|
||
+ .size = 8,
|
||
+ },
|
||
|
||
/* Common commands amongst all types of objects. Must be checked last. */
|
||
[OPEN] = {
|
||
--
|
||
2.18.4
|
||
|