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.39.0
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.39.0
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.39.0
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.39.0
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 e7da4a47ce52..4a8c2f5158ea 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.39.0
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 4a8c2f5158ea..ce47559cfca7 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;
}
@@ -3075,7 +3084,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.39.0
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 ce47559cfca7..dbddb5ea2321 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3791,6 +3791,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;
@@ -3874,6 +3902,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.39.0
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.39.0
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.39.0
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.39.0
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 0b2c7fdbaa5b..35b74bf4b65c 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.39.0
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 04a37fd137ee..af25ec17801b 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;
@@ -1371,29 +1380,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);
@@ -1426,7 +1441,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
@@ -1511,6 +1526,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.39.0
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 af25ec17801b..94ec80e8f9a1 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.39.0
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.39.0
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.39.0
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.39.0
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.39.0
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.39.0
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.39.0