diff mbox

[RFC,V3] sensors: occ: Add support for OCC inband sensors

Message ID 1490876024-21737-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State RFC
Headers show

Commit Message

Shilpasri G Bhat March 30, 2017, 12:13 p.m. UTC
Add support to parse and export OCC inband sensors which are copied
by OCC to main memory in P9. Each OCC writes three buffers which
includes one names buffer for sensor meta data and two buffers for
sensor readings. While OCC writes to one buffer the sensor values
can be read from the other buffer. The sensors are updated every
100ms.

This patch adds power, temperature, current and voltage sensors to
/ibm,opal/sensors device-tree node which can be exported by the
ibmpowernv-hwmon driver in Linux.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
---
Changes from V2:
- Added current and voltage sensors
- Removed 'struct occ_sensor_info' which was used to store sensor
  offset address values
- Added sensor attributes like MIN and MAX
- Moved the header sanity checks to a separate routine
  'occ_sensor_sanity()'
- Added a mapping for OCC sensor name to userspace label. If the
  mapping is not found we fall back to OCC name.

 core/init.c       |   1 +
 core/sensor.c     |   4 +
 hw/Makefile.inc   |   2 +-
 hw/occ-sensor.c   | 596 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/sensor.h  |   1 +
 include/skiboot.h |   4 +
 6 files changed, 607 insertions(+), 1 deletion(-)
 create mode 100644 hw/occ-sensor.c

Comments

Cédric Le Goater March 30, 2017, 12:24 p.m. UTC | #1
On 03/30/2017 02:13 PM, Shilpasri G Bhat wrote:
> Add support to parse and export OCC inband sensors which are copied
> by OCC to main memory in P9. Each OCC writes three buffers which
> includes one names buffer for sensor meta data and two buffers for
> sensor readings. While OCC writes to one buffer the sensor values
> can be read from the other buffer. The sensors are updated every
> 100ms.
> 
> This patch adds power, temperature, current and voltage sensors to
> /ibm,opal/sensors device-tree node which can be exported by the
> ibmpowernv-hwmon driver in Linux.
> 
> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
> ---
> Changes from V2:
> - Added current and voltage sensors
> - Removed 'struct occ_sensor_info' which was used to store sensor
>   offset address values
> - Added sensor attributes like MIN and MAX
> - Moved the header sanity checks to a separate routine
>   'occ_sensor_sanity()'
> - Added a mapping for OCC sensor name to userspace label. If the
>   mapping is not found we fall back to OCC name.

Could you give us a sample output of the command 'sensors' ? 

and also the result of :

	lsprop /proc/device-tree/ibm,opal/sensors/

Thanks,

C.
Shilpasri G Bhat March 30, 2017, 12:27 p.m. UTC | #2
On 03/30/2017 05:54 PM, Cédric Le Goater wrote:
> On 03/30/2017 02:13 PM, Shilpasri G Bhat wrote:
>> Add support to parse and export OCC inband sensors which are copied
>> by OCC to main memory in P9. Each OCC writes three buffers which
>> includes one names buffer for sensor meta data and two buffers for
>> sensor readings. While OCC writes to one buffer the sensor values
>> can be read from the other buffer. The sensors are updated every
>> 100ms.
>>
>> This patch adds power, temperature, current and voltage sensors to
>> /ibm,opal/sensors device-tree node which can be exported by the
>> ibmpowernv-hwmon driver in Linux.
>>
>> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
>> ---
>> Changes from V2:
>> - Added current and voltage sensors
>> - Removed 'struct occ_sensor_info' which was used to store sensor
>>   offset address values
>> - Added sensor attributes like MIN and MAX
>> - Moved the header sanity checks to a separate routine
>>   'occ_sensor_sanity()'
>> - Added a mapping for OCC sensor name to userspace label. If the
>>   mapping is not found we fall back to OCC name.
> 
> Could you give us a sample output of the command 'sensors' ? 
> 
> and also the result of :
> 
> 	lsprop /proc/device-tree/ibm,opal/sensors/
> 
> Thanks,
> 
> C.
> 

# sensors
ibmpowernv-isa-0000
Adapter: ISA adapter
Chip 0 Vdd Remote Sense:  +5.40 V  (lowest =  +0.02 V, highest =  +0.03 V)
Chip 0 Vdd:               +5.40 V  (lowest =  +0.02 V, highest =  +0.03 V)
Core 0:                   +46.0°C
Core 8:                   +47.0°C
Core 16:                  +53.0°C
Core 24:                  +50.0°C
Chip 0 Core 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Core 1 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Core 2 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Core 3 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Core 4 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 GPU 2 :            +46.0°C  (low  = +32.0°C, high = +54.0°C)
Chip 0 GPU 2 DRAM0:       +46.0°C  (low  = +32.0°C, high = +54.0°C)
Chip 0 GPU 1 DRAM2:       +46.0°C  (low  = +32.0°C, high = +54.0°C)
Chip 0 DIMM 6 :           +34.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 DIMM 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 DIMM 3 :           +46.0°C  (low  = +32.0°C, high = +54.0°C)
Centaur 1:                +30.0°C
Chip 0 Nest:              +34.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Quad 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Quad 1 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 Quad 2 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
Chip 0 GPU:              340.00 W  (lowest = 250.00 W, highest = 800.00 W)
Chip 0 :                 540.00 W  (lowest =  23.00 W, highest =  34.00 W)
Chip 0 Vdd:              540.00 W  (lowest =  23.00 W, highest =  34.00 W)
Chip 0 Memory:           540.00 W  (lowest =  23.00 W, highest =  34.00 W)
System:                  940.00 W  (lowest = 250.00 W, highest = 800.00 W)
Fan:                     370.00 W  (lowest = 250.00 W, highest = 800.00 W)
IO:                      360.00 W  (lowest = 250.00 W, highest = 800.00 W)
Storage:                 380.00 W  (lowest = 250.00 W, highest = 800.00 W)
APSS 12 :                540.00 W  (lowest =  23.00 W, highest =  34.00 W)
Chip 0 Vdd:               +0.05 A  (lowest =  +0.03 A, highest =  +0.05 A)

/proc/device-tree/ibm,opal/sensors# lsprop
compatible       "ibm,opal-sensor"
phandle          1000011b (268435739)
name             "sensors"

vrm-curr@c00010:
sensor-data      00c00010 (12582928)
compatible       "ibm,opal-sensor"
occ_label        "CURVDD"
label            "Chip 0 Vdd"
phandle          10000148 (268435784)
sensor-type      "curr"
sensor-data-min  02c00010 (46137360)
sensor-data-max  01c00010 (29360144)
name             "vrm-curr"

gpu-power@c00004:
sensor-data      00c00004 (12582916)
compatible       "ibm,opal-sensor"
occ_label        "PWRGPU"
label            "Chip 0 GPU"
phandle          1000013d (268435773)
sensor-type      "power"
sensor-data-min  02c00004 (46137348)
sensor-data-max  01c00004 (29360132)
name             "gpu-power"

quad-temp@c0000e:
sensor-data      00c0000e (12582926)
compatible       "ibm,opal-sensor"
occ_label        "TEMPQ1"
label            "Chip 0 Quad 1 "
phandle          10000146 (268435782)
sensor-type      "temp"
sensor-data-min  02c0000e (46137358)
sensor-data-max  01c0000e (29360142)
name             "quad-temp"

proc-power@c00016:
sensor-data      00c00016 (12582934)
compatible       "ibm,opal-sensor"
occ_label        "PWRMEM"
label            "Chip 0 Memory"
phandle          1000014e (268435790)
sensor-type      "power"
sensor-data-min  02c00016 (46137366)
sensor-data-max  01c00016 (29360150)
name             "proc-power"

proc-power@c00014:
sensor-data      00c00014 (12582932)
compatible       "ibm,opal-sensor"
occ_label        "PWRVDD"
label            "Chip 0 Vdd"
phandle          1000014c (268435788)
sensor-type      "power"
sensor-data-min  02c00014 (46137364)
sensor-data-max  01c00014 (29360148)
name             "proc-power"

core-temp@c0000b:
sensor-data      00c0000b (12582923)
compatible       "ibm,opal-sensor"
occ_label        "TEMPC3"
label            "Chip 0 Core 3 "
phandle          10000143 (268435779)
sensor-type      "temp"
sensor-data-min  02c0000b (46137355)
sensor-data-max  01c0000b (29360139)
name             "core-temp"

mem-temp@c00017:
sensor-data      00c00017 (12582935)
compatible       "ibm,opal-sensor"
occ_label        "TEMPDIMM0"
label            "Chip 0 DIMM 0 "
phandle          1000014f (268435791)
sensor-type      "temp"
sensor-data-min  02c00017 (46137367)
sensor-data-max  01c00017 (29360151)
name             "mem-temp"

gpu-temp@c0001a:
sensor-data      00c0001a (12582938)
compatible       "ibm,opal-sensor"
occ_label        "TEMPGPU2DRAM0"
label            "Chip 0 GPU 2 DRAM0"
phandle          10000152 (268435794)
sensor-type      "temp"
sensor-data-min  02c0001a (46137370)
sensor-data-max  01c0001a (29360154)
name             "gpu-temp"

sys-power@c00012:
sensor-data      00c00012 (12582930)
compatible       "ibm,opal-sensor"
occ_label        "PWRAPSSCH12"
label            "APSS 12 "
phandle          1000014a (268435786)
sensor-type      "power"
sensor-data-min  02c00012 (46137362)
sensor-data-max  01c00012 (29360146)
name             "sys-power"

core-temp@68:
sensor-data      00e00068 (14680168)
compatible       "ibm,opal-sensor"
ibm,pir          00000068 (104)
label            "Core"
phandle          1000011e (268435742)
sensor-type      "temp"
sensor-status    01e00068 (31457384)
name             "core-temp"

proc-in@c00015:
sensor-data      00c00015 (12582933)
compatible       "ibm,opal-sensor"
occ_label        "VOLTVDDSENSE"
label            "Chip 0 Vdd Remote Sense"
phandle          1000014d (268435789)
sensor-type      "in"
sensor-data-min  02c00015 (46137365)
sensor-data-max  01c00015 (29360149)
name             "proc-in"

sys-power@c00002:
sensor-data      00c00002 (12582914)
compatible       "ibm,opal-sensor"
occ_label        "PWRIO"
label            "IO"
phandle          1000013b (268435771)
sensor-type      "power"
sensor-data-min  02c00002 (46137346)
sensor-data-max  01c00002 (29360130)
name             "sys-power"

