9.PECI(Platform Environment Control Interface):peci是 intel提供的私有协议,openbmc是由intel授权的,其他不授权是不能用。硬件上是一根线,不像i2c是2根线
11.1 模式和命令介绍:peci1.1只支持CPU温度,2.0增加支持MSR相关寄存器,3.0增加支持读intel的PCI配置(根据intel的BDF【Bus/Device/Function】确定读pcie设备里的寄存器地址)
1.PCH模式
:需要先访问ME地址挂在smlink上,如下-b就是挂的bus号(i2c即smlink的bus号),-t是挂的地址,一般都是0x2c(设备地址)。BMC通过IPMI给ME发一个raw date命令,ME再发pcie命令到cpu
。实际是ME不停给cpu发一些peci命令来获取它需要的数据,它把这些数据做一个缓存在自己内部,bmc向它访问数据的话,me会直接把缓存的数据回到bmc上,如下raw 6 1 是读ME的版本号。
2.PECI模式
:obmc上有一个peci-util命令,通过这命令直接访问到cpu内部,peci-util虽是二进制命令,但是底层调用libpeci库(https://github.com/openbmc/libpeci.git),通过libpeci访问 /dev/peci-0节点进行IO操作即那根数据线发peci指令
。Openbmc中使能PECI需要同时修改kernel.cfg和image.bb文件
:在image.bb中IMAGE_INSTALL 变量中追加”peci-util-v2”来安装peci-util二进制文件即命令,在kernel.cfg中打开三行CONFIG_PECI相关宏来使能PECI驱动即生成 /dev/peci-0,如下图:
如下peci3.0支持的方式,如下10个命令也不是所有cpu平台都支持,具体还要看cpu手册,因为cpu平台功能划分比较细,不是所有平台都支持所有功能,前5个全平台支持。
11.2 通过peci读cpu温度:使用RdPkgconfig()命令(read page config),通过peci读到cpu的最大值(tjmax)和一个偏移量(Tcontrol)(距离当前设定的最大值还差多少值),这两个的差值作为cpu实际温度
如上LSB和MSB反一下。
11.3 通过peci读cpu的DIMM温度:不涉及偏差多少,直接读实时温度,也用RdPkgconfig()
11.4 通过peci读MSR:不止msr还有pcie寄存器一些读法,lerrLoggingReg寄存器通过查cpu手册,发现是pcie寄存器。BDFO四个变量才能确定一个地址,带外方式用RdPCIConfigLocal()读PCIE寄存器
如下第一列0-15个物理核(intel最多支持),项目是0-4个物理核相当于5个cpu,现在项目只读物理核。读出如下0x0400寄存器值,具体解析bios做。读取期间不让cpld使cpu复位重启。cpu中所有msr寄存器(model specific register)是x86中监测CPU方面的寄存器,MSR使用RdIAMSR()命令。
# dumplwt.sh
. /usr/local/bin/openbmc-utils.sh
renice -20 -p $$ >/dev/null 2>&1
do_msr_deal()
{
echo
echo CPU MSR DUMP:
echo ==============
echo
echo "MCA_ERR_SRC_LOG"
peci-util 0x30 0x05 0x05 0xA1 0x00 0x00 0x05 0x00
echo
echo "IerrLoggingReg"
peci-util 0x30 0x05 0x05 0xE1 0x00 0xA4 0x50 0x18
echo
echo "MCerrLoggingReg"
peci-util 0x30 0x05 0x05 0xE1 0x00 0xA8 0x50 0x18
echo
echo "********************************************************"
echo "* MC index 00 *"
echo "********************************************************"
echo " IA32_MC0_CTL, ProcessorID from 0 to 4 " # 0x0400,查看RdIAMSR()命令组成
peci-util 0x30 0x05 0x09 0xB1 0x00 0x00 0x00 0x04 # 倒数第三个是ProcessorID即5个cpu
peci-util 0x30 0x05 0x09 0xB1 0x00 0x01 0x00 0x04
peci-util 0x30 0x05 0x09 0xB1 0x00 0x02 0x00 0x04
peci-util 0x30 0x05 0x09 0xB1 0x00 0x03 0x00 0x04
peci-util 0x30 0x05 0x09 0xB1 0x00 0x04 0x00 0x04
echo " IA32_MC0_CTL2, ProcessorID from 0 to 4 " # 0x0280
peci-util 0x30 0x05 0x09 0xB1 0x00 0x00 0x80 0x02
peci-util 0x30 0x05 0x09 0xB1 0x00 0x01 0x80 0x02
peci-util 0x30 0x05 0x09 0xB1 0x00 0x02 0x80 0x02
peci-util 0x30 0x05 0x09 0xB1 0x00 0x03 0x80 0x02
peci-util 0x30 0x05 0x09 0xB1 0x00 0x04 0x80 0x02
do_peci_select 7 #peci通道提前手动选择
do_msr_deal
do_peci_select 8
do_msr_deal
# 如下0x400是MC0起始地址,0x404是MC1起始地址
IA32_MCi_CTL=(0x400 0x404 0x408 0x40c 0x410 0x414 0x418 0x41c 0x420 0x424 0x428)
mce_log(){
modprobe msr
mcelog --daemon # 手动启动mcelog。查看mcelog日志:vim /var/log/mcelog
i=${#IA32_MCi_CTL[@]}
echo "read IA32_MCi_CTL register begin ${IA32_MCi_CTL[*]}"
for ((cpu=0;cpu<8;cpu++));do
echo "cpu $cpu read IA32_MCi_CTL register"
for ((row=0;row<i;row++));do
rdmsr -p $cpu ${IA32_MCi_CTL[row]} -x
done
done
echo "read IA32_MCi_CTL register end"
}
mce_log