#include "dmar.h"
#include "iommu.h"
#include "extern.h"
+#include "vtd.h"
#undef PREFIX
#define PREFIX VTDPREFIX "ACPI DMAR:"
struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
void *dev_scope_start, *dev_scope_end;
struct acpi_drhd_unit *dmaru;
- void *addr;
int ret;
static int include_all = 0;
dprintk(VTDPREFIX, " dmaru->address = %"PRIx64"\n",
dmaru->address);
- addr = map_to_nocache_virt(0, drhd->address);
- dmaru->ecap = dmar_readq(addr, DMAR_ECAP_REG);
+ ret = iommu_alloc(dmaru);
+ if ( ret )
+ goto out;
dev_scope_start = (void *)(drhd + 1);
dev_scope_end = ((void *)drhd) + header->length;
}
if ( ret )
- xfree(dmaru);
+ goto out;
else if ( force_iommu || dmaru->include_all )
acpi_register_drhd_unit(dmaru);
else
if ( invalid_cnt )
{
- xfree(dmaru);
-
if ( iommu_workaround_bios_bug &&
invalid_cnt == dmaru->scope.devices_cnt )
{
dprintk(XENLOG_WARNING VTDPREFIX,
" Workaround BIOS bug: ignore the DRHD due to all "
"devices under its scope are not PCI discoverable!\n");
+
+ iommu_free(dmaru);
+ xfree(dmaru);
}
else
{
acpi_register_drhd_unit(dmaru);
}
+out:
+ if ( ret )
+ {
+ iommu_free(dmaru);
+ xfree(dmaru);
+ }
return ret;
}
struct dmar_scope scope; /* must be first member of struct */
struct list_head list;
u64 address; /* register base address of the unit */
- u64 ecap;
u8 include_all:1;
struct iommu *iommu;
struct list_head ioapic_list;
/* We MUST have a DRHD unit for each IOAPIC. */
for ( apic = 0; apic < nr_ioapics; apic++ )
if ( !ioapic_to_drhd(IO_APIC_ID(apic)) )
+ {
+ dprintk(XENLOG_WARNING VTDPREFIX,
+ "There is not a DRHD for IOAPIC 0x%x (id: 0x%x)!\n",
+ apic, IO_APIC_ID(apic));
return 0;
+ }
if ( list_empty(&acpi_drhd_units) )
return 0;
for_each_drhd_unit ( drhd )
- if ( !ecap_queued_inval(drhd->ecap) ||
- !ecap_intr_remap(drhd->ecap) ||
- !ecap_eim(drhd->ecap) )
+ if ( !ecap_queued_inval(drhd->iommu->ecap) ||
+ !ecap_intr_remap(drhd->iommu->ecap) ||
+ !ecap_eim(drhd->iommu->ecap) )
return 0;
return 1;
return iommu ? &iommu->intel->flush : NULL;
}
-static unsigned int clflush_size;
static int iommus_incoherent;
static void __iommu_flush_cache(void *addr, unsigned int size)
{
int i;
+ static unsigned int clflush_size = 0;
if ( !iommus_incoherent )
return;
+ if ( clflush_size == 0 )
+ clflush_size = get_cache_line_size();
+
for ( i = 0; i < size; i += clflush_size )
cacheline_flush((char *)addr + i);
}
return irq;
}
-static int __init iommu_alloc(struct acpi_drhd_unit *drhd)
+int __init iommu_alloc(struct acpi_drhd_unit *drhd)
{
struct iommu *iommu;
unsigned long sagaw, nr_dom;
return 0;
}
-static void __init iommu_free(struct acpi_drhd_unit *drhd)
+void __init iommu_free(struct acpi_drhd_unit *drhd)
{
struct iommu *iommu = drhd->iommu;
platform_quirks();
- clflush_size = get_cache_line_size();
-
irq_to_iommu = xmalloc_array(struct iommu*, nr_irqs);
BUG_ON(!irq_to_iommu);
memset(irq_to_iommu, 0, nr_irqs * sizeof(struct iommu*));
*/
for_each_drhd_unit ( drhd )
{
- if ( iommu_alloc(drhd) != 0 )
- goto error;
-
iommu = drhd->iommu;
if ( iommu_snoop && !ecap_snp_ctl(iommu->ecap) )
return 0;
error:
- for_each_drhd_unit ( drhd )
- iommu_free(drhd);
iommu_enabled = 0;
iommu_snoop = 0;
iommu_passthrough = 0;
void iommu_flush_cache_entry(void *addr, unsigned int size);
void iommu_flush_cache_page(void *addr, unsigned long npages);
+int iommu_alloc(struct acpi_drhd_unit *drhd);
+void iommu_free(struct acpi_drhd_unit *drhd);
+
#endif // _VTD_H_