1# Copyright (c) 2015, Intel Corporation
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7#     * Redistributions of source code must retain the above copyright notice,
8#       this list of conditions and the following disclaimer.
9#     * Redistributions in binary form must reproduce the above copyright notice,
10#       this list of conditions and the following disclaimer in the documentation
11#       and/or other materials provided with the distribution.
12#     * Neither the name of Intel Corporation nor the names of its contributors
13#       may be used to endorse or promote products derived from this software
14#       without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27"""Tests for ACPI"""
28
29import acpi
30import bits
31import bits.mwait
32import struct
33import testutil
34import testsuite
35import time
36
37def register_tests():
38    testsuite.add_test("ACPI _MAT (Multiple APIC Table Entry) under Processor objects", test_mat, submenu="ACPI Tests")
39#    testsuite.add_test("ACPI _PSS (Pstate) table conformance tests", test_pss, submenu="ACPI Tests")
40#    testsuite.add_test("ACPI _PSS (Pstate) runtime tests", test_pstates, submenu="ACPI Tests")
41    testsuite.add_test("ACPI DSDT (Differentiated System Description Table)", test_dsdt, submenu="ACPI Tests")
42    testsuite.add_test("ACPI FACP (Fixed ACPI Description Table)", test_facp, submenu="ACPI Tests")
43    testsuite.add_test("ACPI HPET (High Precision Event Timer Table)", test_hpet, submenu="ACPI Tests")
44    testsuite.add_test("ACPI MADT (Multiple APIC Description Table)", test_apic, submenu="ACPI Tests")
45    testsuite.add_test("ACPI MPST (Memory Power State Table)", test_mpst, submenu="ACPI Tests")
46    testsuite.add_test("ACPI RSDP (Root System Description Pointer Structure)", test_rsdp, submenu="ACPI Tests")
47    testsuite.add_test("ACPI XSDT (Extended System Description Table)", test_xsdt, submenu="ACPI Tests")
48
49def test_mat():
50    cpupaths = acpi.get_cpupaths()
51    apic = acpi.parse_apic()
52    procid_apicid = apic.procid_apicid
53    uid_x2apicid = apic.uid_x2apicid
54    for cpupath in cpupaths:
55        # Find the ProcId defined by the processor object
56        processor = acpi.evaluate(cpupath)
57        # Find the UID defined by the processor object's _UID method
58        uid = acpi.evaluate(cpupath + "._UID")
59        mat_buffer = acpi.evaluate(cpupath + "._MAT")
60        if mat_buffer is None:
61            continue
62        # Process each _MAT subtable
63        mat = acpi._MAT(mat_buffer)
64        for index, subtable in enumerate(mat):
65            if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC:
66                if subtable.flags.bits.enabled:
67                    testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id)
68                    testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id))
69                    testsuite.print_detail("Processor Declaration: {}".format(processor))
70                    testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
71                    if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid):
72                        testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id)
73                        testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id))
74                        testsuite.print_detail("Processor Declaration: {}".format(processor))
75                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
76            if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC:
77                if subtable.flags.bits.enabled:
78                    if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None):
79                        testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid)
80                        testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid))
81                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
82                    if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid):
83                        testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid)
84                        testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid))
85                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
86
87def test_pss():
88    uniques = acpi.parse_cpu_method("_PSS")
89    # We special-case None here to avoid a double-failure for CPUs without a _PSS
90    testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques))
91    for pss, cpupaths in uniques.iteritems():
92        if not testsuite.test("_PSS must exist", pss is not None):
93            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
94            testsuite.print_detail('No _PSS exists')
95            continue
96
97        if not testsuite.test("_PSS must not be empty", pss.pstates):
98            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
99            testsuite.print_detail('_PSS is empty')
100            continue
101
102        testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
103        for index, pstate in enumerate(pss.pstates):
104            testsuite.print_detail("P[{}]: {}".format(index, pstate))
105
106        testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16)
107        testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates)))
108
109        frequencies = [p.core_frequency for p in pss.pstates]
110        testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True))
111
112        testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies)))
113
114        dissipations = [p.power for p in pss.pstates]
115        testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True))
116
117def test_pstates():
118    """Execute and verify frequency for each Pstate in the _PSS"""
119    IA32_PERF_CTL = 0x199
120    with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL):
121        cpupath_procid = acpi.find_procid()
122        cpupath_uid = acpi.find_uid()
123        apic = acpi.parse_apic()
124        procid_apicid = apic.procid_apicid
125        uid_x2apicid = apic.uid_x2apicid
126        def cpupath_apicid(cpupath):
127            if procid_apicid is not None:
128                procid = cpupath_procid.get(cpupath, None)
129                if procid is not None:
130                    apicid = procid_apicid.get(procid, None)
131                    if apicid is not None:
132                        return apicid
133            if uid_x2apicid is not None:
134                uid = cpupath_uid.get(cpupath, None)
135                if uid is not None:
136                    apicid = uid_x2apicid.get(uid, None)
137                    if apicid is not None:
138                        return apicid
139            return bits.cpus()[0]
140
141        bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000
142
143        uniques = acpi.parse_cpu_method("_PSS")
144        for pss, cpupaths in uniques.iteritems():
145            if not testsuite.test("_PSS must exist", pss is not None):
146                testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
147                testsuite.print_detail('No _PSS exists')
148                continue
149
150            for n, pstate in enumerate(pss.pstates):
151                for cpupath in cpupaths:
152                    apicid = cpupath_apicid(cpupath)
153                    if apicid is None:
154                        print 'Failed to find apicid for cpupath {}'.format(cpupath)
155                        continue
156                    bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control)
157
158                # Detecting Turbo frequency requires at least 2 pstates
159                # since turbo frequency = max non-turbo frequency + 1
160                turbo = False
161                if len(pss.pstates) >= 2:
162                    turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1))
163                    if turbo:
164                        # Needs to busywait, not sleep
165                        start = time.time()
166                        while (time.time() - start < 2):
167                            pass
168
169                for duration in (0.1, 1.0):
170                    frequency_data = bits.cpu_frequency(duration)
171                    # Abort the test if no cpu frequency is not available
172                    if frequency_data is None:
173                        continue
174                    aperf = frequency_data[1]
175                    aperf = testutil.adjust_to_nearest(aperf, bclk/2)
176                    aperf = int(aperf / 1000000)
177                    if turbo:
178                        if aperf >= pstate.core_frequency:
179                            break
180                    else:
181                        if aperf == pstate.core_frequency:
182                            break
183
184                if turbo:
185                    testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency)
186                else:
187                    testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency)
188
189def test_psd_thread_scope():
190    uniques = acpi.parse_cpu_method("_PSD")
191    if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques):
192        testsuite.print_detail(acpi.factor_commonprefix(uniques[None]))
193        testsuite.print_detail('No _PSD exists')
194        return
195    unique_num_dependencies = {}
196    unique_num_entries = {}
197    unique_revision = {}
198    unique_domain = {}
199    unique_coordination_type = {}
200    unique_num_processors = {}
201    for value, cpupaths in uniques.iteritems():
202        unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths)
203        unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths)
204        unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths)
205        unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths)
206        unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths)
207        unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths)
208    def detail(d, fmt):
209        for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)):
210            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
211            testsuite.print_detail(fmt.format(value))
212
213    testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1])
214    detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)')
215    testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5])
216    detail(unique_num_entries, 'num_entries = {} (Expected 5)')
217    testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0])
218    detail(unique_revision, 'revision = {}')
219    testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe])
220    detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)')
221    testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths()))
222    detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)')
223    testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1])
224    detail(unique_num_processors, 'num_processors = {} (Expected 1)')
225
226def test_table_checksum(data):
227    csum = sum(ord(c) for c in data) % 0x100
228    testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0)
229    testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum))
230
231def test_apic():
232    data = acpi.get_table("APIC")
233    if data is None:
234        return
235    test_table_checksum(data)
236    apic = acpi.parse_apic()
237
238def test_dsdt():
239    data = acpi.get_table("DSDT")
240    if data is None:
241        return
242    test_table_checksum(data)
243
244def test_facp():
245    data = acpi.get_table("FACP")
246    if data is None:
247        return
248    test_table_checksum(data)
249    facp = acpi.parse_facp()
250
251def test_hpet():
252    data = acpi.get_table("HPET")
253    if data is None:
254        return
255    test_table_checksum(data)
256    hpet = acpi.parse_hpet()
257
258def test_mpst():
259    data = acpi.get_table("MPST")
260    if data is None:
261        return
262    test_table_checksum(data)
263    mpst = acpi.MPST(data)
264
265def test_rsdp():
266    data = acpi.get_table("RSD PTR ")
267    if data is None:
268        return
269
270    # Checksum the first 20 bytes per ACPI 1.0
271    csum = sum(ord(c) for c in data[:20]) % 0x100
272    testsuite.test('ACPI 1.0 table first 20 bytes cummulative checksum must equal 0', csum == 0)
273    testsuite.print_detail("Cummulative checksum = {} (Expected 0)".format(csum))
274
275    test_table_checksum(data)
276    rsdp = acpi.parse_rsdp()
277
278def test_xsdt():
279    data = acpi.get_table("XSDT")
280    if data is None:
281        return
282    test_table_checksum(data)
283    xsdt = acpi.parse_xsdt()
284