Dynamically generate PNP0C02 mainboard resources in SSDT
While adding the area between TOM1 and 4GB to \SB.PCI0._CRS seems to be the easiest way to get both Linux and Windows happy, it is not quite correct because reserved areas like APIC, MMCONF etc. ranges need to be excluded.
This is a proof of concept patch for the M2V board that dynamically creates a ResourceTemplate() containing these in the SSDT and adds a corresponding PNP0C02 device to the DSDT.
All resources that have IORESOURCE_RESERVE and (IORESOURCE_MEM or IORESOURCE_IO) set are added.
Here applied on top of the "Ranges unavailable for PCI BARs should be marked as reserved in the E820 memory map, in case the OS wants to change the BARs" patch, which adds the IORESOURCE_RESERVE flag to via k8t890/vt8237 apic/mmconf/bios resources.
coreboot log excerpt: |ACPI: * SSDT |processor_brand=AMD Athlon(tm) 64 Processor 3200+ |Pstates Algorithm ... |Pstate_freq[0] = 2000MHz Pstate_vid[0] = 8 Pstate_volt[0] = 1350mv Pstate_power[0] = 62000mw |Pstate_freq[1] = 1800MHz Pstate_vid[1] = 10 Pstate_volt[1] = 1300mv Pstate_power[1] = 51743mw |Pstate_freq[2] = 1000MHz Pstate_vid[2] = 18 Pstate_volt[2] = 1100mv Pstate_power[2] = 20581mw |m2v_write_mainboard_resources() |Adding M2V reserved resources |acpigen_add_mainboard_rsvd_mem32: base=fec00000 size=00000100 |acpigen_add_mainboard_rsvd_mem32: base=ffc00000 size=00400000 |acpigen_add_mainboard_rsvd_mem32: base=fecc0000 size=00000100 |acpigen_add_mainboard_rsvd_mem32: base=c0000000 size=10000000 |acpigen_add_mainboard_rsvd_io: base=0a20 size=0008 |ACPI: added table 7/32 Length now 64
Linux dmesg excerpt: |ACPI: ACPI bus type pnp unregistered |system 00:04: [io 0x0a20-0x0a27] has been reserved |system 00:04: [mem 0xfec00000-0xfec000ff] could not be reserved |system 00:04: [mem 0xffc00000-0xffffffff] has been reserved |system 00:04: [mem 0xfecc0000-0xfecc00ff] could not be reserved |system 00:04: [mem 0xc0000000-0xcfffffff] has been reserved |pci 0000:00:03.0: BAR 9: assigned [mem 0xd0500000-0xd06fffff 64bit pref]
Signed-off-by: Tobias Diedrich ranma+coreboot@tdiedrich.de
---
Index: src/mainboard/asus/m2v/acpi_tables.c =================================================================== --- src/mainboard/asus/m2v/acpi_tables.c.orig 2010-11-10 02:39:36.000000000 +0100 +++ src/mainboard/asus/m2v/acpi_tables.c 2010-11-10 02:39:41.000000000 +0100 @@ -25,6 +25,7 @@ #include <console/console.h> #include <string.h> #include <arch/acpi.h> +#include <arch/acpigen.h> #include <arch/smp/mpspec.h> #include <arch/ioapic.h> #include <device/device.h> @@ -84,10 +85,30 @@ return current; }
+struct lb_memory; + +extern int add_mainboard_resources(struct lb_memory *mem); + +static void m2v_write_mainboard_resources(void) +{ + int lens; + const char pscope[] = "\_SB.PCI0"; + + printk(BIOS_INFO, "m2v_write_mainboard_resources()\n"); + + add_mainboard_resources(NULL); + + lens = acpigen_write_scope(pscope); + lens += acpigen_write_name("RSVD"); + lens += acpigen_write_mainboard_resources(); + acpigen_patch_len(lens - 1); +} + unsigned long acpi_fill_ssdt_generator(unsigned long current, const char *oem_table_id) { k8acpi_write_vars(); amd_model_fxx_generate_powernow(0, 0, 0); + m2v_write_mainboard_resources(); return (unsigned long) (acpigen_get_current()); }
Index: src/mainboard/asus/m2v/dsdt.asl =================================================================== --- src/mainboard/asus/m2v/dsdt.asl.orig 2010-11-10 02:39:36.000000000 +0100 +++ src/mainboard/asus/m2v/dsdt.asl 2010-11-10 02:39:41.000000000 +0100 @@ -399,6 +399,16 @@ } }
+ External(RSVD) /* CRS with reserved mainboard resources */ + Device(MBRS) { + Name (_HID, EisaId ("PNP0C02")) + Name (_UID, 0x01) + + Method(_CRS) { + Return (RSVD) + } + } + External(TOM1) /* top of memory below 4GB */
Method(_CRS, 0) { Index: src/arch/i386/boot/acpigen.c =================================================================== --- src/arch/i386/boot/acpigen.c.orig 2010-11-10 02:39:36.000000000 +0100 +++ src/arch/i386/boot/acpigen.c 2010-11-10 02:39:41.000000000 +0100 @@ -28,6 +28,7 @@ #include <string.h> #include <arch/acpigen.h> #include <console/console.h> +#include <device/device.h>
static char *gencurrent;
@@ -372,3 +373,97 @@ acpigen_patch_len(len - 1); return len + lenh; } + +int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size) +{ + acpigen_emit_byte(0x86); + acpigen_emit_byte(0x09); + acpigen_emit_byte(0x00); + acpigen_emit_byte(readwrite ? 0x01 : 0x00); + acpigen_emit_byte(base & 0xff); + acpigen_emit_byte((base >> 8) & 0xff); + acpigen_emit_byte((base >> 16) & 0xff); + acpigen_emit_byte((base >> 24) & 0xff); + acpigen_emit_byte(size & 0xff); + acpigen_emit_byte((size >> 8) & 0xff); + acpigen_emit_byte((size >> 16) & 0xff); + acpigen_emit_byte((size >> 24) & 0xff); + return 12; +} + +int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len) +{ + acpigen_emit_byte(0x47); + acpigen_emit_byte(0x01); + acpigen_emit_byte(min & 0xff); + acpigen_emit_byte((min >> 8) & 0xff); + acpigen_emit_byte(max & 0xff); + acpigen_emit_byte((max >> 8) & 0xff); + acpigen_emit_byte(align & 0xff); + acpigen_emit_byte(len & 0xff); + return 8; +} + +int acpigen_write_resourcetemplate_header(void) +{ + int len; + len = acpigen_emit_byte(0x11); + len += acpigen_write_len_f(); + len += acpigen_emit_byte(0x0b); /* word */ + len_stack[ltop++] = acpigen_get_current(); + len += acpigen_emit_byte(0x00); + len += acpigen_emit_byte(0x00); + return len; +} + +int acpigen_write_resourcetemplate_footer(int len) +{ + len += acpigen_emit_byte(0x79); + len += acpigen_emit_byte(0x00); + acpigen_patch_len(len-4); + acpigen_patch_len(len-1); + return len; +} + +static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, + struct resource *res) +{ + printk(BIOS_INFO, "acpigen_add_mainboard_rsvd_mem32: base=%08x size=%08x\n", (int)res->base, (int)res->size); + acpigen_write_mem32fixed(0, res->base, res->size); +} + +static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, + struct resource *res) +{ + printk(BIOS_INFO, "acpigen_add_mainboard_rsvd_io: base=%04x size=%04x\n", (int)res->base, (int)res->size); + if (res->size > 255) { + printk(BIOS_ERR, "acpigen_add_mainboard_rsvd_io: size %d > 255!\n", (int)res->size); + } + acpigen_write_io16(res->base, res->base, 0, res->size); +} + +int acpigen_write_mainboard_resources(void) +{ + int len; + char *start; + char *end; + len = acpigen_write_resourcetemplate_header(); + start = acpigen_get_current(); + + /* Add reserved memory ranges */ + search_global_resources( + IORESOURCE_MEM | IORESOURCE_RESERVE, + IORESOURCE_MEM | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_mem32, 0); + + /* Add reserved io ranges */ + search_global_resources( + IORESOURCE_IO | IORESOURCE_RESERVE, + IORESOURCE_IO | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_io, 0); + + end = acpigen_get_current(); + len += end-start; + len += acpigen_write_resourcetemplate_footer(len); + return len; +} Index: src/arch/i386/include/arch/acpigen.h =================================================================== --- src/arch/i386/include/arch/acpigen.h.orig 2010-11-10 02:39:36.000000000 +0100 +++ src/arch/i386/include/arch/acpigen.h 2010-11-10 02:39:41.000000000 +0100 @@ -46,5 +46,10 @@ typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } PSD_coord; int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype); int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len); +int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size); +int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len); +int acpigen_write_resourcetemplate_header(void); +int acpigen_write_resourcetemplate_footer(int len); +int acpigen_write_mainboard_resources(void);
#endif Index: src/mainboard/asus/m2v/mainboard.c =================================================================== --- src/mainboard/asus/m2v/mainboard.c.orig 2010-11-10 02:39:36.000000000 +0100 +++ src/mainboard/asus/m2v/mainboard.c 2010-11-10 02:39:41.000000000 +0100 @@ -17,9 +17,39 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include <console/console.h> #include <device/device.h> +#include <device/pci_ids.h> +#include <boot/tables.h> #include "chip.h"
+#define IT8712F_GPIO_BASE 0x0a20 + +int add_mainboard_resources(struct lb_memory *mem) +{ + struct device *dev; + struct resource *res; + + printk(BIOS_INFO, "Adding M2V reserved resources\n"); + + dev = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VT8237A_LPC, 0); + if (!dev) { + printk(BIOS_ERR, "LPC not found!\n"); + return 0; + } + + res = new_resource(dev, 42); + res->base = IT8712F_GPIO_BASE; + res->size = 8; + res->limit = 0xffff; + res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_RESERVE | + IORESOURCE_STORED | IORESOURCE_ASSIGNED; + + return 0; +} + + struct chip_operations mainboard_ops = { CHIP_NAME("ASUS M2V") }; Index: src/mainboard/asus/m2v/Kconfig =================================================================== --- src/mainboard/asus/m2v/Kconfig.orig 2010-11-10 02:39:41.000000000 +0100 +++ src/mainboard/asus/m2v/Kconfig 2010-11-10 02:39:41.000000000 +0100 @@ -21,6 +21,7 @@ select PIRQ_ROUTE select HAVE_ACPI_TABLES select HAVE_MP_TABLE + select HAVE_MAINBOARD_RESOURCES
config MAINBOARD_DIR string
Updated version, fixed some bugs in the aml bytecode generation that Linux didn't care about, but gave me a Stop A5 with XP. Also removed the add_mainboard_resources part I used to test the IO space reservation (And unfortunately add_mainboard_resources() normally runs after the acpi tables are already generated).
Dynamically generate PNP0C02 mainboard resources in SSDT
While adding the area between TOM1 and 4GB to \SB.PCI0._CRS seems to be the easiest way to get both Linux and Windows happy, it is not quite correct because reserved areas like APIC, MMCONF etc. ranges need to be excluded.
This is a proof of concept patch for the M2V board that dynamically creates a ResourceTemplate() containing these in the SSDT and adds a corresponding PNP0C02 device to the DSDT.
All resources that have IORESOURCE_RESERVE and (IORESOURCE_MEM or IORESOURCE_IO) set are added.
Here applied on top of the "Ranges unavailable for PCI BARs should be marked as reserved in the E820 memory map, in case the OS wants to change the BARs" patch, which adds the IORESOURCE_RESERVE flag to via k8t890/vt8237 apic/mmconf/bios resources.
coreboot log excerpt: |ACPI: * SSDT |processor_brand=AMD Athlon(tm) 64 Processor 3200+ |Pstates Algorithm ... |Pstate_freq[0] = 2000MHz Pstate_vid[0] = 8 Pstate_volt[0] = 1350mv Pstate_power[0] = 62000mw |Pstate_freq[1] = 1800MHz Pstate_vid[1] = 10 Pstate_volt[1] = 1300mv Pstate_power[1] = 51743mw |Pstate_freq[2] = 1000MHz Pstate_vid[2] = 18 Pstate_volt[2] = 1100mv Pstate_power[2] = 20581mw |m2v_write_mainboard_resources() |Adding M2V reserved resources |acpigen_add_mainboard_rsvd_mem32: base=fec00000 size=00000100 |acpigen_add_mainboard_rsvd_mem32: base=ffc00000 size=00400000 |acpigen_add_mainboard_rsvd_mem32: base=fecc0000 size=00000100 |acpigen_add_mainboard_rsvd_mem32: base=c0000000 size=10000000 |acpigen_add_mainboard_rsvd_io: base=0a20 size=0008 |ACPI: added table 7/32 Length now 64
Linux dmesg excerpt: |ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff]) |pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] |pci_root PNP0A03:00: host bridge window [io 0x0d00-0xffff] |pci_root PNP0A03:00: host bridge window [mem 0xc0000000-0xffffffff] |[...] |system 00:04: [io 0x0a20-0x0a27] has been reserved |system 00:04: [mem 0xfec00000-0xfec000ff] could not be reserved |system 00:04: [mem 0xffc00000-0xffffffff] has been reserved |system 00:04: [mem 0xfecc0000-0xfecc00ff] could not be reserved |system 00:04: [mem 0xc0000000-0xcfffffff] has been reserved |pci 0000:00:03.0: BAR 9: assigned [mem 0xd0500000-0xd06fffff 64bit pref]
Signed-off-by: Tobias Diedrich ranma+coreboot@tdiedrich.de
---
Index: src/mainboard/asus/m2v/acpi_tables.c =================================================================== --- src/mainboard/asus/m2v/acpi_tables.c.orig 2010-11-10 15:08:13.000000000 +0100 +++ src/mainboard/asus/m2v/acpi_tables.c 2010-11-10 19:25:06.000000000 +0100 @@ -25,6 +25,7 @@ #include <console/console.h> #include <string.h> #include <arch/acpi.h> +#include <arch/acpigen.h> #include <arch/smp/mpspec.h> #include <arch/ioapic.h> #include <device/device.h> @@ -88,6 +89,7 @@ { k8acpi_write_vars(); amd_model_fxx_generate_powernow(0, 0, 0); + acpigen_write_mainboard_resources("\_SB.PCI0.MBRS", "_CRS"); return (unsigned long) (acpigen_get_current()); }
Index: src/mainboard/asus/m2v/dsdt.asl =================================================================== --- src/mainboard/asus/m2v/dsdt.asl.orig 2010-11-10 15:08:13.000000000 +0100 +++ src/mainboard/asus/m2v/dsdt.asl 2010-11-10 19:24:47.000000000 +0100 @@ -399,6 +399,13 @@ } }
+ Device(MBRS) { + Name (_HID, EisaId ("PNP0C02")) + Name (_UID, 0x01) + + External(_CRS) /* Resource Template in SSDT */ + } + External(TOM1) /* top of memory below 4GB */
Method(_CRS, 0) { Index: src/arch/i386/boot/acpigen.c =================================================================== --- src/arch/i386/boot/acpigen.c.orig 2010-11-10 15:08:13.000000000 +0100 +++ src/arch/i386/boot/acpigen.c 2010-11-10 19:27:18.000000000 +0100 @@ -28,6 +28,7 @@ #include <string.h> #include <arch/acpigen.h> #include <console/console.h> +#include <device/device.h>
static char *gencurrent;
@@ -372,3 +373,111 @@ acpigen_patch_len(len - 1); return len + lenh; } + +int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size) +{ + acpigen_emit_byte(0x86); + acpigen_emit_byte(0x09); + acpigen_emit_byte(0x00); + acpigen_emit_byte(readwrite ? 0x01 : 0x00); + acpigen_emit_byte(base & 0xff); + acpigen_emit_byte((base >> 8) & 0xff); + acpigen_emit_byte((base >> 16) & 0xff); + acpigen_emit_byte((base >> 24) & 0xff); + acpigen_emit_byte(size & 0xff); + acpigen_emit_byte((size >> 8) & 0xff); + acpigen_emit_byte((size >> 16) & 0xff); + acpigen_emit_byte((size >> 24) & 0xff); + return 12; +} + +int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len) +{ + acpigen_emit_byte(0x47); + acpigen_emit_byte(0x01); + acpigen_emit_byte(min & 0xff); + acpigen_emit_byte((min >> 8) & 0xff); + acpigen_emit_byte(max & 0xff); + acpigen_emit_byte((max >> 8) & 0xff); + acpigen_emit_byte(align & 0xff); + acpigen_emit_byte(len & 0xff); + return 8; +} + +int acpigen_write_resourcetemplate_header(void) +{ + int len; + len = acpigen_emit_byte(0x11); /* resourcetemplate */ + len += acpigen_write_len_f(); + len += acpigen_emit_byte(0x0b); /* word */ + len_stack[ltop++] = acpigen_get_current(); + len += acpigen_emit_byte(0x00); + len += acpigen_emit_byte(0x00); + return len; +} + +int acpigen_write_resourcetemplate_footer(int len) +{ + char *p = len_stack[--ltop]; + len += acpigen_emit_byte(0x79); + len += acpigen_emit_byte(0x00); + p[0] = (len-6) & 0xff; + p[1] = ((len-6) >> 8) & 0xff; + acpigen_patch_len(len-1); + return 2; +} + +static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, + struct resource *res) +{ + acpigen_write_mem32fixed(0, res->base, res->size); +} + +static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, + struct resource *res) +{ + resource_t base = res->base; + resource_t size = res->size; + while (size > 0) { + resource_t sz = size > 255 ? 255 : size; + acpigen_write_io16(base, base+sz-1, 0, sz); + size -= sz; + base += sz; + } +} + +int acpigen_write_mainboard_resource_template(void) +{ + int len; + char *start; + char *end; + len = acpigen_write_resourcetemplate_header(); + start = acpigen_get_current(); + + /* Add reserved memory ranges */ + search_global_resources( + IORESOURCE_MEM | IORESOURCE_RESERVE, + IORESOURCE_MEM | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_mem32, 0); + + /* Add reserved io ranges */ + search_global_resources( + IORESOURCE_IO | IORESOURCE_RESERVE, + IORESOURCE_IO | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_io, 0); + + end = acpigen_get_current(); + len += end-start; + len += acpigen_write_resourcetemplate_footer(len); + return len; +} + +int acpigen_write_mainboard_resources(const char *scope, const char *name) +{ + int len; + len = acpigen_write_scope(scope); + len += acpigen_write_name(name); + len += acpigen_write_mainboard_resource_template(); + acpigen_patch_len(len - 1); + return len; +} Index: src/arch/i386/include/arch/acpigen.h =================================================================== --- src/arch/i386/include/arch/acpigen.h.orig 2010-11-10 15:08:13.000000000 +0100 +++ src/arch/i386/include/arch/acpigen.h 2010-11-10 15:10:49.000000000 +0100 @@ -46,5 +46,11 @@ typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } PSD_coord; int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype); int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len); +int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size); +int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len); +int acpigen_write_resourcetemplate_header(void); +int acpigen_write_resourcetemplate_footer(int len); +int acpigen_write_mainboard_resource_template(void); +int acpigen_write_mainboard_resources(const char *scope, const char *name);
#endif