Previously, the configuration cache was keyed only by the SMMU device (sdev). This is insufficient for a model where a single device can issue both secure and non-secure transactions, as it could lead to cache lookups returning the wrong configuration (e.g., a secure transaction hitting a non-secure cache entry).
This commit refactors the configuration cache management. The cache key is now a composite of the device and its security state (SMMUDevice *sdev, bool is_secure). This ensures that lookups correctly differentiate between security states for the same physical device, guaranteeing that a transaction always retrieves the appropriate cached configuration. This is a critical step towards enabling full parallel processing of secure and non-secure streams. Signed-off-by: Tao Tang <tangtao1...@phytium.com.cn> --- hw/arm/smmu-common.c | 27 +++++++++++++++++++++++++-- hw/arm/smmuv3.c | 13 ++++++++++--- include/hw/arm/smmu-common.h | 6 ++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 0877248a88..80f94a85e7 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -37,6 +37,26 @@ void smmu_enable_secure_address_space(void) arm_secure_as_available = true; } +/* Configuration Cache Management */ +static guint smmu_config_key_hash(gconstpointer key) +{ + const SMMUConfigKey *k = key; + return g_direct_hash(k->sdev) ^ (k->is_secure ? 1 : 0); +} + +static gboolean smmu_config_key_equal(gconstpointer a, gconstpointer b) +{ + const SMMUConfigKey *ka = a; + const SMMUConfigKey *kb = b; + return ka->sdev == kb->sdev && ka->is_secure == kb->is_secure; +} + +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, bool is_secure) +{ + SMMUConfigKey key = {.sdev = sdev, .is_secure = is_secure}; + return key; +} + /* IOTLB Management */ static guint smmu_iotlb_key_hash(gconstpointer v) @@ -236,7 +256,8 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value, static gboolean smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data) { - SMMUDevice *sdev = (SMMUDevice *)key; + SMMUConfigKey *config_key = (SMMUConfigKey *)key; + SMMUDevice *sdev = config_key->sdev; uint32_t sid = smmu_get_sid(sdev); SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data; @@ -943,7 +964,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - s->configs = g_hash_table_new_full(NULL, NULL, NULL, g_free); + s->configs = g_hash_table_new_full(smmu_config_key_hash, + smmu_config_key_equal, + g_free, g_free); s->iotlb = g_hash_table_new_full(smmu_iotlb_key_hash, smmu_iotlb_key_equal, g_free, g_free); s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 5f28e27503..972cbc872f 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -953,8 +953,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event, SMMUv3State *s = sdev->smmu; SMMUState *bc = &s->smmu_state; SMMUTransCfg *cfg; + SMMUConfigKey lookup_key = smmu_get_config_key(sdev, is_secure); - cfg = g_hash_table_lookup(bc->configs, sdev); + cfg = g_hash_table_lookup(bc->configs, &lookup_key); if (cfg) { sdev->cfg_cache_hits++; trace_smmuv3_config_cache_hit(smmu_get_sid(sdev), @@ -971,7 +972,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event, cfg->secure = is_secure; if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) { - g_hash_table_insert(bc->configs, sdev, cfg); + SMMUConfigKey *persistent_key = g_new(SMMUConfigKey, 1); + *persistent_key = smmu_get_config_key(sdev, is_secure); + g_hash_table_insert(bc->configs, persistent_key, cfg); } else { g_free(cfg); cfg = NULL; @@ -984,9 +987,13 @@ static void smmuv3_flush_config(SMMUDevice *sdev) { SMMUv3State *s = sdev->smmu; SMMUState *bc = &s->smmu_state; + SMMUConfigKey key_secure = smmu_get_config_key(sdev, true); + SMMUConfigKey key_nonsecure = smmu_get_config_key(sdev, false); trace_smmu_config_cache_inv(smmu_get_sid(sdev)); - g_hash_table_remove(bc->configs, sdev); + /* Remove both secure and non-secure configurations for this device */ + g_hash_table_remove(bc->configs, &key_secure); + g_hash_table_remove(bc->configs, &key_nonsecure); } static void smmuv3_invalidate_all_caches(SMMUv3State *s) diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 597c5ef6c9..e07a9c35e7 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -156,6 +156,11 @@ typedef struct SMMUIOTLBKey { uint8_t level; } SMMUIOTLBKey; +typedef struct SMMUConfigKey { + SMMUDevice *sdev; + bool is_secure; +} SMMUConfigKey; + typedef struct SMMUSIDRange { uint32_t start; uint32_t end; @@ -230,6 +235,7 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg, void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry); SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova, uint8_t tg, uint8_t level); +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, bool is_secure); void smmu_iotlb_inv_all(SMMUState *s); void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid); void smmu_iotlb_inv_vmid(SMMUState *s, int vmid); -- 2.34.1