From 063e1567d8fcb397f08fc3d427f3c23cfefe85e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kr=C3=B3l?= Date: Sun, 22 Jul 2018 20:52:26 +0200 Subject: nb/amd/pi/00730F01: use MMIO and performance counters from AGESA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch contain minimal set of changes to initial IVRS implementation to make it work reliably. Code in this patch was tested with Xen 4.8 and Debian 4.14.y - this software stack survived 100x reboots without any hang on PC Engines apu2c4. Previously using IVRS provided by AGESA lead to 29/100 hangs. MMIO base shall not be hard coded since this value depends on platform design. Performance counters were selected experimentally, since lack of them cause 4.14.y panic: [ 1.064229] AMD-Vi: IOMMU performance counters supported [ 1.069579] BUG: unable to handle kernel paging request at ffffaffc4065c000 [ 1.073554] IP: iommu_go_to_state+0xf8a/0x1260 [ 1.073554] PGD 12a11f067 P4D 12a11f067 PUD 12a120067 PMD 129b69067 PTE 0 [ 1.073554] Oops: 0000 [#1] SMP NOPTI [ 1.073554] Modules linked in: [ 1.073554] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.14.50 #13 [ 1.073554] Hardware name: PC Engines apu2/apu2, BIOS 4.8-1174-gf12b3046f0-d2 [ 1.073554] task: ffff8d5d69b9f040 task.stack: ffffaffc40648000 [ 1.073554] RIP: 0010:iommu_go_to_state+0xf8a/0x1260 [ 1.073554] RSP: 0018:ffffaffc4064be28 EFLAGS: 00010282 [ 1.073554] RAX: ffffaffc40658000 RBX: ffff8d5d69bae000 RCX: ffffffff99e57b88 [ 1.073554] RDX: 0000000000000000 RSI: 0000000000000092 RDI: 0000000000000246 [ 1.073554] RBP: 0000000000000040 R08: 0000000000000001 R09: 0000000000000170 [ 1.073554] R10: 0000000000000000 R11: ffffffff9a435e2d R12: 0000000000000000 [ 1.073554] R13: ffffffff9a29a830 R14: 0000000000000000 R15: 0000000000000000 [ 1.073554] FS: 0000000000000000(0000) GS:ffff8d5d6ec80000(0000) knlGS:00000 [ 1.073554] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1.073554] CR2: ffffaffc4065c000 CR3: 000000010fa0a000 CR4: 00000000000406e0 [ 1.073554] Call Trace: [ 1.073554] ? set_debug_rodata+0x11/0x11 [ 1.073554] amd_iommu_init+0x11/0x89 [ 1.073554] pci_iommu_init+0x16/0x3f [ 1.073554] ? e820__memblock_setup+0x60/0x60 [ 1.073554] do_one_initcall+0x51/0x190 [ 1.073554] ? set_debug_rodata+0x11/0x11 [ 1.073554] kernel_init_freeable+0x16b/0x1ec [ 1.073554] ? rest_init+0xb0/0xb0 [ 1.073554] kernel_init+0xa/0xf7 [ 1.073554] ret_from_fork+0x22/0x40 [ 1.073554] Code: d2 31 f6 48 89 df e8 d8 15 02 ff 85 c0 75 d1 48 8b 44 24 2 [ 1.073554] RIP: iommu_go_to_state+0xf8a/0x1260 RSP: ffffaffc4064be28 [ 1.073554] CR2: ffffaffc4065c000 [ 1.073554] ---[ end trace 44588f98aa7c7c0b ]--- [ 1.255973] Kernel panic - not syncing: Attempted to kill init! exitcode=0x09 [ 1.255973] [ 1.259934] ---[ end Kernel panic - not syncing: Attempted to kill init! exi9 Possible future improvements: - compare device entries with values returned by AGESA - enable EFRSup (this is enabled in AGESA) - try various IVHD flags (there is difference between initial implementation and AGESA) Change-Id: I7e3a3d21f295ae96962d7718b9568fc4b67eb23d Signed-off-by: Piotr Król Reviewed-on: https://review.coreboot.org/27602 Tested-by: build bot (Jenkins) Reviewed-by: Marc Jones --- src/northbridge/amd/pi/00730F01/northbridge.c | 61 +++++++++++++++++---------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'src/northbridge/amd/pi') diff --git a/src/northbridge/amd/pi/00730F01/northbridge.c b/src/northbridge/amd/pi/00730F01/northbridge.c index ab67b43e81..f4c39d6be1 100644 --- a/src/northbridge/amd/pi/00730F01/northbridge.c +++ b/src/northbridge/amd/pi/00730F01/northbridge.c @@ -582,6 +582,7 @@ unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) static unsigned long acpi_fill_ivrs(acpi_ivrs_t *ivrs, unsigned long current) { uint8_t *p; + acpi_ivrs_t *ivrs_agesa; struct device *nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); if (!nb_dev) { @@ -592,29 +593,43 @@ static unsigned long acpi_fill_ivrs(acpi_ivrs_t *ivrs, unsigned long current) return (unsigned long)ivrs; } - ivrs->iv_info = 0x0; - /* Maximum supported virtual address size */ - ivrs->iv_info |= (0x40 << 15); - /* Maximum supported physical address size */ - ivrs->iv_info |= (0x30 << 8); - /* Guest virtual address width */ - ivrs->iv_info |= (0x2 << 5); - - ivrs->ivhd.type = 0x10; - ivrs->ivhd.flags = 0x0e; - /* Enable ATS support */ - ivrs->ivhd.flags |= 0x10; - ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); - /* BDF :00.2 */ - ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); - /* Capability block 0x40 (type 0xf, "Secure device") */ - ivrs->ivhd.capability_offset = 0x40; - ivrs->ivhd.iommu_base_low = 0xfeb00000; - ivrs->ivhd.iommu_base_high = 0x0; - ivrs->ivhd.pci_segment_group = 0x0; - ivrs->ivhd.iommu_info = 0x0; - ivrs->ivhd.iommu_info |= (0x13 << 8); - ivrs->ivhd.iommu_feature_info = 0x0; + + /* obtain IOMMU base address */ + ivrs_agesa = agesawrapper_getlateinitptr(PICK_IVRS); + if (ivrs_agesa != NULL) { + ivrs->iv_info = 0x0; + /* Maximum supported virtual address size */ + ivrs->iv_info |= (0x40 << 15); + /* Maximum supported physical address size */ + ivrs->iv_info |= (0x30 << 8); + /* Guest virtual address width */ + ivrs->iv_info |= (0x2 << 5); + + ivrs->ivhd.type = 0x10; + ivrs->ivhd.flags = 0x0e; + /* Enable ATS support */ + ivrs->ivhd.flags |= 0x10; + ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); + /* BDF :00.2 */ + ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); + /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.capability_offset = 0x40; + ivrs->ivhd.iommu_base_low = ivrs_agesa->ivhd.iommu_base_low; + ivrs->ivhd.iommu_base_high = ivrs_agesa->ivhd.iommu_base_high; + ivrs->ivhd.pci_segment_group = 0x0; + ivrs->ivhd.iommu_info = 0x0; + ivrs->ivhd.iommu_info |= (0x13 << 8); + /* use only performance counters related bits: + * PNCounters[16:13] and + * PNBanks[22:17], + * otherwise 0 */ + ivrs->ivhd.iommu_feature_info = + ivrs_agesa->ivhd.iommu_feature_info & 0x7fe000; + } else { + printk(BIOS_WARNING, "%s: AGESA returned NULL IVRS\n", __func__); + + return (unsigned long)ivrs; + } /* Describe HPET */ p = (uint8_t *)current; -- cgit v1.2.3