core-temp@c00009:
sensor-data      00c00009 (12582921)
compatible       "ibm,opal-sensor"
occ_label        "TEMPC1"
label            "Chip 0 Core 1 "
phandle          10000141 (268435777)
sensor-type      "temp"
sensor-data-min  02c00009 (46137353)
sensor-data-max  01c00009 (29360137)
name             "core-temp"

core-temp@28:
sensor-data      00e00028 (14680104)
compatible       "ibm,opal-sensor"
ibm,pir          00000028 (40)
label            "Core"
phandle          1000011d (268435741)
sensor-type      "temp"
sensor-status    01e00028 (31457320)
name             "core-temp"

sys-power@c00000:
sensor-data      00c00000 (12582912)
compatible       "ibm,opal-sensor"
occ_label        "PWRSYS"
label            "System"
phandle          10000139 (268435769)
sensor-type      "power"
sensor-data-min  02c00000 (46137344)
sensor-data-max  01c00000 (29360128)
name             "sys-power"

proc-temp@c00005:
sensor-data      00c00005 (12582917)
compatible       "ibm,opal-sensor"
occ_label        "TEMPNEST"
label            "Chip 0 Nest"
phandle          1000013e (268435774)
sensor-type      "temp"
sensor-data-min  02c00005 (46137349)
sensor-data-max  01c00005 (29360133)
name             "proc-temp"

quad-temp@c0000f:
sensor-data      00c0000f (12582927)
compatible       "ibm,opal-sensor"
occ_label        "TEMPQ2"
label            "Chip 0 Quad 2 "
phandle          10000147 (268435783)
sensor-type      "temp"
sensor-data-min  02c0000f (46137359)
sensor-data-max  01c0000f (29360143)
name             "quad-temp"

quad-temp@c0000d:
sensor-data      00c0000d (12582925)
compatible       "ibm,opal-sensor"
occ_label        "TEMPQ0"
label            "Chip 0 Quad 0 "
phandle          10000145 (268435781)
sensor-type      "temp"
sensor-data-min  02c0000d (46137357)
sensor-data-max  01c0000d (29360141)
name             "quad-temp"

core-temp@c0000c:
sensor-data      00c0000c (12582924)
compatible       "ibm,opal-sensor"
occ_label        "TEMPC4"
label            "Chip 0 Core 4 "
phandle          10000144 (268435780)
sensor-type      "temp"
sensor-data-min  02c0000c (46137356)
sensor-data-max  01c0000c (29360140)
name             "core-temp"

mem-temp@c00018:
sensor-data      00c00018 (12582936)
compatible       "ibm,opal-sensor"
occ_label        "TEMPDIMM3"
label            "Chip 0 DIMM 3 "
phandle          10000150 (268435792)
sensor-type      "temp"
sensor-data-min  02c00018 (46137368)
sensor-data-max  01c00018 (29360152)
name             "mem-temp"

core-temp@70:
sensor-data      00e00070 (14680176)
compatible       "ibm,opal-sensor"
ibm,pir          00000070 (112)
label            "Core"
phandle          1000011f (268435743)
sensor-type      "temp"
sensor-status    01e00070 (31457392)
name             "core-temp"

gpu-temp@c0001b:
sensor-data      00c0001b (12582939)
compatible       "ibm,opal-sensor"
occ_label        "TEMPGPU1DRAM2"
label            "Chip 0 GPU 1 DRAM2"
phandle          10000153 (268435795)
sensor-type      "temp"
sensor-data-min  02c0001b (46137371)
sensor-data-max  01c0001b (29360155)
name             "gpu-temp"

proc-power@c00013:
sensor-data      00c00013 (12582931)
compatible       "ibm,opal-sensor"
occ_label        "PWRPROC"
label            "Chip 0 "
phandle          1000014b (268435787)
sensor-type      "power"
sensor-data-min  02c00013 (46137363)
sensor-data-max  01c00013 (29360147)
name             "proc-power"

core-temp@c0000a:
sensor-data      00c0000a (12582922)
compatible       "ibm,opal-sensor"
occ_label        "TEMPC2"
label            "Chip 0 Core 2 "
phandle          10000142 (268435778)
sensor-type      "temp"
sensor-data-min  02c0000a (46137354)
sensor-data-max  01c0000a (29360138)
name             "core-temp"

vrm-in@c00011:
sensor-data      00c00011 (12582929)
compatible       "ibm,opal-sensor"
occ_label        "VOLTVDD"
label            "Chip 0 Vdd"
phandle          10000149 (268435785)
sensor-type      "in"
sensor-data-min  02c00011 (46137361)
sensor-data-max  01c00011 (29360145)
name             "vrm-in"

mem-temp@c00006:
sensor-data      00c00006 (12582918)
compatible       "ibm,opal-sensor"
occ_label        "TEMPDIMM6"
label            "Chip 0 DIMM 6 "
phandle          1000013f (268435775)
sensor-type      "temp"
sensor-data-min  02c00006 (46137350)
sensor-data-max  01c00006 (29360134)
name             "mem-temp"

sys-power@c00003:
sensor-data      00c00003 (12582915)
compatible       "ibm,opal-sensor"
occ_label        "PWRSTORE"
label            "Storage"
phandle          1000013c (268435772)
sensor-type      "power"
sensor-data-min  02c00003 (46137347)
sensor-data-max  01c00003 (29360131)
name             "sys-power"

mem-temp@80000001:
sensor-data      00e10001 (14745601)
compatible       "ibm,opal-sensor"
label            "Centaur"
ibm,chip-id      80000001
phandle          10000120 (268435744)
sensor-type      "temp"
sensor-status    01e10001 (31522817)
name             "mem-temp"

core-temp@10:
sensor-data      00e00010 (14680080)
compatible       "ibm,opal-sensor"
ibm,pir          00000010 (16)
label            "Core"
phandle          1000011c (268435740)
sensor-type      "temp"
sensor-status    01e00010 (31457296)
name             "core-temp"

sys-power@c00001:
sensor-data      00c00001 (12582913)
compatible       "ibm,opal-sensor"
occ_label        "PWRFAN"
label            "Fan"
phandle          1000013a (268435770)
sensor-type      "power"
sensor-data-min  02c00001 (46137345)
sensor-data-max  01c00001 (29360129)
name             "sys-power"

gpu-temp@c00019:
sensor-data      00c00019 (12582937)
compatible       "ibm,opal-sensor"
occ_label        "TEMPGPU2"
label            "Chip 0 GPU 2 "
phandle          10000151 (268435793)
sensor-type      "temp"
sensor-data-min  02c00019 (46137369)
sensor-data-max  01c00019 (29360153)
name             "gpu-temp"

core-temp@c00008:
sensor-data      00c00008 (12582920)
compatible       "ibm,opal-sensor"
occ_label        "TEMPC0"
label            "Chip 0 Core 0 "
phandle          10000140 (268435776)
sensor-type      "temp"
sensor-data-min  02c00008 (46137352)
sensor-data-max  01c00008 (29360136)
name             "core-temp"
Shilpasri G Bhat March 30, 2017, 12:45 p.m. UTC | #3
Hi,

On 03/30/2017 05:57 PM, Shilpasri G Bhat wrote:
> 
> 
> On 03/30/2017 05:54 PM, Cédric Le Goater wrote:
>> On 03/30/2017 02:13 PM, Shilpasri G Bhat wrote:
>>> Add support to parse and export OCC inband sensors which are copied
>>> by OCC to main memory in P9. Each OCC writes three buffers which
>>> includes one names buffer for sensor meta data and two buffers for
>>> sensor readings. While OCC writes to one buffer the sensor values
>>> can be read from the other buffer. The sensors are updated every
>>> 100ms.
>>>
>>> This patch adds power, temperature, current and voltage sensors to
>>> /ibm,opal/sensors device-tree node which can be exported by the
>>> ibmpowernv-hwmon driver in Linux.
>>>
>>> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
>>> ---
>>> Changes from V2:
>>> - Added current and voltage sensors
>>> - Removed 'struct occ_sensor_info' which was used to store sensor
>>>   offset address values
>>> - Added sensor attributes like MIN and MAX
>>> - Moved the header sanity checks to a separate routine
>>>   'occ_sensor_sanity()'
>>> - Added a mapping for OCC sensor name to userspace label. If the
>>>   mapping is not found we fall back to OCC name.
>>
>> Could you give us a sample output of the command 'sensors' ? 
>>
>> and also the result of :
>>
>> 	lsprop /proc/device-tree/ibm,opal/sensors/
>>
>> Thanks,
>>
>> C.
>>

The sensor values are all *dummy values* created to test the patch imitating the
possible known OCC sensor layout so far. These numbers do not match any readings
and should not be inferred as is.

Thanks and Regards,
Shilpa

