二、PCC实例应用
2.1 概述
平台通信通道(PCC)是用于PC和服务器平台的ACPI规范定义的机制,作为平台固件(如系统固件或管理控制器)和操作系统(OSPM)之间双向通信的标准机制。
PCC是一种通用机制,是一种管道,可用于其他基于ACPI的特性。一些基于ACPI的特性使用PCC在平台固件和OSPM之间建立通信的例子是RASF, MPST等。
PCC共享内存区
为了在平台固件和OPSM之间建立通信,PCC定义了一个邮箱和一个事件接口。邮箱称为“通用通信通道共享内存区域”。平台固件(如系统固件)为此保留了一定范围的系统内存。在这个共享内存区域中,为每个特性分配了槽(子空间)。在我们的例子中,在PCC共享内存区域中将有一个RASF槽。给定的ACPI特性使用哪个槽,在相应的特性的ACPI表中指定。
例如,RASF特性定义了它自己的ACPI表(“RASF”),该表中的“平台通信通道ID”(PCC ID)字段间接指定了共享内存区域中的子空间插槽位置,这将在后面的章节中解释。注意:在本文档中,术语“槽”用于表示PCC共享内存区域内的子空间区域,对应于给定的ACPI特性。这是为了避免与PCC表(“PCCT”)中使用的术语“PCC子空间结构”混淆。
2.2 实例表与PCCT表的相关性
2.2.1表结构关联性
下图描述了如何使用PCC ID建立feature表(如MPST、RASF)、PCC共享内存区域和PCCT表之间的相关性。
为ACPI特性(如RASF)提供服务的OSPM将做以下工作:
1. 将找到对应的ACPI表(如RASF)。
2. 将从表中读取PCC ID(如图1-1所示)。
3.使用此ID作为ACPI PCC表中PCC子空间结构数组的索引。(PCCT),定位对应的PCC子空间结构(图1-2)。
4. 利用PCC子空间结构中的信息定位“PCC共享内存区域”中对应的槽。
5. 使用“PCC共享内存区域”中的槽(子空间)作为通信邮箱。
下图为OSPM初始化RASF实例表流程:
2.2.2 PCC通道通信
1> PCC完成
OSPM使用“门铃寄存器”、“门铃保存”和“门铃写入”字段来调用平台PCC流。请参见“图2-2 PCC子空间结构”。
这些字段由平台固件在启动期间填充传递给OSPM,OSPM使用的已有实现来调用平台固件。“门铃寄存器”使用ACPI定义的标准“通用地址结构”(GAS)。具体结构的定义请参考ACPI规范。
GAS结构提供了一种机制来引用任何寄存器(系统内存、IO、PCIe空间等)。系统固件填充“门铃寄存器”,以指向OSPM必须写入的寄存器,以调用平台PCC流。它还填充“门铃保存”和“门铃写入”字段,以通知OSPM它应该写入指定寄存器的值。“门铃保存”和“门铃写入”字段为读-改-写语义提供了and掩码和OR掩码。本质上,
Doorbell Register = (Doorbell Register & Doorbell Preserve) | (Doorbell Write)
写入“Doorbell register”执行平台PCC流程。
- 执行完成通知
如果OSPM希望得到PCC事件完成的通知,可以选择在执行PCC之前在PCC通用通信结构的命令域中设置“Generate SCI”位(参见图2-3 PCC共享内存区域槽)。
一旦平台固件完成PCC的执行,它将生成一个SCI (ACPI中断;请参阅ACPI规范)通知OSPM。为了使OSPM能够确定SCI发生的原因,平台固件将在PCC通用通信结构的状态字段(参见图2-3 PCC共享内存区域槽)中设置“SCI门铃”位和“command complete”位。收到SCI事件,OSPM应该查询“SCI门铃”在“状态”字段的PCC通用的通信结构,以确定哪些槽(例如RASF)负责触发SCI事件,然后调查中的“命令完成”字段相同的结构来确定SCI事件是由于之前完成的PCC命令(而不是异步SCI, 3.4节中描述)
- 通过轮询确定事件完成情况
如果OSPM选择轮询PCC完成而不是SCI通知,则不设置“Generate SCI”位,而是利用“PCC子空间结构”(参见图2-2 PCC子空间结构)中提供的“Nominal Latency”值来确定轮询间隔。
通过轮询“Status”字段中的“Command Complete”位(图2-3 PCC共享内存区域槽),OSPM可以确定之前发出的PCC命令的完成情况。
- 异步事件通知
到目前为止,我们已经讨论了OSPM用于调用平台PCC流的机制以及在执行命令后,来自平台的响应。
在某些情况下,平台可能希望针对某些事件独立地引起OSPM的注意。这可能是为了响应平台固件希望异步向操作系统报告的平台事件。在这种情况下,平台固件将在“状态字段”(图2-3 PCC共享内存区域槽)中通过Platform interrupt和Platform Notification位域来消除响应PCC完成中断或异步平台事件的SCI通知之间的歧义。
下图为PCC事件处理流程:
- 实例概述及实现
3.1 RASF
下表定义了RAS能力
Bit | RAS Feature |
0 | 表示平台支持DRAM内存基于硬件的循环擦除 |
1 | 表示平台支持基于硬件的循环擦除且对软件透明 |
2 | 表示当系统断电平台确保cpu刷新cache的数据写回到内存 |
3 | 表示平台提供了在平台断电时自动将未完成的写入数据从内存控制器刷新到持久内存的机制。 注意:如果设置了第2位,那么这个位也应该设置。 |
4 | 指示平台支持一起镜像多字节可寻址的持久内存区域。如果支持并启用了该特性,健康硬件镜像交错集将在NFIT表中的系统物理地址范围结构中设置EFI_MEMORY_MORE_RELIABLE地址范围内存映射属性。 |
5-127 | 保留 |
Parameter Block
Field | RAS Feature |
Type | 0x0000 – Patrol scrub |
Patrol Scrub Command (INPUT) | 0x01 - GET_PATROL_PARAMETERS 0x02 - START_PATROL_SCRUBBER 0x03 – STOP_PATROL_SCRUBBER |
Requested Address Range (INPUT) | OSPM指定Patrol scrub基地址和长度 |
Actual Address Range (OUTPUT) | 平台返回这个值以响应GET_PATROL_PARAMETERS。平台从它可以开始的地方计算最近的Patrol scrub边界地址。 这个范围应该是请求地址范围的超集。 基数(字节7-0)和大小(字节15-8)的地址 |
Flags (OUTPUT) | 平台返回这个值以响应GET_PATROL_PARAMETERS [0]位:如果在“实际地址范围”中指定的地址范围已经运行的情况下,将被设置Bit [3:1]:当前Patrol 速度,如果设置bit[0]则Bits [3:1]表示当前速度: 000b – Slow 100b – Medium 111b – Fast Bits [15:4]: 保留。 |
Requested Speed (INPUT) | OSPM为START_PATROL_SCRUBBER命令设置这个字段如下 [0]位:如果在“实际地址范围”中指定的地址范围已经运行的情况下,将被设置 bit[2:0]:请求的Patrol速度 000 b -缓慢 100 b -介质 111 b -快 所有其他组合均保留。 位(7:3):保留 |
下面的序列记录OSPM识别平台是否支持基于硬件的循环擦除(patrol scrub)的步骤,并调用命令请求硬件循环擦除指定的地址范围。
1.识别平台是否支持基于硬件的循环擦除,并通过读取RASF表中的RAS能力位图来确定对软件的支持
2. 通过设置请求的地址范围,调用GET_PATROL_PARAMETERS。
3.平台返回实际地址范围和标志。
4. 根据以上两个数据,如果OPSM决定启动循环擦除器或改变循环擦除器的速度,则OSPM通过设置请求的地址范围和请求的速度,调用START_PATROL_SCRUBBER。
3.2 MPST
此表描述了新的ACPI内存电源状态表(MPST)的结构。 该表定义了配置的存储电源节点拓扑,如第1节中所述。该配置包括指定存储电源节点及其相关信息。 使用地址范围,支持的内存电源状态指定每个内存电源节点。存储器电源状态将包括硬件控制的和软件控制的存储器电源状态。 给定的存储器电源节点可以有多个条目,以支持不连续的地址范围。 MPST表还定义了OSPM和平台运行时固件之间的通信机制,用于触发在平台运行时固件中实现的软件控制的存储器电源状态转换。
MPST PCC子通道
平台在此字段中提供的MPST PCC子信道标识符值应设置为PCC通信子空间结构的“类型”字段。 MPST表通过此标识符在给定平台中引用其PCC子空间,如表5-89所示。
PCC寄存器
OSPM将通过在PCC子通道空间中填充寄存器值并发出PCC Execute命令来写入PCC寄存器。 请参阅下面的表5-90。 所有其他命令值均保留。
配置内存电源状态流程:
SetMemoryPowerState:需要执行以下顺序来设置内存电源状态
1.将目标POWER NODE ID值写入PCC子通道的MEMORY_POWER_NODE_ID寄存器。
2. 将所需的电源状态ID值写入PCC子通道的电源状态ID寄存器。
3. 将SET(见表5-91)写入PCC子通道的MEMORY_POWER_STATE寄存器。
4. 将PCC EXECUTE(参见表5-90)写入PCC子通道的PCC命令寄存器。
5. OSPM通过写门铃寄存器来使门铃响起。
6. 平台完成请求,并将生成SCI以指示命令已完成。
7. OSPM读取PCC子通道的状态寄存器,并确认命令已成功完成。
注:Power state Values:
0(MPS0)--- 此状态值映射到内存节点的活动状态(正常操作)。 OSPM可以在此状态下访问内存。
1(MPS1)--- 根据平台功能,可以将此状态值映射到任何内存电源状态。 该平台将使用内存电源状态结构来通知MPS1状态的功能。 按照惯例,要求低值电源状态比高值电源状态具有更低的功耗节省和更低的延迟。
GetMemoryPowerState:需要完成以下序列以获取当前的内存电源状态
1.将目标POWER NODE ID值写入PCC子通道的MEMORY_POWER_NODE_ID寄存器。
2. 将GET(参见表5-91)写入PCC子通道的MEMORY_POWER_STATE寄存器。
3. 将PCC EXECUTE(参见表5-90)写入PCC子通道的PCC命令寄存器。
4. OSPM通过写门铃寄存器来使门铃响起。
5. 平台完成请求,并将生成SCI以指示命令已完成。
6. OSPM读取PCC子通道的状态寄存器,并确认命令已成功完成。
7. OSPM从PCC子通道的POWER_STATE_ID寄存器中读取POWER STATE。
3.3 PDTT
本节描述了平台调试触发器表(PDTT)描述表的格式,该表是一个可选表,描述了一个或多个PCC子空间标识符,这些标识符可用于触发/通知特定于平台的调试工具以捕获非体系结构系统状态。这作为OSPM通知平台致命崩溃的标准机制(例如,内核崩溃或错误检查)。
该表适用于提供调试硬件功能的平台,这些功能可以捕获正常OS故障转储以外的系统信息。该触发器可用于捕获平台特定的状态信息(例如,固件状态,片上硬件设施,辅助控制器等)。可以在移动平台,客户端和企业平台上利用这种调试功能。
某些平台可能具有必须单独触发的多个调试子系统。该表通过允许列出多个触发器来容纳此类系统。
触发调试工具后,CPU必须继续按预期运行,以便内核可以继续进行崩溃处理/处理(例如,可能在重新引导系统之前尝试连接调试器或进行完整的崩溃转储)。在某些平台上,调试触发器可能会将某些硬件组件/外围设备置于冻结的非操作状态,因此建议不要在正常运行时操作中使用调试触发器。
其他平台可能允许用于捕获系统状态的调试触发器来调试由表AAA中的“运行时”标志字段指定的运行时行为问题(例如,系统性能和电源问题)。
如果存在多个触发器,则OSPM必须按照表中列出的顺序执行触发器。 OSPM可能需要等待PCC完成,然后才能根据表AAA中的“等待完成”标志字段执行下一次触发。
注意:用户检索此系统调试状态信息的机制是特定于平台和供应商的。这很可能需要特殊的工具和特权才能访问和解析此触发器捕获的平台调试信息。
示例:操作系统调用多个调试触发器
为了说明操作系统打算如何使用这些调试触发器,请考虑具有4个独立调试触发器的系统示例,如表5-31所示。 这些触发器通过表5-148中的PDTT示例描述给OS。
注意:此示例假定不需要特定于供应商的通信,因此仅使用PCC命令0x0。
当操作系统遇到致命故障时,在收集故障转储并重新引导系统之前,操作系统可以选择以PDTT中列出的顺序调用调试触发器。 门铃寄存器和PCC通用通信空间(如果需要)的地址从PCCT中检索,具体取决于PCC子空间类型(请参见表14-354,表14-355或表14-356)。
遍历PDTT中的触发器列表,操作系统可以执行以下步骤:
1.对于触发器0,按照PCC子空间ID 4从PCCT中检索门铃寄存器地址,并使用适当的写/保留掩码对其进行写操作。由于OS不需要等待完成,因此OS不需要发送PCC命令,并且应该忽略PCC子空间基地址。
2.对于触发器1,每个PCC子空间ID 1从PCCT中检索门铃寄存器地址和PCC子空间地址。由于OS必须等待完成,因此OS必须写入PCC命令(0x0)并按第14节写入门铃寄存器,并轮询完成位。
3.对于触发器2,每个PCC子空间ID 2从PCCT中检索门铃寄存器地址,并使用适当的写/保留掩码对其进行写操作。由于OS不需要等待完成,因此OS不需要发送PCC命令,并且应该忽略PCC子空间基地址。
4.对于触发器3,每个PCC子空间ID 3从PCCT中检索门铃寄存器地址和PCC子空间地址。由于OS必须等待完成,因此OS必须写入PCC命令(0x0)并按第14节写入门
寄存器并轮询完成位。
3.4 CPPC
协作处理器性能控制为OSPM定义了一种抽象且灵活的机制,可与平台中的实体进行协作以管理逻辑处理器的性能。在此方案中,平台实体负责创建和维护性能定义,该定义支持连续的,抽象的,无单元的性能量表。在运行时,OSPM在此抽象级别上请求所需的性能,并且平台实体负责将OSPM性能请求转换为实际的硬件性能状态。
该平台还可以支持自主选择适合当前工作负载的性能级别的能力。在这种情况下,OSPM将信息传达给平台,以指导平台的性能级别选择。平台必须对系统中的所有处理器使用相同的性能等级。在具有异构处理器的平台上,所有处理器的性能特征可能并不相同。在这种情况下,平台必须综合根据处理器差异进行调整的性能量表,以使在相同性能水平下运行相同工作负载的任何两个处理器将在大约相同的时间内完成。该平台应针对不同类别的处理器公开不同的功能,以便准确反映每个处理器的性能特征。
_CPC对象方法抽象了控制机制,该方法描述了如何以通用方式控制和监视处理器性能。寄存器方法可以在平台通信通道(PCC)接口中实现(请参见第14节)。这提供了足够的灵活性,OSPM与之通信的实体可以是处理器本身,平台芯片组或单独的实体(例如BMC)。
3.4.1_CPC概述
此可选对象声明一个接口,该接口允许OSPM根据连续范围的允许值将处理器转换到相应的性能状态。OSPM将所需的性能值写入所需的性能寄存器,平台将所需的性能映射到内部性能状态。如果平台支持,则OSPM可以在指定最低和最高性能要求的同时启用自主性能级别选择。
_CPC对象为OSPM提供特定于平台的性能功能/阈值和控制寄存器,OSPM使用这些功能来控制平台的处理器性能设置。这些将在以下各节中进行描述。尽管平台可能会在允许范围内指定寄存器大小,但是功能/阈值寄存器的大小必须与控制寄存器的大小兼容。如果平台支持CPPC,则_CPC对象必须存在于所有处理器对象下。也就是说,预计OSPM不支持混合模式(CPPC和旧版PSS,_PCT,_PPC)操作。
从ACPI规范6.2开始,所有_CPC寄存器都可以位于PCC,系统内存,系统IO或功能性固定硬件地址空间中。 OSPM对这种更灵活的寄存器空间方案的支持由“ CPPC寄存器的灵活地址空间” _OSC位指示。
3.4.2性能/阈值
基于性能的控件在一系列连续的处理器性能级别上运行,而不是在离散的处理器状态下运行。结果,根据性能阈值指定了平台功能和OSPM请求。图8-50概述了平台的静态性能阈值和动态保证性能阈值。
注意:并非所有性能级别都需要唯一。例如,平台的标称性能水平也可以是其最高性能水平。
3.4.3使用PCC寄存器
如果使用PCC寄存器空间,则必须将同一性能域(由_PSD定义)中所有处理器的所有PCC寄存器定义为位于同一子空间中。如果未使用_PSD,则此限制适用于给定_CPC对象内的所有寄存器。 OSPM将通过填写寄存器值并发出PCC写命令来写寄存器(请参见表8-278)。它可以通过发出读取命令来读取静态寄存器,计数器和性能限制寄存器(请参见表8-278)。为了分摊PCC事务的成本,OSPM应该在可能的情况下通过单个读取或写入命令来读取或写入所有PCC寄存器。
3.4.4与其他ACPI定义的对象和通知的关系
如果存在_CPC,则它的使用将取代以下现有的ACPI对象的使用:
•P_BLK P_CNT寄存器
•_PTC
•_TSS
•_TPC
•_TSD
•_TDL
•_PCT
•_PSS
•_PPC
•_PDL
•在处理器设备上通知0x80
•在处理器设备上通知0x82
_PSD对象可用于指定处理器之间的域依赖性。 在具有异构处理器的系统上,单个域内的所有处理器必须具有相同的性能。
3.5 cppc实现
3.5.1 固件实现
a、PCCT表的实现
根据规范中的定义,在UEFI中生成PCCT表,并根据实例_CPC对象填写相关内容:
[000h 0000 4] Signature : "PCCT" [Platform Communications Channel Table]
[004h 0004 4] Table Length : 0000006E
[008h 0008 1] Revision : 02
[009h 0009 1] Checksum : 18
[00Ah 0010 6] Oem ID : "LOONGS"
[010h 0016 8] Oem Table ID : "LOONGSON"
[018h 0024 4] Oem Revision : 00000002
[01Ch 0028 4] Asl Compiler ID : "LIUX"
[020h 0032 4] Asl Compiler Revision : 01000013
[024h 0036 4] Flags (decoded below) : 00000000
Doorbell : 0
[028h 0040 8] Reserved : 0000000000000000
[030h 0048 1] Subtable Type : 00 [Generic Communications Subspace]
[031h 0049 1] Length : 3E
[032h 0050 6] Reserved : 000000000000
[038h 0056 8] Base Address : 00000000FD159000
[040h 0064 8] Address Length : 0000000000000100
[048h 0072 12] Doorbell Register : [Generic Address Structure]
[048h 0072 1] Space ID : 00 [SystemMemory]
[049h 0073 1] Bit Width : 20
[04Ah 0074 1] Bit Offset : 00
[04Bh 0075 1] Encoded Access Width : 00 [Undefined/Legacy]
[04Ch 0076 8] Address : 00000000FD159100
[054h 0084 8] Preserve Mask : 0000000000000000
[05Ch 0092 8] Write Mask : 0000000000000000
[064h 0100 4] Command Latency : 00000100
[068h 0104 4] Maximum Access Rate : 00000010
[06Ch 0108 2] Minimum Turnaround Time : 0000
b、_CPC对象
Name (_CPC, Package (0x15) // _CPC: Continuous Performance Control
{
0x15,
0x02,
ResourceTemplate ()
{
Register (PCC,
0x20, // Bit Width
0x00, // Bit Offset
0x0000000000000000, // Address
,)
},
ResourceTemplate ()
{
Register (PCC,
0x20, // Bit Width
0x00, // Bit Offset
0x0000000000000004, // Address
,)
},
ResourceTemplate ()
{
Register (PCC,
0x20, // Bit Width
0x00, // Bit Offset
0x0000000000000008, // Address
,)
},
ResourceTemplate ()
{
Register (PCC,
0x20, // Bit Width
0x00, // Bit Offset
0x000000000000000C, // Address
,)
},
。。。
}
3.5.2 内核流程
内核中开内核线程主要负责当OSPM需要设置核的频率时,将相应数据写入共享内存中,且按门铃通知平台实现相关调频动作时,线程负责将内核相关标志置位,模拟实现了平台调频动作。实现流程在内核中的闭环。将内核流程模拟实现。
下面为内核中调频相关调用流程:
- 系统初始化/CPU热插拔:
[ 6.460937] [<ffffffff80d6d1c4>] pcc_send_data+0x10c/0x160
[ 6.460937] [<ffffffff80d6b504>] msg_submit+0xbc/0x140
[ 6.460937] [<ffffffff80d6b6d4>] mbox_send_message+0x9c/0x1b0
[ 6.460937] [<ffffffff8095ff54>] send_pcc_cmd+0xbc/0x340
[ 6.460937] [<ffffffff80960d44>] cppc_get_perf_caps+0x124/0x3e8
[ 6.460937] [<ffffffff80d3b764>] cppc_cpufreq_cpu_init+0x5c/0x1d8
[ 6.460937] [<ffffffff80d379bc>] cpufreq_online+0x104/0x728
[ 6.460937] [<ffffffff80d38098>] cpufreq_add_dev+0x98/0xb0
[ 6.460937] [<ffffffff80a31aa0>] subsys_interface_register+0xb0/0x108
[ 6.460937] [<ffffffff80d36a7c>] cpufreq_register_driver+0x15c/0x208
[ 6.460937] [<ffffffff81455230>] cppc_cpufreq_init+0x100/0x1a8
调用CPU调频驱动注册的init函数,调用cppc_get_perf_caps函数获取_CPC对象传递给内核的CPU频率相关参数,初始化相应数据结构。并调用cppc_set_perf设置当前CPU频率。
- echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor;
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor;
切换governor/设置相关参数
Call Trace:
[ 40.050781] [<ffffffff8021bd5c>] show_stack+0x9c/0x130
[ 40.050781] [<ffffffff80f77210>] dump_stack+0xa0/0xe0
[ 40.050781] [<ffffffff809611dc>] send_pcc_cmd+0xdc/0x308
[ 40.050781] [<ffffffff80962d74>] cppc_set_perf+0x26c/0x3c8
[ 40.050781] [<ffffffff80d3c89c>] cppc_cpufreq_set_target+0xc4/0x170
[ 40.050781] [<ffffffff80d37258>] __cpufreq_driver_target+0x708/0x768
[ 40.050781] [<ffffffff80d3740c>] cpufreq_start_governor+0x7c/0xb0
[ 40.195312] [<ffffffff80d38638>] cpufreq_set_policy+0x1a0/0x210
[ 40.199218] [<ffffffff80d38840>] store_scaling_governor+0x80/0xd8
[ 40.207031] [<ffffffff80d35e50>] store+0xc8/0xe0
[ 40.210937] [<ffffffff804a6320>] kernfs_fop_write+0xd0/0x1f8
[ 40.218750] [<ffffffff8040f1b8>] __vfs_write+0x38/0x190
[ 40.222656] [<ffffffff8040f4e8>] vfs_write+0xc0/0x1d8
[ 40.226562] [<ffffffff8040f7c0>] ksys_write+0x70/0x118
[ 40.230468] [<ffffffff80224474>] syscall_common+0x34/0x58
static int cpufreq_start_governor(struct cpufreq_policy *policy)
{
int ret;
if (cpufreq_suspended)
return 0;
if (!policy->governor)
return -EINVAL;
pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
cpufreq_update_current_freq(policy);
if (policy->governor->start) {
ret = policy->governor->start(policy);
if (ret)
return ret;
}
if (policy->governor->limits)
policy->governor->limits(policy);
return 0;
}
- cat /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf
查看当前系统CPU频率范围
[ 19.054687] [<ffffffff80d6d1c4>] pcc_send_data+0x10c/0x160
[ 19.058593] [<ffffffff80d6b504>] msg_submit+0xbc/0x140
[ 19.066406] [<ffffffff80d6b6d4>] mbox_send_message+0x9c/0x1b0
[ 19.070312] [<ffffffff8095ff54>] send_pcc_cmd+0xbc/0x340
[ 19.078125] [<ffffffff80960d44>] cppc_get_perf_caps+0x124/0x3e8
[ 19.082031] [<ffffffff809612c0>] show_highest_perf+0x38/0x80
- 休眠唤醒
[ 4998.308593] [<ffffffff80d6d1c4>] pcc_send_data+0x10c/0x160
[ 4998.308593] [<ffffffff80d6b504>] msg_submit+0xbc/0x140
[ 4998.308593] [<ffffffff80d6b6d4>] mbox_send_message+0x9c/0x1b0
[ 4998.308593] [<ffffffff8095ff54>] send_pcc_cmd+0xbc/0x340
[ 4998.308593] [<ffffffff8096152c>] cppc_get_perf_ctrs+0x224/0x358
[ 4998.308593] [<ffffffff80d3b9f4>] cppc_cpufreq_get_rate+0xa4/0x160
[ 4998.308593] [<ffffffff80d3583c>] cpufreq_update_current_freq+0x2c/0xe0
[ 4998.308593] [<ffffffff80d361d0>] cpufreq_start_governor+0xa0/0xb0
[ 4998.308593] [<ffffffff80d37068>] cpufreq_resume+0xd0/0x188
[ 4998.308593] [<ffffffff80a459ec>] dpm_resume_end+0x14/0x28
[ 4998.308593] [<ffffffff802cdfd0>] suspend_devices_and_enter+0x1f0/0x640
[ 4998.308593] [<ffffffff802ce6c8>] pm_suspend+0x2a8/0x310