Jetway J7F5M-DVI ACPI DSDT fixes

The Jetway J7F5M MiniTIX motherboard is yet another entry in the 17x17cm small HTPC/low-powered server market. This particular model runs at 2GHz and features Jetway’s proprietary expansion connector for adding additional network, video, or serial ports. I have a 2xRS232 expansion card on mine, to allow me to fix otherwise broken servers via a serial link – it’s the way of the future 🙂

What impressed me is that options for the expansion board appeared in the BIOS, and without any obvious option-ROM loading sequence as is often seen delaying the boot sequence nowadays (JMicron, I’m looking at you) – I can configure the additional ports along with the rest of the system.

What is unfortunate, then, is that Jetway have broken ACPI DSDT tables, built with Microsoft’s non standards-compliant ASL compiler, installed with their BIOS.

This causes a number of issues, including premature shutdown and standby/resume failures – but luckily these are all fixable!

Jump directly to the DSDT fixes.

First, a bit of background:

Up until recently, I had a single infrastructure server (a 5 disc RAID5 array built around a VIA EN12000EG MiniITX motherboard) which, after some initial teething problems has been brilliant.

… up until recently at least, when it became hugely unstable and often not running for 24 hours without locking up. Whilst I eventually found the cause of this (I had installed symon for systems-monitoring purposes, but it turns out that this has a massive memory leak. The server mirrors its Compact Flash-based root filesystem into system memory as soon as the kernel has loaded and then unmounts the CF card. This means that the card is never written to except for upgrades (and so doesn’t burn through write-cycles), but also that Out Of Memory situation are invariably fatal: The system has 1Gb memory (minus 16Mb framebuffer), and up to 768Mb of this is allocated to hold the 480Mb (512Mb minus 32Mb boot parition) root filesystem, plus approximately 10Mb of configuration overlays copied from the RAID array, if present. Given that this server has hosting the software RAID array whilst also running a webserver, database, mail, monitoring tools, etc., memory was always going to be a valuable resource.

Since the server runs headless I didn’t see the exact fatal error, but it appears that symon’s leak was eating up all memory but that the OOM killer wasn’t choosing that task to terminate, eventually taking down the server. These problems did go away as soon as I removed symon, as did a weird issue where a single disc – but a different one each time – would always drop off the array each morning around 7am, even though nothing was scheduled to run at this time. Unless it happens again, I’ll attribute that to software-RAID weirdness in low-memory situations.

What these ongoing problems did convince me of, however, is that my idea for an elegant one-server-for-everything configuration had significant real-world drawbacks – not least that if the storage array went offline, it invariably took DNS and DHCP services and therefore the house’ internet access with it. The plan for the new server started out as a simple serial-server that would allow me to fix any problems with the master server without having to dig to the bottom of the cupboard where it lives. This remit expanded, and the new Jetway server now hosts all infrastructure and web-based services, with the storage array only providing remote storage facilities as well as certain services which make more sense when coupled to the storage system than not – Slim Devices/Logitech’s SqueezeCenter software, for example.

There are a number of issues with the Jetway board, however. Most noticeably amongst these, especially when the 2GHz system is housed in a small-form-factor case, is that the BIOS shutdown temperatures are relatively low: 50°C, 60°C, and 70°C. The problem here is that the CPU will be over 50° pretty much before the BIOS has had chance to start, and over 60° not long afterwards. Although I’d prefer to have a higher-temperature option (80°C would seem a good compromise) this option can be disabled.

What can’t be easily changed, though, is that the ACPI DSDT table fixes the Critical Shutdown temperature at 60°C. This means that, if the ACPI Thermal driver is loaded under Linux (and it certainly should be) then on any reboot after the system has been running for any length of time, the thermal driver will try to shut-down the system when (auto) loaded. This behavior can be adjusted with the “thermal.nocrt=1” kernel parameter, but this only works if the ACPI Thermal driver is built-in rather than built as a module. Adding the option to /etc/modules.d/ solves the problem – but leaves the system open to thermal failure. What’s really needed is a higher critical shutdown temperature, rather than no critical shutdown temperature.

Update: In the latest BIOS 05.2, this has been fixed – the critical temperature is now 127°C. The only BIOS CPU cooling option is now on-die throttling (the previous multiplier-based throttler option is no longer present), and the system appears to be running much cooler, at only 40°C.

The real solution is to fix Jetway’s ACPI implementation – which should also allow the system to correctly resume from standby.

The binary DSDT representation can be found in /proc/acpi/dsdt or, failing this, with acpidump -b -t DSDT -o <filename> (from the pmtools package). This then needs to be decompiled to source with Intel’s iasl compiler (the ‘-d‘ option), resulting in a .dsl file which can be edited.

The patch for the DSDT tables included with the 05..2 Jetway BIOS dated “09/03/2008” (according to the output of dmidecode) is as follows:

--- dsdt.dsl.orig       2008-10-14 17:01:44.517995410 +0100
+++ dsdt.dsl    2008-10-14 17:15:27.747904808 +0100
@@ -393,18 +393,19 @@
                 Notify (\_SB.PWRB, 0x02)
             }
         }
+        Return (Package (0x02) {0x00, 0x00})
     }
 
     Scope (\_SI)
     {
         Method (_MSG, 1, NotSerialized)
         {
-            Store (Local0, Local0)
+            /* Store (Local0, Local0) */
         }
 
         Method (_SST, 1, NotSerialized)
         {
-            Store (Local0, Local0)
+            /* Store (Local0, Local0) */
         }
     }
 
@@ -790,7 +791,7 @@
             Return (0x00)
         }
 
