>From 581045edb168717c7f5691be1af5f75d35c3ebf5 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 15 May 2012 10:38:05 +0200
Subject: [PATCH] update dsdt ressources at runtime

Write the pci window location to memory and add a pointer to the SSDT
(BDAT region).  Turn \\SB.PCI0._CRS into a method which looks up the
information there and updates the ressources accordingly.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 src/acpi-dsdt.dsl |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/acpi.c        |   28 ++++++++++++++++++-
 src/acpi.h        |    9 ++++++
 3 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl
index 4bdc268..3e3999a 100644
--- a/src/acpi-dsdt.dsl
+++ b/src/acpi-dsdt.dsl
@@ -61,6 +61,38 @@ DefinitionBlock (
 
 
 /****************************************************************
+ * Data area filled by seabios (see acpi.h, struct bfld)
+ ****************************************************************/
+
+    Scope(\_SB) {
+        Device(BFLD) {
+            External (\_SB.BDAT)
+            Field(\_SB.BDAT, QWordAcc, NoLock, Preserve) {
+                P0S, 64,
+                P0E, 64,
+                P0L, 64,
+                P1S, 64,
+                P1E, 64,
+                P1L, 64,
+            }
+            Field(\_SB.BDAT, DWordAcc, NoLock, Preserve) {
+                P0SL, 64,
+                P0SH, 64,
+                P0EL, 64,
+                P0EH, 64,
+                P0LL, 64,
+                P0LH, 64,
+                P1SL, 64,
+                P1SH, 64,
+                P1EL, 64,
+                P1EH, 64,
+                P1LL, 64,
+                P1LH, 64,
+            }
+        }
+    }
+
+/****************************************************************
  * PCI Bus definition
  ****************************************************************/
 
@@ -132,7 +164,7 @@ DefinitionBlock (
                 B0EJ, 32,
             }
 
-            Name (_CRS, ResourceTemplate ()
+            Name (CRES, ResourceTemplate ()
             {
                 WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
                     0x0000,             // Address Space Granularity
@@ -174,8 +206,49 @@ DefinitionBlock (
                     0xFEBFFFFF,         // Address Range Maximum
                     0x00000000,         // Address Translation Offset
                     0x1EC00000,         // Address Length
-                    ,, , AddressRangeMemory, TypeStatic)
+                    ,, PW32, AddressRangeMemory, TypeStatic)
+            })
+            Name (CR64, ResourceTemplate ()
+            {
+                QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x00000000,          // Address Space Granularity
+                    0x8000000000,        // Address Range Minimum
+                    0xFFFFFFFFFF,        // Address Range Maximum
+                    0x00000000,          // Address Translation Offset
+                    0x8000000000,        // Address Length
+                    ,, PW64, AddressRangeMemory, TypeStatic)
             })
+            Method (_CRS, 0)
+            {
+                DBUG("pci0 _crs: enter")
+
+                /* fixup 32bit pci io window */
+		CreateDWordField (CRES,\_SB.PCI0.PW32._MIN, PS32)
+		CreateDWordField (CRES,\_SB.PCI0.PW32._MAX, PE32)
+		CreateDWordField (CRES,\_SB.PCI0.PW32._LEN, PL32)
+		Store (\_SB.BFLD.P0SL, PS32)
+		Store (\_SB.BFLD.P0EL, PE32)
+		Store (\_SB.BFLD.P0LL, PL32)
+
+		If (LAnd(LEqual(\_SB.BFLD.P1SL, 0x00),
+                         LEqual(\_SB.BFLD.P1SH, 0x00))) {
+		    DBUG("pci0 _crs: 32bit")
+		    Return (CRES)
+		} Else {
+		    DBUG("pci0 _crs: 64bit")
+		    /* fixup 64bit pci io window */
+		    CreateQWordField (CR64,\_SB.PCI0.PW64._MIN, PS64)
+		    CreateQWordField (CR64,\_SB.PCI0.PW64._MAX, PE64)
+		    CreateQWordField (CR64,\_SB.PCI0.PW64._LEN, PL64)
+		    Store (\_SB.BFLD.P1S, PS64)
+		    Store (\_SB.BFLD.P1E, PE64)
+		    Store (\_SB.BFLD.P1L, PL64)
+		    /* add window and return result */
+		    ConcatenateResTemplate (CRES, CR64, Local0)
+		    DBUG("pci0 _crs: done")
+		    Return (Local0)
+		}
+            }
         }
     }
 
diff --git a/src/acpi.c b/src/acpi.c
index 30888b9..5c3aaec 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -415,7 +415,8 @@ build_ssdt(void)
     int length = ((1+3+4)
                   + (acpi_cpus * SD_SIZEOF)
                   + (1+2+5+(12*acpi_cpus))
-                  + (6+2+1+(1*acpi_cpus)));
+                  + (6+2+1+(1*acpi_cpus))
+                  + 17);
     u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length);
     if (! ssdt) {
         warn_noalloc();
@@ -477,6 +478,31 @@ build_ssdt(void)
     for (i=0; i<acpi_cpus; i++)
         *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
 
+    // store pci io windows: start, end, length
+    // this way we don't have to do the math in the dsdt
+    struct bfld *bfld = malloc_high(sizeof(struct bfld));
+    bfld->p0s = pcimem_start;
+    bfld->p0e = pcimem_end - 1;
+    bfld->p0l = pcimem_end - pcimem_start - 1;
+    bfld->p1s = pcimem64_start;
+    bfld->p1e = pcimem64_end - 1;
+    bfld->p1l = pcimem64_end - pcimem64_start - 1;
+
+    // build "OperationRegion(BDAT, SystemMemory, 0x12345678, 0x87654321)"
+    *(ssdt_ptr++) = 0x5B; // ExtOpPrefix
+    *(ssdt_ptr++) = 0x80; // OpRegionOp
+    *(ssdt_ptr++) = 'B';
+    *(ssdt_ptr++) = 'D';
+    *(ssdt_ptr++) = 'A';
+    *(ssdt_ptr++) = 'T';
+    *(ssdt_ptr++) = 0x00; // SystemMemory
+    *(ssdt_ptr++) = 0x0C; // DWordPrefix
+    *(u32*)ssdt_ptr = (u32)bfld;
+    ssdt_ptr += 4;
+    *(ssdt_ptr++) = 0x0C; // DWordPrefix
+    *(u32*)ssdt_ptr = sizeof(struct bfld);
+    ssdt_ptr += 4;
+
     build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
 
     //hexdump(ssdt, ssdt_ptr - ssdt);
diff --git a/src/acpi.h b/src/acpi.h
index e01315a..cb21561 100644
--- a/src/acpi.h
+++ b/src/acpi.h
@@ -98,4 +98,13 @@ struct fadt_descriptor_rev1
 #endif
 } PACKED;
 
+struct bfld {
+    u64 p0s;  /* pci window 0 (below 4g) - start  */
+    u64 p0e;  /* pci window 0 (below 4g) - end    */
+    u64 p0l;  /* pci window 0 (below 4g) - length */
+    u64 p1s;  /* pci window 1 (above 4g) - start  */
+    u64 p1e;  /* pci window 1 (above 4g) - end    */
+    u64 p1l;  /* pci window 1 (above 4g) - length */
+} PACKED;
+
 #endif // acpi.h
-- 
1.7.1

