diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_i225.c')
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_i225.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c index fb1487727d79..c25f555aaf82 100644 --- a/drivers/net/ethernet/intel/igc/igc_i225.c +++ b/drivers/net/ethernet/intel/igc/igc_i225.c | |||
@@ -9,6 +9,32 @@ | |||
9 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore | 9 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore |
10 | * @hw: pointer to the HW structure | 10 | * @hw: pointer to the HW structure |
11 | * | 11 | * |
12 | * Acquire the necessary semaphores for exclusive access to the EEPROM. | ||
13 | * Set the EEPROM access request bit and wait for EEPROM access grant bit. | ||
14 | * Return successful if access grant bit set, else clear the request for | ||
15 | * EEPROM access and return -IGC_ERR_NVM (-1). | ||
16 | */ | ||
17 | static s32 igc_acquire_nvm_i225(struct igc_hw *hw) | ||
18 | { | ||
19 | return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); | ||
20 | } | ||
21 | |||
22 | /** | ||
23 | * igc_release_nvm_i225 - Release exclusive access to EEPROM | ||
24 | * @hw: pointer to the HW structure | ||
25 | * | ||
26 | * Stop any current commands to the EEPROM and clear the EEPROM request bit, | ||
27 | * then release the semaphores acquired. | ||
28 | */ | ||
29 | static void igc_release_nvm_i225(struct igc_hw *hw) | ||
30 | { | ||
31 | igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore | ||
36 | * @hw: pointer to the HW structure | ||
37 | * | ||
12 | * Acquire the HW semaphore to access the PHY or NVM | 38 | * Acquire the HW semaphore to access the PHY or NVM |
13 | */ | 39 | */ |
14 | static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw) | 40 | static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw) |
@@ -139,3 +165,326 @@ void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask) | |||
139 | 165 | ||
140 | igc_put_hw_semaphore(hw); | 166 | igc_put_hw_semaphore(hw); |
141 | } | 167 | } |
168 | |||
169 | /** | ||
170 | * igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register | ||
171 | * @hw: pointer to the HW structure | ||
172 | * @offset: offset of word in the Shadow Ram to read | ||
173 | * @words: number of words to read | ||
174 | * @data: word read from the Shadow Ram | ||
175 | * | ||
176 | * Reads a 16 bit word from the Shadow Ram using the EERD register. | ||
177 | * Uses necessary synchronization semaphores. | ||
178 | */ | ||
179 | static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words, | ||
180 | u16 *data) | ||
181 | { | ||
182 | s32 status = 0; | ||
183 | u16 i, count; | ||
184 | |||
185 | /* We cannot hold synchronization semaphores for too long, | ||
186 | * because of forceful takeover procedure. However it is more efficient | ||
187 | * to read in bursts than synchronizing access for each word. | ||
188 | */ | ||
189 | for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { | ||
190 | count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? | ||
191 | IGC_EERD_EEWR_MAX_COUNT : (words - i); | ||
192 | |||
193 | status = hw->nvm.ops.acquire(hw); | ||
194 | if (status) | ||
195 | break; | ||
196 | |||
197 | status = igc_read_nvm_eerd(hw, offset, count, data + i); | ||
198 | hw->nvm.ops.release(hw); | ||
199 | if (status) | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | return status; | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * igc_write_nvm_srwr - Write to Shadow Ram using EEWR | ||
208 | * @hw: pointer to the HW structure | ||
209 | * @offset: offset within the Shadow Ram to be written to | ||
210 | * @words: number of words to write | ||
211 | * @data: 16 bit word(s) to be written to the Shadow Ram | ||
212 | * | ||
213 | * Writes data to Shadow Ram at offset using EEWR register. | ||
214 | * | ||
215 | * If igc_update_nvm_checksum is not called after this function , the | ||
216 | * Shadow Ram will most likely contain an invalid checksum. | ||
217 | */ | ||
218 | static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words, | ||
219 | u16 *data) | ||
220 | { | ||
221 | struct igc_nvm_info *nvm = &hw->nvm; | ||
222 | u32 attempts = 100000; | ||
223 | u32 i, k, eewr = 0; | ||
224 | s32 ret_val = 0; | ||
225 | |||
226 | /* A check for invalid values: offset too large, too many words, | ||
227 | * too many words for the offset, and not enough words. | ||
228 | */ | ||
229 | if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) || | ||
230 | words == 0) { | ||
231 | hw_dbg("nvm parameter(s) out of bounds\n"); | ||
232 | ret_val = -IGC_ERR_NVM; | ||
233 | goto out; | ||
234 | } | ||
235 | |||
236 | for (i = 0; i < words; i++) { | ||
237 | eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) | | ||
238 | (data[i] << IGC_NVM_RW_REG_DATA) | | ||
239 | IGC_NVM_RW_REG_START; | ||
240 | |||
241 | wr32(IGC_SRWR, eewr); | ||
242 | |||
243 | for (k = 0; k < attempts; k++) { | ||
244 | if (IGC_NVM_RW_REG_DONE & | ||
245 | rd32(IGC_SRWR)) { | ||
246 | ret_val = 0; | ||
247 | break; | ||
248 | } | ||
249 | udelay(5); | ||
250 | } | ||
251 | |||
252 | if (ret_val) { | ||
253 | hw_dbg("Shadow RAM write EEWR timed out\n"); | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | out: | ||
259 | return ret_val; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR | ||
264 | * @hw: pointer to the HW structure | ||
265 | * @offset: offset within the Shadow RAM to be written to | ||
266 | * @words: number of words to write | ||
267 | * @data: 16 bit word(s) to be written to the Shadow RAM | ||
268 | * | ||
269 | * Writes data to Shadow RAM at offset using EEWR register. | ||
270 | * | ||
271 | * If igc_update_nvm_checksum is not called after this function , the | ||
272 | * data will not be committed to FLASH and also Shadow RAM will most likely | ||
273 | * contain an invalid checksum. | ||
274 | * | ||
275 | * If error code is returned, data and Shadow RAM may be inconsistent - buffer | ||
276 | * partially written. | ||
277 | */ | ||
278 | static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words, | ||
279 | u16 *data) | ||
280 | { | ||
281 | s32 status = 0; | ||
282 | u16 i, count; | ||
283 | |||
284 | /* We cannot hold synchronization semaphores for too long, | ||
285 | * because of forceful takeover procedure. However it is more efficient | ||
286 | * to write in bursts than synchronizing access for each word. | ||
287 | */ | ||
288 | for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { | ||
289 | count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? | ||
290 | IGC_EERD_EEWR_MAX_COUNT : (words - i); | ||
291 | |||
292 | status = hw->nvm.ops.acquire(hw); | ||
293 | if (status) | ||
294 | break; | ||
295 | |||
296 | status = igc_write_nvm_srwr(hw, offset, count, data + i); | ||
297 | hw->nvm.ops.release(hw); | ||
298 | if (status) | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | return status; | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * igc_validate_nvm_checksum_i225 - Validate EEPROM checksum | ||
307 | * @hw: pointer to the HW structure | ||
308 | * | ||
309 | * Calculates the EEPROM checksum by reading/adding each word of the EEPROM | ||
310 | * and then verifies that the sum of the EEPROM is equal to 0xBABA. | ||
311 | */ | ||
312 | static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw) | ||
313 | { | ||
314 | s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count, | ||
315 | u16 *data); | ||
316 | s32 status = 0; | ||
317 | |||
318 | status = hw->nvm.ops.acquire(hw); | ||
319 | if (status) | ||
320 | goto out; | ||
321 | |||
322 | /* Replace the read function with semaphore grabbing with | ||
323 | * the one that skips this for a while. | ||
324 | * We have semaphore taken already here. | ||
325 | */ | ||
326 | read_op_ptr = hw->nvm.ops.read; | ||
327 | hw->nvm.ops.read = igc_read_nvm_eerd; | ||
328 | |||
329 | status = igc_validate_nvm_checksum(hw); | ||
330 | |||
331 | /* Revert original read operation. */ | ||
332 | hw->nvm.ops.read = read_op_ptr; | ||
333 | |||
334 | hw->nvm.ops.release(hw); | ||
335 | |||
336 | out: | ||
337 | return status; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * igc_pool_flash_update_done_i225 - Pool FLUDONE status | ||
342 | * @hw: pointer to the HW structure | ||
343 | */ | ||
344 | static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw) | ||
345 | { | ||
346 | s32 ret_val = -IGC_ERR_NVM; | ||
347 | u32 i, reg; | ||
348 | |||
349 | for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) { | ||
350 | reg = rd32(IGC_EECD); | ||
351 | if (reg & IGC_EECD_FLUDONE_I225) { | ||
352 | ret_val = 0; | ||
353 | break; | ||
354 | } | ||
355 | udelay(5); | ||
356 | } | ||
357 | |||
358 | return ret_val; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * igc_update_flash_i225 - Commit EEPROM to the flash | ||
363 | * @hw: pointer to the HW structure | ||
364 | */ | ||
365 | static s32 igc_update_flash_i225(struct igc_hw *hw) | ||
366 | { | ||
367 | s32 ret_val = 0; | ||
368 | u32 flup; | ||
369 | |||
370 | ret_val = igc_pool_flash_update_done_i225(hw); | ||
371 | if (ret_val == -IGC_ERR_NVM) { | ||
372 | hw_dbg("Flash update time out\n"); | ||
373 | goto out; | ||
374 | } | ||
375 | |||
376 | flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225; | ||
377 | wr32(IGC_EECD, flup); | ||
378 | |||
379 | ret_val = igc_pool_flash_update_done_i225(hw); | ||
380 | if (ret_val) | ||
381 | hw_dbg("Flash update time out\n"); | ||
382 | else | ||
383 | hw_dbg("Flash update complete\n"); | ||
384 | |||
385 | out: | ||
386 | return ret_val; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * igc_update_nvm_checksum_i225 - Update EEPROM checksum | ||
391 | * @hw: pointer to the HW structure | ||
392 | * | ||
393 | * Updates the EEPROM checksum by reading/adding each word of the EEPROM | ||
394 | * up to the checksum. Then calculates the EEPROM checksum and writes the | ||
395 | * value to the EEPROM. Next commit EEPROM data onto the Flash. | ||
396 | */ | ||
397 | static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw) | ||
398 | { | ||
399 | u16 checksum = 0; | ||
400 | s32 ret_val = 0; | ||
401 | u16 i, nvm_data; | ||
402 | |||
403 | /* Read the first word from the EEPROM. If this times out or fails, do | ||
404 | * not continue or we could be in for a very long wait while every | ||
405 | * EEPROM read fails | ||
406 | */ | ||
407 | ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data); | ||
408 | if (ret_val) { | ||
409 | hw_dbg("EEPROM read failed\n"); | ||
410 | goto out; | ||
411 | } | ||
412 | |||
413 | ret_val = hw->nvm.ops.acquire(hw); | ||
414 | if (ret_val) | ||
415 | goto out; | ||
416 | |||
417 | /* Do not use hw->nvm.ops.write, hw->nvm.ops.read | ||
418 | * because we do not want to take the synchronization | ||
419 | * semaphores twice here. | ||
420 | */ | ||
421 | |||
422 | for (i = 0; i < NVM_CHECKSUM_REG; i++) { | ||
423 | ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data); | ||
424 | if (ret_val) { | ||
425 | hw->nvm.ops.release(hw); | ||
426 | hw_dbg("NVM Read Error while updating checksum.\n"); | ||
427 | goto out; | ||
428 | } | ||
429 | checksum += nvm_data; | ||
430 | } | ||
431 | checksum = (u16)NVM_SUM - checksum; | ||
432 | ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, | ||
433 | &checksum); | ||
434 | if (ret_val) { | ||
435 | hw->nvm.ops.release(hw); | ||
436 | hw_dbg("NVM Write Error while updating checksum.\n"); | ||
437 | goto out; | ||
438 | } | ||
439 | |||
440 | hw->nvm.ops.release(hw); | ||
441 | |||
442 | ret_val = igc_update_flash_i225(hw); | ||
443 | |||
444 | out: | ||
445 | return ret_val; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * igc_get_flash_presence_i225 - Check if flash device is detected | ||
450 | * @hw: pointer to the HW structure | ||
451 | */ | ||
452 | bool igc_get_flash_presence_i225(struct igc_hw *hw) | ||
453 | { | ||
454 | bool ret_val = false; | ||
455 | u32 eec = 0; | ||
456 | |||
457 | eec = rd32(IGC_EECD); | ||
458 | if (eec & IGC_EECD_FLASH_DETECTED_I225) | ||
459 | ret_val = true; | ||
460 | |||
461 | return ret_val; | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * igc_init_nvm_params_i225 - Init NVM func ptrs. | ||
466 | * @hw: pointer to the HW structure | ||
467 | */ | ||
468 | s32 igc_init_nvm_params_i225(struct igc_hw *hw) | ||
469 | { | ||
470 | struct igc_nvm_info *nvm = &hw->nvm; | ||
471 | |||
472 | nvm->ops.acquire = igc_acquire_nvm_i225; | ||
473 | nvm->ops.release = igc_release_nvm_i225; | ||
474 | |||
475 | /* NVM Function Pointers */ | ||
476 | if (igc_get_flash_presence_i225(hw)) { | ||
477 | hw->nvm.type = igc_nvm_flash_hw; | ||
478 | nvm->ops.read = igc_read_nvm_srrd_i225; | ||
479 | nvm->ops.write = igc_write_nvm_srwr_i225; | ||
480 | nvm->ops.validate = igc_validate_nvm_checksum_i225; | ||
481 | nvm->ops.update = igc_update_nvm_checksum_i225; | ||
482 | } else { | ||
483 | hw->nvm.type = igc_nvm_invm; | ||
484 | nvm->ops.read = igc_read_nvm_eerd; | ||
485 | nvm->ops.write = NULL; | ||
486 | nvm->ops.validate = NULL; | ||
487 | nvm->ops.update = NULL; | ||
488 | } | ||
489 | return 0; | ||
490 | } | ||