The AMD IOMMU must be discovered and initialized by the BIOS if present.
Signed-off-by: Eduard - Gabriel Munteanu eduard.munteanu@linux360.ro --- Makefile | 2 +- src/iommu.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/iommu.h | 12 ++++++++++ src/pci_ids.h | 1 + src/pci_regs.h | 1 + src/pciinit.c | 15 +++++++++++++ 6 files changed, 93 insertions(+), 1 deletions(-) create mode 100644 src/iommu.c create mode 100644 src/iommu.h
diff --git a/Makefile b/Makefile index 47f5625..cee286a 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ - virtio-ring.c virtio-pci.c virtio-blk.c + virtio-ring.c virtio-pci.c virtio-blk.c iommu.c SRC16=$(SRCBOTH) system.c disk.c apm.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/iommu.c b/src/iommu.c new file mode 100644 index 0000000..4ff62fc --- /dev/null +++ b/src/iommu.c @@ -0,0 +1,63 @@ +// AMD IOMMU initialization code. +// +// Copyright (C) 2010 Eduard - Gabriel Munteanu eduard.munteanu@linux360.ro +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "iommu.h" +#include "pci.h" +#include "types.h" + +#define IOMMU_CAP_BAR_LOW 0x04 +#define IOMMU_CAP_BAR_HIGH 0x08 +#define IOMMU_CAP_RANGE 0x0C +#define IOMMU_CAP_MISC 0x10 + +static int iommu_bdf = -1; +static u8 iommu_cap_offset; +static u32 iommu_base; + +void iommu_init(int bdf, u32 base) +{ + u8 ptr, cap, type; + + /* Only one IOMMU is supported. */ + if (iommu_bdf >= 0) + return; + + foreachcap(bdf, ptr, cap) { + type = pci_config_readb(bdf, cap); + if (type == PCI_CAP_ID_SEC) + break; + } + if (!cap) + return; + + pci_config_writel(bdf, cap + IOMMU_CAP_RANGE, 0); + pci_config_writel(bdf, cap + IOMMU_CAP_BAR_HIGH, 0); + pci_config_writel(bdf, cap + IOMMU_CAP_BAR_LOW, base | 1); + + iommu_bdf = bdf; + iommu_cap_offset = cap; + iommu_base = base; +} + +int iommu_get_bdf(void) +{ + return iommu_bdf; +} + +u8 iommu_get_cap_offset(void) +{ + return iommu_cap_offset; +} + +u32 iommu_get_misc(void) +{ + return pci_config_readw(iommu_bdf, iommu_cap_offset + IOMMU_CAP_MISC + 2); +} + +u32 iommu_get_base(void) +{ + return iommu_base; +} diff --git a/src/iommu.h b/src/iommu.h new file mode 100644 index 0000000..27ae2c7 --- /dev/null +++ b/src/iommu.h @@ -0,0 +1,12 @@ +#ifndef __IOMMU_H +#define __IOMMU_H + +#include "types.h" + +void iommu_init(int bdf, u32 base); +int iommu_get_bdf(void); +u8 iommu_get_cap_offset(void); +u32 iommu_get_misc(void); +u32 iommu_get_base(void); + +#endif // __IOMMU_H diff --git a/src/pci_ids.h b/src/pci_ids.h index 441c086..6876fbe 100644 --- a/src/pci_ids.h +++ b/src/pci_ids.h @@ -72,6 +72,7 @@ #define PCI_CLASS_SYSTEM_RTC 0x0803 #define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804 #define PCI_CLASS_SYSTEM_SDHCI 0x0805 +#define PCI_CLASS_SYSTEM_IOMMU 0x0806 #define PCI_CLASS_SYSTEM_OTHER 0x0880
#define PCI_BASE_CLASS_INPUT 0x09 diff --git a/src/pci_regs.h b/src/pci_regs.h index e6180ce..46b048f 100644 --- a/src/pci_regs.h +++ b/src/pci_regs.h @@ -208,6 +208,7 @@ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define PCI_CAP_ID_SEC 0x0F /* Secure Device (AMD IOMMU) */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ diff --git a/src/pciinit.c b/src/pciinit.c index f75e552..7cb67c6 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -11,6 +11,7 @@ #include "pci_ids.h" // PCI_VENDOR_ID_INTEL #include "pci_regs.h" // PCI_COMMAND #include "dev-i440fx.h" +#include "iommu.h"
#define PCI_ROM_SLOT 6 #define PCI_NUM_REGIONS 7 @@ -262,6 +263,16 @@ static void apple_macio_init(u16 bdf, void *arg) pci_set_io_region_addr(bdf, 0, 0x80800000); }
+static void pci_bios_init_iommu(u16 bdf, void *arg) +{ + u32 base; + + base = ALIGN(pci_bios_mem_addr, 0x4000); + pci_bios_mem_addr += 0x4000; + + iommu_init(bdf, base); +} + static const struct pci_device_id pci_class_tbl[] = { /* STORAGE IDE */ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, @@ -285,6 +296,10 @@ static const struct pci_device_id pci_class_tbl[] = { PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, pci_bios_init_device_bridge),
+ /* AMD IOMMU */ + PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SYSTEM_IOMMU, + pci_bios_init_iommu), + /* default */ PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID, pci_bios_allocate_regions),