diff options
author | Emil Tantilov <emil.s.tantilov@intel.com> | 2011-03-23 20:57:50 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-04-13 22:23:38 -0400 |
commit | eb9c3e3ea2981e56c71e8f5477c51783856090b1 (patch) | |
tree | ff6ddad23c34e96de2083c46598f7aab0eb62425 /drivers | |
parent | 032b4325b61b03f87f0346d0e92e39f785e24105 (diff) |
ixgbe: fix semaphores in eeprom routines for x540
HW can upload EEPROM content from flash while
in a middle of checksum calculation. Take NVM ownership for the whole
process of checksum update.
Call ixgbe_read_eerd_generic() and ixgbe_write_eewr_generic() directly to
avoid double take of semaphores which leads to long loading times.
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_common.c | 44 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_common.h | 2 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_x540.c | 154 |
3 files changed, 153 insertions, 47 deletions
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index a67cba5149d1..fc31e0256c18 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c | |||
@@ -54,6 +54,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); | |||
54 | static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, | 54 | static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, |
55 | u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); | 55 | u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); |
56 | static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); | 56 | static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); |
57 | static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); | ||
57 | 58 | ||
58 | /** | 59 | /** |
59 | * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx | 60 | * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx |
@@ -778,6 +779,47 @@ out: | |||
778 | } | 779 | } |
779 | 780 | ||
780 | /** | 781 | /** |
782 | * ixgbe_write_eewr_generic - Write EEPROM word using EEWR | ||
783 | * @hw: pointer to hardware structure | ||
784 | * @offset: offset of word in the EEPROM to write | ||
785 | * @data: word write to the EEPROM | ||
786 | * | ||
787 | * Write a 16 bit word to the EEPROM using the EEWR register. | ||
788 | **/ | ||
789 | s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) | ||
790 | { | ||
791 | u32 eewr; | ||
792 | s32 status; | ||
793 | |||
794 | hw->eeprom.ops.init_params(hw); | ||
795 | |||
796 | if (offset >= hw->eeprom.word_size) { | ||
797 | status = IXGBE_ERR_EEPROM; | ||
798 | goto out; | ||
799 | } | ||
800 | |||
801 | eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | | ||
802 | (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START; | ||
803 | |||
804 | status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); | ||
805 | if (status != 0) { | ||
806 | hw_dbg(hw, "Eeprom write EEWR timed out\n"); | ||
807 | goto out; | ||
808 | } | ||
809 | |||
810 | IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); | ||
811 | |||
812 | status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); | ||
813 | if (status != 0) { | ||
814 | hw_dbg(hw, "Eeprom write EEWR timed out\n"); | ||
815 | goto out; | ||
816 | } | ||
817 | |||
818 | out: | ||
819 | return status; | ||
820 | } | ||
821 | |||
822 | /** | ||
781 | * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status | 823 | * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status |
782 | * @hw: pointer to hardware structure | 824 | * @hw: pointer to hardware structure |
783 | * @ee_reg: EEPROM flag for polling | 825 | * @ee_reg: EEPROM flag for polling |
@@ -785,7 +827,7 @@ out: | |||
785 | * Polls the status bit (bit 1) of the EERD or EEWR to determine when the | 827 | * Polls the status bit (bit 1) of the EERD or EEWR to determine when the |
786 | * read or write is done respectively. | 828 | * read or write is done respectively. |
787 | **/ | 829 | **/ |
788 | s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) | 830 | static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) |
789 | { | 831 | { |
790 | u32 i; | 832 | u32 i; |
791 | u32 reg; | 833 | u32 reg; |
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 2585bf38391d..e18dc136ad34 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h | |||
@@ -50,13 +50,13 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); | |||
50 | s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); | 50 | s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); |
51 | s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); | 51 | s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); |
52 | s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); | 52 | s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); |
53 | s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); | ||
53 | s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, | 54 | s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, |
54 | u16 *data); | 55 | u16 *data); |
55 | u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); | 56 | u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); |
56 | s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, | 57 | s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, |
57 | u16 *checksum_val); | 58 | u16 *checksum_val); |
58 | s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); | 59 | s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); |
59 | s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); | ||
60 | 60 | ||
61 | s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, | 61 | s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, |
62 | u32 enable_addr); | 62 | u32 enable_addr); |
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 8aa1dc1155a9..5433f15c1e1b 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c | |||
@@ -322,55 +322,33 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) | |||
322 | } | 322 | } |
323 | 323 | ||
324 | /** | 324 | /** |
325 | * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR | 325 | * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR |
326 | * @hw: pointer to hardware structure | 326 | * @hw: pointer to hardware structure |
327 | * @offset: offset of word in the EEPROM to write | 327 | * @offset: offset of word in the EEPROM to write |
328 | * @data: word write to the EEPROM | 328 | * @data: word write to the EEPROM |
329 | * | 329 | * |
330 | * Write a 16 bit word to the EEPROM using the EEWR register. | 330 | * Write a 16 bit word to the EEPROM using the EEWR register. |
331 | **/ | 331 | **/ |
332 | static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) | 332 | static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) |
333 | { | 333 | { |
334 | u32 eewr; | 334 | s32 status = 0; |
335 | s32 status; | ||
336 | |||
337 | hw->eeprom.ops.init_params(hw); | ||
338 | |||
339 | if (offset >= hw->eeprom.word_size) { | ||
340 | status = IXGBE_ERR_EEPROM; | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | | ||
345 | (data << IXGBE_EEPROM_RW_REG_DATA) | | ||
346 | IXGBE_EEPROM_RW_REG_START; | ||
347 | |||
348 | if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { | ||
349 | status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); | ||
350 | if (status != 0) { | ||
351 | hw_dbg(hw, "Eeprom write EEWR timed out\n"); | ||
352 | goto out; | ||
353 | } | ||
354 | |||
355 | IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); | ||
356 | 335 | ||
357 | status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); | 336 | if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) |
358 | if (status != 0) { | 337 | status = ixgbe_write_eewr_generic(hw, offset, data); |
359 | hw_dbg(hw, "Eeprom write EEWR timed out\n"); | 338 | else |
360 | goto out; | ||
361 | } | ||
362 | } else { | ||
363 | status = IXGBE_ERR_SWFW_SYNC; | 339 | status = IXGBE_ERR_SWFW_SYNC; |
364 | } | ||
365 | 340 | ||
366 | out: | 341 | hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); |
367 | ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); | ||
368 | return status; | 342 | return status; |
369 | } | 343 | } |
370 | 344 | ||
371 | /** | 345 | /** |
372 | * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum | 346 | * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum |
373 | * @hw: pointer to hardware structure | 347 | * |
348 | * This function does not use synchronization for EERD and EEWR. It can | ||
349 | * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. | ||
350 | * | ||
351 | * @hw: pointer to hardware structure | ||
374 | **/ | 352 | **/ |
375 | static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | 353 | static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) |
376 | { | 354 | { |
@@ -381,9 +359,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
381 | u16 pointer = 0; | 359 | u16 pointer = 0; |
382 | u16 word = 0; | 360 | u16 word = 0; |
383 | 361 | ||
362 | /* | ||
363 | * Do not use hw->eeprom.ops.read because we do not want to take | ||
364 | * the synchronization semaphores here. Instead use | ||
365 | * ixgbe_read_eerd_generic | ||
366 | */ | ||
367 | |||
384 | /* Include 0x0-0x3F in the checksum */ | 368 | /* Include 0x0-0x3F in the checksum */ |
385 | for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { | 369 | for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { |
386 | if (hw->eeprom.ops.read(hw, i, &word) != 0) { | 370 | if (ixgbe_read_eerd_generic(hw, i, &word) != 0) { |
387 | hw_dbg(hw, "EEPROM read failed\n"); | 371 | hw_dbg(hw, "EEPROM read failed\n"); |
388 | break; | 372 | break; |
389 | } | 373 | } |
@@ -398,7 +382,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
398 | if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) | 382 | if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) |
399 | continue; | 383 | continue; |
400 | 384 | ||
401 | if (hw->eeprom.ops.read(hw, i, &pointer) != 0) { | 385 | if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) { |
402 | hw_dbg(hw, "EEPROM read failed\n"); | 386 | hw_dbg(hw, "EEPROM read failed\n"); |
403 | break; | 387 | break; |
404 | } | 388 | } |
@@ -408,7 +392,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
408 | pointer >= hw->eeprom.word_size) | 392 | pointer >= hw->eeprom.word_size) |
409 | continue; | 393 | continue; |
410 | 394 | ||
411 | if (hw->eeprom.ops.read(hw, pointer, &length) != 0) { | 395 | if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) { |
412 | hw_dbg(hw, "EEPROM read failed\n"); | 396 | hw_dbg(hw, "EEPROM read failed\n"); |
413 | break; | 397 | break; |
414 | } | 398 | } |
@@ -419,7 +403,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
419 | continue; | 403 | continue; |
420 | 404 | ||
421 | for (j = pointer+1; j <= pointer+length; j++) { | 405 | for (j = pointer+1; j <= pointer+length; j++) { |
422 | if (hw->eeprom.ops.read(hw, j, &word) != 0) { | 406 | if (ixgbe_read_eerd_generic(hw, j, &word) != 0) { |
423 | hw_dbg(hw, "EEPROM read failed\n"); | 407 | hw_dbg(hw, "EEPROM read failed\n"); |
424 | break; | 408 | break; |
425 | } | 409 | } |
@@ -433,6 +417,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
433 | } | 417 | } |
434 | 418 | ||
435 | /** | 419 | /** |
420 | * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum | ||
421 | * @hw: pointer to hardware structure | ||
422 | * @checksum_val: calculated checksum | ||
423 | * | ||
424 | * Performs checksum calculation and validates the EEPROM checksum. If the | ||
425 | * caller does not need checksum_val, the value can be NULL. | ||
426 | **/ | ||
427 | static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, | ||
428 | u16 *checksum_val) | ||
429 | { | ||
430 | s32 status; | ||
431 | u16 checksum; | ||
432 | u16 read_checksum = 0; | ||
433 | |||
434 | /* | ||
435 | * Read the first word from the EEPROM. If this times out or fails, do | ||
436 | * not continue or we could be in for a very long wait while every | ||
437 | * EEPROM read fails | ||
438 | */ | ||
439 | status = hw->eeprom.ops.read(hw, 0, &checksum); | ||
440 | |||
441 | if (status != 0) { | ||
442 | hw_dbg(hw, "EEPROM read failed\n"); | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { | ||
447 | checksum = hw->eeprom.ops.calc_checksum(hw); | ||
448 | |||
449 | /* | ||
450 | * Do not use hw->eeprom.ops.read because we do not want to take | ||
451 | * the synchronization semaphores twice here. | ||
452 | */ | ||
453 | ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, | ||
454 | &read_checksum); | ||
455 | |||
456 | /* | ||
457 | * Verify read checksum from EEPROM is the same as | ||
458 | * calculated checksum | ||
459 | */ | ||
460 | if (read_checksum != checksum) | ||
461 | status = IXGBE_ERR_EEPROM_CHECKSUM; | ||
462 | |||
463 | /* If the user cares, return the calculated checksum */ | ||
464 | if (checksum_val) | ||
465 | *checksum_val = checksum; | ||
466 | } else { | ||
467 | status = IXGBE_ERR_SWFW_SYNC; | ||
468 | } | ||
469 | |||
470 | hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); | ||
471 | out: | ||
472 | return status; | ||
473 | } | ||
474 | |||
475 | /** | ||
436 | * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash | 476 | * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash |
437 | * @hw: pointer to hardware structure | 477 | * @hw: pointer to hardware structure |
438 | * | 478 | * |
@@ -443,11 +483,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) | |||
443 | static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) | 483 | static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) |
444 | { | 484 | { |
445 | s32 status; | 485 | s32 status; |
486 | u16 checksum; | ||
446 | 487 | ||
447 | status = ixgbe_update_eeprom_checksum_generic(hw); | 488 | /* |
489 | * Read the first word from the EEPROM. If this times out or fails, do | ||
490 | * not continue or we could be in for a very long wait while every | ||
491 | * EEPROM read fails | ||
492 | */ | ||
493 | status = hw->eeprom.ops.read(hw, 0, &checksum); | ||
494 | |||
495 | if (status != 0) | ||
496 | hw_dbg(hw, "EEPROM read failed\n"); | ||
497 | |||
498 | if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { | ||
499 | checksum = hw->eeprom.ops.calc_checksum(hw); | ||
448 | 500 | ||
449 | if (status) | 501 | /* |
502 | * Do not use hw->eeprom.ops.write because we do not want to | ||
503 | * take the synchronization semaphores twice here. | ||
504 | */ | ||
505 | status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, | ||
506 | checksum); | ||
507 | |||
508 | if (status == 0) | ||
450 | status = ixgbe_update_flash_X540(hw); | 509 | status = ixgbe_update_flash_X540(hw); |
510 | else | ||
511 | status = IXGBE_ERR_SWFW_SYNC; | ||
512 | } | ||
513 | |||
514 | hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); | ||
451 | 515 | ||
452 | return status; | 516 | return status; |
453 | } | 517 | } |
@@ -728,7 +792,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_X540 = { | |||
728 | .read = &ixgbe_read_eerd_X540, | 792 | .read = &ixgbe_read_eerd_X540, |
729 | .write = &ixgbe_write_eewr_X540, | 793 | .write = &ixgbe_write_eewr_X540, |
730 | .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, | 794 | .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, |
731 | .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, | 795 | .validate_checksum = &ixgbe_validate_eeprom_checksum_X540, |
732 | .update_checksum = &ixgbe_update_eeprom_checksum_X540, | 796 | .update_checksum = &ixgbe_update_eeprom_checksum_X540, |
733 | }; | 797 | }; |
734 | 798 | ||