mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
AMD IOMMU: cover all functions of a device even if ACPI only tells us of func 0
This ought to work as all functions of a device have the same place in the bus topology, i.e. use the same IOMMU. Also fix the type of ivrs_bdf_entries (when it's 'unsigned short' and the last device found on a segment is ff:1f.x, it would otherwise end up being zero). And drop the bogus 'last_bdf' static variable, which conflicted anyway with various functions' parameters. Signed-off-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
6420870328
commit
a90bc1471a
4 files changed
+49
-14
No files matched your search
@@ -54,8 +54,6 @@ union acpi_ivhd_device {
|
||||
struct acpi_ivrs_device8c special;
|
||||
};
|
||||
|
||||
static unsigned short __initdata last_bdf;
|
||||
|
||||
static void __init add_ivrs_mapping_entry(
|
||||
u16 bdf, u16 alias_id, u8 flags, struct amd_iommu *iommu)
|
||||
{
|
||||
@@ -991,6 +989,7 @@ static int __init get_last_bdf_ivhd(
|
||||
{
|
||||
const union acpi_ivhd_device *ivhd_device;
|
||||
u16 block_length, dev_length;
|
||||
int last_bdf = 0;
|
||||
|
||||
if ( ivhd_block->header.length < sizeof(*ivhd_block) )
|
||||
{
|
||||
@@ -1051,27 +1050,34 @@ static int __init get_last_bdf_ivhd(
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return last_bdf;
|
||||
}
|
||||
|
||||
static int __init get_last_bdf_acpi(struct acpi_table_header *table)
|
||||
{
|
||||
const struct acpi_ivrs_header *ivrs_block;
|
||||
unsigned long length = sizeof(struct acpi_table_ivrs);
|
||||
int last_bdf = 0;
|
||||
|
||||
while ( table->length > (length + sizeof(*ivrs_block)) )
|
||||
{
|
||||
ivrs_block = (struct acpi_ivrs_header *)((u8 *)table + length);
|
||||
if ( table->length < (length + ivrs_block->length) )
|
||||
return -ENODEV;
|
||||
if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE &&
|
||||
get_last_bdf_ivhd(
|
||||
if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE )
|
||||
{
|
||||
int ret = get_last_bdf_ivhd(
|
||||
container_of(ivrs_block, const struct acpi_ivrs_hardware,
|
||||
header)) != 0 )
|
||||
return -ENODEV;
|
||||
header));
|
||||
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
UPDATE_LAST_BDF(ret);
|
||||
}
|
||||
length += ivrs_block->length;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return last_bdf;
|
||||
}
|
||||
|
||||
int __init amd_iommu_detect_acpi(void)
|
||||
@@ -1081,8 +1087,9 @@ int __init amd_iommu_detect_acpi(void)
|
||||
|
||||
int __init amd_iommu_get_ivrs_dev_entries(void)
|
||||
{
|
||||
acpi_table_parse(ACPI_SIG_IVRS, get_last_bdf_acpi);
|
||||
return last_bdf + 1;
|
||||
int ret = acpi_table_parse(ACPI_SIG_IVRS, get_last_bdf_acpi);
|
||||
|
||||
return ret < 0 ? ret : (ret | PCI_FUNC(~0)) + 1;
|
||||
}
|
||||
|
||||
int __init amd_iommu_update_ivrs_mapping_acpi(void)
|
||||
|
||||
@@ -35,7 +35,7 @@ static int __initdata nr_amd_iommus;
|
||||
|
||||
static struct tasklet amd_iommu_irq_tasklet;
|
||||
|
||||
unsigned short ivrs_bdf_entries;
|
||||
unsigned int __read_mostly ivrs_bdf_entries;
|
||||
static struct radix_tree_root ivrs_maps;
|
||||
struct list_head amd_iommu_head;
|
||||
struct table_struct device_table;
|
||||
|
||||
@@ -28,12 +28,38 @@
|
||||
#include <asm/hvm/svm/amd-iommu-proto.h>
|
||||
#include "../ats.h"
|
||||
|
||||
static bool_t __read_mostly init_done;
|
||||
|
||||
struct amd_iommu *find_iommu_for_device(int seg, int bdf)
|
||||
{
|
||||
struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
|
||||
|
||||
return ivrs_mappings && bdf < ivrs_bdf_entries ? ivrs_mappings[bdf].iommu
|
||||
: NULL;
|
||||
if ( !ivrs_mappings || bdf >= ivrs_bdf_entries )
|
||||
return NULL;
|
||||
|
||||
if ( unlikely(!ivrs_mappings[bdf].iommu) && likely(init_done) )
|
||||
{
|
||||
unsigned int bd0 = bdf & ~PCI_FUNC(~0);
|
||||
|
||||
if ( ivrs_mappings[bd0].iommu )
|
||||
{
|
||||
struct ivrs_mappings tmp = ivrs_mappings[bd0];
|
||||
|
||||
tmp.iommu = NULL;
|
||||
if ( tmp.dte_requestor_id == bd0 )
|
||||
tmp.dte_requestor_id = bdf;
|
||||
ivrs_mappings[bdf] = tmp;
|
||||
|
||||
printk(XENLOG_WARNING "%04x:%02x:%02x.%u not found in ACPI tables;"
|
||||
" using same IOMMU as function 0\n",
|
||||
seg, PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf));
|
||||
|
||||
/* write iommu field last */
|
||||
ivrs_mappings[bdf].iommu = ivrs_mappings[bd0].iommu;
|
||||
}
|
||||
}
|
||||
|
||||
return ivrs_mappings[bdf].iommu;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -179,6 +205,8 @@ int __init amd_iov_detect(void)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
init_done = 1;
|
||||
|
||||
/*
|
||||
* AMD IOMMUs don't distinguish between vectors destined for
|
||||
* different cpus when doing interrupt remapping. This means
|
||||
|
||||
@@ -125,7 +125,7 @@ struct ivrs_mappings {
|
||||
u8 device_flags;
|
||||
};
|
||||
|
||||
extern unsigned short ivrs_bdf_entries;
|
||||
extern unsigned int ivrs_bdf_entries;
|
||||
|
||||
struct ivrs_mappings *get_ivrs_mappings(u16 seg);
|
||||
int iterate_ivrs_mappings(int (*)(u16 seg, struct ivrs_mappings *));
|
||||
|
||||