blob: 757f701715342754875cb0ff3b26c385ab481311 [file] [log] [blame]
Bill Hoffa41a142e2015-04-03 10:35:48 -05001From 3f630837040bae961612214307d2903e65af9e5d Mon Sep 17 00:00:00 2001
2From: Mike Baiocchi <baiocchi@us.ibm.com>
3Date: Thu, 2 Apr 2015 13:42:00 -0500
4Subject: [PATCH 05/10] Fix I2C Reset to resolve I2C Bus Arbitration Lost
5 Errors
6
7This commit fixes 2 bugs where the full "Force Reset and Unlock"
8I2C reset procedure used to both avoid and recover from I2C Bus
9Arbitration Lost errors was not being performed correctly on any
10ports but port 0.
11
12Change-Id: Ie967d81917e9b942d5cb516856075ebdb5029487
13CQ: SW297864
14(cherry picked from commit 01ee7107170c867d25af2485b75307e3bfa87339)
15---
16 src/include/usr/i2c/i2creasoncodes.H | 1 +
17 src/usr/i2c/i2c.C | 182 ++++++++++++++++++++++++-----------
18 src/usr/i2c/i2c.H | 4 +-
19 3 files changed, 130 insertions(+), 57 deletions(-)
20
21diff --git a/src/include/usr/i2c/i2creasoncodes.H b/src/include/usr/i2c/i2creasoncodes.H
22index a63e8d5..454ef15 100644
23--- a/src/include/usr/i2c/i2creasoncodes.H
24+++ b/src/include/usr/i2c/i2creasoncodes.H
25@@ -58,6 +58,7 @@ enum i2cModuleId
26 I2C_SETUP_MASTERS = 0x08,
27 I2C_SEND_SLAVE_STOP = 0x09,
28 I2C_PROCESS_ACTIVE_MASTERS = 0x0A,
29+ I2C_FORCE_RESET_AND_UNLOCK = 0x0B,
30 };
31
32
33diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
34index bc4bb7b..ee7e5e3 100755
35--- a/src/usr/i2c/i2c.C
36+++ b/src/usr/i2c/i2c.C
37@@ -1925,6 +1925,11 @@ errlHndl_t i2cForceResetAndUnlock( TARGETING::Target * i_target,
38 {
39
40 errlHndl_t err = NULL;
41+ mode_reg_t mode;
42+ uint64_t l_speed = I2C_BUS_SPEED_FROM_MRW;
43+
44+ // I2C Bus Speed Array
45+ TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speed_array;
46
47 TRACDCOMP( g_trac_i2c,
48 ENTER_MRK"i2cForceResetAndUnlock()" );
49@@ -1932,62 +1937,122 @@ errlHndl_t i2cForceResetAndUnlock( TARGETING::Target * i_target,
50 do
51 {
52
53- // enable diagnostic mode
54- // set bit in mode register
55- mode_reg_t diagnostic;
56-
57- diagnostic.diag_mode = 0x1;
58-
59- err = i2cRegisterOp( DeviceFW::WRITE,
60- i_target,
61- &diagnostic.value,
62- I2C_REG_MODE,
63- i_args );
64-
65- if( err )
66+ // Get I2C Bus Speed Array attribute. It will be used to determine
67+ // which engine/port combinations have devices on them
68+ if ( !( i_target->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY>
69+ (speed_array) ) )
70 {
71 TRACFCOMP( g_trac_i2c,
72- ERR_MRK"I2C Enable Diagnostic mode Failed!!" );
73+ ERR_MRK"i2cForceResetAndUnlock() - Cannot find "
74+ "ATTR_I2C_BUS_SPEED_ARRAY needed for operation");
75+ /*@
76+ * @errortype
77+ * @reasoncode I2C_ATTRIBUTE_NOT_FOUND
78+ * @severity ERRORLOG_SEV_UNRECOVERABLE
79+ * @moduleid I2C_FORCE_RESET_AND_UNLOCK
80+ * @userdata1 Target for the attribute
81+ * @userdata2 <UNUSED>
82+ * @devdesc ATTR_I2C_BUS_SPEED_ARRAY not found
83+ * @custdesc I2C configuration data missing
84+ */
85+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
86+ I2C_FORCE_RESET_AND_UNLOCK,
87+ I2C_ATTRIBUTE_NOT_FOUND,
88+ TARGETING::get_huid(i_target),
89+ 0x0,
90+ true /*Add HB SW Callout*/ );
91+
92+ err->collectTrace( I2C_COMP_NAME, 256);
93+
94 break;
95 }
96
97+ // Need to send slave stop to all ports with a device on the engine
98+ for( uint32_t port = 0; port < P8_MASTER_PORTS; port++ )
99+ {
100
101- //toggle clock line
102- err = i2cToggleClockLine( i_target,
103- i_args );
104+ // Only send stop to a port if there are devices on it
105+ l_speed = speed_array[i_args.engine][port];
106+ if ( l_speed == 0 )
107+ {
108+ continue;
109+ }
110
111- if( err )
112- {
113- break;
114- }
115+ TRACUCOMP( g_trac_i2c,
116+ INFO_MRK"i2cForceResetAndUnlock() - Performing op on "
117+ "engine=%d, port=%d",
118+ i_args.engine, port);
119
120- //manually send stop signal
121- err = i2cSendStopSignal( i_target,
122- i_args );
123+ // Clear mode register
124+ mode.value = 0x0ull;
125
126- if( err )
127- {
128- break;
129- }
130+ // set port in mode register
131+ mode.port_num = port;
132
133- //disable diagnostic mode
134- //set bit in mode register
135- diagnostic.diag_mode = 0x0;
136+ // enable diagnostic mode in mode register
137+ mode.diag_mode = 0x1;
138
139- err = i2cRegisterOp( DeviceFW::WRITE,
140- i_target,
141- &diagnostic.value,
142- I2C_REG_MODE,
143- i_args );
144+ err = i2cRegisterOp( DeviceFW::WRITE,
145+ i_target,
146+ &mode.value,
147+ I2C_REG_MODE,
148+ i_args );
149
150+ if( err )
151+ {
152+ TRACFCOMP( g_trac_i2c,
153+ ERR_MRK"I2C Enable Diagnostic mode Failed!!" );
154
155- if( err )
156- {
157- TRACFCOMP( g_trac_i2c,
158- ERR_MRK"I2C disable Diagnostic mode Failed!!" );
159- break;
160- }
161
162+ // We still need to reset the other ports on this I2C engine
163+ errlCommit( err, I2C_COMP_ID );
164+ continue;
165+ }
166+
167+
168+ //toggle clock line
169+ err = i2cToggleClockLine( i_target,
170+ i_args );
171+
172+ if( err )
173+ {
174+ // We still need to reset the other ports on this I2C engine
175+ errlCommit( err, I2C_COMP_ID );
176+ continue;
177+ }
178+
179+ //manually send stop signal
180+ err = i2cSendStopSignal( i_target,
181+ i_args );
182+
183+ if( err )
184+ {
185+ // We still need to reset the other ports on this I2C engine
186+ errlCommit( err, I2C_COMP_ID );
187+ continue;
188+ }
189+
190+ // disable diagnostic mode in mode register
191+ mode.diag_mode = 0x0;
192+
193+ err = i2cRegisterOp( DeviceFW::WRITE,
194+ i_target,
195+ &mode.value,
196+ I2C_REG_MODE,
197+ i_args );
198+
199+
200+ if( err )
201+ {
202+ TRACFCOMP( g_trac_i2c,
203+ ERR_MRK"I2C disable Diagnostic mode Failed!!" );
204+ // We still need to reset the other ports on this I2C engine
205+ errlCommit( err, I2C_COMP_ID );
206+ continue;
207+ }
208+
209+
210+ } // end of port for loop
211
212 }while(0);
213
214@@ -2036,8 +2101,10 @@ errlHndl_t i2cReset ( TARGETING::Target * i_target,
215
216 if( err )
217 {
218- //error trying to force a reset break
219- break;
220+ // We still want to send the slave stop command since the
221+ // initial reset completed above.
222+ // So just commit the log here and let the function continue.
223+ errlCommit( err, I2C_COMP_ID );
224 }
225 }
226
227@@ -2114,13 +2181,6 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
228 // Need to send slave stop to all ports with a device on the engine
229 for( uint32_t port = 0; port < P8_MASTER_PORTS; port++ )
230 {
231- // Only do port 0 for FSI I2C
232- if ( ( i_args.switches.useFsiI2C == 1 ) &&
233- ( port != 0 ) )
234- {
235- break;
236- }
237-
238 // Only send stop to a port if there are devices on it
239 l_speed = speed_array[i_args.engine][port];
240 if ( l_speed == 0 )
241@@ -2139,7 +2199,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
242 i_args );
243 if( err )
244 {
245- break;
246+ // We still need to send the slave stop to the other ports
247+ // on this I2C engine
248+ errlCommit( err, I2C_COMP_ID );
249+ continue;
250 }
251
252 mode.bit_rate_div = i_args.bit_rate_divisor;
253@@ -2156,7 +2219,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
254
255 if( err )
256 {
257- break;
258+ // We still need to send the slave stop to the other ports
259+ // on this I2C engine
260+ errlCommit( err, I2C_COMP_ID );
261+ continue;
262 }
263
264 cmd.value = 0x0ull;
265@@ -2174,7 +2240,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
266
267 if( err )
268 {
269- break;
270+ // We still need to send the slave stop to the other ports
271+ // on this I2C engine
272+ errlCommit( err, I2C_COMP_ID );
273+ continue;
274 }
275
276 // Now wait for cmd Complete
277@@ -2183,7 +2252,10 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target,
278
279 if( err )
280 {
281- break;
282+ // We still need to send the slave stop to the other ports
283+ // on this I2C engine
284+ errlCommit( err, I2C_COMP_ID );
285+ continue;
286 }
287
288 } // end of port for-loop
289diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H
290index c3e5278..4a74663 100755
291--- a/src/usr/i2c/i2c.H
292+++ b/src/usr/i2c/i2c.H
293@@ -723,8 +723,8 @@ errlHndl_t i2cSendStopSignal(TARGETING::Target * i_target,
294
295 /**
296 * @brief This function will reset the I2C Master engine specified
297- * by the args. It will also then initiate a Stop cmd to the
298- * slave device.
299+ * by the args. It will also end the sequence by initiating a Stop
300+ * cmd to all ports on the engine that have a slave device.
301 *
302 * @param[in] i_target - The I2C master target.
303 *
304--
3051.8.2.2
306