> 
> # sensors
> ibmpowernv-isa-0000
> Adapter: ISA adapter
> Chip 0 Vdd Remote Sense:  +5.40 V  (lowest =  +0.02 V, highest =  +0.03 V)
> Chip 0 Vdd:               +5.40 V  (lowest =  +0.02 V, highest =  +0.03 V)
> Core 0:                   +46.0°C
> Core 8:                   +47.0°C
> Core 16:                  +53.0°C
> Core 24:                  +50.0°C
> Chip 0 Core 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Core 1 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Core 2 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Core 3 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Core 4 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 GPU 2 :            +46.0°C  (low  = +32.0°C, high = +54.0°C)
> Chip 0 GPU 2 DRAM0:       +46.0°C  (low  = +32.0°C, high = +54.0°C)
> Chip 0 GPU 1 DRAM2:       +46.0°C  (low  = +32.0°C, high = +54.0°C)
> Chip 0 DIMM 6 :           +34.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 DIMM 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 DIMM 3 :           +46.0°C  (low  = +32.0°C, high = +54.0°C)
> Centaur 1:                +30.0°C
> Chip 0 Nest:              +34.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Quad 0 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Quad 1 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 Quad 2 :           +30.0°C  (low  = +25.0°C, high = +80.0°C)
> Chip 0 GPU:              340.00 W  (lowest = 250.00 W, highest = 800.00 W)
> Chip 0 :                 540.00 W  (lowest =  23.00 W, highest =  34.00 W)
> Chip 0 Vdd:              540.00 W  (lowest =  23.00 W, highest =  34.00 W)
> Chip 0 Memory:           540.00 W  (lowest =  23.00 W, highest =  34.00 W)
> System:                  940.00 W  (lowest = 250.00 W, highest = 800.00 W)
> Fan:                     370.00 W  (lowest = 250.00 W, highest = 800.00 W)
> IO:                      360.00 W  (lowest = 250.00 W, highest = 800.00 W)
> Storage:                 380.00 W  (lowest = 250.00 W, highest = 800.00 W)
> APSS 12 :                540.00 W  (lowest =  23.00 W, highest =  34.00 W)
> Chip 0 Vdd:               +0.05 A  (lowest =  +0.03 A, highest =  +0.05 A)
> 
> /proc/device-tree/ibm,opal/sensors# lsprop
> compatible       "ibm,opal-sensor"
> phandle          1000011b (268435739)
> name             "sensors"
> 
> vrm-curr@c00010:
> sensor-data      00c00010 (12582928)
> compatible       "ibm,opal-sensor"
> occ_label        "CURVDD"
> label            "Chip 0 Vdd"
> phandle          10000148 (268435784)
> sensor-type      "curr"
> sensor-data-min  02c00010 (46137360)
> sensor-data-max  01c00010 (29360144)
> name             "vrm-curr"
> 
> gpu-power@c00004:
> sensor-data      00c00004 (12582916)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRGPU"
> label            "Chip 0 GPU"
> phandle          1000013d (268435773)
> sensor-type      "power"
> sensor-data-min  02c00004 (46137348)
> sensor-data-max  01c00004 (29360132)
> name             "gpu-power"
> 
> quad-temp@c0000e:
> sensor-data      00c0000e (12582926)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPQ1"
> label            "Chip 0 Quad 1 "
> phandle          10000146 (268435782)
> sensor-type      "temp"
> sensor-data-min  02c0000e (46137358)
> sensor-data-max  01c0000e (29360142)
> name             "quad-temp"
> 
> proc-power@c00016:
> sensor-data      00c00016 (12582934)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRMEM"
> label            "Chip 0 Memory"
> phandle          1000014e (268435790)
> sensor-type      "power"
> sensor-data-min  02c00016 (46137366)
> sensor-data-max  01c00016 (29360150)
> name             "proc-power"
> 
> proc-power@c00014:
> sensor-data      00c00014 (12582932)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRVDD"
> label            "Chip 0 Vdd"
> phandle          1000014c (268435788)
> sensor-type      "power"
> sensor-data-min  02c00014 (46137364)
> sensor-data-max  01c00014 (29360148)
> name             "proc-power"
> 
> core-temp@c0000b:
> sensor-data      00c0000b (12582923)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPC3"
> label            "Chip 0 Core 3 "
> phandle          10000143 (268435779)
> sensor-type      "temp"
> sensor-data-min  02c0000b (46137355)
> sensor-data-max  01c0000b (29360139)
> name             "core-temp"
> 
> mem-temp@c00017:
> sensor-data      00c00017 (12582935)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPDIMM0"
> label            "Chip 0 DIMM 0 "
> phandle          1000014f (268435791)
> sensor-type      "temp"
> sensor-data-min  02c00017 (46137367)
> sensor-data-max  01c00017 (29360151)
> name             "mem-temp"
> 
> gpu-temp@c0001a:
> sensor-data      00c0001a (12582938)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPGPU2DRAM0"
> label            "Chip 0 GPU 2 DRAM0"
> phandle          10000152 (268435794)
> sensor-type      "temp"
> sensor-data-min  02c0001a (46137370)
> sensor-data-max  01c0001a (29360154)
> name             "gpu-temp"
> 
> sys-power@c00012:
> sensor-data      00c00012 (12582930)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRAPSSCH12"
> label            "APSS 12 "
> phandle          1000014a (268435786)
> sensor-type      "power"
> sensor-data-min  02c00012 (46137362)
> sensor-data-max  01c00012 (29360146)
> name             "sys-power"
> 
> core-temp@68:
> sensor-data      00e00068 (14680168)
> compatible       "ibm,opal-sensor"
> ibm,pir          00000068 (104)
> label            "Core"
> phandle          1000011e (268435742)
> sensor-type      "temp"
> sensor-status    01e00068 (31457384)
> name             "core-temp"
> 
> proc-in@c00015:
> sensor-data      00c00015 (12582933)
> compatible       "ibm,opal-sensor"
> occ_label        "VOLTVDDSENSE"
> label            "Chip 0 Vdd Remote Sense"
> phandle          1000014d (268435789)
> sensor-type      "in"
> sensor-data-min  02c00015 (46137365)
> sensor-data-max  01c00015 (29360149)
> name             "proc-in"
> 
> sys-power@c00002:
> sensor-data      00c00002 (12582914)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRIO"
> label            "IO"
> phandle          1000013b (268435771)
> sensor-type      "power"
> sensor-data-min  02c00002 (46137346)
> sensor-data-max  01c00002 (29360130)
> name             "sys-power"
> 
> core-temp@c00009:
> sensor-data      00c00009 (12582921)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPC1"
> label            "Chip 0 Core 1 "
> phandle          10000141 (268435777)
> sensor-type      "temp"
> sensor-data-min  02c00009 (46137353)
> sensor-data-max  01c00009 (29360137)
> name             "core-temp"
> 
> core-temp@28:
> sensor-data      00e00028 (14680104)
> compatible       "ibm,opal-sensor"
> ibm,pir          00000028 (40)
> label            "Core"
> phandle          1000011d (268435741)
> sensor-type      "temp"
> sensor-status    01e00028 (31457320)
> name             "core-temp"
> 
> sys-power@c00000:
> sensor-data      00c00000 (12582912)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRSYS"
> label            "System"
> phandle          10000139 (268435769)
> sensor-type      "power"
> sensor-data-min  02c00000 (46137344)
> sensor-data-max  01c00000 (29360128)
> name             "sys-power"
> 
> proc-temp@c00005:
> sensor-data      00c00005 (12582917)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPNEST"
> label            "Chip 0 Nest"
> phandle          1000013e (268435774)
> sensor-type      "temp"
> sensor-data-min  02c00005 (46137349)
> sensor-data-max  01c00005 (29360133)
> name             "proc-temp"
> 
> quad-temp@c0000f:
> sensor-data      00c0000f (12582927)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPQ2"
> label            "Chip 0 Quad 2 "
> phandle          10000147 (268435783)
> sensor-type      "temp"
> sensor-data-min  02c0000f (46137359)
> sensor-data-max  01c0000f (29360143)
> name             "quad-temp"
> 
> quad-temp@c0000d:
> sensor-data      00c0000d (12582925)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPQ0"
> label            "Chip 0 Quad 0 "
> phandle          10000145 (268435781)
> sensor-type      "temp"
> sensor-data-min  02c0000d (46137357)
> sensor-data-max  01c0000d (29360141)
> name             "quad-temp"
> 
> core-temp@c0000c:
> sensor-data      00c0000c (12582924)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPC4"
> label            "Chip 0 Core 4 "
> phandle          10000144 (268435780)
> sensor-type      "temp"
> sensor-data-min  02c0000c (46137356)
> sensor-data-max  01c0000c (29360140)
> name             "core-temp"
> 
> mem-temp@c00018:
> sensor-data      00c00018 (12582936)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPDIMM3"
> label            "Chip 0 DIMM 3 "
> phandle          10000150 (268435792)
> sensor-type      "temp"
> sensor-data-min  02c00018 (46137368)
> sensor-data-max  01c00018 (29360152)
> name             "mem-temp"
> 
> core-temp@70:
> sensor-data      00e00070 (14680176)
> compatible       "ibm,opal-sensor"
> ibm,pir          00000070 (112)
> label            "Core"
> phandle          1000011f (268435743)
> sensor-type      "temp"
> sensor-status    01e00070 (31457392)
> name             "core-temp"
> 
> gpu-temp@c0001b:
> sensor-data      00c0001b (12582939)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPGPU1DRAM2"
> label            "Chip 0 GPU 1 DRAM2"
> phandle          10000153 (268435795)
> sensor-type      "temp"
> sensor-data-min  02c0001b (46137371)
> sensor-data-max  01c0001b (29360155)
> name             "gpu-temp"
> 
> proc-power@c00013:
> sensor-data      00c00013 (12582931)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRPROC"
> label            "Chip 0 "
> phandle          1000014b (268435787)
> sensor-type      "power"
> sensor-data-min  02c00013 (46137363)
> sensor-data-max  01c00013 (29360147)
> name             "proc-power"
> 
> core-temp@c0000a:
> sensor-data      00c0000a (12582922)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPC2"
> label            "Chip 0 Core 2 "
> phandle          10000142 (268435778)
> sensor-type      "temp"
> sensor-data-min  02c0000a (46137354)
> sensor-data-max  01c0000a (29360138)
> name             "core-temp"
> 
> vrm-in@c00011:
> sensor-data      00c00011 (12582929)
> compatible       "ibm,opal-sensor"
> occ_label        "VOLTVDD"
> label            "Chip 0 Vdd"
> phandle          10000149 (268435785)
> sensor-type      "in"
> sensor-data-min  02c00011 (46137361)
> sensor-data-max  01c00011 (29360145)
> name             "vrm-in"
> 
> mem-temp@c00006:
> sensor-data      00c00006 (12582918)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPDIMM6"
> label            "Chip 0 DIMM 6 "
> phandle          1000013f (268435775)
> sensor-type      "temp"
> sensor-data-min  02c00006 (46137350)
> sensor-data-max  01c00006 (29360134)
> name             "mem-temp"
> 
> sys-power@c00003:
> sensor-data      00c00003 (12582915)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRSTORE"
> label            "Storage"
> phandle          1000013c (268435772)
> sensor-type      "power"
> sensor-data-min  02c00003 (46137347)
> sensor-data-max  01c00003 (29360131)
> name             "sys-power"
> 
> mem-temp@80000001:
> sensor-data      00e10001 (14745601)
> compatible       "ibm,opal-sensor"
> label            "Centaur"
> ibm,chip-id      80000001
> phandle          10000120 (268435744)
> sensor-type      "temp"
> sensor-status    01e10001 (31522817)
> name             "mem-temp"
> 
> core-temp@10:
> sensor-data      00e00010 (14680080)
> compatible       "ibm,opal-sensor"
> ibm,pir          00000010 (16)
> label            "Core"
> phandle          1000011c (268435740)
> sensor-type      "temp"
> sensor-status    01e00010 (31457296)
> name             "core-temp"
> 
> sys-power@c00001:
> sensor-data      00c00001 (12582913)
> compatible       "ibm,opal-sensor"
> occ_label        "PWRFAN"
> label            "Fan"
> phandle          1000013a (268435770)
> sensor-type      "power"
> sensor-data-min  02c00001 (46137345)
> sensor-data-max  01c00001 (29360129)
> name             "sys-power"
> 
> gpu-temp@c00019:
> sensor-data      00c00019 (12582937)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPGPU2"
> label            "Chip 0 GPU 2 "
> phandle          10000151 (268435793)
> sensor-type      "temp"
> sensor-data-min  02c00019 (46137369)
> sensor-data-max  01c00019 (29360153)
> name             "gpu-temp"
> 
> core-temp@c00008:
> sensor-data      00c00008 (12582920)
> compatible       "ibm,opal-sensor"
> occ_label        "TEMPC0"
> label            "Chip 0 Core 0 "
> phandle          10000140 (268435776)
> sensor-type      "temp"
> sensor-data-min  02c00008 (46137352)
> sensor-data-max  01c00008 (29360136)
> name             "core-temp"
> 
> _______________________________________________
> Skiboot mailing list
> Skiboot@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
>
Cédric Le Goater March 30, 2017, 1:12 p.m. UTC | #4
> 
> The sensor values are all *dummy values* created to test the patch imitating the
> possible known OCC sensor layout so far. These numbers do not match any readings
> and should not be inferred as is.