-        Name (PPS1, Package (0x02)
+        Name (PPS1, Package (0x08)
         {
             Package (0x06)
             {
@@ -872,7 +873,7 @@
                 0xFFFF
             }
         })
-        Name (PPS2, Package (0x02)
+        Name (PPS2, Package (0x08)
         {
             Package (0x06)
             {
@@ -1937,17 +1938,17 @@
                 {
                     Method (DISD, 1, NotSerialized)
                     {
-                        Store (Local0, Local0)
+                        /* Store (Local0, Local0) */
                     }
 
                     Method (CKIO, 2, NotSerialized)
                     {
-                        Store (Local0, Local0)
+                        /* Store (Local0, Local0) */
                     }
 
                     Method (SLDM, 2, NotSerialized)
                     {
-                        Store (Local0, Local0)
+                        /* Store (Local0, Local0) */
                     }
                 }
             }
@@ -2139,6 +2140,27 @@
 
                     Method (_STM, 3, NotSerialized)
                     {
+                        Store (Arg0, TMD0)
+                        Store (PMPT, GMPT)
+                        Store (PMUE, GMUE)
+                        Store (PMUT, GMUT)
+                        Store (PSPT, GSPT)
+                        Store (PSUE, GSUE)
+                        Store (PSUT, GSUT)
+                        If (REGF)
+                        {
+                            STM ()
+                            Store (GMPT, PMPT)
+                            Store (GMUE, PMUE)
+                            Store (GMUT, PMUT)
+                            Store (GSPT, PSPT)
+                            Store (GSUE, PSUE)
+                            Store (GSUT, PSUT)
+                        }
+                        Else
+                        {
+                            Store ("Trying to access IDE HWIF registers when not allowed", Debug)
+                        }
                     }
 
                     Device (DRV0)
@@ -2146,6 +2168,7 @@
                         Name (_ADR, 0x00)
                         Method (_GTF, 0, NotSerialized)
                         {
+                            Return (GTF (0x02, PMUE, PMUT, PMPT))
                         }
                     }
 
@@ -2154,6 +2177,7 @@
                         Name (_ADR, 0x01)
                         Method (_GTF, 0, NotSerialized)
                         {
+                            Return (GTF (0x03, PSUE, PSUT, PSPT))
                         }
                     }
                 }
@@ -2187,13 +2211,20 @@
                         Store (SSPT, GSPT)
                         Store (SSUE, GSUE)
                         Store (SSUT, GSUT)
-                        STM ()
-                        Store (GMPT, SMPT)
-                        Store (GMUE, SMUE)
-                        Store (GMUT, SMUT)
-                        Store (GSPT, SSPT)
-                        Store (GSUE, SSUE)
-                        Store (GSUT, SSUT)
+                        If (REGF)
+                        {
+                            STM ()
+                            Store (GMPT, SMPT)
+                            Store (GMUE, SMUE)
+                            Store (GMUT, SMUT)
+                            Store (GSPT, SSPT)
+                            Store (GSUE, SSUE)
+                            Store (GSUT, SSUT)
+                        }
+                        Else
+                        {
+                            Store ("Trying to access IDE HWIF registers when not allowed", Debug)
+                        }
                     }
 
                     Device (DRV0)
@@ -2342,11 +2373,12 @@
 
                 Method (STM, 0, Serialized)
                 {
-                    If (REGF) {}
-                    Else
-                    {
-                        Return (TMD0)
-                    }
+                    /*  If (REGF) {}
+                     *  Else
+                     *  {
+                     *      Return (TMD0)
+                     *  }
+                     */
 
                     Store (0x00, GMUE)
                     Store (0x00, GSUE)
@@ -5068,8 +5100,8 @@
                 {
                     ENFG ()
                     Store (0x02, LDN)
-                    Return (0x0105D041)
                     EXFG ()
+                    Return (0x0105D041)
                 }
 
                 Name (_UID, 0x02)
@@ -5280,7 +5312,7 @@
                         DISD (0x01)
                     }
 
-                    Store (Local0, Local0)
+                    /* Store (Local0, Local0) */
                 }
 
                 Method (_CRS, 0, NotSerialized)

The only significant different in the original patch was an additional function to override the critical temperature:

@@ -567,15 +568,24 @@
                 }
             }
 
+            Method (KELV, 1, NotSerialized)
+           {
+               Store (Arg0, Local0)
+               Multiply (0x0A, Local0, Local0)
+               Add(Local0, 0x0AAC, Local0)
+               Return (Local0)
+           }
+
             Method (_CRT, 0, NotSerialized)
             {
-                Return (TRPC)
+                /* Return (TRPC) */
+               Return (KELV (0x55)) /* 85 degrees centigrade */
             }
 
             Method (_TMP, 0, NotSerialized)
             {

The modified .dsl file can then be compiled with ‘iasl -tc <filename>.dsl‘, which should succeed with 0 errors and 0 warnings! If so, this process will create a <filename>.hex file, ready to be bundled directly into your kernel image or into an initrd (although this approach may still require third-party kernel patches).

I won’t do into too many details about exactly how to get the replacement tables loaded by the kernel – this is a potentially dangerous operation, so if you’re not familiar with the process then it’s well work reading up on it before you start. Briefly, in your kernel’s .config you need to unset CONFIG_STANDALONE, set CONFIG_ACPI_CUSTOM_DSDT and finally set CONFIG_ACPI_CUSTOM_DSDT_FILE to the name of the file within your source directory’s include directory of the DSDT hex file. Rebuild the kernel, and you should see:

ACPI: Core revision 20070126
ACPI: Override [DSDT-AWRDACPI], this is unsafe: tainting kernel
ACPI: Table DSDT replaced by host OS
ACPI: DSDT 00000000, 5984 (r1 CX700  AWRDACPI     1000 INTL 20060912)
ACPI: DSDT override uses original SSDTs unless "acpi_no_auto_ssdt"

… which shows that the change has taken.