@@ -127,6 +127,7 @@ struct ipmmu_vmsa_device {
spinlock_t lock; /* Protects ctx and domains[] */
DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];
+ unsigned int utlb_refcount[IPMMU_UTLB_MAX];
const struct ipmmu_features *features;
};
@@ -468,12 +469,17 @@ static int ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
}
/*
- * TODO: Reference-count the micro-TLB as several bus masters can be
- * connected to the same micro-TLB.
+ * Reference-count the micro-TLBs as several bus masters can be connected
+ * to the same micro-TLB. The platform devices get assigned/deassigned
+ * together during domain creation/destruction. The PCI devices which use
+ * the same micro-TLB must also be hot-(un)plugged together.
*/
- ipmmu_imuasid_write(mmu, utlb, 0);
- ipmmu_imuctr_write(mmu, utlb, imuctr |
- IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_MMUEN);
+ if ( mmu->utlb_refcount[utlb]++ == 0 )
+ {
+ ipmmu_imuasid_write(mmu, utlb, 0);
+ ipmmu_imuctr_write(mmu, utlb, imuctr |
+ IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_MMUEN);
+ }
return 0;
}
@@ -484,7 +490,10 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
{
struct ipmmu_vmsa_device *mmu = domain->mmu;
- ipmmu_imuctr_write(mmu, utlb, 0);
+ ASSERT(mmu->utlb_refcount[utlb] > 0);
+
+ if ( --mmu->utlb_refcount[utlb] == 0 )
+ ipmmu_imuctr_write(mmu, utlb, 0);
}
/* Domain/Context Management */