So you are generating OCC data and writing in main memory to test ? 

C.
Shilpasri G Bhat March 30, 2017, 1:27 p.m. UTC | #5
On 03/30/2017 06:42 PM, Cédric Le Goater wrote:
>>
>> The sensor values are all *dummy values* created to test the patch imitating the
>> possible known OCC sensor layout so far. These numbers do not match any readings
>> and should not be inferred as is.
> 
> So you are generating OCC data and writing in main memory to test ? 
> 
> C. 
> 

Yes. Till OCC enables sensor data, this is the one of the way to test the data.
Cédric Le Goater March 30, 2017, 1:54 p.m. UTC | #6
Hello,

I think you can remove the RFC now. Looks good, some minor comments
below.

On 03/30/2017 02:13 PM, Shilpasri G Bhat wrote:
> Add support to parse and export OCC inband sensors which are copied
> by OCC to main memory in P9. Each OCC writes three buffers which
> includes one names buffer for sensor meta data and two buffers for
> sensor readings. While OCC writes to one buffer the sensor values
> can be read from the other buffer. The sensors are updated every
> 100ms.
> 
> This patch adds power, temperature, current and voltage sensors to
> /ibm,opal/sensors device-tree node which can be exported by the
> ibmpowernv-hwmon driver in Linux.
> 
> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
> ---
> Changes from V2:
> - Added current and voltage sensors
> - Removed 'struct occ_sensor_info' which was used to store sensor
>   offset address values
> - Added sensor attributes like MIN and MAX
> - Moved the header sanity checks to a separate routine
>   'occ_sensor_sanity()'
> - Added a mapping for OCC sensor name to userspace label. If the
>   mapping is not found we fall back to OCC name.
> 
>  core/init.c       |   1 +
>  core/sensor.c     |   4 +
>  hw/Makefile.inc   |   2 +-
>  hw/occ-sensor.c   | 596 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/sensor.h  |   1 +
>  include/skiboot.h |   4 +
>  6 files changed, 607 insertions(+), 1 deletion(-)
>  create mode 100644 hw/occ-sensor.c
> 
> diff --git a/core/init.c b/core/init.c
> index 983ead5..dab76ea 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -501,6 +501,7 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
>  	 * as possible to avoid delay.
>  	 */
>  	occ_pstates_init();
> +	occ_sensors_init();
>  
>  	/* Use nvram bootargs over device tree */
>  	cmdline = nvram_query("bootargs");
> diff --git a/core/sensor.c b/core/sensor.c
> index cc5341c..b0d3c5e 100644
> --- a/core/sensor.c
> +++ b/core/sensor.c
> @@ -29,6 +29,10 @@ static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
>  	switch (sensor_get_family(sensor_hndl)) {
>  	case SENSOR_DTS:
>  		return dts_sensor_read(sensor_hndl, sensor_data);
> +	case SENSOR_OCC:
> +		return occ_sensor_read(sensor_hndl, sensor_data);
> +	default:
> +		break;
>  	}
>  
>  	if (platform.sensor_read)
> diff --git a/hw/Makefile.inc b/hw/Makefile.inc
> index d87f85e..194097f 100644
> --- a/hw/Makefile.inc
> +++ b/hw/Makefile.inc
> @@ -1,7 +1,7 @@
>  # -*-Makefile-*-
>  SUBDIRS += hw
>  HW_OBJS  = xscom.o chiptod.o gx.o cec.o lpc.o lpc-uart.o psi.o
> -HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o
> +HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o occ-sensor.o
>  HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o
>  HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o
>  HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o
> diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
> new file mode 100644
> index 0000000..d3d9ee4
> --- /dev/null
> +++ b/hw/occ-sensor.c
> @@ -0,0 +1,596 @@
> +/* Copyright 2017 IBM Corp.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *	http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <skiboot.h>
> +#include <opal.h>
> +#include <chip.h>
> +#include <sensor.h>
> +#include <device.h>
> +
> +/*
> + * OCC Sensor Data
> + *
> + * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
> + * Starting address is at offset 0x00580000 from BAR2 base address.
> + * Maximum size is 1.5MB.
> + *
> + * -------------------------------------------------------------------------
> + * | Start (Offset from |	End	| Size	   |Description		   |
> + * | BAR2 base address) |		|	   |			   |
> + * -------------------------------------------------------------------------
> + * |	0x00580000      |  0x005A57FF   |150kB     |OCC 0 Sensor Data Block|
> + * |	0x005A5800      |  0x005CAFFF   |150kB	   |OCC 1 Sensor Data Block|
> + * |	    :		|	:	|  :	   |		:          |
> + * |	0x00686800	|  0x006ABFFF   |150kB	   |OCC 7 Sensor Data Block|
> + * |	0x006AC000	|  0x006FFFFF   |336kB     |Reserved		   |
> + * -------------------------------------------------------------------------
> + *
> + *
> + * OCC N Sensor Data Block Layout (150kB)
> + *
> + * The sensor data block layout is the same for each OCC N. It contains
> + * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
> + * sensor-readings-pong buffer.
> + *
> + * ----------------------------------------------------------------------------
> + * | Start (Offset from OCC |   End	   | Size |Description		      |
> + * | N Sensor Data Block)   |		   |	  |			      |
> + * ----------------------------------------------------------------------------
> + * |	0x00000000	    |  0x000003FF  |1kB   |Sensor Data Header Block   |
> + * |	0x00000400	    |  0x0000CBFF  |50kB  |Sensor Names		      |
> + * |	0x0000CC00	    |  0x0000DBFF  |4kB   |Reserved		      |
> + * |	0x0000DC00	    |  0x00017BFF  |40kB  |Sensor Readings ping buffer|
> + * |	0x00017C00	    |  0x00018BFF  |4kB   |Reserved		      |
> + * |	0x00018C00	    |  0x00022BFF  |40kB  |Sensor Readings pong buffer|
> + * |	0x00022C00	    |  0x000257FF  |11kB  |Reserved		      |
> + * ----------------------------------------------------------------------------
> + *
> + * Sensor Data Header Block : This is written once by the OCC during
> + * initialization after a load or reset. Layout is defined in 'struct
> + * occ_sensor_data_header'
> + *
> + * Sensor Names : This is written once by the OCC during initialization after a
> + * load or reset. It contains static information for each sensor. The number of
> + * sensors, format version and length of each sensor is defined in
> + * 'Sensor Data Header Block'. Format of each sensor name is defined in
> + * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
> + * immediately by the next sensor.
> + *
> + * Sensor Readings Ping/Pong Buffer:
> + * There are two 40kB buffers to store the sensor readings. One buffer that
> + * is currently being updated by the OCC and one that is available to be read.
> + * Each of these buffers will be of the same format. The number of sensors and
> + * the format version of the ping and pong buffers is defined in the
> + * 'Sensor Data Header Block'.
> + *
> + * Each sensor within the ping and pong buffers may be of a different format
> + * and length. For each sensor the length and format is determined by its
> + * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
> + *
> + * --------------------------------------------------------------------------
> + * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
> + * --------------------------------------------------------------------------
> + * | 0x0000 |Valid  |		   Reserved				    |
> + * |        |(0x01) |							    |
> + * --------------------------------------------------------------------------
> + * | 0x0008 |			Sensor Readings				    |
> + * --------------------------------------------------------------------------
> + * |	:   |				:				    |
> + * --------------------------------------------------------------------------
> + * | 0xA000 |                     End of Data				    |
> + * --------------------------------------------------------------------------
> + *
> + */
> +
> +#define MAX_OCCS			8
> +#define MAX_CHARS_SENSOR_NAME		16
> +#define MAX_CHARS_SENSOR_UNIT		4
> +
> +#define OCC_SENSOR_DATA_BLOCK_OFFSET		0x00580000
> +#define OCC_SENSOR_DATA_BLOCK_SIZE		0x00025800
> +
> +enum occ_sensor_type {
> +	OCC_SENSOR_TYPE_GENERIC		= 0x0001,
> +	OCC_SENSOR_TYPE_CURRENT		= 0x0002,
> +	OCC_SENSOR_TYPE_VOLTAGE		= 0x0004,
> +	OCC_SENSOR_TYPE_TEMPERATURE	= 0x0008,
> +	OCC_SENSOR_TYPE_UTILIZATION	= 0x0010,
> +	OCC_SENSOR_TYPE_TIME		= 0x0020,
> +	OCC_SENSOR_TYPE_FREQUENCY	= 0x0040,
> +	OCC_SENSOR_TYPE_POWER		= 0x0080,
> +	OCC_SENSOR_TYPE_PERFORMANCE	= 0x0200,

0x200 ? just checking, I don't have the specs.

> +};
> +
> +enum occ_sensor_location {
> +	OCC_SENSOR_LOC_SYSTEM		= 0x0001,
> +	OCC_SENSOR_LOC_PROCESSOR	= 0x0002,
> +	OCC_SENSOR_LOC_PARTITION	= 0x0004,
> +	OCC_SENSOR_LOC_MEMORY		= 0x0008,
> +	OCC_SENSOR_LOC_VRM		= 0x0010,
> +	OCC_SENSOR_LOC_OCC		= 0x0020,
> +	OCC_SENSOR_LOC_CORE		= 0x0040,
> +	OCC_SENSOR_LOC_QUAD		= 0x0080,
> +	OCC_SENSOR_LOC_GPU		= 0x0100,
> +};
> +
> +enum sensor_struct_type {
> +	OCC_SENSOR_READING_FULL		= 0x01,
> +	OCC_SENSOR_READING_COUNTER	= 0x02,
> +};
> +
> +/**
> + * struct occ_sensor_data_header -	Sensor Data Header Block
> + * @valid:				When the value is 0x01 it indicates
> + *					that this header block and the sensor
> + *					names buffer are ready
> + * @version:				Format version of this block
> + * @nr_sensors:				Number of sensors in names, ping and
> + *					pong buffer
> + * @sensor_reading_version:		Format version of the Ping/Pong buffer
> + * @sensor_names_offset:		Offset to the location of names buffer
> + * @sensor_names_version:		Format version of names buffer
> + * @sensor_names_length:		Length of each sensor in names buffer
> + * @sensor_reading_ping_offset:		Offset to the location of Ping buffer
> + * @sensor_reading_pong_offset:		Offset to the location of Pong buffer
> + * @pad/reserved:			Unused data
> + */
> +struct occ_sensor_data_header {
> +	u8 valid;
> +	u8 version;
> +	u16 nr_sensors;
> +	u8 sensor_reading_version;
> +	u8 pad[3];
> +	u32 sensor_names_offset;
> +	u8 sensor_names_version;
> +	u8 sensor_name_length;
> +	u16 reserved;
> +	u32 sensor_reading_ping_offset;
> +	u32 sensor_reading_pong_offset;
> +} __packed;
>

