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:
parent
04230c1199
commit
eda797a277
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user