Print this page
6064 ixgbe needs X550 support

*** 1,8 **** /****************************************************************************** ! Copyright (c) 2001-2012, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: --- 1,8 ---- /****************************************************************************** ! Copyright (c) 2001-2015, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*** 28,46 **** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ ! /*$FreeBSD: src/sys/dev/ixgbe/ixgbe_x540.c,v 1.2 2012/07/05 20:51:44 jfv Exp $*/ #include "ixgbe_x540.h" #include "ixgbe_type.h" #include "ixgbe_api.h" #include "ixgbe_common.h" #include "ixgbe_phy.h" ! static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw); /** --- 28,52 ---- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ ! /*$FreeBSD$*/ #include "ixgbe_x540.h" #include "ixgbe_type.h" #include "ixgbe_api.h" #include "ixgbe_common.h" #include "ixgbe_phy.h" ! #define IXGBE_X540_MAX_TX_QUEUES 128 ! #define IXGBE_X540_MAX_RX_QUEUES 128 ! #define IXGBE_X540_RAR_ENTRIES 128 ! #define IXGBE_X540_MC_TBL_SIZE 128 ! #define IXGBE_X540_VFT_TBL_SIZE 128 ! #define IXGBE_X540_RX_PB_SIZE 384 ! static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw); /**
*** 62,148 **** ret_val = ixgbe_init_phy_ops_generic(hw); ret_val = ixgbe_init_ops_generic(hw); /* EEPROM */ ! eeprom->ops.init_params = &ixgbe_init_eeprom_params_X540; ! eeprom->ops.read = &ixgbe_read_eerd_X540; ! eeprom->ops.read_buffer = &ixgbe_read_eerd_buffer_X540; ! eeprom->ops.write = &ixgbe_write_eewr_X540; ! eeprom->ops.write_buffer = &ixgbe_write_eewr_buffer_X540; ! eeprom->ops.update_checksum = &ixgbe_update_eeprom_checksum_X540; ! eeprom->ops.validate_checksum = &ixgbe_validate_eeprom_checksum_X540; ! eeprom->ops.calc_checksum = &ixgbe_calc_eeprom_checksum_X540; /* PHY */ ! phy->ops.init = &ixgbe_init_phy_ops_generic; phy->ops.reset = NULL; /* MAC */ ! mac->ops.reset_hw = &ixgbe_reset_hw_X540; ! mac->ops.enable_relaxed_ordering = &ixgbe_enable_relaxed_ordering_gen2; ! mac->ops.get_media_type = &ixgbe_get_media_type_X540; mac->ops.get_supported_physical_layer = ! &ixgbe_get_supported_physical_layer_X540; mac->ops.read_analog_reg8 = NULL; mac->ops.write_analog_reg8 = NULL; ! mac->ops.start_hw = &ixgbe_start_hw_X540; ! mac->ops.get_san_mac_addr = &ixgbe_get_san_mac_addr_generic; ! mac->ops.set_san_mac_addr = &ixgbe_set_san_mac_addr_generic; ! mac->ops.get_device_caps = &ixgbe_get_device_caps_generic; ! mac->ops.get_wwn_prefix = &ixgbe_get_wwn_prefix_generic; ! mac->ops.get_fcoe_boot_status = &ixgbe_get_fcoe_boot_status_generic; ! mac->ops.acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540; ! mac->ops.release_swfw_sync = &ixgbe_release_swfw_sync_X540; ! mac->ops.disable_sec_rx_path = &ixgbe_disable_sec_rx_path_generic; ! mac->ops.enable_sec_rx_path = &ixgbe_enable_sec_rx_path_generic; /* RAR, Multicast, VLAN */ ! mac->ops.set_vmdq = &ixgbe_set_vmdq_generic; ! mac->ops.set_vmdq_san_mac = &ixgbe_set_vmdq_san_mac_generic; ! mac->ops.clear_vmdq = &ixgbe_clear_vmdq_generic; ! mac->ops.insert_mac_addr = &ixgbe_insert_mac_addr_generic; mac->rar_highwater = 1; ! mac->ops.set_vfta = &ixgbe_set_vfta_generic; ! mac->ops.set_vlvf = &ixgbe_set_vlvf_generic; ! mac->ops.clear_vfta = &ixgbe_clear_vfta_generic; ! mac->ops.init_uta_tables = &ixgbe_init_uta_tables_generic; ! mac->ops.set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing; ! mac->ops.set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing; /* Link */ mac->ops.get_link_capabilities = ! &ixgbe_get_copper_link_capabilities_generic; ! mac->ops.setup_link = &ixgbe_setup_mac_link_X540; ! mac->ops.setup_rxpba = &ixgbe_set_rxpba_generic; ! mac->ops.check_link = &ixgbe_check_mac_link_generic; ! mac->mcft_size = 128; ! mac->vft_size = 128; ! mac->num_rar_entries = 128; ! mac->rx_pb_size = 384; ! mac->max_tx_queues = 128; ! mac->max_rx_queues = 128; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); /* * FWSM register * ARC supported; valid only if manageability features are * enabled. */ ! mac->arc_subsystem_valid = (IXGBE_READ_REG(hw, IXGBE_FWSM) & ! IXGBE_FWSM_MODE_MASK) ? TRUE : FALSE; hw->mbx.ops.init_params = ixgbe_init_mbx_params_pf; /* LEDs */ mac->ops.blink_led_start = ixgbe_blink_led_start_X540; mac->ops.blink_led_stop = ixgbe_blink_led_stop_X540; /* Manageability interface */ ! mac->ops.set_fw_drv_ver = &ixgbe_set_fw_drv_ver_generic; return ret_val; } /** * ixgbe_get_link_capabilities_X540 - Determines link capabilities --- 68,158 ---- ret_val = ixgbe_init_phy_ops_generic(hw); ret_val = ixgbe_init_ops_generic(hw); /* EEPROM */ ! eeprom->ops.init_params = ixgbe_init_eeprom_params_X540; ! eeprom->ops.read = ixgbe_read_eerd_X540; ! eeprom->ops.read_buffer = ixgbe_read_eerd_buffer_X540; ! eeprom->ops.write = ixgbe_write_eewr_X540; ! eeprom->ops.write_buffer = ixgbe_write_eewr_buffer_X540; ! eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X540; ! eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X540; ! eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X540; /* PHY */ ! phy->ops.init = ixgbe_init_phy_ops_generic; phy->ops.reset = NULL; + phy->ops.set_phy_power = ixgbe_set_copper_phy_power; /* MAC */ ! mac->ops.reset_hw = ixgbe_reset_hw_X540; ! mac->ops.enable_relaxed_ordering = ixgbe_enable_relaxed_ordering_gen2; ! mac->ops.get_media_type = ixgbe_get_media_type_X540; mac->ops.get_supported_physical_layer = ! ixgbe_get_supported_physical_layer_X540; mac->ops.read_analog_reg8 = NULL; mac->ops.write_analog_reg8 = NULL; ! mac->ops.start_hw = ixgbe_start_hw_X540; ! mac->ops.get_san_mac_addr = ixgbe_get_san_mac_addr_generic; ! mac->ops.set_san_mac_addr = ixgbe_set_san_mac_addr_generic; ! mac->ops.get_device_caps = ixgbe_get_device_caps_generic; ! mac->ops.get_wwn_prefix = ixgbe_get_wwn_prefix_generic; ! mac->ops.get_fcoe_boot_status = ixgbe_get_fcoe_boot_status_generic; ! mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540; ! mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X540; ! mac->ops.disable_sec_rx_path = ixgbe_disable_sec_rx_path_generic; ! mac->ops.enable_sec_rx_path = ixgbe_enable_sec_rx_path_generic; /* RAR, Multicast, VLAN */ ! mac->ops.set_vmdq = ixgbe_set_vmdq_generic; ! mac->ops.set_vmdq_san_mac = ixgbe_set_vmdq_san_mac_generic; ! mac->ops.clear_vmdq = ixgbe_clear_vmdq_generic; ! mac->ops.insert_mac_addr = ixgbe_insert_mac_addr_generic; mac->rar_highwater = 1; ! mac->ops.set_vfta = ixgbe_set_vfta_generic; ! mac->ops.set_vlvf = ixgbe_set_vlvf_generic; ! mac->ops.clear_vfta = ixgbe_clear_vfta_generic; ! mac->ops.init_uta_tables = ixgbe_init_uta_tables_generic; ! mac->ops.set_mac_anti_spoofing = ixgbe_set_mac_anti_spoofing; ! mac->ops.set_vlan_anti_spoofing = ixgbe_set_vlan_anti_spoofing; /* Link */ mac->ops.get_link_capabilities = ! ixgbe_get_copper_link_capabilities_generic; ! mac->ops.setup_link = ixgbe_setup_mac_link_X540; ! mac->ops.setup_rxpba = ixgbe_set_rxpba_generic; ! mac->ops.check_link = ixgbe_check_mac_link_generic; ! ! mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; ! mac->vft_size = IXGBE_X540_VFT_TBL_SIZE; ! mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES; ! mac->rx_pb_size = IXGBE_X540_RX_PB_SIZE; ! mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES; ! mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); /* * FWSM register * ARC supported; valid only if manageability features are * enabled. */ ! mac->arc_subsystem_valid = !!(IXGBE_READ_REG(hw, IXGBE_FWSM_BY_MAC(hw)) ! & IXGBE_FWSM_MODE_MASK); hw->mbx.ops.init_params = ixgbe_init_mbx_params_pf; /* LEDs */ mac->ops.blink_led_start = ixgbe_blink_led_start_X540; mac->ops.blink_led_stop = ixgbe_blink_led_stop_X540; /* Manageability interface */ ! mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_generic; + mac->ops.get_rtrup2tc = ixgbe_dcb_get_rtrup2tc_generic; + return ret_val; } /** * ixgbe_get_link_capabilities_X540 - Determines link capabilities
*** 154,164 **** **/ s32 ixgbe_get_link_capabilities_X540(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { ! return ixgbe_get_copper_link_capabilities_generic(hw, speed, autoneg); } /** * ixgbe_get_media_type_X540 - Get media type * @hw: pointer to hardware structure --- 164,176 ---- **/ s32 ixgbe_get_link_capabilities_X540(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { ! ixgbe_get_copper_link_capabilities_generic(hw, speed, autoneg); ! ! return IXGBE_SUCCESS; } /** * ixgbe_get_media_type_X540 - Get media type * @hw: pointer to hardware structure
*** 173,192 **** /** * ixgbe_setup_mac_link_X540 - Sets the auto advertised capabilities * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed **/ s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ! ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) { DEBUGFUNC("ixgbe_setup_mac_link_X540"); ! return hw->phy.ops.setup_link_speed(hw, speed, autoneg, ! autoneg_wait_to_complete); } /** * ixgbe_reset_hw_X540 - Perform hardware reset * @hw: pointer to hardware structure --- 185,202 ---- /** * ixgbe_setup_mac_link_X540 - Sets the auto advertised capabilities * @hw: pointer to hardware structure * @speed: new link speed * @autoneg_wait_to_complete: TRUE when waiting for completion is needed **/ s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ! ixgbe_link_speed speed, bool autoneg_wait_to_complete) { DEBUGFUNC("ixgbe_setup_mac_link_X540"); ! return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete); } /** * ixgbe_reset_hw_X540 - Perform hardware reset * @hw: pointer to hardware structure
*** 223,233 **** break; } if (ctrl & IXGBE_CTRL_RST_MASK) { status = IXGBE_ERR_RESET_FAILED; ! DEBUGOUT("Reset polling failed to complete.\n"); } msec_delay(100); /* * Double resets are required for recovery from certain error --- 233,244 ---- break; } if (ctrl & IXGBE_CTRL_RST_MASK) { status = IXGBE_ERR_RESET_FAILED; ! ERROR_REPORT1(IXGBE_ERROR_POLLING, ! "Reset polling failed to complete.\n"); } msec_delay(100); /* * Double resets are required for recovery from certain error
*** 342,352 **** if (eeprom->type == ixgbe_eeprom_uninitialized) { eeprom->semaphore_delay = 10; eeprom->type = ixgbe_flash; ! eec = IXGBE_READ_REG(hw, IXGBE_EEC); eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> IXGBE_EEC_SIZE_SHIFT); eeprom->word_size = 1 << (eeprom_size + IXGBE_EEPROM_WORD_SIZE_SHIFT); --- 353,363 ---- if (eeprom->type == ixgbe_eeprom_uninitialized) { eeprom->semaphore_delay = 10; eeprom->type = ixgbe_flash; ! eec = IXGBE_READ_REG(hw, IXGBE_EEC_BY_MAC(hw)); eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> IXGBE_EEC_SIZE_SHIFT); eeprom->word_size = 1 << (eeprom_size + IXGBE_EEPROM_WORD_SIZE_SHIFT);
*** 369,384 **** { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_read_eerd_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) status = ixgbe_read_eerd_generic(hw, offset, data); ! else status = IXGBE_ERR_SWFW_SYNC; - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** * ixgbe_read_eerd_buffer_X540- Read EEPROM word(s) using EERD --- 380,396 ---- { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_read_eerd_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { status = ixgbe_read_eerd_generic(hw, offset, data); ! hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ! } else { status = IXGBE_ERR_SWFW_SYNC; + } return status; } /** * ixgbe_read_eerd_buffer_X540- Read EEPROM word(s) using EERD
*** 394,410 **** { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_read_eerd_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data); ! else status = IXGBE_ERR_SWFW_SYNC; - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR --- 406,423 ---- { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_read_eerd_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data); ! hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ! } else { status = IXGBE_ERR_SWFW_SYNC; + } return status; } /** * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
*** 418,433 **** { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_write_eewr_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) status = ixgbe_write_eewr_generic(hw, offset, data); ! else status = IXGBE_ERR_SWFW_SYNC; - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** * ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR --- 431,447 ---- { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_write_eewr_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { status = ixgbe_write_eewr_generic(hw, offset, data); ! hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ! } else { status = IXGBE_ERR_SWFW_SYNC; + } return status; } /** * ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR
*** 443,459 **** { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_write_eewr_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data); ! else status = IXGBE_ERR_SWFW_SYNC; - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum --- 457,474 ---- { s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_write_eewr_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data); ! hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ! } else { status = IXGBE_ERR_SWFW_SYNC; + } return status; } /** * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
*** 460,538 **** * * This function does not use synchronization for EERD and EEWR. It can * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. * * @hw: pointer to hardware structure **/ ! u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { ! u16 i; ! u16 j; u16 checksum = 0; u16 length = 0; u16 pointer = 0; u16 word = 0; ! /* ! * Do not use hw->eeprom.ops.read because we do not want to take * the synchronization semaphores here. Instead use * ixgbe_read_eerd_generic */ DEBUGFUNC("ixgbe_calc_eeprom_checksum_X540"); /* Include 0x0-0x3F in the checksum */ ! for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { ! if (ixgbe_read_eerd_generic(hw, i, &word) != IXGBE_SUCCESS) { DEBUGOUT("EEPROM read failed\n"); ! break; } checksum += word; } ! /* ! * Include all data from pointers 0x3, 0x6-0xE. This excludes the * FW, PHY module, and PCIe Expansion/Option ROM pointers. */ ! for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) continue; ! if (ixgbe_read_eerd_generic(hw, i, &pointer) != IXGBE_SUCCESS) { DEBUGOUT("EEPROM read failed\n"); ! break; } /* Skip pointer section if the pointer is invalid. */ if (pointer == 0xFFFF || pointer == 0 || pointer >= hw->eeprom.word_size) continue; ! if (ixgbe_read_eerd_generic(hw, pointer, &length) != ! IXGBE_SUCCESS) { DEBUGOUT("EEPROM read failed\n"); ! break; } /* Skip pointer section if length is invalid. */ if (length == 0xFFFF || length == 0 || (pointer + length) >= hw->eeprom.word_size) continue; ! for (j = pointer+1; j <= pointer+length; j++) { ! if (ixgbe_read_eerd_generic(hw, j, &word) != ! IXGBE_SUCCESS) { DEBUGOUT("EEPROM read failed\n"); ! break; } checksum += word; } } checksum = (u16)IXGBE_EEPROM_SUM - checksum; ! return checksum; } /** * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum * @hw: pointer to hardware structure --- 475,553 ---- * * This function does not use synchronization for EERD and EEWR. It can * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. * * @hw: pointer to hardware structure + * + * Returns a negative error code on error, or the 16-bit checksum **/ ! s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { ! u16 i, j; u16 checksum = 0; u16 length = 0; u16 pointer = 0; u16 word = 0; + u16 checksum_last_word = IXGBE_EEPROM_CHECKSUM; + u16 ptr_start = IXGBE_PCIE_ANALOG_PTR; ! /* Do not use hw->eeprom.ops.read because we do not want to take * the synchronization semaphores here. Instead use * ixgbe_read_eerd_generic */ DEBUGFUNC("ixgbe_calc_eeprom_checksum_X540"); /* Include 0x0-0x3F in the checksum */ ! for (i = 0; i <= checksum_last_word; i++) { ! if (ixgbe_read_eerd_generic(hw, i, &word)) { DEBUGOUT("EEPROM read failed\n"); ! return IXGBE_ERR_EEPROM; } + if (i != IXGBE_EEPROM_CHECKSUM) checksum += word; } ! /* Include all data from pointers 0x3, 0x6-0xE. This excludes the * FW, PHY module, and PCIe Expansion/Option ROM pointers. */ ! for (i = ptr_start; i < IXGBE_FW_PTR; i++) { if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) continue; ! if (ixgbe_read_eerd_generic(hw, i, &pointer)) { DEBUGOUT("EEPROM read failed\n"); ! return IXGBE_ERR_EEPROM; } /* Skip pointer section if the pointer is invalid. */ if (pointer == 0xFFFF || pointer == 0 || pointer >= hw->eeprom.word_size) continue; ! if (ixgbe_read_eerd_generic(hw, pointer, &length)) { DEBUGOUT("EEPROM read failed\n"); ! return IXGBE_ERR_EEPROM; } /* Skip pointer section if length is invalid. */ if (length == 0xFFFF || length == 0 || (pointer + length) >= hw->eeprom.word_size) continue; ! for (j = pointer + 1; j <= pointer + length; j++) { ! if (ixgbe_read_eerd_generic(hw, j, &word)) { DEBUGOUT("EEPROM read failed\n"); ! return IXGBE_ERR_EEPROM; } checksum += word; } } checksum = (u16)IXGBE_EEPROM_SUM - checksum; ! return (s32)checksum; } /** * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum * @hw: pointer to hardware structure
*** 548,598 **** u16 checksum; u16 read_checksum = 0; DEBUGFUNC("ixgbe_validate_eeprom_checksum_X540"); ! /* ! * Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); ! ! if (status != IXGBE_SUCCESS) { DEBUGOUT("EEPROM read failed\n"); ! goto out; } ! if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { ! checksum = hw->eeprom.ops.calc_checksum(hw); ! /* ! * Do not use hw->eeprom.ops.read because we do not want to take * the synchronization semaphores twice here. */ status = ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); ! if (status == IXGBE_SUCCESS) { ! /* ! * Verify read checksum from EEPROM is the same as * calculated checksum */ ! if (read_checksum != checksum) status = IXGBE_ERR_EEPROM_CHECKSUM; /* If the user cares, return the calculated checksum */ if (checksum_val) *checksum_val = checksum; - } - } else { - status = IXGBE_ERR_SWFW_SYNC; - } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); out: return status; } /** * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash --- 563,615 ---- u16 checksum; u16 read_checksum = 0; DEBUGFUNC("ixgbe_validate_eeprom_checksum_X540"); ! /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); ! if (status) { DEBUGOUT("EEPROM read failed\n"); ! return status; } ! if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) ! return IXGBE_ERR_SWFW_SYNC; ! status = hw->eeprom.ops.calc_checksum(hw); ! if (status < 0) ! goto out; ! ! checksum = (u16)(status & 0xffff); ! ! /* Do not use hw->eeprom.ops.read because we do not want to take * the synchronization semaphores twice here. */ status = ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + if (status) + goto out; ! /* Verify read checksum from EEPROM is the same as * calculated checksum */ ! if (read_checksum != checksum) { ! ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, ! "Invalid EEPROM checksum"); status = IXGBE_ERR_EEPROM_CHECKSUM; + } /* If the user cares, return the calculated checksum */ if (checksum_val) *checksum_val = checksum; out: + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return status; } /** * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash
*** 607,643 **** s32 status; u16 checksum; DEBUGFUNC("ixgbe_update_eeprom_checksum_X540"); ! /* ! * Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); ! ! if (status != IXGBE_SUCCESS) DEBUGOUT("EEPROM read failed\n"); ! if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == ! IXGBE_SUCCESS) { ! checksum = hw->eeprom.ops.calc_checksum(hw); ! /* ! * Do not use hw->eeprom.ops.write because we do not want to * take the synchronization semaphores twice here. */ ! status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, ! checksum); - if (status == IXGBE_SUCCESS) status = ixgbe_update_flash_X540(hw); - else - status = IXGBE_ERR_SWFW_SYNC; - } hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } --- 624,662 ---- s32 status; u16 checksum; DEBUGFUNC("ixgbe_update_eeprom_checksum_X540"); ! /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); ! if (status) { DEBUGOUT("EEPROM read failed\n"); + return status; + } ! if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) ! return IXGBE_ERR_SWFW_SYNC; ! status = hw->eeprom.ops.calc_checksum(hw); ! if (status < 0) ! goto out; ! ! checksum = (u16)(status & 0xffff); ! ! /* Do not use hw->eeprom.ops.write because we do not want to * take the synchronization semaphores twice here. */ ! status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, checksum); ! if (status) ! goto out; status = ixgbe_update_flash_X540(hw); + out: hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; }
*** 646,683 **** * @hw: pointer to hardware structure * * Set FLUP (bit 23) of the EEC register to instruct Hardware to copy * EEPROM from shadow RAM to the flash device. **/ ! static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) { u32 flup; ! s32 status = IXGBE_ERR_EEPROM; DEBUGFUNC("ixgbe_update_flash_X540"); status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_ERR_EEPROM) { DEBUGOUT("Flash update time out\n"); goto out; } ! flup = IXGBE_READ_REG(hw, IXGBE_EEC) | IXGBE_EEC_FLUP; ! IXGBE_WRITE_REG(hw, IXGBE_EEC, flup); status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_SUCCESS) DEBUGOUT("Flash update complete\n"); else DEBUGOUT("Flash update time out\n"); ! if (hw->revision_id == 0) { ! flup = IXGBE_READ_REG(hw, IXGBE_EEC); if (flup & IXGBE_EEC_SEC1VAL) { flup |= IXGBE_EEC_FLUP; ! IXGBE_WRITE_REG(hw, IXGBE_EEC, flup); } status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_SUCCESS) DEBUGOUT("Flash update complete\n"); --- 665,702 ---- * @hw: pointer to hardware structure * * Set FLUP (bit 23) of the EEC register to instruct Hardware to copy * EEPROM from shadow RAM to the flash device. **/ ! s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) { u32 flup; ! s32 status; DEBUGFUNC("ixgbe_update_flash_X540"); status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_ERR_EEPROM) { DEBUGOUT("Flash update time out\n"); goto out; } ! flup = IXGBE_READ_REG(hw, IXGBE_EEC_BY_MAC(hw)) | IXGBE_EEC_FLUP; ! IXGBE_WRITE_REG(hw, IXGBE_EEC_BY_MAC(hw), flup); status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_SUCCESS) DEBUGOUT("Flash update complete\n"); else DEBUGOUT("Flash update time out\n"); ! if (hw->mac.type == ixgbe_mac_X540 && hw->revision_id == 0) { ! flup = IXGBE_READ_REG(hw, IXGBE_EEC_BY_MAC(hw)); if (flup & IXGBE_EEC_SEC1VAL) { flup |= IXGBE_EEC_FLUP; ! IXGBE_WRITE_REG(hw, IXGBE_EEC_BY_MAC(hw), flup); } status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_SUCCESS) DEBUGOUT("Flash update complete\n");
*** 702,718 **** s32 status = IXGBE_ERR_EEPROM; DEBUGFUNC("ixgbe_poll_flash_update_done_X540"); for (i = 0; i < IXGBE_FLUDONE_ATTEMPTS; i++) { ! reg = IXGBE_READ_REG(hw, IXGBE_EEC); if (reg & IXGBE_EEC_FLUDONE) { status = IXGBE_SUCCESS; break; } ! usec_delay(5); } return status; } /** * ixgbe_acquire_swfw_sync_X540 - Acquire SWFW semaphore --- 721,742 ---- s32 status = IXGBE_ERR_EEPROM; DEBUGFUNC("ixgbe_poll_flash_update_done_X540"); for (i = 0; i < IXGBE_FLUDONE_ATTEMPTS; i++) { ! reg = IXGBE_READ_REG(hw, IXGBE_EEC_BY_MAC(hw)); if (reg & IXGBE_EEC_FLUDONE) { status = IXGBE_SUCCESS; break; } ! msec_delay(5); } + + if (i == IXGBE_FLUDONE_ATTEMPTS) + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Flash update status polling timed out"); + return status; } /** * ixgbe_acquire_swfw_sync_X540 - Acquire SWFW semaphore
*** 720,802 **** * @mask: Mask to specify which semaphore to acquire * * Acquires the SWFW semaphore thought the SW_FW_SYNC register for * the specified function (CSR, PHY0, PHY1, NVM, Flash) **/ ! s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) { ! u32 swfw_sync; ! u32 swmask = mask; ! u32 fwmask = mask << 5; ! u32 hwmask = 0; u32 timeout = 200; u32 i; - s32 ret_val = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_acquire_swfw_sync_X540"); ! if (swmask == IXGBE_GSSR_EEP_SM) ! hwmask = IXGBE_GSSR_FLASH_SM; /* SW only mask doesn't have FW bit pair */ ! if (swmask == IXGBE_GSSR_SW_MNG_SM) ! fwmask = 0; for (i = 0; i < timeout; i++) { ! /* ! * SW NVM semaphore bit is used for access to all * SW_FW_SYNC bits (not just NVM) */ ! if (ixgbe_get_swfw_sync_semaphore(hw)) { ! ret_val = IXGBE_ERR_SWFW_SYNC; ! goto out; ! } ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); if (!(swfw_sync & (fwmask | swmask | hwmask))) { swfw_sync |= swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); ! goto out; ! } else { ! /* ! * Firmware currently using resource (fwmask), hardware * currently using resource (hwmask), or other software * thread currently using resource (swmask) */ ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } - } /* Failed to get SW only semaphore */ if (swmask == IXGBE_GSSR_SW_MNG_SM) { ! ret_val = IXGBE_ERR_SWFW_SYNC; ! goto out; } /* If the resource is not released by the FW/HW the SW can assume that ! * the FW/HW malfunctions. In that case the SW should sets the SW bit(s) * of the requested resource(s) while ignoring the corresponding FW/HW * bits in the SW_FW_SYNC register. */ ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); if (swfw_sync & (fwmask | hwmask)) { - if (ixgbe_get_swfw_sync_semaphore(hw)) { - ret_val = IXGBE_ERR_SWFW_SYNC; - goto out; - } - swfw_sync |= swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } ! out: ! return ret_val; } /** * ixgbe_release_swfw_sync_X540 - Release SWFW semaphore * @hw: pointer to hardware structure --- 744,838 ---- * @mask: Mask to specify which semaphore to acquire * * Acquires the SWFW semaphore thought the SW_FW_SYNC register for * the specified function (CSR, PHY0, PHY1, NVM, Flash) **/ ! s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) { ! u32 swmask = mask & IXGBE_GSSR_NVM_PHY_MASK; ! u32 fwmask = swmask << 5; ! u32 swi2c_mask = mask & IXGBE_GSSR_I2C_MASK; u32 timeout = 200; + u32 hwmask = 0; + u32 swfw_sync; u32 i; DEBUGFUNC("ixgbe_acquire_swfw_sync_X540"); ! if (swmask & IXGBE_GSSR_EEP_SM) ! hwmask |= IXGBE_GSSR_FLASH_SM; /* SW only mask doesn't have FW bit pair */ ! if (mask & IXGBE_GSSR_SW_MNG_SM) ! swmask |= IXGBE_GSSR_SW_MNG_SM; + swmask |= swi2c_mask; + fwmask |= swi2c_mask << 2; for (i = 0; i < timeout; i++) { ! /* SW NVM semaphore bit is used for access to all * SW_FW_SYNC bits (not just NVM) */ ! if (ixgbe_get_swfw_sync_semaphore(hw)) ! return IXGBE_ERR_SWFW_SYNC; ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); if (!(swfw_sync & (fwmask | swmask | hwmask))) { swfw_sync |= swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), ! swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); ! return IXGBE_SUCCESS; ! } ! /* Firmware currently using resource (fwmask), hardware * currently using resource (hwmask), or other software * thread currently using resource (swmask) */ ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } /* Failed to get SW only semaphore */ if (swmask == IXGBE_GSSR_SW_MNG_SM) { ! ERROR_REPORT1(IXGBE_ERROR_POLLING, ! "Failed to get SW only semaphore"); ! return IXGBE_ERR_SWFW_SYNC; } /* If the resource is not released by the FW/HW the SW can assume that ! * the FW/HW malfunctions. In that case the SW should set the SW bit(s) * of the requested resource(s) while ignoring the corresponding FW/HW * bits in the SW_FW_SYNC register. */ ! if (ixgbe_get_swfw_sync_semaphore(hw)) ! return IXGBE_ERR_SWFW_SYNC; ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); if (swfw_sync & (fwmask | hwmask)) { swfw_sync |= swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); + return IXGBE_SUCCESS; } + /* If the resource is not released by other SW the SW can assume that + * the other SW malfunctions. In that case the SW should clear all SW + * flags that it does not own and then repeat the whole process once + * again. + */ + if (swfw_sync & swmask) { + u32 rmask = IXGBE_GSSR_EEP_SM | IXGBE_GSSR_PHY0_SM | + IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_MAC_CSR_SM; ! if (swi2c_mask) ! rmask |= IXGBE_GSSR_I2C_MASK; ! ixgbe_release_swfw_sync_X540(hw, rmask); ! ixgbe_release_swfw_sync_semaphore(hw); ! return IXGBE_ERR_SWFW_SYNC; ! } ! ixgbe_release_swfw_sync_semaphore(hw); ! ! return IXGBE_ERR_SWFW_SYNC; } /** * ixgbe_release_swfw_sync_X540 - Release SWFW semaphore * @hw: pointer to hardware structure
*** 803,831 **** * @mask: Mask to specify which semaphore to release * * Releases the SWFW semaphore through the SW_FW_SYNC register * for the specified function (CSR, PHY0, PHY1, EVM, Flash) **/ ! void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) { u32 swfw_sync; - u32 swmask = mask; DEBUGFUNC("ixgbe_release_swfw_sync_X540"); ! (void) ixgbe_get_swfw_sync_semaphore(hw); ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); swfw_sync &= ~swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } /** ! * ixgbe_get_nvm_semaphore - Get hardware semaphore * @hw: pointer to hardware structure * * Sets the hardware semaphores so SW/FW can gain control of shared resources **/ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) --- 839,869 ---- * @mask: Mask to specify which semaphore to release * * Releases the SWFW semaphore through the SW_FW_SYNC register * for the specified function (CSR, PHY0, PHY1, EVM, Flash) **/ ! void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) { + u32 swmask = mask & (IXGBE_GSSR_NVM_PHY_MASK | IXGBE_GSSR_SW_MNG_SM); u32 swfw_sync; DEBUGFUNC("ixgbe_release_swfw_sync_X540"); ! if (mask & IXGBE_GSSR_I2C_MASK) ! swmask |= mask & IXGBE_GSSR_I2C_MASK; ! ixgbe_get_swfw_sync_semaphore(hw); ! swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); swfw_sync &= ~swmask; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } /** ! * ixgbe_get_swfw_sync_semaphore - Get hardware semaphore * @hw: pointer to hardware structure * * Sets the hardware semaphores so SW/FW can gain control of shared resources **/ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
*** 841,851 **** for (i = 0; i < timeout; i++) { /* * If the SMBI bit is 0 when we read it, then the bit will be * set and we have the semaphore */ ! swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); if (!(swsm & IXGBE_SWSM_SMBI)) { status = IXGBE_SUCCESS; break; } usec_delay(50); --- 879,889 ---- for (i = 0; i < timeout; i++) { /* * If the SMBI bit is 0 when we read it, then the bit will be * set and we have the semaphore */ ! swsm = IXGBE_READ_REG(hw, IXGBE_SWSM_BY_MAC(hw)); if (!(swsm & IXGBE_SWSM_SMBI)) { status = IXGBE_SUCCESS; break; } usec_delay(50);
*** 852,862 **** } /* Now get the semaphore between SW/FW through the REGSMP bit */ if (status == IXGBE_SUCCESS) { for (i = 0; i < timeout; i++) { ! swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); if (!(swsm & IXGBE_SWFW_REGSMP)) break; usec_delay(50); } --- 890,900 ---- } /* Now get the semaphore between SW/FW through the REGSMP bit */ if (status == IXGBE_SUCCESS) { for (i = 0; i < timeout; i++) { ! swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); if (!(swsm & IXGBE_SWFW_REGSMP)) break; usec_delay(50); }
*** 864,888 **** /* * Release semaphores and return error if SW NVM semaphore * was not granted because we don't have access to the EEPROM */ if (i >= timeout) { ! DEBUGOUT("REGSMP Software NVM semaphore not " ! "granted.\n"); ixgbe_release_swfw_sync_semaphore(hw); status = IXGBE_ERR_EEPROM; } } else { ! DEBUGOUT("Software semaphore SMBI between device drivers " "not granted.\n"); } return status; } /** ! * ixgbe_release_nvm_semaphore - Release hardware semaphore * @hw: pointer to hardware structure * * This function clears hardware semaphore bits. **/ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw) --- 902,927 ---- /* * Release semaphores and return error if SW NVM semaphore * was not granted because we don't have access to the EEPROM */ if (i >= timeout) { ! ERROR_REPORT1(IXGBE_ERROR_POLLING, ! "REGSMP Software NVM semaphore not granted.\n"); ixgbe_release_swfw_sync_semaphore(hw); status = IXGBE_ERR_EEPROM; } } else { ! ERROR_REPORT1(IXGBE_ERROR_POLLING, ! "Software semaphore SMBI between device drivers " "not granted.\n"); } return status; } /** ! * ixgbe_release_swfw_sync_semaphore - Release hardware semaphore * @hw: pointer to hardware structure * * This function clears hardware semaphore bits. **/ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw)
*** 891,908 **** DEBUGFUNC("ixgbe_release_swfw_sync_semaphore"); /* Release both semaphores by writing 0 to the bits REGSMP and SMBI */ ! swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); ! swsm &= ~IXGBE_SWSM_SMBI; ! IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); ! ! swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); swsm &= ~IXGBE_SWFW_REGSMP; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swsm); IXGBE_WRITE_FLUSH(hw); } /** * ixgbe_blink_led_start_X540 - Blink LED based on index. --- 930,947 ---- DEBUGFUNC("ixgbe_release_swfw_sync_semaphore"); /* Release both semaphores by writing 0 to the bits REGSMP and SMBI */ ! swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); swsm &= ~IXGBE_SWFW_REGSMP; ! IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), swsm); + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM_BY_MAC(hw)); + swsm &= ~IXGBE_SWSM_SMBI; + IXGBE_WRITE_REG(hw, IXGBE_SWSM_BY_MAC(hw), swsm); + IXGBE_WRITE_FLUSH(hw); } /** * ixgbe_blink_led_start_X540 - Blink LED based on index.
*** 970,975 **** IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg); IXGBE_WRITE_FLUSH(hw); return IXGBE_SUCCESS; } - --- 1009,1013 ----