minor: may be you can remove the 'sensor_' prefix in this struct. 
The field names are rather long.

> +/**
> + * struct occ_sensor_name -		Format of Sensor Name
> + * @name:				Sensor name
> + * @units:				Sensor units of measurement
> + * @gsid:				Global sensor id (OCC)
> + * @freq:				Update frequency
> + * @scale_factor:			Scaling factor
> + * @type:				Sensor type as defined in
> + *					'enum occ_sensor_type'
> + * @location:				Sensor location as defined in
> + *					'enum occ_sensor_location'
> + * @structure_type:			Indicates type of data structure used
> + *					for the sensor readings in the ping and
> + *					pong buffers for this sensor as defined
> + *					in 'enum sensor_struct_type'
> + * @reading_offset:			Offset from the start of the ping/pong
> + *					reading buffers for this sensor
> + * @sensor_data:			Sensor specific info
> + * @pad:				Padding to fit the size of 48 bytes.
> + */
> +struct occ_sensor_name {
> +	char name[MAX_CHARS_SENSOR_NAME];
> +	char units[MAX_CHARS_SENSOR_UNIT];
> +	u16 gsid;
> +	u32 freq;
> +	u32 scale_factor;
> +	u16 type;
> +	u16 location;
> +	u8 structure_type;
> +	u32 reading_offset;
> +	u8 sensor_data;
> +	u8 pad[8];
> +} __packed;
> +
> +/**
> + * struct occ_sensor_record -		Sensor Reading Full
> + * @gsid:				Global sensor id (OCC)
> + * @timestamp:				Time base counter value while updating
> + *					the sensor
> + * @sample:				Latest sample of this sensor
> + * @sample_min:				Minimum value since last OCC reset
> + * @sample_max:				Maximum value since last OCC reset
> + * @CSM_min:				Minimum value since last reset request
> + *					by CSM (CORAL)
> + * @CSM_max:				Maximum value since last reset request
> + *					by CSM (CORAL)
> + * @profiler_min:			Minimum value since last reset request
> + *					by profiler (CORAL)
> + * @profiler_max:			Maximum value since last reset request
> + *					by profiler (CORAL)
> + * @job_scheduler_min:			Minimum value since last reset request
> + *					by job scheduler(CORAL)
> + * @job_scheduler_max:			Maximum value since last reset request
> + *					by job scheduler (CORAL)
> + * @accumulator:			Accumulator for this sensor
> + * @update_tag:				Count of the number of ticks that have
> + *					passed between updates
> + * @pad:				Padding to fit the size of 48 bytes
> + */
> +struct occ_sensor_record {
> +	u16 gsid;
> +	u64 timestamp;
> +	u16 sample;
> +	u16 sample_min;
> +	u16 sample_max;
> +	u16 CSM_min;
> +	u16 CSM_max;
> +	u16 profiler_min;
> +	u16 profiler_max;
> +	u16 job_scheduler_min;
> +	u16 job_scheduler_max;
> +	u64 accumulator;
> +	u32 update_tag;
> +	u8 pad[8];
> +} __packed;
> +
> +/**
> + * struct occ_sensor_counter -		Sensor Reading Counter
> + * @gsid:				Global sensor id (OCC)
> + * @timestamp:				Time base counter value while updating
> + *					the sensor
> + * @accumulator:			Accumulator/Counter
> + * @sample:				Latest sample of this sensor (0/1)
> + * @pad:				Padding to fit the size of 24 bytes
> + */
> +struct occ_sensor_counter {
> +	u16 gsid;
> +	u64 timestamp;
> +	u64 accumulator;
> +	u8 sample;
> +	u8 pad[5];
> +} __packed;
> +
> +enum sensor_attr {
> +	SENSOR_SAMPLE,
> +	SENSOR_MAX,
> +	SENSOR_MIN,
> +	MAX_SENSOR_ATTR,
> +};
> +
> +static struct str_map {
> +	const char *occ_str;
> +	const char *opal_str;
> +} str_maps[] = {
> +	{"PWRSYS", "System"},
> +	{"PWRFAN", "Fan"},
> +	{"PWRIO", "IO"},
> +	{"PWRSTORE", "Storage"},
> +	{"PWRGPU", "GPU"},
> +	{"PWRAPSSCH", "APSS"},/
> +	{"PWRPROC", ""},
> +	{"PWRVDD", "Vdd"},
> +	{"CURVDD", "Vdd"},
> +	{"VOLTVDDSENSE", "Vdd Remote Sense"},
> +	{"VOLTVDD", "Vdd"},
> +	{"PWRVDN", "Vdn"},
> +	{"CURVDN", "Vdn"},
> +	{"VOLTVDNSENSE", "Vdn Remote Sense"},
> +	{"VOLTVDN", "Vdn"},
> +	{"PWRMEM", "Memory"},
> +	{"TEMPC", "Core"},
> +	{"TEMPQ", "Quad"},
> +	{"TEMPNEST", "Nest"},
> +	{"TEMPPROCTHRM", "Chip"},
> +	{"TEMPDIMM", "DIMM"},
> +	{"TEMPGPU", "GPU"},
> +};
> +
> +static u64 occ_sensor_base;
> +static int occ_to_chipid[MAX_CHIPS];

I am not sure this occ_to_chipid[] array is required.

