Commit eda797a2 authored by Suravee Suthikulpanit's avatar Suravee Suthikulpanit Committed by Joerg Roedel
Browse files

iommu/amd: Introduce per PCI segment rlookup table



This will replace global rlookup table (amd_iommu_rlookup_table).
Add helper functions to set/get rlookup table for the given device.
Also add macros to get seg/devid from sbdf.

Co-developed-by: default avatarVasant Hegde <vasant.hegde@amd.com>
Signed-off-by: default avatarVasant Hegde <vasant.hegde@amd.com>
Signed-off-by: default avatarSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20220706113825.25582-5-vasant.hegde@amd.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 04230c11
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ extern int amd_iommu_init_devices(void);
extern void amd_iommu_uninit_devices(void);
extern void amd_iommu_init_notifier(void);
extern int amd_iommu_init_api(void);
extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);

#ifdef CONFIG_AMD_IOMMU_DEBUGFS
void amd_iommu_debugfs_setup(struct amd_iommu *iommu);
+11 −0
Original line number Diff line number Diff line
@@ -456,6 +456,9 @@ extern bool amdr_ivrs_remap_support;
/* kmem_cache to get tables with 128 byte alignement */
extern struct kmem_cache *amd_iommu_irq_cache;

#define PCI_SBDF_TO_SEGID(sbdf)		(((sbdf) >> 16) & 0xffff)
#define PCI_SBDF_TO_DEVID(sbdf)		((sbdf) & 0xffff)

/* Make iterating over all pci segment easier */
#define for_each_pci_segment(pci_seg) \
	list_for_each_entry((pci_seg), &amd_iommu_pci_seg_list, list)
@@ -490,6 +493,7 @@ struct amd_iommu_fault {
};


struct amd_iommu;
struct iommu_domain;
struct irq_domain;
struct amd_irte_ops;
@@ -554,6 +558,13 @@ struct amd_iommu_pci_seg {
	 * page table root pointer.
	 */
	struct dev_table_entry *dev_table;

	/*
	 * The rlookup iommu table is used to find the IOMMU which is
	 * responsible for a specific device. It is indexed by the PCI
	 * device id.
	 */
	struct amd_iommu **rlookup_table;
};

/*
+23 −0
Original line number Diff line number Diff line
@@ -665,6 +665,26 @@ static inline void free_dev_table(struct amd_iommu_pci_seg *pci_seg)
	pci_seg->dev_table = NULL;
}

/* Allocate per PCI segment IOMMU rlookup table. */
static inline int __init alloc_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
{
	pci_seg->rlookup_table = (void *)__get_free_pages(
						GFP_KERNEL | __GFP_ZERO,
						get_order(rlookup_table_size));
	if (pci_seg->rlookup_table == NULL)
		return -ENOMEM;

	return 0;
}

static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
{
	free_pages((unsigned long)pci_seg->rlookup_table,
		   get_order(rlookup_table_size));
	pci_seg->rlookup_table = NULL;
}


/*
 * Allocates the command buffer. This buffer is per AMD IOMMU. We can
 * write commands to that buffer later and the IOMMU will execute them
@@ -1491,6 +1511,8 @@ static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)

	if (alloc_dev_table(pci_seg))
		return NULL;
	if (alloc_rlookup_table(pci_seg))
		return NULL;

	return pci_seg;
}
@@ -1513,6 +1535,7 @@ static void __init free_pci_segments(void)

	for_each_pci_segment_safe(pci_seg, next) {
		list_del(&pci_seg->list);
		free_rlookup_table(pci_seg);
		free_dev_table(pci_seg);
		kfree(pci_seg);
	}
+44 −0
Original line number Diff line number Diff line
@@ -146,6 +146,50 @@ struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
	return dev_table;
}

static inline u16 get_device_segment(struct device *dev)
{
	u16 seg;

	if (dev_is_pci(dev)) {
		struct pci_dev *pdev = to_pci_dev(dev);

		seg = pci_domain_nr(pdev->bus);
	} else {
		u32 devid = get_acpihid_device_id(dev, NULL);

		seg = PCI_SBDF_TO_SEGID(devid);
	}

	return seg;
}

/* Writes the specific IOMMU for a device into the PCI segment rlookup table */
void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid)
{
	struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;

	pci_seg->rlookup_table[devid] = iommu;
}

static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 devid)
{
	struct amd_iommu_pci_seg *pci_seg;

	for_each_pci_segment(pci_seg) {
		if (pci_seg->id == seg)
			return pci_seg->rlookup_table[devid];
	}
	return NULL;
}

static struct amd_iommu *rlookup_amd_iommu(struct device *dev)
{
	u16 seg = get_device_segment(dev);
	u16 devid = get_device_id(dev);

	return __rlookup_amd_iommu(seg, devid);
}

static struct protection_domain *to_pdomain(struct iommu_domain *dom)
{
	return container_of(dom, struct protection_domain, domain);