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_uninit_devices(void);
|
||||||
extern void amd_iommu_init_notifier(void);
|
extern void amd_iommu_init_notifier(void);
|
||||||
extern int amd_iommu_init_api(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
|
#ifdef CONFIG_AMD_IOMMU_DEBUGFS
|
||||||
void amd_iommu_debugfs_setup(struct amd_iommu *iommu);
|
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 */
|
/* kmem_cache to get tables with 128 byte alignement */
|
||||||
extern struct kmem_cache *amd_iommu_irq_cache;
|
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 */
|
/* Make iterating over all pci segment easier */
|
||||||
#define for_each_pci_segment(pci_seg) \
|
#define for_each_pci_segment(pci_seg) \
|
||||||
list_for_each_entry((pci_seg), &amd_iommu_pci_seg_list, list)
|
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 iommu_domain;
|
||||||
struct irq_domain;
|
struct irq_domain;
|
||||||
struct amd_irte_ops;
|
struct amd_irte_ops;
|
||||||
@ -554,6 +558,13 @@ struct amd_iommu_pci_seg {
|
|||||||
* page table root pointer.
|
* page table root pointer.
|
||||||
*/
|
*/
|
||||||
struct dev_table_entry *dev_table;
|
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;
|
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
|
* Allocates the command buffer. This buffer is per AMD IOMMU. We can
|
||||||
* write commands to that buffer later and the IOMMU will execute them
|
* 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))
|
if (alloc_dev_table(pci_seg))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (alloc_rlookup_table(pci_seg))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return pci_seg;
|
return pci_seg;
|
||||||
}
|
}
|
||||||
@ -1513,6 +1535,7 @@ static void __init free_pci_segments(void)
|
|||||||
|
|
||||||
for_each_pci_segment_safe(pci_seg, next) {
|
for_each_pci_segment_safe(pci_seg, next) {
|
||||||
list_del(&pci_seg->list);
|
list_del(&pci_seg->list);
|
||||||
|
free_rlookup_table(pci_seg);
|
||||||
free_dev_table(pci_seg);
|
free_dev_table(pci_seg);
|
||||||
kfree(pci_seg);
|
kfree(pci_seg);
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,50 @@ struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
|
|||||||
return dev_table;
|
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)
|
static struct protection_domain *to_pdomain(struct iommu_domain *dom)
|
||||||
{
|
{
|
||||||
return container_of(dom, struct protection_domain, domain);
|
return container_of(dom, struct protection_domain, domain);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user