> +
> +static inline
> +struct occ_sensor_data_header *get_sensor_header_block(int occ_num)
> +{
> +	return (struct occ_sensor_data_header *)
> +		(occ_sensor_base + occ_num * OCC_SENSOR_DATA_BLOCK_SIZE);
> +}
> +
> +static inline
> +struct occ_sensor_name *get_names_block(struct occ_sensor_data_header *hb)
> +{
> +	return ((struct occ_sensor_name *)((u64)hb + hb->sensor_names_offset));
> +}
> +
> +static inline u32 sensor_handler(int occ_num, int sensor_id, int attr)
> +{
> +	return sensor_make_handler(SENSOR_OCC, occ_num, sensor_id, attr);
> +}
> +
> +int occ_sensor_read(u32 handle, u32 *data)
> +{
> +	struct occ_sensor_data_header *hb;
> +	struct occ_sensor_name *md;
> +	struct occ_sensor_record *sping, *spong;
> +	struct occ_sensor_record *sensor;
> +	u8 *ping, *pong;
> +	u16 id = sensor_get_rid(handle);
> +	u8 occ_num = sensor_get_frc(handle);
> +	u8 attr = sensor_get_attr(handle);
> +
> +	if (occ_num > MAX_OCCS)
> +		return OPAL_PARAMETER;
> +
> +	if (attr > MAX_SENSOR_ATTR)
> +		return OPAL_PARAMETER;
> +
> +	hb = get_sensor_header_block(occ_num);
> +	md = get_names_block(hb);
> +
> +	if (hb->valid != 1)
> +		return OPAL_BUSY;
> +
> +	if (id > hb->nr_sensors)
> +		return OPAL_PARAMETER;
> +
> +	ping = (u8 *)((u64)hb + hb->sensor_reading_ping_offset);
> +	pong = (u8 *)((u64)hb + hb->sensor_reading_pong_offset);
> +	sping = (struct occ_sensor_record *)((u64)ping + md[id].reading_offset);
> +	spong = (struct occ_sensor_record *)((u64)pong + md[id].reading_offset);
> +
> +	/* Check which buffer is valid  and read the data from that.
> +	 * Ping Pong	Action
> +	 *  0	0	Return with error
> +	 *  0	1	Read Pong
> +	 *  1	0	Read Ping
> +	 *  1	1	Read the buffer with latest timestamp
> +	 */
> +	if (*ping && *pong) {
> +		if (sping->timestamp > spong->timestamp)
> +			sensor = sping;
> +		else
> +			sensor = spong;
> +
> +	} else if (*ping && !*pong) {
> +		sensor = sping;
> +	} else if (!*ping && *pong) {
> +		sensor = spong;
> +	} else if (!*ping && !*pong) {
> +		prlog(PR_DEBUG, "OCC: Both ping and pong sensor buffers are invalid\n");
> +		return OPAL_BUSY;
> +	}
> +
> +	switch (attr) {
> +	case SENSOR_SAMPLE:
> +		*data = sensor->sample;
> +		break;
> +	case SENSOR_MAX:
> +		*data = sensor->sample_max;
> +		break;
> +	case SENSOR_MIN:
> +		*data = sensor->sample_min;
> +		break;
> +	default:
> +		*data = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +static bool occ_sensor_sanity(int nr_occs)
> +{
> +	struct occ_sensor_data_header *hb;
> +	int occ_num;

you could loop on the chips and increment occ_num.

> +	for (occ_num = 0; occ_num < nr_occs; occ_num++) {
> +		hb = get_sensor_header_block(occ_num);
> +		if (hb->valid != 0x01) {
> +			prerror("OCC: Sensor data invalid\n");
> +			return false;
> +		}
> +
> +		if (hb->version != 0x01) {
> +			prerror("OCC: Unsupported sensor header block version %d\n",
> +				hb->version);
> +			return false;
> +		}
> +
> +		if (hb->sensor_reading_version != 0x01) {
> +			prerror("OCC: Unsupported sensor record format %d\n",
> +				hb->sensor_reading_version);
> +			return false;
> +		}
> +
> +		if (hb->sensor_names_version != 0x01) {
> +			prerror("OCC: Unsupported sensor info format %d\n",
> +				hb->sensor_names_version);
> +			return false;
> +		}
> +
> +		if (hb->sensor_name_length != sizeof(struct occ_sensor_name)) {
> +			prerror("OCC: Unsupported sensor info record length %d\n",
> +				hb->sensor_name_length);
> +			return false;
> +		}
> +
> +		if (!hb->nr_sensors) {
> +			prerror("OCC: No sensors found for chip %d\n",
> +				occ_to_chipid[occ_num]);
> +			continue;
> +		}
> +
> +		if (!hb->sensor_names_offset ||
> +		    !hb->sensor_reading_ping_offset ||
> +		    !hb->sensor_reading_pong_offset) {
> +			prerror("OCC: Invalid sensor buffer pointers\n");
> +			return false;
> +		}
> +	}
> +
> +	return true;
> +}
> +
> +static int parse_entity(const char *name, char **end)
> +{
> +	while (*name != '\0') {
> +		if (isdigit(*name))
> +			break;
> +		name++;
> +	}
> +
> +	if (*name)
> +		return strtol(name, end, 10);
> +	else
> +		return -1;
> +}

Please add some comments what this parsing does. What is the input format ?  

> +static void add_sensor_label(struct dt_node *node, struct occ_sensor_name *md,
> +			     int occ)
> +{
> +	char sname[30] = "";
> +	char prefix[30] = "";
> +	int i;
> +
> +	if (md->location != OCC_SENSOR_LOC_SYSTEM)
> +		snprintf(prefix, sizeof(prefix), "%s %d ", "Chip",
> +			 occ_to_chipid[occ]);

you could pass the chip->id instead of 'occ' ?
 
> +	for (i = 0; i < ARRAY_SIZE(str_maps); i++)
> +		if (!strncmp(str_maps[i].occ_str, md->name,
> +			     strlen(str_maps[i].occ_str))) {
> +			char *end;
> +			int num;
> +
> +			num = parse_entity(md->name, &end);
> +			if (num != -1) {
> +				snprintf(sname, sizeof(sname), "%s%s %d %s",
> +					 prefix, str_maps[i].opal_str, num,
> +					 end);
> +			} else {
> +				snprintf(sname, sizeof(sname), "%s%s", prefix,
> +					 str_maps[i].opal_str);
> +			}
> +			dt_add_property_string(node, "label", sname);
> +			return;
> +		}
> +
> +	if (md->location == OCC_SENSOR_LOC_SYSTEM) {
> +		dt_add_property_string(node, "label", md->name);
> +	} else {
> +		snprintf(sname, sizeof(sname), "P%d_%s", occ_to_chipid[occ],
> +			 md->name);
> +		dt_add_property_string(node, "label", sname);
> +	}
> +}
> +
> +void occ_sensors_init(void)
> +{
> +	struct proc_chip *chip;
> +	struct occ_sensor_name *md;
> +	struct occ_sensor_data_header *hb;
> +	int nr_occs = 0;
> +	int occ_num, i;
> +
> +	/* OCC inband sensors is only supported in P9 */
> +	if (proc_gen != proc_gen_p9)
> +		return;
> +
> +	/* Sensors are copied to BAR2 OCC Common Area */
> +	chip = next_chip(NULL);
> +	if (!chip->occ_common_base) {
> +		prerror("OCC: Unassigned OCC Common Area. No sensors found\n");
> +		return;
> +	}
> +
> +	occ_sensor_base = chip->occ_common_base + OCC_SENSOR_DATA_BLOCK_OFFSET;
> +
> +	for_each_chip(chip)
> +		occ_to_chipid[nr_occs++] = chip->id;
> +
> +	/* Sanity check of the Sensor Data Header Block */
> +	if (!occ_sensor_sanity(nr_occs))
> +		return;

so, if one occ has some bogus data we don't get the others' ? May be you
could do this sanity check per chip and move it under the loop below ? 

> +	for (occ_num = 0; occ_num < nr_occs; occ_num++) {

why not loop directly on the chips and increment occ_num ? 

> +		hb = get_sensor_header_block(occ_num);
> +		md = get_names_block(hb);
> +
> +		for (i = 0; i < hb->nr_sensors; i++) {
> +			char name[30];
> +			const char *type, *loc;
> +			struct dt_node *node;
> +			u32 handler;
> +
> +			if (md[i].type != OCC_SENSOR_TYPE_TEMPERATURE &&
> +			    md[i].type != OCC_SENSOR_TYPE_POWER &&
> +			    md[i].type != OCC_SENSOR_TYPE_CURRENT &&
> +			    md[i].type != OCC_SENSOR_TYPE_VOLTAGE)
> +				continue;

you could use a mask to filter out unwanted sensor type.

> +
> +			switch (md[i].type) {
> +			case OCC_SENSOR_TYPE_POWER:
> +				type = "power";
> +				break;
> +			case OCC_SENSOR_TYPE_TEMPERATURE:
> +				type = "temp";
> +				break;
> +			case OCC_SENSOR_TYPE_CURRENT:
> +				type = "curr";
> +				break;
> +			case OCC_SENSOR_TYPE_VOLTAGE:
> +				type = "in";
> +				break;
> +			default:
> +				return;
> +			}

May be we you could use a static const array for the above, with a 'type' BIT 
index ? or use a specific routine at least.

> +			switch (md[i].location) {
> +			case OCC_SENSOR_LOC_SYSTEM:
> +				loc = "sys";
> +				break;
> +			case OCC_SENSOR_LOC_PROCESSOR:
> +				loc = "proc";
> +				break;
> +			case OCC_SENSOR_LOC_MEMORY:
> +				loc = "mem";
> +				break;
> +			case OCC_SENSOR_LOC_VRM:
> +				loc = "vrm";
> +				break;
> +			case OCC_SENSOR_LOC_CORE:
> +				loc = "core";
> +				break;
> +			case OCC_SENSOR_LOC_QUAD:
> +				loc = "quad";
> +				break;
> +			case OCC_SENSOR_LOC_GPU:
> +				loc = "gpu";
> +				break;
> +			default:
> +				loc = "unknown";
> +				break;
> +			}

same here.

Thanks,

C.

> +			snprintf(name, sizeof(name), "%s-%s", loc, type);
> +			handler = sensor_handler(occ_num, i, SENSOR_SAMPLE);
> +			node = dt_new_addr(sensor_node, name, handler);
> +
> +			dt_add_property_string(node, "sensor-type", type);
> +			dt_add_property_cells(node, "sensor-data", handler);
> +
> +			handler = sensor_handler(occ_num, i, SENSOR_MAX);
> +			dt_add_property_cells(node, "sensor-data-max", handler);
> +
> +			handler = sensor_handler(occ_num, i, SENSOR_MIN);
> +			dt_add_property_cells(node, "sensor-data-min", handler);
> +
> +			dt_add_property_string(node, "compatible",
> +					       "ibm,opal-sensor");
> +			dt_add_property_string(node, "occ_label", md[i].name);
> +			add_sensor_label(node, &md[i], occ_num);
> +		}
> +	}
> +}
> diff --git a/include/sensor.h b/include/sensor.h
> index 7eb3fa5..445a6bc 100644
> --- a/include/sensor.h
> +++ b/include/sensor.h
> @@ -53,6 +53,7 @@
>   */
>  enum {
>  	SENSOR_FSP = 0,
> +	SENSOR_OCC = 6,
>  	SENSOR_DTS = 7,
>  };
>  
> diff --git a/include/skiboot.h b/include/skiboot.h
> index bb0a7b5..a8e1534 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -302,4 +302,8 @@ extern int fake_nvram_info(uint32_t *total_size);
>  extern int fake_nvram_start_read(void *dst, uint32_t src, uint32_t len);
>  extern int fake_nvram_write(uint32_t offset, void *src, uint32_t size);
>  
> +/* OCC Inband Sensors */
> +extern void occ_sensors_init(void);
> +extern int occ_sensor_read(u32 handle, u32 *data);
> +
>  #endif /* __SKIBOOT_H */
>
diff mbox

Patch

diff --git a/core/init.c b/core/init.c
index 983ead5..dab76ea 100644
--- a/core/init.c
+++ b/core/init.c
@@ -501,6 +501,7 @@  void __noreturn load_and_boot_kernel(bool is_reboot)
 	 * as possible to avoid delay.
 	 */
 	occ_pstates_init();
+	occ_sensors_init();
 
 	/* Use nvram bootargs over device tree */
 	cmdline = nvram_query("bootargs");
diff --git a/core/sensor.c b/core/sensor.c
index cc5341c..b0d3c5e 100644
--- a/core/sensor.c
+++ b/core/sensor.c
@@ -29,6 +29,10 @@  static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
 	switch (sensor_get_family(sensor_hndl)) {
 	case SENSOR_DTS:
 		return dts_sensor_read(sensor_hndl, sensor_data);
+	case SENSOR_OCC:
+		return occ_sensor_read(sensor_hndl, sensor_data);
+	default:
+		break;
 	}
 
 	if (platform.sensor_read)
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index d87f85e..194097f 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -1,7 +1,7 @@ 
 # -*-Makefile-*-
 SUBDIRS += hw
 HW_OBJS  = xscom.o chiptod.o gx.o cec.o lpc.o lpc-uart.o psi.o
-HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o
+HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o occ-sensor.o
 HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o
 HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o
 HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
new file mode 100644
index 0000000..d3d9ee4
--- /dev/null
+++ b/hw/occ-sensor.c
@@ -0,0 +1,596 @@ 
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <opal.h>
+#include <chip.h>
+#include <sensor.h>
+#include <device.h>
+
+/*
+ * OCC Sensor Data
+ *
+ * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
+ * Starting address is at offset 0x00580000 from BAR2 base address.
+ * Maximum size is 1.5MB.
+ *
+ * -------------------------------------------------------------------------
+ * | Start (Offset from |	End	| Size	   |Description		   |
+ * | BAR2 base address) |		|	   |			   |
+ * -------------------------------------------------------------------------
+ * |	0x00580000      |  0x005A57FF   |150kB     |OCC 0 Sensor Data Block|
+ * |	0x005A5800      |  0x005CAFFF   |150kB	   |OCC 1 Sensor Data Block|
+ * |	    :		|	:	|  :	   |		:          |
+ * |	0x00686800	|  0x006ABFFF   |150kB	   |OCC 7 Sensor Data Block|
+ * |	0x006AC000	|  0x006FFFFF   |336kB     |Reserved		   |
+ * -------------------------------------------------------------------------
+ *
+ *
+ * OCC N Sensor Data Block Layout (150kB)
+ *
+ * The sensor data block layout is the same for each OCC N. It contains
+ * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
+ * sensor-readings-pong buffer.
+ *
+ * ----------------------------------------------------------------------------
+ * | Start (Offset from OCC |   End	   | Size |Description		      |
+ * | N Sensor Data Block)   |		   |	  |			      |
+ * ----------------------------------------------------------------------------
+ * |	0x00000000	    |  0x000003FF  |1kB   |Sensor Data Header Block   |
+ * |	0x00000400	    |  0x0000CBFF  |50kB  |Sensor Names		      |
+ * |	0x0000CC00	    |  0x0000DBFF  |4kB   |Reserved		      |
+ * |	0x0000DC00	    |  0x00017BFF  |40kB  |Sensor Readings ping buffer|
+ * |	0x00017C00	    |  0x00018BFF  |4kB   |Reserved		      |
+ * |	0x00018C00	    |  0x00022BFF  |40kB  |Sensor Readings pong buffer|
+ * |	0x00022C00	    |  0x000257FF  |11kB  |Reserved		      |
+ * ----------------------------------------------------------------------------
+ *
+ * Sensor Data Header Block : This is written once by the OCC during
+ * initialization after a load or reset. Layout is defined in 'struct
+ * occ_sensor_data_header'
+ *
+ * Sensor Names : This is written once by the OCC during initialization after a
+ * load or reset. It contains static information for each sensor. The number of
+ * sensors, format version and length of each sensor is defined in
+ * 'Sensor Data Header Block'. Format of each sensor name is defined in
+ * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
+ * immediately by the next sensor.
+ *
+ * Sensor Readings Ping/Pong Buffer:
+ * There are two 40kB buffers to store the sensor readings. One buffer that
+ * is currently being updated by the OCC and one that is available to be read.
+ * Each of these buffers will be of the same format. The number of sensors and
+ * the format version of the ping and pong buffers is defined in the
+ * 'Sensor Data Header Block'.
+ *
+ * Each sensor within the ping and pong buffers may be of a different format
+ * and length. For each sensor the length and format is determined by its
+ * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
+ *
+ * --------------------------------------------------------------------------
+ * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
+ * --------------------------------------------------------------------------
+ * | 0x0000 |Valid  |		   Reserved				    |
+ * |        |(0x01) |							    |
+ * --------------------------------------------------------------------------
+ * | 0x0008 |			Sensor Readings				    |
+ * --------------------------------------------------------------------------
+ * |	:   |				:				    |
+ * --------------------------------------------------------------------------
+ * | 0xA000 |                     End of Data				    |
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#define MAX_OCCS			8
+#define MAX_CHARS_SENSOR_NAME		16
+#define MAX_CHARS_SENSOR_UNIT		4
+
+#define OCC_SENSOR_DATA_BLOCK_OFFSET		0x00580000
+#define OCC_SENSOR_DATA_BLOCK_SIZE		0x00025800
+
+enum occ_sensor_type {
+	OCC_SENSOR_TYPE_GENERIC		= 0x0001,
+	OCC_SENSOR_TYPE_CURRENT		= 0x0002,
+	OCC_SENSOR_TYPE_VOLTAGE		= 0x0004,
+	OCC_SENSOR_TYPE_TEMPERATURE	= 0x0008,
+	OCC_SENSOR_TYPE_UTILIZATION	= 0x0010,
+	OCC_SENSOR_TYPE_TIME		= 0x0020,
+	OCC_SENSOR_TYPE_FREQUENCY	= 0x0040,
+	OCC_SENSOR_TYPE_POWER		= 0x0080,
+	OCC_SENSOR_TYPE_PERFORMANCE	= 0x0200,
+};
+
+enum occ_sensor_location {
+	OCC_SENSOR_LOC_SYSTEM		= 0x0001,
+	OCC_SENSOR_LOC_PROCESSOR	= 0x0002,
+	OCC_SENSOR_LOC_PARTITION	= 0x0004,
+	OCC_SENSOR_LOC_MEMORY		= 0x0008,
+	OCC_SENSOR_LOC_VRM		= 0x0010,
+	OCC_SENSOR_LOC_OCC		= 0x0020,
+	OCC_SENSOR_LOC_CORE		= 0x0040,
+	OCC_SENSOR_LOC_QUAD		= 0x0080,
+	OCC_SENSOR_LOC_GPU		= 0x0100,
+};
+
+enum sensor_struct_type {
+	OCC_SENSOR_READING_FULL		= 0x01,
+	OCC_SENSOR_READING_COUNTER	= 0x02,
+};
+
+/**
+ * struct occ_sensor_data_header -	Sensor Data Header Block
+ * @valid:				When the value is 0x01 it indicates
+ *					that this header block and the sensor
+ *					names buffer are ready
+ * @version:				Format version of this block
+ * @nr_sensors:				Number of sensors in names, ping and
+ *					pong buffer
+ * @sensor_reading_version:		Format version of the Ping/Pong buffer
+ * @sensor_names_offset:		Offset to the location of names buffer
+ * @sensor_names_version:		Format version of names buffer
+ * @sensor_names_length:		Length of each sensor in names buffer
+ * @sensor_reading_ping_offset:		Offset to the location of Ping buffer
+ * @sensor_reading_pong_offset:		Offset to the location of Pong buffer
+ * @pad/reserved:			Unused data
+ */
+struct occ_sensor_data_header {
+	u8 valid;
+	u8 version;
+	u16 nr_sensors;
+	u8 sensor_reading_version;
+	u8 pad[3];
+	u32 sensor_names_offset;
+	u8 sensor_names_version;
+	u8 sensor_name_length;
+	u16 reserved;
+	u32 sensor_reading_ping_offset;
+	u32 sensor_reading_pong_offset;
+} __packed;
+
+/**
+ * struct occ_sensor_name -		Format of Sensor Name
+ * @name:				Sensor name
+ * @units:				Sensor units of measurement
+ * @gsid:				Global sensor id (OCC)
+ * @freq:				Update frequency
+ * @scale_factor:			Scaling factor
+ * @type:				Sensor type as defined in
+ *					'enum occ_sensor_type'
+ * @location:				Sensor location as defined in
+ *					'enum occ_sensor_location'
+ * @structure_type:			Indicates type of data structure used
+ *					for the sensor readings in the ping and
+ *					pong buffers for this sensor as defined
+ *					in 'enum sensor_struct_type'
+ * @reading_offset:			Offset from the start of the ping/pong
+ *					reading buffers for this sensor
+ * @sensor_data:			Sensor specific info
+ * @pad:				Padding to fit the size of 48 bytes.
+ */
+struct occ_sensor_name {
+	char name[MAX_CHARS_SENSOR_NAME];
+	char units[MAX_CHARS_SENSOR_UNIT];
+	u16 gsid;
+	u32 freq;
+	u32 scale_factor;
+	u16 type;
+	u16 location;
+	u8 structure_type;
+	u32 reading_offset;
+	u8 sensor_data;
+	u8 pad[8];
+} __packed;
+
+/**
+ * struct occ_sensor_record -		Sensor Reading Full
+ * @gsid:				Global sensor id (OCC)
+ * @timestamp:				Time base counter value while updating
+ *					the sensor
+ * @sample:				Latest sample of this sensor
+ * @sample_min:				Minimum value since last OCC reset
+ * @sample_max:				Maximum value since last OCC reset
+ * @CSM_min:				Minimum value since last reset request
+ *					by CSM (CORAL)
+ * @CSM_max:				Maximum value since last reset request
+ *					by CSM (CORAL)
+ * @profiler_min:			Minimum value since last reset request
+ *					by profiler (CORAL)
+ * @profiler_max:			Maximum value since last reset request
+ *					by profiler (CORAL)
+ * @job_scheduler_min:			Minimum value since last reset request
+ *					by job scheduler(CORAL)
+ * @job_scheduler_max:			Maximum value since last reset request
+ *					by job scheduler (CORAL)
+ * @accumulator:			Accumulator for this sensor
+ * @update_tag:				Count of the number of ticks that have
+ *					passed between updates
+ * @pad:				Padding to fit the size of 48 bytes
+ */
+struct occ_sensor_record {
+	u16 gsid;
+	u64 timestamp;
+	u16 sample;
+	u16 sample_min;
+	u16 sample_max;
+	u16 CSM_min;
+	u16 CSM_max;
+	u16 profiler_min;
+	u16 profiler_max;
+	u16 job_scheduler_min;
+	u16 job_scheduler_max;
+	u64 accumulator;
+	u32 update_tag;
+	u8 pad[8];
+} __packed;
+
+/**
+ * struct occ_sensor_counter -		Sensor Reading Counter
+ * @gsid:				Global sensor id (OCC)
+ * @timestamp:				Time base counter value while updating
+ *					the sensor
+ * @accumulator:			Accumulator/Counter
+ * @sample:				Latest sample of this sensor (0/1)
+ * @pad:				Padding to fit the size of 24 bytes
+ */
+struct occ_sensor_counter {
+	u16 gsid;
+	u64 timestamp;
+	u64 accumulator;
+	u8 sample;
+	u8 pad[5];
+} __packed;
+
+enum sensor_attr {
+	SENSOR_SAMPLE,
+	SENSOR_MAX,
+	SENSOR_MIN,
+	MAX_SENSOR_ATTR,
+};
+
+static struct str_map {
+	const char *occ_str;
+	const char *opal_str;
+} str_maps[] = {
+	{"PWRSYS", "System"},
+	{"PWRFAN", "Fan"},
+	{"PWRIO", "IO"},
+	{"PWRSTORE", "Storage"},
+	{"PWRGPU", "GPU"},
+	{"PWRAPSSCH", "APSS"},
+	{"PWRPROC", ""},
+	{"PWRVDD", "Vdd"},
+	{"CURVDD", "Vdd"},
+	{"VOLTVDDSENSE", "Vdd Remote Sense"},
+	{"VOLTVDD", "Vdd"},
+	{"PWRVDN", "Vdn"},
+	{"CURVDN", "Vdn"},
+	{"VOLTVDNSENSE", "Vdn Remote Sense"},
+	{"VOLTVDN", "Vdn"},
+	{"PWRMEM", "Memory"},
+	{"TEMPC", "Core"},
+	{"TEMPQ", "Quad"},
+	{"TEMPNEST", "Nest"},
+	{"TEMPPROCTHRM", "Chip"},
+	{"TEMPDIMM", "DIMM"},
+	{"TEMPGPU", "GPU"},
+};
+
+static u64 occ_sensor_base;
+static int occ_to_chipid[MAX_CHIPS];
+
+static inline
+struct occ_sensor_data_header *get_sensor_header_block(int occ_num)
+{
+	return (struct occ_sensor_data_header *)
+		(occ_sensor_base + occ_num * OCC_SENSOR_DATA_BLOCK_SIZE);
+}
+
+static inline
+struct occ_sensor_name *get_names_block(struct occ_sensor_data_header *hb)
+{
+	return ((struct occ_sensor_name *)((u64)hb + hb->sensor_names_offset));
+}
+
+static inline u32 sensor_handler(int occ_num, int sensor_id, int attr)
+{
+	return sensor_make_handler(SENSOR_OCC, occ_num, sensor_id, attr);
+}
+
+int occ_sensor_read(u32 handle, u32 *data)
+{
+	struct occ_sensor_data_header *hb;
+	struct occ_sensor_name *md;
+	struct occ_sensor_record *sping, *spong;
+	struct occ_sensor_record *sensor;
+	u8 *ping, *pong;
+	u16 id = sensor_get_rid(handle);
+	u8 occ_num = sensor_get_frc(handle);
+	u8 attr = sensor_get_attr(handle);
+
+	if (occ_num > MAX_OCCS)
+		return OPAL_PARAMETER;
+
+	if (attr > MAX_SENSOR_ATTR)
+		return OPAL_PARAMETER;
+
+	hb = get_sensor_header_block(occ_num);
+	md = get_names_block(hb);
+
+	if (hb->valid != 1)
+		return OPAL_BUSY;
+
+	if (id > hb->nr_sensors)
+		return OPAL_PARAMETER;
+
+	ping = (u8 *)((u64)hb + hb->sensor_reading_ping_offset);
+	pong = (u8 *)((u64)hb + hb->sensor_reading_pong_offset);
+	sping = (struct occ_sensor_record *)((u64)ping + md[id].reading_offset);
+	spong = (struct occ_sensor_record *)((u64)pong + md[id].reading_offset);
+
+	/* Check which buffer is valid  and read the data from that.
+	 * Ping Pong	Action
+	 *  0	0	Return with error
+	 *  0	1	Read Pong
+	 *  1	0	Read Ping
+	 *  1	1	Read the buffer with latest timestamp
+	 */
+	if (*ping && *pong) {
+		if (sping->timestamp > spong->timestamp)
+			sensor = sping;
+		else
+			sensor = spong;
+
+	} else if (*ping && !*pong) {
+		sensor = sping;
+	} else if (!*ping && *pong) {
+		sensor = spong;
+	} else if (!*ping && !*pong) {
+		prlog(PR_DEBUG, "OCC: Both ping and pong sensor buffers are invalid\n");
+		return OPAL_BUSY;
+	}
+
+	switch (attr) {
+	case SENSOR_SAMPLE:
+		*data = sensor->sample;
+		break;
+	case SENSOR_MAX:
+		*data = sensor->sample_max;
+		break;
+	case SENSOR_MIN:
+		*data = sensor->sample_min;
+		break;
+	default:
+		*data = 0;
+	}
+
+	return 0;
+}
+
+static bool occ_sensor_sanity(int nr_occs)
+{
+	struct occ_sensor_data_header *hb;
+	int occ_num;
+
+	for (occ_num = 0; occ_num < nr_occs; occ_num++) {
+		hb = get_sensor_header_block(occ_num);
+		if (hb->valid != 0x01) {
+			prerror("OCC: Sensor data invalid\n");
+			return false;
+		}
+
+		if (hb->version != 0x01) {
+			prerror("OCC: Unsupported sensor header block version %d\n",
+				hb->version);
+			return false;
+		}
+
+		if (hb->sensor_reading_version != 0x01) {
+			prerror("OCC: Unsupported sensor record format %d\n",
+				hb->sensor_reading_version);
+			return false;
+		}
+
+		if (hb->sensor_names_version != 0x01) {
+			prerror("OCC: Unsupported sensor info format %d\n",
+				hb->sensor_names_version);
+			return false;
+		}
+
+		if (hb->sensor_name_length != sizeof(struct occ_sensor_name)) {
+			prerror("OCC: Unsupported sensor info record length %d\n",
+				hb->sensor_name_length);
+			return false;
+		}
+
+		if (!hb->nr_sensors) {
+			prerror("OCC: No sensors found for chip %d\n",
+				occ_to_chipid[occ_num]);
+			continue;
+		}
+
+		if (!hb->sensor_names_offset ||
+		    !hb->sensor_reading_ping_offset ||
+		    !hb->sensor_reading_pong_offset) {
+			prerror("OCC: Invalid sensor buffer pointers\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int parse_entity(const char *name, char **end)
+{
+	while (*name != '\0') {
+		if (isdigit(*name))
+			break;
+		name++;
+	}
+
+	if (*name)
+		return strtol(name, end, 10);
+	else
+		return -1;
+}
+
+static void add_sensor_label(struct dt_node *node, struct occ_sensor_name *md,
+			     int occ)
+{
+	char sname[30] = "";
+	char prefix[30] = "";
+	int i;
+
+	if (md->location != OCC_SENSOR_LOC_SYSTEM)
+		snprintf(prefix, sizeof(prefix), "%s %d ", "Chip",
+			 occ_to_chipid[occ]);
+
+	for (i = 0; i < ARRAY_SIZE(str_maps); i++)
+		if (!strncmp(str_maps[i].occ_str, md->name,
+			     strlen(str_maps[i].occ_str))) {
+			char *end;
+			int num;
+
+			num = parse_entity(md->name, &end);
+			if (num != -1) {
+				snprintf(sname, sizeof(sname), "%s%s %d %s",
+					 prefix, str_maps[i].opal_str, num,
+					 end);
+			} else {
+				snprintf(sname, sizeof(sname), "%s%s", prefix,
+					 str_maps[i].opal_str);
+			}
+			dt_add_property_string(node, "label", sname);
+			return;
+		}
+
+	if (md->location == OCC_SENSOR_LOC_SYSTEM) {
+		dt_add_property_string(node, "label", md->name);
+	} else {
+		snprintf(sname, sizeof(sname), "P%d_%s", occ_to_chipid[occ],
+			 md->name);
+		dt_add_property_string(node, "label", sname);
+	}
+}
+
+void occ_sensors_init(void)
+{
+	struct proc_chip *chip;
+	struct occ_sensor_name *md;
+	struct occ_sensor_data_header *hb;
+	int nr_occs = 0;
+	int occ_num, i;
+
+	/* OCC inband sensors is only supported in P9 */
+	if (proc_gen != proc_gen_p9)
+		return;
+
+	/* Sensors are copied to BAR2 OCC Common Area */
+	chip = next_chip(NULL);
+	if (!chip->occ_common_base) {
+		prerror("OCC: Unassigned OCC Common Area. No sensors found\n");
+		return;
+	}
+
+	occ_sensor_base = chip->occ_common_base + OCC_SENSOR_DATA_BLOCK_OFFSET;
+
+	for_each_chip(chip)
+		occ_to_chipid[nr_occs++] = chip->id;
+
+	/* Sanity check of the Sensor Data Header Block */
+	if (!occ_sensor_sanity(nr_occs))
+		return;
+
+	for (occ_num = 0; occ_num < nr_occs; occ_num++) {
+		hb = get_sensor_header_block(occ_num);
+		md = get_names_block(hb);
+
+		for (i = 0; i < hb->nr_sensors; i++) {
+			char name[30];
+			const char *type, *loc;
+			struct dt_node *node;
+			u32 handler;
+
+			if (md[i].type != OCC_SENSOR_TYPE_TEMPERATURE &&
+			    md[i].type != OCC_SENSOR_TYPE_POWER &&
+			    md[i].type != OCC_SENSOR_TYPE_CURRENT &&
+			    md[i].type != OCC_SENSOR_TYPE_VOLTAGE)
+				continue;
+
+			switch (md[i].type) {
+			case OCC_SENSOR_TYPE_POWER:
+				type = "power";
+				break;
+			case OCC_SENSOR_TYPE_TEMPERATURE:
+				type = "temp";
+				break;
+			case OCC_SENSOR_TYPE_CURRENT:
+				type = "curr";
+				break;
+			case OCC_SENSOR_TYPE_VOLTAGE:
+				type = "in";
+				break;
+			default:
+				return;
+			}
+
+			switch (md[i].location) {
+			case OCC_SENSOR_LOC_SYSTEM:
+				loc = "sys";
+				break;
+			case OCC_SENSOR_LOC_PROCESSOR:
+				loc = "proc";
+				break;
+			case OCC_SENSOR_LOC_MEMORY:
+				loc = "mem";
+				break;
+			case OCC_SENSOR_LOC_VRM:
+				loc = "vrm";
+				break;
+			case OCC_SENSOR_LOC_CORE:
+				loc = "core";
+				break;
+			case OCC_SENSOR_LOC_QUAD:
+				loc = "quad";
+				break;
+			case OCC_SENSOR_LOC_GPU:
+				loc = "gpu";
+				break;
+			default:
+				loc = "unknown";
+				break;
+			}
+
+			snprintf(name, sizeof(name), "%s-%s", loc, type);
+			handler = sensor_handler(occ_num, i, SENSOR_SAMPLE);
+			node = dt_new_addr(sensor_node, name, handler);
+
+			dt_add_property_string(node, "sensor-type", type);
+			dt_add_property_cells(node, "sensor-data", handler);
+
+			handler = sensor_handler(occ_num, i, SENSOR_MAX);
+			dt_add_property_cells(node, "sensor-data-max", handler);
+
+			handler = sensor_handler(occ_num, i, SENSOR_MIN);
+			dt_add_property_cells(node, "sensor-data-min", handler);
+
+			dt_add_property_string(node, "compatible",
+					       "ibm,opal-sensor");
+			dt_add_property_string(node, "occ_label", md[i].name);
+			add_sensor_label(node, &md[i], occ_num);
+		}
+	}
+}
diff --git a/include/sensor.h b/include/sensor.h
index 7eb3fa5..445a6bc 100644
--- a/include/sensor.h
+++ b/include/sensor.h
@@ -53,6 +53,7 @@ 
  */
 enum {
 	SENSOR_FSP = 0,
+	SENSOR_OCC = 6,
 	SENSOR_DTS = 7,
 };
 
diff --git a/include/skiboot.h b/include/skiboot.h
index bb0a7b5..a8e1534 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -302,4 +302,8 @@  extern int fake_nvram_info(uint32_t *total_size);
 extern int fake_nvram_start_read(void *dst, uint32_t src, uint32_t len);
 extern int fake_nvram_write(uint32_t offset, void *src, uint32_t size);
 
+/* OCC Inband Sensors */
+extern void occ_sensors_init(void);
+extern int occ_sensor_read(u32 handle, u32 *data);
+
 #endif /* __SKIBOOT_H */