Skip to content

Commit 8bf4781

Browse files
committed
iommu/vt-d: Split up iommu->domains array
This array is indexed by the domain-id and contains the pointers to the domains attached to this iommu. Modern systems support 65536 domain ids, so that this array has a size of 512kb, per iommu. This is a huge waste of space, as the array is usually sparsely populated. This patch makes the array two-dimensional and allocates the memory for the domain pointers on-demand. Signed-off-by: Joerg Roedel <[email protected]>
1 parent 9452d5b commit 8bf4781

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

drivers/iommu/intel-iommu.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -571,13 +571,32 @@ static struct kmem_cache *iommu_devinfo_cache;
571571

572572
static struct dmar_domain* get_iommu_domain(struct intel_iommu *iommu, u16 did)
573573
{
574-
return iommu->domains[did];
574+
struct dmar_domain **domains;
575+
int idx = did >> 8;
576+
577+
domains = iommu->domains[idx];
578+
if (!domains)
579+
return NULL;
580+
581+
return domains[did & 0xff];
575582
}
576583

577584
static void set_iommu_domain(struct intel_iommu *iommu, u16 did,
578585
struct dmar_domain *domain)
579586
{
580-
iommu->domains[did] = domain;
587+
struct dmar_domain **domains;
588+
int idx = did >> 8;
589+
590+
if (!iommu->domains[idx]) {
591+
size_t size = 256 * sizeof(struct dmar_domain *);
592+
iommu->domains[idx] = kzalloc(size, GFP_ATOMIC);
593+
}
594+
595+
domains = iommu->domains[idx];
596+
if (WARN_ON(!domains))
597+
return;
598+
else
599+
domains[did & 0xff] = domain;
581600
}
582601

583602
static inline void *alloc_pgtable_page(int node)
@@ -1530,35 +1549,43 @@ static void iommu_disable_translation(struct intel_iommu *iommu)
15301549

15311550
static int iommu_init_domains(struct intel_iommu *iommu)
15321551
{
1533-
unsigned long ndomains;
1534-
unsigned long nlongs;
1552+
u32 ndomains, nlongs;
1553+
size_t size;
15351554

15361555
ndomains = cap_ndoms(iommu->cap);
1537-
pr_debug("%s: Number of Domains supported <%ld>\n",
1556+
pr_debug("%s: Number of Domains supported <%d>\n",
15381557
iommu->name, ndomains);
15391558
nlongs = BITS_TO_LONGS(ndomains);
15401559

15411560
spin_lock_init(&iommu->lock);
15421561

1543-
/* TBD: there might be 64K domains,
1544-
* consider other allocation for future chip
1545-
*/
15461562
iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
15471563
if (!iommu->domain_ids) {
15481564
pr_err("%s: Allocating domain id array failed\n",
15491565
iommu->name);
15501566
return -ENOMEM;
15511567
}
1552-
iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
1553-
GFP_KERNEL);
1554-
if (!iommu->domains) {
1568+
1569+
size = ((ndomains >> 8) + 1) * sizeof(struct dmar_domain **);
1570+
iommu->domains = kzalloc(size, GFP_KERNEL);
1571+
1572+
if (iommu->domains) {
1573+
size = 256 * sizeof(struct dmar_domain *);
1574+
iommu->domains[0] = kzalloc(size, GFP_KERNEL);
1575+
}
1576+
1577+
if (!iommu->domains || !iommu->domains[0]) {
15551578
pr_err("%s: Allocating domain array failed\n",
15561579
iommu->name);
15571580
kfree(iommu->domain_ids);
1581+
kfree(iommu->domains);
15581582
iommu->domain_ids = NULL;
1583+
iommu->domains = NULL;
15591584
return -ENOMEM;
15601585
}
15611586

1587+
1588+
15621589
/*
15631590
* If Caching mode is set, then invalid translations are tagged
15641591
* with domain-id 0, hence we need to pre-allocate it. We also
@@ -1600,6 +1627,11 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
16001627
static void free_dmar_iommu(struct intel_iommu *iommu)
16011628
{
16021629
if ((iommu->domains) && (iommu->domain_ids)) {
1630+
int elems = (cap_ndoms(iommu->cap) >> 8) + 1;
1631+
int i;
1632+
1633+
for (i = 0; i < elems; i++)
1634+
kfree(iommu->domains[i]);
16031635
kfree(iommu->domains);
16041636
kfree(iommu->domain_ids);
16051637
iommu->domains = NULL;

include/linux/intel-iommu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ struct intel_iommu {
344344

345345
#ifdef CONFIG_INTEL_IOMMU
346346
unsigned long *domain_ids; /* bitmap of domains */
347-
struct dmar_domain **domains; /* ptr to domains */
347+
struct dmar_domain ***domains; /* ptr to domains */
348348
spinlock_t lock; /* protect context, domain ids */
349349
struct root_entry *root_entry; /* virtual address */
350350

0 commit comments

Comments
 (0)