@@ -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 \
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
@@ -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
@@ -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 */
@@ -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),