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: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20220706113825.25582-5-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Suravee Suthikulpanit 2022-07-06 17:07:54 +05:30 committed by Joerg Roedel
parent 04230c1199
commit eda797a277
4 changed files with 79 additions and 0 deletions

View File

@ -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);

View File

@ -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;
};
/*

View File

@ -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);
}

View File

@ -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);