it replaces a static complied in DSDT MMIO region for memory hotplug with one created at runtime leaving only truly static memory hotplug related ASL bits in DSDT. And replaces template patching of MEMORY_SLOTS_NUMBER value with ASL API created named value. Later it also would make easier to reuse current ACPI memory hotplug on other targets. Also later it would be possible to move remaining memory hotplug ASL methods into build_ssdt() and add all memory hotplug related AML into SSDT only when memory hotplug is enabled, further reducing ACPI tables blob if memory hotplug isn't used. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
161 lines
6.7 KiB
Plaintext
161 lines
6.7 KiB
Plaintext
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
|
|
|
|
Scope(\_SB.PCI0) {
|
|
Device(MEMORY_HOTPLUG_DEVICE) {
|
|
Name(_HID, "PNP0A06")
|
|
Name(_UID, "Memory hotplug resources")
|
|
External(MEMORY_SLOTS_NUMBER, IntObj)
|
|
|
|
/* Memory hotplug IO registers */
|
|
External(MEMORY_SLOT_ADDR_LOW, FieldUnitObj) // read only
|
|
External(MEMORY_SLOT_ADDR_HIGH, FieldUnitObj) // read only
|
|
External(MEMORY_SLOT_SIZE_LOW, FieldUnitObj) // read only
|
|
External(MEMORY_SLOT_SIZE_HIGH, FieldUnitObj) // read only
|
|
External(MEMORY_SLOT_PROXIMITY, FieldUnitObj) // read only
|
|
External(MEMORY_SLOT_ENABLED, FieldUnitObj) // 1 if enabled, read only
|
|
External(MEMORY_SLOT_INSERT_EVENT, FieldUnitObj) // (read) 1 if has a insert event. (write) 1 to clear event
|
|
External(MEMORY_SLOT_SLECTOR, FieldUnitObj) // DIMM selector, write only
|
|
External(MEMORY_SLOT_OST_EVENT, FieldUnitObj) // _OST event code, write only
|
|
External(MEMORY_SLOT_OST_STATUS, FieldUnitObj) // _OST status code, write only
|
|
|
|
Method(_STA, 0) {
|
|
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
|
Return(0x0)
|
|
}
|
|
/* present, functioning, decoding, not shown in UI */
|
|
Return(0xB)
|
|
}
|
|
|
|
Mutex (MEMORY_SLOT_LOCK, 0)
|
|
|
|
Method(MEMORY_SLOT_SCAN_METHOD, 0) {
|
|
If (LEqual(MEMORY_SLOTS_NUMBER, Zero)) {
|
|
Return(Zero)
|
|
}
|
|
|
|
Store(Zero, Local0) // Mem devs iterrator
|
|
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
|
while (LLess(Local0, MEMORY_SLOTS_NUMBER)) {
|
|
Store(Local0, MEMORY_SLOT_SLECTOR) // select Local0 DIMM
|
|
If (LEqual(MEMORY_SLOT_INSERT_EVENT, One)) { // Memory device needs check
|
|
MEMORY_SLOT_NOTIFY_METHOD(Local0, 1)
|
|
Store(1, MEMORY_SLOT_INSERT_EVENT)
|
|
}
|
|
// TODO: handle memory eject request
|
|
Add(Local0, One, Local0) // goto next DIMM
|
|
}
|
|
Release(MEMORY_SLOT_LOCK)
|
|
Return(One)
|
|
}
|
|
|
|
Method(MEMORY_SLOT_STATUS_METHOD, 1) {
|
|
Store(Zero, Local0)
|
|
|
|
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
|
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
|
|
|
If (LEqual(MEMORY_SLOT_ENABLED, One)) {
|
|
Store(0xF, Local0)
|
|
}
|
|
|
|
Release(MEMORY_SLOT_LOCK)
|
|
Return(Local0)
|
|
}
|
|
|
|
Method(MEMORY_SLOT_CRS_METHOD, 1, Serialized) {
|
|
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
|
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
|
|
|
Name(MR64, ResourceTemplate() {
|
|
QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed,
|
|
Cacheable, ReadWrite,
|
|
0x0000000000000000, // Address Space Granularity
|
|
0x0000000000000000, // Address Range Minimum
|
|
0xFFFFFFFFFFFFFFFE, // Address Range Maximum
|
|
0x0000000000000000, // Address Translation Offset
|
|
0xFFFFFFFFFFFFFFFF, // Address Length
|
|
,, MW64, AddressRangeMemory, TypeStatic)
|
|
})
|
|
|
|
CreateDWordField(MR64, 14, MINL)
|
|
CreateDWordField(MR64, 18, MINH)
|
|
CreateDWordField(MR64, 38, LENL)
|
|
CreateDWordField(MR64, 42, LENH)
|
|
CreateDWordField(MR64, 22, MAXL)
|
|
CreateDWordField(MR64, 26, MAXH)
|
|
|
|
Store(MEMORY_SLOT_ADDR_HIGH, MINH)
|
|
Store(MEMORY_SLOT_ADDR_LOW, MINL)
|
|
Store(MEMORY_SLOT_SIZE_HIGH, LENH)
|
|
Store(MEMORY_SLOT_SIZE_LOW, LENL)
|
|
|
|
// 64-bit math: MAX = MIN + LEN - 1
|
|
Add(MINL, LENL, MAXL)
|
|
Add(MINH, LENH, MAXH)
|
|
If (LLess(MAXL, MINL)) {
|
|
Add(MAXH, One, MAXH)
|
|
}
|
|
If (LLess(MAXL, One)) {
|
|
Subtract(MAXH, One, MAXH)
|
|
}
|
|
Subtract(MAXL, One, MAXL)
|
|
|
|
If (LEqual(MAXH, Zero)){
|
|
Name(MR32, ResourceTemplate() {
|
|
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed,
|
|
Cacheable, ReadWrite,
|
|
0x00000000, // Address Space Granularity
|
|
0x00000000, // Address Range Minimum
|
|
0xFFFFFFFE, // Address Range Maximum
|
|
0x00000000, // Address Translation Offset
|
|
0xFFFFFFFF, // Address Length
|
|
,, MW32, AddressRangeMemory, TypeStatic)
|
|
})
|
|
CreateDWordField(MR32, MW32._MIN, MIN)
|
|
CreateDWordField(MR32, MW32._MAX, MAX)
|
|
CreateDWordField(MR32, MW32._LEN, LEN)
|
|
Store(MINL, MIN)
|
|
Store(MAXL, MAX)
|
|
Store(LENL, LEN)
|
|
|
|
Release(MEMORY_SLOT_LOCK)
|
|
Return(MR32)
|
|
}
|
|
|
|
Release(MEMORY_SLOT_LOCK)
|
|
Return(MR64)
|
|
}
|
|
|
|
Method(MEMORY_SLOT_PROXIMITY_METHOD, 1) {
|
|
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
|
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
|
Store(MEMORY_SLOT_PROXIMITY, Local0)
|
|
Release(MEMORY_SLOT_LOCK)
|
|
Return(Local0)
|
|
}
|
|
|
|
Method(MEMORY_SLOT_OST_METHOD, 4) {
|
|
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
|
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
|
Store(Arg1, MEMORY_SLOT_OST_EVENT)
|
|
Store(Arg2, MEMORY_SLOT_OST_STATUS)
|
|
Release(MEMORY_SLOT_LOCK)
|
|
}
|
|
} // Device()
|
|
} // Scope()
|