blob: 172d6acc2bb9a213811050c26b50732002007d6a [file] [log] [blame]
Jim Yuanf5da1de2019-03-25 09:49:24 -07001From bdd6ce1bbfe0ee77feefe84662e961fb253c6195 Mon Sep 17 00:00:00 2001
2From: Jim Yuan <jim.yuan@supermicro.com>
3Date: Fri, 22 Jul 2016 17:50:57 -0700
4Subject: [PATCH 10/14] Adjust APSS gain and offset from PWS FRU information.
5
6Signed-off-by: Jim Yuan <jim.yuan@supermicro.com>
7---
8 src/include/usr/ipmi/ipmiif.H | 4 +-
9 src/usr/htmgt/htmgt_cfgdata.C | 2 +
10 src/usr/hwpf/hwp/start_payload/start_payload.C | 212 +++++++++++++++++++++
11 .../common/xmltohb/attribute_types_hb.xml | 2 +
12 4 files changed, 218 insertions(+), 2 deletions(-)
13
14diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H
15index 9dfd8ee63..5416ddca0 100644
16--- a/src/include/usr/ipmi/ipmiif.H
17+++ b/src/include/usr/ipmi/ipmiif.H
18@@ -251,8 +251,8 @@ namespace IPMI
19 inline const command_t set_sel_time(void)
20 { return std::make_pair(NETFUN_STORAGE, 0x49); }
21
22- inline const command_t read_fru_data(void)
23- { return std::make_pair(NETFUN_STORAGE, 0x11); }
24+ inline const command_t read_fru_data(void)
25+ { return std::make_pair(NETFUN_STORAGE, 0x11); }
26
27 inline const command_t write_fru_data(void)
28 { return std::make_pair(NETFUN_STORAGE, 0x12); }
29diff --git a/src/usr/htmgt/htmgt_cfgdata.C b/src/usr/htmgt/htmgt_cfgdata.C
30index 19e7b21bf..7c42abdb6 100644
31--- a/src/usr/htmgt/htmgt_cfgdata.C
32+++ b/src/usr/htmgt/htmgt_cfgdata.C
33@@ -1025,6 +1025,8 @@ void getApssMessageData(uint8_t* o_data,
34 ATTR_ADC_CHANNEL_OFFSETS_type offset;
35 sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset);
36
37+ TMGT_INF("getApssMessageData: gain is %d, offset is %d", gain[15], offset[15]); //jim
38+
39 CPPASSERT(sizeof(function) == sizeof(ground));
40 CPPASSERT(sizeof(function) == sizeof(gain));
41 CPPASSERT(sizeof(function) == sizeof(offset));
42diff --git a/src/usr/hwpf/hwp/start_payload/start_payload.C b/src/usr/hwpf/hwp/start_payload/start_payload.C
43index 5d7865a12..ad155f19e 100644
44--- a/src/usr/hwpf/hwp/start_payload/start_payload.C
45+++ b/src/usr/hwpf/hwp/start_payload/start_payload.C
46@@ -88,6 +88,7 @@
47 #include <algorithm>
48 #include <config.h>
49 #include <ipmi/ipmiwatchdog.H>
50+#include <ipmi/ipmiif.H> //jim
51 #include <vpd/vpd_if.H>
52
53 #include <hwpf/hwpf_reasoncodes.H>
54@@ -95,6 +96,7 @@
55 // Uncomment these files as they become available:
56 // #include "host_start_payload/host_start_payload.H"
57
58+
59 namespace START_PAYLOAD
60 {
61
62@@ -277,6 +279,214 @@ errlHndl_t setMaxPstate ( void )
63 }
64 #endif
65
66+//jim-start
67+enum
68+{
69+PWS_1600 = 0,
70+PWS_1000 = 1,
71+PWS_1200 = 2,
72+PWS_UNKNOWN = 0xFE,
73+};
74+
75+uint8_t getPSUFRUFromIPMICommands(void)
76+{
77+ errlHndl_t l_err = NULL;
78+ uint8_t* frudata = new uint8_t[120];
79+ size_t len = 4;
80+ uint8_t fru_header_version = 0;
81+ uint8_t j = 0, loop_break = 0, read_offset = 0;
82+
83+ //create request data buffer
84+ uint8_t* data = new uint8_t[len];
85+
86+ IPMI::completion_code cc = IPMI::CC_UNKBAD;
87+
88+ data[0] = 60; //try to read from PWS1. 60-PWS1, 61-PWS2
89+ data[1] = 0x0;
90+ data[2] = 0x0;
91+ data[3] = 8;
92+ l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data);
93+
94+ for (uint8_t i = 0; i <= 8; i++ )
95+ fru_header_version = data[1] & 0xF; //normal should be 0x01.
96+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "fru header version is %x", fru_header_version);
97+ delete[] data;
98+
99+ if((l_err == NULL) && (cc == IPMI::CC_OK) && (fru_header_version == 1))
100+ {
101+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS1");
102+
103+ while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100))
104+ {
105+ //create request data buffer
106+ len = 4; //must set len every time
107+ uint8_t* data = new uint8_t[len];
108+
109+ IPMI::completion_code cc = IPMI::CC_UNKBAD;
110+
111+ data[0] = 60; //read from PWS1
112+ data[1] = read_offset;
113+ data[2] = 0x0;
114+ data[3] = 8;
115+ l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data);
116+
117+ if (cc != IPMI::CC_OK) loop_break = 1;
118+
119+ read_offset += 8;
120+ for (uint8_t i = 1; i <= 8; i++ )
121+ {
122+ frudata[j] = data[i];
123+ j++;
124+ }
125+ delete[] data;
126+ }
127+
128+
129+ }
130+ else
131+ {
132+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "could get FRU from PWS2");
133+
134+ while ((l_err == NULL) && (loop_break == 0) && (read_offset < 100))
135+ {
136+ //create request data buffer
137+ len = 4;//must set len every time
138+ uint8_t* data = new uint8_t[len];
139+
140+ IPMI::completion_code cc = IPMI::CC_UNKBAD;
141+
142+ data[0] = 61; //read from PWS2
143+ data[1] = read_offset;
144+ data[2] = 0x0;
145+ data[3] = 8;
146+ l_err = IPMI::sendrecv(IPMI::read_fru_data(), cc, len, data);
147+
148+ if (cc != IPMI::CC_OK) loop_break = 1;
149+
150+ read_offset += 8;
151+ for (uint8_t i = 1; i <= 8; i++ )
152+ {
153+ frudata[j] = data[i];
154+ j++;
155+ }
156+ delete[] data;
157+ }
158+
159+ }
160+
161+ uint8_t product_info_offset, manufacture_name_offset, manufacture_name_length, product_name_offset, product_name_length;
162+ uint8_t product_partnumber_offset, product_partnumber_length;
163+ uint8_t fru_offset, powerSupplyFru = PWS_UNKNOWN;
164+ uint8_t pws1600[] = {'P','W','S','-','1','K','6','2','A','-','1','R'};
165+ uint8_t pws1000[] = {'P','W','S','-','1','K','0','2','A','-','1','R'};
166+ uint8_t pws1200[] = {'P','W','S','-','1','K','2','2','A','-','1','R'};
167+
168+ //code to calculate product part number size and offset. should use structure. refer to FRU spec.
169+ product_info_offset = frudata[4] * 8;
170+ manufacture_name_offset = product_info_offset + 3;
171+ manufacture_name_length = frudata[manufacture_name_offset] & 0x3F;
172+ product_name_offset = manufacture_name_offset + manufacture_name_length + 1;
173+ product_name_length = frudata[product_name_offset] & 0x3F;
174+ product_partnumber_offset = product_name_offset + product_name_length + 1;
175+ product_partnumber_length = frudata[product_partnumber_offset] & 0x3F;
176+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "product_partnumber_length is %x", product_partnumber_length);
177+ fru_offset = product_partnumber_offset + 1;
178+
179+ if (product_partnumber_length == 12)
180+ {
181+ for (uint8_t i = 0; pws1600[i] == frudata[fru_offset + i] ; i ++)
182+ if (i == 11)
183+ powerSupplyFru = PWS_1600;
184+
185+ for (uint8_t i = 0; pws1000[i] == frudata[fru_offset + i] ; i ++)
186+ if (i == 11)
187+ powerSupplyFru = PWS_1000;
188+
189+ for (uint8_t i = 0; pws1200[i] == frudata[fru_offset + i] ; i ++)
190+ if (i == 11)
191+ powerSupplyFru = PWS_1200;
192+ }
193+ else
194+ powerSupplyFru = PWS_UNKNOWN;
195+
196+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "powerSupplyFru is %x", powerSupplyFru);
197+
198+ return powerSupplyFru;
199+
200+}
201+//find apss channel number from XML.
202+enum
203+{
204+V12_SENSE = 0,
205+PROC0_POWER = 1,
206+PROC1_POWER = 2,
207+PCIE_PROC0_POWER = 5,
208+PCIE_PROC1_POWER = 6,
209+TOTAL_SYSTEM_POWER = 15,
210+};
211+
212+void setAPSSGainOffsetFromPWSInfo(void)
213+{
214+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "before load OCC");
215+
216+ //Get Gain/Offset ATTR
217+ TARGETING::Target* sys = NULL;
218+ targetService().getTopLevelTarget(sys);
219+
220+ ATTR_ADC_CHANNEL_GAINS_type gain;
221+ sys->tryGetAttr<ATTR_ADC_CHANNEL_GAINS>(gain);
222+
223+ ATTR_ADC_CHANNEL_OFFSETS_type offset;
224+ sys->tryGetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset);
225+
226+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "gain is %d, offset is %d", gain[15], offset[15]);
227+
228+ //Note that the function/ APSS channel ids can be indirect. I've hardcoded here, you will need to look at the XML to find the channel/function number that matches
229+ //const uint8_t SYS_CHANNEL = 15; //APSS Channel 15 is sys power, ie the gain/offset we need to tweak
230+
231+ //Get power supply data from BMC
232+ uint8_t powerSupplyFru = getPSUFRUFromIPMICommands();
233+
234+ switch(powerSupplyFru)
235+ {
236+ case PWS_1600: //PWS-1K62A-1R (1600W):
237+ gain[TOTAL_SYSTEM_POWER] = 67800;
238+ offset[TOTAL_SYSTEM_POWER] = 0;
239+ break;
240+
241+ case PWS_1000: //PWS-1K02A-1R (1000W):
242+ gain[TOTAL_SYSTEM_POWER] = 41500;
243+ offset[TOTAL_SYSTEM_POWER] = 0;
244+ break;
245+
246+ case PWS_1200: //PWS-1K22A-1R (1200W):
247+ gain[TOTAL_SYSTEM_POWER] = 50000;
248+ offset[TOTAL_SYSTEM_POWER] = 0;
249+ break;
250+
251+ default:
252+ //Do nothing, leave defaults
253+ //Gen error for user attention?
254+ break;
255+ }
256+
257+ //Now write the attributes back so they get picked up by OCC code
258+ if (!sys->trySetAttr<ATTR_ADC_CHANNEL_GAINS>(gain))
259+ {
260+ //unlikely, crash
261+ //Emit failing trace/console data
262+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set gain failed");
263+ assert(0);
264+ }
265+
266+ if (!sys->trySetAttr<ATTR_ADC_CHANNEL_OFFSETS>(offset))
267+ {
268+ //unlikely, crash
269+ //Emit failing trace/console data
270+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "set offset failed");
271+ assert(0);
272+ }
273+}
274 //
275 // Wrapper function to call host_runtime_setup
276 //
277@@ -318,6 +528,8 @@ void* call_host_runtime_setup( void *io_pArgs )
278 break;
279 }
280
281+ setAPSSGainOffsetFromPWSInfo(); //jim add code before activate OCC. START_OCC_DURING_BOOT is defined in config.
282+
283 bool l_activateOCC = is_avp_load();
284
285 #ifdef CONFIG_START_OCC_DURING_BOOT
286diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
287index c4eb6603d..64a0c9bae 100644
288--- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
289+++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
290@@ -747,6 +747,7 @@
291 </simpleType>
292 <persistency>non-volatile</persistency>
293 <readable/>
294+ <writeable/>
295 </attribute>
296
297 <attribute>
298@@ -758,6 +759,7 @@
299 </simpleType>
300 <persistency>non-volatile</persistency>
301 <readable/>
302+ <writeable/>
303 </attribute>
304
305 <attribute>
306--
3072.16.2.windows.1
308