blob: 3f8159479d2b1504ade213df82b7ad6803aa5a3c [file] [log] [blame]
Lei YUa03e55e2018-08-03 17:43:25 +08001#!/usr/bin/env python3
2
Lei YUa03e55e2018-08-03 17:43:25 +08003import argparse
Lei YUd4051652018-08-06 17:02:00 +08004from typing import NamedTuple
5
Patrick Williamsa3db66b2022-12-04 16:27:08 -06006import yaml
7
Lei YUd4051652018-08-06 17:02:00 +08008
9class RptSensor(NamedTuple):
10 name: str
11 entityId: int
12 typeId: int
13 evtType: int
14 sensorId: int
15 fru: int
16 targetPath: str
17
18
Lei YU206f7c42018-08-07 15:12:19 +080019sampleDimmTemp = {
Patrick Williamsa3db66b2022-12-04 16:27:08 -060020 "bExp": 0,
21 "entityID": 32,
22 "entityInstance": 2,
23 "interfaces": {
24 "xyz.openbmc_project.Sensor.Value": {
25 "Value": {"Offsets": {255: {"type": "int64_t"}}}
Lei YU206f7c42018-08-07 15:12:19 +080026 }
27 },
Patrick Williamsa3db66b2022-12-04 16:27:08 -060028 "multiplierM": 1,
29 "mutability": "Mutability::Write|Mutability::Read",
30 "offsetB": -127,
31 "path": "/xyz/openbmc_project/sensors/temperature/dimm0_temp",
32 "rExp": 0,
33 "readingType": "readingData",
34 "scale": -3,
35 "sensorNamePattern": "nameLeaf",
36 "sensorReadingType": 1,
37 "sensorType": 1,
38 "serviceInterface": "org.freedesktop.DBus.Properties",
39 "unit": "xyz.openbmc_project.Sensor.Value.Unit.DegreesC",
Lei YU206f7c42018-08-07 15:12:19 +080040}
41sampleCoreTemp = {
Patrick Williamsa3db66b2022-12-04 16:27:08 -060042 "bExp": 0,
43 "entityID": 208,
44 "entityInstance": 2,
45 "interfaces": {
46 "xyz.openbmc_project.Sensor.Value": {
47 "Value": {"Offsets": {255: {"type": "int64_t"}}}
Lei YU206f7c42018-08-07 15:12:19 +080048 }
49 },
Patrick Williamsa3db66b2022-12-04 16:27:08 -060050 "multiplierM": 1,
51 "mutability": "Mutability::Write|Mutability::Read",
52 "offsetB": -127,
53 "path": "/xyz/openbmc_project/sensors/temperature/p0_core0_temp",
54 "rExp": 0,
55 "readingType": "readingData",
56 "scale": -3,
57 "sensorNamePattern": "nameLeaf",
58 "sensorReadingType": 1,
59 "sensorType": 1,
60 "serviceInterface": "org.freedesktop.DBus.Properties",
61 "unit": "xyz.openbmc_project.Sensor.Value.Unit.DegreesC",
Lei YU206f7c42018-08-07 15:12:19 +080062}
Lei YU4c7f1082018-08-23 16:25:58 +080063samplePower = {
Patrick Williamsa3db66b2022-12-04 16:27:08 -060064 "bExp": 0,
65 "entityID": 10,
66 "entityInstance": 13,
67 "interfaces": {
68 "xyz.openbmc_project.Sensor.Value": {
69 "Value": {"Offsets": {255: {"type": "int64_t"}}}
Lei YU4c7f1082018-08-23 16:25:58 +080070 }
71 },
Patrick Williamsa3db66b2022-12-04 16:27:08 -060072 "multiplierM": 2,
73 "offsetB": 0,
74 "path": "/xyz/openbmc_project/sensors/power/p0_power",
75 "rExp": 0,
76 "readingType": "readingData",
77 "scale": -6,
78 "sensorNamePattern": "nameLeaf",
79 "sensorReadingType": 1,
80 "sensorType": 8,
81 "serviceInterface": "org.freedesktop.DBus.Properties",
82 "unit": "xyz.openbmc_project.Sensor.Value.Unit.Watts",
Lei YU4c7f1082018-08-23 16:25:58 +080083}
84
Lei YUa49f04f2018-08-09 15:14:53 +080085sampleDcmiSensor = {
86 "instance": 1,
87 "dbus": "/xyz/openbmc_project/sensors/temperature/p0_core0_temp",
Patrick Williamsa3db66b2022-12-04 16:27:08 -060088 "record_id": 91,
Lei YUa49f04f2018-08-09 15:14:53 +080089}
Lei YU206f7c42018-08-07 15:12:19 +080090
91
Lei YUa03e55e2018-08-03 17:43:25 +080092def openYaml(f):
93 return yaml.load(open(f))
94
95
Lei YUdf0c4172018-08-08 10:42:08 +080096def saveYaml(y, f, safe=True):
97 if safe:
98 noaliasDumper = yaml.dumper.SafeDumper
99 noaliasDumper.ignore_aliases = lambda self, data: True
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600100 yaml.dump(
101 y, open(f, "w"), default_flow_style=False, Dumper=noaliasDumper
102 )
Lei YUdf0c4172018-08-08 10:42:08 +0800103 else:
104 yaml.dump(y, open(f, "w"))
Lei YUa03e55e2018-08-03 17:43:25 +0800105
106
Lei YU9f394032018-08-08 11:25:21 +0800107def getEntityIdAndNamePattern(p, intfs, m):
108 key = (p, intfs)
109 match = m.get(key, None)
110 if match is None:
Lei YU25ecc552018-08-23 14:20:45 +0800111 # Workaround for P8's occ sensors, where the path look like
112 # /org/open_power/control/occ_3_0050
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600113 if (
114 "/org/open_power/control/occ" in p
115 and "org.open_power.OCC.Status" in intfs
116 ):
117 return (210, "nameLeaf")
118 raise Exception("Unable to find sensor", key, "from map")
119 return (m[key]["entityID"], m[key]["sensorNamePattern"])
Lei YUa03e55e2018-08-03 17:43:25 +0800120
121
122# Global entity instances
123entityInstances = {}
124
125
126def getEntityInstance(id):
127 instanceId = entityInstances.get(id, 0)
128 instanceId = instanceId + 1
129 entityInstances[id] = instanceId
130 print("EntityId:", id, "InstanceId:", instanceId)
131 return instanceId
132
133
Lei YUd4051652018-08-06 17:02:00 +0800134def loadRpt(rptFile):
135 sensors = []
136 with open(rptFile) as f:
137 next(f)
138 next(f)
139 for line in f:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600140 fields = line.strip().split("|")
Lei YUd4051652018-08-06 17:02:00 +0800141 fields = list(map(str.strip, fields))
142 sensor = RptSensor(
143 fields[0],
144 int(fields[2], 16) if fields[2] else None,
145 int(fields[3], 16) if fields[3] else None,
146 int(fields[4], 16) if fields[4] else None,
147 int(fields[5], 16) if fields[5] else None,
148 int(fields[7], 16) if fields[7] else None,
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600149 fields[9],
150 )
Lei YUd4051652018-08-06 17:02:00 +0800151 # print(sensor)
152 sensors.append(sensor)
153 return sensors
154
155
Lei YU206f7c42018-08-07 15:12:19 +0800156def getDimmTempPath(p):
157 # Convert path like: /sys-0/node-0/motherboard-0/dimmconn-0/dimm-0
158 # to: /xyz/openbmc_project/sensors/temperature/dimm0_temp
159 import re
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600160
161 dimmconn = re.search(r"dimmconn-\d+", p).group()
162 dimmId = re.search(r"\d+", dimmconn).group()
163 return "/xyz/openbmc_project/sensors/temperature/dimm{}_temp".format(
164 dimmId
165 )
Lei YU206f7c42018-08-07 15:12:19 +0800166
167
Lei YU25ecc552018-08-23 14:20:45 +0800168def getMembufTempPath(name):
169 # Convert names like MEMBUF0_Temp or CENTAUR0_Temp
170 # to: /xyz/openbmc_project/sensors/temperature/membuf0_temp
171 # to: /xyz/openbmc_project/sensors/temperature/centaur0_temp
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600172 return "/xyz/openbmc_project/sensors/temperature/{}".format(name.lower())
Lei YU25ecc552018-08-23 14:20:45 +0800173
174
175def getCoreTempPath(name, p):
176 # For different rpts:
177 # Convert path like:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600178 # /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/eq0/ex0/core0 (for P9) # noqa: E501
Lei YU206f7c42018-08-07 15:12:19 +0800179 # to: /xyz/openbmc_project/sensors/temperature/p0_core0_temp
Lei YU25ecc552018-08-23 14:20:45 +0800180 # or name like: CORE0_Temp (for P8)
181 # to: /xyz/openbmc_project/sensors/temperature/core0_temp (for P8)
Lei YU206f7c42018-08-07 15:12:19 +0800182 import re
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600183
184 if "p9_proc" in p:
185 splitted = p.split("/")
186 socket = re.search(r"\d+", splitted[4]).group()
187 core = re.search(r"\d+", splitted[9]).group()
188 return (
189 "/xyz/openbmc_project/sensors/temperature/p{}_core{}_temp".format(
190 socket, core
191 )
192 )
Lei YU25ecc552018-08-23 14:20:45 +0800193 else:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600194 core = re.search(r"\d+", name).group()
195 return "/xyz/openbmc_project/sensors/temperature/core{}_temp".format(
196 core
197 )
Lei YU206f7c42018-08-07 15:12:19 +0800198
199
Lei YU4c7f1082018-08-23 16:25:58 +0800200def getPowerPath(name):
201 # Convert name like Proc0_Power
202 # to: /xyz/openbmc_project/sensors/power/p0_power
203 import re
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600204
205 r = re.search(r"\d+", name)
Lei YU4c7f1082018-08-23 16:25:58 +0800206 if r:
207 index = r.group()
208 else:
209 # Handle cases like IO_A_Power, Storage_Power_A
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600210 r = re.search(r"_[A|B|C|D]", name).group()[-1]
211 index = str(ord(r) - ord("A"))
212 prefix = "p"
Lei YU4c7f1082018-08-23 16:25:58 +0800213 m = None
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600214 if "memory_proc" in name.lower():
Lei YU4c7f1082018-08-23 16:25:58 +0800215 prefix = None
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600216 m = "centaur"
217 elif "pcie_proc" in name.lower():
218 m = "pcie"
219 elif "io" in name.lower():
220 m = "io"
221 elif "fan" in name.lower():
222 m = "fan"
223 elif "storage" in name.lower():
224 m = "disk"
225 elif "total" in name.lower():
Lei YU4c7f1082018-08-23 16:25:58 +0800226 prefix = None
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600227 m = "total"
228 elif "proc" in name.lower():
Lei YU4c7f1082018-08-23 16:25:58 +0800229 # Default
230 pass
231
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600232 ret = "/xyz/openbmc_project/sensors/power/"
Lei YU4c7f1082018-08-23 16:25:58 +0800233 if prefix:
234 ret = ret + prefix + index
235 if m:
236 if prefix:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600237 ret = ret + "_" + m
Lei YU4c7f1082018-08-23 16:25:58 +0800238 else:
239 ret = ret + m
240 if prefix is None:
241 ret = ret + index
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600242 ret = ret + "_power"
Lei YU4c7f1082018-08-23 16:25:58 +0800243 return ret
244
245
Lei YU206f7c42018-08-07 15:12:19 +0800246def getDimmTempConfig(s):
247 r = sampleDimmTemp.copy()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600248 r["entityInstance"] = getEntityInstance(r["entityID"])
249 r["path"] = getDimmTempPath(s.targetPath)
Lei YU206f7c42018-08-07 15:12:19 +0800250 return r
251
252
Lei YU25ecc552018-08-23 14:20:45 +0800253def getMembufTempConfig(s):
254 r = sampleDimmTemp.copy()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600255 r["entityID"] = 0xD1
256 r["entityInstance"] = getEntityInstance(r["entityID"])
257 r["path"] = getMembufTempPath(s.name)
Lei YU25ecc552018-08-23 14:20:45 +0800258 return r
259
260
Lei YU206f7c42018-08-07 15:12:19 +0800261def getCoreTempConfig(s):
262 r = sampleCoreTemp.copy()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600263 r["entityInstance"] = getEntityInstance(r["entityID"])
264 r["path"] = getCoreTempPath(s.name, s.targetPath)
Lei YU206f7c42018-08-07 15:12:19 +0800265 return r
266
267
Lei YU4c7f1082018-08-23 16:25:58 +0800268def getPowerConfig(s):
269 r = samplePower.copy()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600270 r["entityInstance"] = getEntityInstance(r["entityID"])
271 r["path"] = getPowerPath(s.name)
Lei YU4c7f1082018-08-23 16:25:58 +0800272 return r
273
274
Lei YUa49f04f2018-08-09 15:14:53 +0800275def isCoreTemp(p):
276 import re
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600277
278 m = re.search(r"p\d+_core\d+_temp", p)
Lei YUa49f04f2018-08-09 15:14:53 +0800279 return m is not None
280
281
282def getDcmiSensor(i, sensor):
283 import re
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600284
285 path = sensor["path"]
286 name = path.split("/")[-1]
287 m = re.findall(r"\d+", name)
Lei YUa49f04f2018-08-09 15:14:53 +0800288 socket, core = int(m[0]), int(m[1])
289 instance = socket * 24 + core + 1
290 r = sampleDcmiSensor.copy()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600291 r["instance"] = instance
292 r["dbus"] = path
293 r["record_id"] = i
Lei YUa49f04f2018-08-09 15:14:53 +0800294 return r
295
296
297def saveJson(data, f):
298 import json
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600299
300 with open(f, "w") as outfile:
Lei YUa49f04f2018-08-09 15:14:53 +0800301 json.dump(data, outfile, indent=4)
302
303
Lei YUa03e55e2018-08-03 17:43:25 +0800304def main():
305 parser = argparse.ArgumentParser(
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600306 description="Yaml tool for updating ipmi sensor yaml config"
307 )
308 parser.add_argument(
309 "-i",
310 "--input",
311 required=True,
312 dest="input",
313 help="The ipmi sensor yaml config",
314 )
315 parser.add_argument(
316 "-o",
317 "--output",
318 required=True,
319 dest="output",
320 help="The output yaml file",
321 )
322 parser.add_argument(
323 "-m",
324 "--map",
325 dest="map",
326 default="sensor_map.yaml",
327 help="The sample map yaml file",
328 )
329 parser.add_argument(
330 "-r", "--rpt", dest="rpt", help="The .rpt file generated by op-build"
331 )
332 parser.add_argument(
333 "-f",
334 "--fix",
335 action="store_true",
336 help="Fix entities and sensorNamePattern",
337 )
Lei YUa49f04f2018-08-09 15:14:53 +0800338
339 # -g expects output as yaml for mapping of entityID/sensorNamePattern
340 # -d expects output as json config for dcmi sensors
341 # Do not mess the output by enforcing only one argument is passed
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600342 # TODO: -f and -r could be used together, and they are conflicted with
343 # -g or -d
Lei YUa49f04f2018-08-09 15:14:53 +0800344 group = parser.add_mutually_exclusive_group()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600345 group.add_argument(
346 "-g",
347 "--generate",
348 action="store_true",
349 help="Generate maps for entityID and sensorNamePattern",
350 )
351 group.add_argument(
352 "-d",
353 "--dcmi",
354 action="store_true",
355 help="Generate dcmi sensors json config",
356 )
Lei YUa03e55e2018-08-03 17:43:25 +0800357
358 args = parser.parse_args()
359 args = vars(args)
360
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600361 if args["input"] is None or args["output"] is None:
Lei YUa03e55e2018-08-03 17:43:25 +0800362 parser.print_help()
363 exit(1)
364
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600365 y = openYaml(args["input"])
Lei YUa03e55e2018-08-03 17:43:25 +0800366
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600367 if args["fix"]:
Lei YU9f394032018-08-08 11:25:21 +0800368 # Fix entities and sensorNamePattern
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600369 m = openYaml(args["map"])
Lei YU9f394032018-08-08 11:25:21 +0800370
Lei YUa03e55e2018-08-03 17:43:25 +0800371 for i in y:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600372 path = y[i]["path"]
373 intfs = tuple(sorted(list(y[i]["interfaces"].keys())))
Lei YU9f394032018-08-08 11:25:21 +0800374 entityId, namePattern = getEntityIdAndNamePattern(path, intfs, m)
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600375 y[i]["entityID"] = entityId
376 y[i]["entityInstance"] = getEntityInstance(entityId)
377 y[i]["sensorNamePattern"] = namePattern
378 print(
379 y[i]["path"],
380 "id:",
381 entityId,
382 "instance:",
383 y[i]["entityInstance"],
384 )
Lei YUa03e55e2018-08-03 17:43:25 +0800385
Lei YU206f7c42018-08-07 15:12:19 +0800386 sensorIds = list(y.keys())
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600387 if args["rpt"]:
Lei YU25ecc552018-08-23 14:20:45 +0800388 unhandledSensors = []
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600389 rptSensors = loadRpt(args["rpt"])
Lei YU206f7c42018-08-07 15:12:19 +0800390 for s in rptSensors:
391 if s.sensorId is not None and s.sensorId not in sensorIds:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600392 print(
393 "Sensor ID",
394 s.sensorId,
395 "not in yaml:",
396 s.name,
397 ", path:",
398 s.targetPath,
399 )
Lei YU4c7f1082018-08-23 16:25:58 +0800400 isAdded = False
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600401 if "temp" in s.name.lower():
402 if "dimm" in s.targetPath.lower():
Lei YU206f7c42018-08-07 15:12:19 +0800403 y[s.sensorId] = getDimmTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800404 isAdded = True
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600405 elif "core" in s.targetPath.lower():
Lei YU206f7c42018-08-07 15:12:19 +0800406 y[s.sensorId] = getCoreTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800407 isAdded = True
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600408 elif (
409 "centaur" in s.name.lower()
410 or "membuf" in s.name.lower()
411 ):
Lei YU25ecc552018-08-23 14:20:45 +0800412 y[s.sensorId] = getMembufTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800413 isAdded = True
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600414 elif s.name.lower().endswith("_power"):
Lei YU4c7f1082018-08-23 16:25:58 +0800415 y[s.sensorId] = getPowerConfig(s)
416 isAdded = True
417
418 if isAdded:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600419 print(
420 "Added sensor id:",
421 s.sensorId,
422 ", path:",
423 y[s.sensorId]["path"],
424 )
Lei YU25ecc552018-08-23 14:20:45 +0800425 else:
426 unhandledSensors.append(s)
427
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600428 print("Unhandled sensors:")
Lei YU25ecc552018-08-23 14:20:45 +0800429 for s in unhandledSensors:
430 print(s)
Lei YU206f7c42018-08-07 15:12:19 +0800431
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600432 if args["generate"]:
Lei YUdf0c4172018-08-08 10:42:08 +0800433 m = {}
434 for i in y:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600435 path = y[i]["path"]
436 intfs = tuple(sorted(list(y[i]["interfaces"].keys())))
437 entityId = y[i]["entityID"]
438 sensorNamePattern = y[i]["sensorNamePattern"]
439 m[(path, intfs)] = {
440 "entityID": entityId,
441 "sensorNamePattern": sensorNamePattern,
442 }
Lei YUdf0c4172018-08-08 10:42:08 +0800443 y = m
444
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600445 if args["dcmi"]:
Lei YUa49f04f2018-08-09 15:14:53 +0800446 d = []
447 for i in y:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600448 if isCoreTemp(y[i]["path"]):
Lei YUa49f04f2018-08-09 15:14:53 +0800449 s = getDcmiSensor(i, y[i])
450 d.append(s)
451 print(s)
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600452 saveJson(d, args["output"])
Lei YUa49f04f2018-08-09 15:14:53 +0800453 return
Lei YUdf0c4172018-08-08 10:42:08 +0800454
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600455 safe = False if args["generate"] else True
456 saveYaml(y, args["output"], safe)
Lei YUa03e55e2018-08-03 17:43:25 +0800457
458
459if __name__ == "__main__":
460 main()