diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_phy.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_phy.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 981e6d849592..5a8669aedf64 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c | |||
@@ -127,6 +127,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) | |||
127 | case QT2022_PHY_ID: | 127 | case QT2022_PHY_ID: |
128 | phy_type = ixgbe_phy_qt; | 128 | phy_type = ixgbe_phy_qt; |
129 | break; | 129 | break; |
130 | case ATH_PHY_ID: | ||
131 | phy_type = ixgbe_phy_nl; | ||
132 | break; | ||
130 | default: | 133 | default: |
131 | phy_type = ixgbe_phy_unknown; | 134 | phy_type = ixgbe_phy_unknown; |
132 | break; | 135 | break; |
@@ -430,6 +433,261 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, | |||
430 | } | 433 | } |
431 | 434 | ||
432 | /** | 435 | /** |
436 | * ixgbe_reset_phy_nl - Performs a PHY reset | ||
437 | * @hw: pointer to hardware structure | ||
438 | **/ | ||
439 | s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) | ||
440 | { | ||
441 | u16 phy_offset, control, eword, edata, block_crc; | ||
442 | bool end_data = false; | ||
443 | u16 list_offset, data_offset; | ||
444 | u16 phy_data = 0; | ||
445 | s32 ret_val = 0; | ||
446 | u32 i; | ||
447 | |||
448 | hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | ||
449 | IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | ||
450 | |||
451 | /* reset the PHY and poll for completion */ | ||
452 | hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | ||
453 | IXGBE_MDIO_PHY_XS_DEV_TYPE, | ||
454 | (phy_data | IXGBE_MDIO_PHY_XS_RESET)); | ||
455 | |||
456 | for (i = 0; i < 100; i++) { | ||
457 | hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | ||
458 | IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | ||
459 | if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) | ||
460 | break; | ||
461 | msleep(10); | ||
462 | } | ||
463 | |||
464 | if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { | ||
465 | hw_dbg(hw, "PHY reset did not complete.\n"); | ||
466 | ret_val = IXGBE_ERR_PHY; | ||
467 | goto out; | ||
468 | } | ||
469 | |||
470 | /* Get init offsets */ | ||
471 | ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, | ||
472 | &data_offset); | ||
473 | if (ret_val != 0) | ||
474 | goto out; | ||
475 | |||
476 | ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); | ||
477 | data_offset++; | ||
478 | while (!end_data) { | ||
479 | /* | ||
480 | * Read control word from PHY init contents offset | ||
481 | */ | ||
482 | ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); | ||
483 | control = (eword & IXGBE_CONTROL_MASK_NL) >> | ||
484 | IXGBE_CONTROL_SHIFT_NL; | ||
485 | edata = eword & IXGBE_DATA_MASK_NL; | ||
486 | switch (control) { | ||
487 | case IXGBE_DELAY_NL: | ||
488 | data_offset++; | ||
489 | hw_dbg(hw, "DELAY: %d MS\n", edata); | ||
490 | msleep(edata); | ||
491 | break; | ||
492 | case IXGBE_DATA_NL: | ||
493 | hw_dbg(hw, "DATA: \n"); | ||
494 | data_offset++; | ||
495 | hw->eeprom.ops.read(hw, data_offset++, | ||
496 | &phy_offset); | ||
497 | for (i = 0; i < edata; i++) { | ||
498 | hw->eeprom.ops.read(hw, data_offset, &eword); | ||
499 | hw->phy.ops.write_reg(hw, phy_offset, | ||
500 | IXGBE_TWINAX_DEV, eword); | ||
501 | hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, | ||
502 | phy_offset); | ||
503 | data_offset++; | ||
504 | phy_offset++; | ||
505 | } | ||
506 | break; | ||
507 | case IXGBE_CONTROL_NL: | ||
508 | data_offset++; | ||
509 | hw_dbg(hw, "CONTROL: \n"); | ||
510 | if (edata == IXGBE_CONTROL_EOL_NL) { | ||
511 | hw_dbg(hw, "EOL\n"); | ||
512 | end_data = true; | ||
513 | } else if (edata == IXGBE_CONTROL_SOL_NL) { | ||
514 | hw_dbg(hw, "SOL\n"); | ||
515 | } else { | ||
516 | hw_dbg(hw, "Bad control value\n"); | ||
517 | ret_val = IXGBE_ERR_PHY; | ||
518 | goto out; | ||
519 | } | ||
520 | break; | ||
521 | default: | ||
522 | hw_dbg(hw, "Bad control type\n"); | ||
523 | ret_val = IXGBE_ERR_PHY; | ||
524 | goto out; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | out: | ||
529 | return ret_val; | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns | ||
534 | * the PHY type. | ||
535 | * @hw: pointer to hardware structure | ||
536 | * | ||
537 | * Searches for and indentifies the SFP module. Assings appropriate PHY type. | ||
538 | **/ | ||
539 | s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) | ||
540 | { | ||
541 | s32 status = IXGBE_ERR_PHY_ADDR_INVALID; | ||
542 | u32 vendor_oui = 0; | ||
543 | u8 identifier = 0; | ||
544 | u8 comp_codes_1g = 0; | ||
545 | u8 comp_codes_10g = 0; | ||
546 | u8 oui_bytes[4] = {0, 0, 0, 0}; | ||
547 | u8 transmission_media = 0; | ||
548 | |||
549 | status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, | ||
550 | &identifier); | ||
551 | |||
552 | if (status == IXGBE_ERR_SFP_NOT_PRESENT) { | ||
553 | hw->phy.sfp_type = ixgbe_sfp_type_not_present; | ||
554 | goto out; | ||
555 | } | ||
556 | |||
557 | if (identifier == IXGBE_SFF_IDENTIFIER_SFP) { | ||
558 | hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, | ||
559 | &comp_codes_1g); | ||
560 | hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, | ||
561 | &comp_codes_10g); | ||
562 | hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, | ||
563 | &transmission_media); | ||
564 | |||
565 | /* ID Module | ||
566 | * ========= | ||
567 | * 0 SFP_DA_CU | ||
568 | * 1 SFP_SR | ||
569 | * 2 SFP_LR | ||
570 | */ | ||
571 | if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) | ||
572 | hw->phy.sfp_type = ixgbe_sfp_type_da_cu; | ||
573 | else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) | ||
574 | hw->phy.sfp_type = ixgbe_sfp_type_sr; | ||
575 | else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) | ||
576 | hw->phy.sfp_type = ixgbe_sfp_type_lr; | ||
577 | else | ||
578 | hw->phy.sfp_type = ixgbe_sfp_type_unknown; | ||
579 | |||
580 | /* Determine PHY vendor */ | ||
581 | if (hw->phy.type == ixgbe_phy_unknown) { | ||
582 | hw->phy.id = identifier; | ||
583 | hw->phy.ops.read_i2c_eeprom(hw, | ||
584 | IXGBE_SFF_VENDOR_OUI_BYTE0, | ||
585 | &oui_bytes[0]); | ||
586 | hw->phy.ops.read_i2c_eeprom(hw, | ||
587 | IXGBE_SFF_VENDOR_OUI_BYTE1, | ||
588 | &oui_bytes[1]); | ||
589 | hw->phy.ops.read_i2c_eeprom(hw, | ||
590 | IXGBE_SFF_VENDOR_OUI_BYTE2, | ||
591 | &oui_bytes[2]); | ||
592 | |||
593 | vendor_oui = | ||
594 | ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | | ||
595 | (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | | ||
596 | (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); | ||
597 | |||
598 | switch (vendor_oui) { | ||
599 | case IXGBE_SFF_VENDOR_OUI_TYCO: | ||
600 | if (transmission_media & | ||
601 | IXGBE_SFF_TWIN_AX_CAPABLE) | ||
602 | hw->phy.type = ixgbe_phy_tw_tyco; | ||
603 | break; | ||
604 | case IXGBE_SFF_VENDOR_OUI_FTL: | ||
605 | hw->phy.type = ixgbe_phy_sfp_ftl; | ||
606 | break; | ||
607 | case IXGBE_SFF_VENDOR_OUI_AVAGO: | ||
608 | hw->phy.type = ixgbe_phy_sfp_avago; | ||
609 | break; | ||
610 | default: | ||
611 | if (transmission_media & | ||
612 | IXGBE_SFF_TWIN_AX_CAPABLE) | ||
613 | hw->phy.type = ixgbe_phy_tw_unknown; | ||
614 | else | ||
615 | hw->phy.type = ixgbe_phy_sfp_unknown; | ||
616 | break; | ||
617 | } | ||
618 | } | ||
619 | status = 0; | ||
620 | } | ||
621 | |||
622 | out: | ||
623 | return status; | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see | ||
628 | * if it supports a given SFP+ module type, if so it returns the offsets to the | ||
629 | * phy init sequence block. | ||
630 | * @hw: pointer to hardware structure | ||
631 | * @list_offset: offset to the SFP ID list | ||
632 | * @data_offset: offset to the SFP data block | ||
633 | **/ | ||
634 | s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, | ||
635 | u16 *list_offset, | ||
636 | u16 *data_offset) | ||
637 | { | ||
638 | u16 sfp_id; | ||
639 | |||
640 | if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) | ||
641 | return IXGBE_ERR_SFP_NOT_SUPPORTED; | ||
642 | |||
643 | if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) | ||
644 | return IXGBE_ERR_SFP_NOT_PRESENT; | ||
645 | |||
646 | if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && | ||
647 | (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) | ||
648 | return IXGBE_ERR_SFP_NOT_SUPPORTED; | ||
649 | |||
650 | /* Read offset to PHY init contents */ | ||
651 | hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); | ||
652 | |||
653 | if ((!*list_offset) || (*list_offset == 0xFFFF)) | ||
654 | return IXGBE_ERR_PHY; | ||
655 | |||
656 | /* Shift offset to first ID word */ | ||
657 | (*list_offset)++; | ||
658 | |||
659 | /* | ||
660 | * Find the matching SFP ID in the EEPROM | ||
661 | * and program the init sequence | ||
662 | */ | ||
663 | hw->eeprom.ops.read(hw, *list_offset, &sfp_id); | ||
664 | |||
665 | while (sfp_id != IXGBE_PHY_INIT_END_NL) { | ||
666 | if (sfp_id == hw->phy.sfp_type) { | ||
667 | (*list_offset)++; | ||
668 | hw->eeprom.ops.read(hw, *list_offset, data_offset); | ||
669 | if ((!*data_offset) || (*data_offset == 0xFFFF)) { | ||
670 | hw_dbg(hw, "SFP+ module not supported\n"); | ||
671 | return IXGBE_ERR_SFP_NOT_SUPPORTED; | ||
672 | } else { | ||
673 | break; | ||
674 | } | ||
675 | } else { | ||
676 | (*list_offset) += 2; | ||
677 | if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) | ||
678 | return IXGBE_ERR_PHY; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | if (sfp_id == IXGBE_PHY_INIT_END_NL) { | ||
683 | hw_dbg(hw, "No matching SFP+ module found\n"); | ||
684 | return IXGBE_ERR_SFP_NOT_SUPPORTED; | ||
685 | } | ||
686 | |||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | /** | ||
433 | * ixgbe_check_phy_link_tnx - Determine link and speed status | 691 | * ixgbe_check_phy_link_tnx - Determine link and speed status |
434 | * @hw: pointer to hardware structure | 692 | * @hw: pointer to hardware structure |
435 | * | 693 | * |