From edf65cc897500e23b0d9320fdb5832ab973bb1c8 Mon Sep 17 00:00:00 2001 From: Xinyu Date: Fri, 19 Aug 2022 10:48:39 +0800 Subject: [PATCH 01/11] [Credo][Ycable] add missing checking condition of 'clear_on_read', otherwise the manual switch count will be reset after each calling of get_switch_count_tor_a() Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 77d4f1152..8931266c2 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1052,11 +1052,12 @@ def get_switch_count_tor_a(self, clear_on_read=False): lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+3, 1) count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - buffer = bytearray([4]) - curr_offset = YCable.OFFSET_CLEAR_SWITCH_COUNT - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR + if clear_on_read: + buffer = bytearray([4]) + curr_offset = YCable.OFFSET_CLEAR_SWITCH_COUNT + result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return YCable.EEPROM_ERROR else: self.log_error('acquire lock timeout, failed to get switch count (tor A)') return YCableBase.EEPROM_ERROR From ea75939352aa4271654d4ee56f641f036ae553ee Mon Sep 17 00:00:00 2001 From: Xinyu Date: Fri, 19 Aug 2022 11:22:08 +0800 Subject: [PATCH 02/11] [Credo][Ycable] return YCable.EEPROM_ERROR if any error of api calling due to the variable EEPROM_ERROR was moved to YCable class Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 92 ++++++++++++++-------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 8931266c2..12f8fffc6 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -524,7 +524,7 @@ def toggle_mux_to_tor_a(self): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to toggle mux to TOR A') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") return YCable.EEPROM_ERROR @@ -554,7 +554,7 @@ def toggle_mux_to_tor_b(self): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to toggle mux to TOR B') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") return YCable.EEPROM_ERROR @@ -585,7 +585,7 @@ def get_read_side(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error('acquire lock timeout, failed to check read side') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to check read side") return YCable.EEPROM_ERROR @@ -645,7 +645,7 @@ def get_mux_direction(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error('acquire lock timeout, failed to get mux direction') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error( "platform_chassis is not loaded, failed to get mux direction") @@ -707,7 +707,7 @@ def get_active_linked_tor_side(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error('acquire lock timeout, failed to check Active Linked and routing TOR side') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error( "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") @@ -772,7 +772,7 @@ def is_link_active(self, target): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error('acquire lock timeout, failed to check if link is Active on target side') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error( "platform_chassis is not loaded, failed to check if link is Active on target side") @@ -874,7 +874,7 @@ def get_eye_heights(self, target): idx += 2 else: self.log_error('acquire lock timeout, failed to get eye height') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get eye height") return YCable.EEPROM_ERROR @@ -900,7 +900,7 @@ def get_vendor(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error('acquire lock timeout, failed to get vendor name') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get Vendor name") return YCable.EEPROM_ERROR @@ -927,7 +927,7 @@ def get_part_number(self): part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error('acquire lock timeout, failed to get part number') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get part number") return YCable.EEPROM_ERROR @@ -954,7 +954,7 @@ def get_serial_number(self): part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error('acquire lock timeout, failed to get serial number') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get serial number") return YCable.EEPROM_ERROR @@ -1000,7 +1000,7 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) else: self.log_error('acquire lock timeout, failed to get switch count') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("not a valid switch_count_type, failed to get switch count") return YCable.EEPROM_ERROR @@ -1016,7 +1016,7 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): return YCable.EEPROM_ERROR else: self.log_error('acquire lock timeout, failed to clear switch count') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get switch count") return YCable.EEPROM_ERROR @@ -1060,7 +1060,7 @@ def get_switch_count_tor_a(self, clear_on_read=False): return YCable.EEPROM_ERROR else: self.log_error('acquire lock timeout, failed to get switch count (tor A)') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get manual switch count") return YCable.EEPROM_ERROR @@ -1104,7 +1104,7 @@ def get_switch_count_tor_b(self, clear_on_read=False): return YCable.EEPROM_ERROR else: self.log_error('acquire lock timeout, failed to get switch count (tor B)') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get manual switch count") return YCable.EEPROM_ERROR @@ -1187,7 +1187,7 @@ def get_switch_count_target(self, switch_count_type, target, clear_on_read=False return YCable.EEPROM_ERROR else: self.log_error('acquire lock timeout, failed to get switch count target') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get switch count target") return YCable.EEPROM_ERROR @@ -1235,7 +1235,7 @@ def get_target_cursor_values(self, lane, target): result.append(c_int8(post2[0]).value) else: self.log_error('acquire lock timeout, failed to get target cursor values') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get target cursor values") return YCable.EEPROM_ERROR @@ -1279,7 +1279,7 @@ def set_target_cursor_values(self, lane, cursor_values, target): idx += 1 else: self.log_error('acquire lock timeout, failed to set target cursor values') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get target cursor values") return YCable.EEPROM_ERROR @@ -1327,7 +1327,7 @@ def get_firmware_version(self, target): return None else: self.log_error("platform_chassis is not loaded, failed to get firmware version") - return YCable.EEPROM_ERROR + return None result = {} NUM_MCU_SIDE = 3 @@ -1724,7 +1724,7 @@ def set_switching_mode(self, mode): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to set switching mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to set switching mode") return YCable.EEPROM_ERROR @@ -1756,7 +1756,7 @@ def get_switching_mode(self): return YCableBase.SWITCHING_MODE_MANUAL else: self.log_error('acquire lock timeout, failed to get the switch mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get the switch mode") return YCable.EEPROM_ERROR @@ -1782,7 +1782,7 @@ def get_nic_temperature(self): temp = result[0] else: self.log_error('acquire lock timeout, failed to get NIC temp') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get NIC temp") return -1 @@ -1811,7 +1811,7 @@ def get_local_temperature(self): temp = result[0] else: self.log_error('acquire lock timeout, failed to get local temp') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get local temp") return YCable.EEPROM_ERROR @@ -1841,7 +1841,7 @@ def get_nic_voltage(self): voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) else: self.log_error('acquire lock timeout, failed to get NIC voltage') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get NIC voltage") return -1 @@ -1871,7 +1871,7 @@ def get_local_voltage(self): voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) else: self.log_error('acquire lock timeout, failed to get local voltage') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get local voltage") return YCable.EEPROM_ERROR @@ -1903,7 +1903,7 @@ def get_alive_status(self): return False else: self.log_error('acquire lock timeout, failed to get active status') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get active status") return YCable.EEPROM_ERROR @@ -1955,7 +1955,7 @@ def reset(self, target): time.sleep(2) else: self.log_error('acquire lock timeout, failed to reset') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to reset") return YCable.EEPROM_ERROR @@ -2028,7 +2028,7 @@ def create_port(self, speed, fec_mode_tor = YCableBase.FEC_MODE_NONE, fec_mode_n return result else: self.log_error('acquire lock timeout, failed to create port') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to create port") return YCable.EEPROM_ERROR @@ -2066,7 +2066,7 @@ def get_speed(self): return -1 else: self.log_error('acquire lock timeout, failed to get speed') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get speed") return YCable.EEPROM_ERROR @@ -2117,7 +2117,7 @@ def set_fec_mode(self, fec_mode, target): return result else: self.log_error('acquire lock timeout, failed to set fec mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to set fec mode") return YCable.EEPROM_ERROR @@ -2161,7 +2161,7 @@ def get_fec_mode(self, target): self.log_error("get fec mode: unsupported target") else: self.log_error('acquire lock timeout, failed to get fec mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get fec mode") return YCable.EEPROM_ERROR @@ -2210,7 +2210,7 @@ def set_anlt(self, enable, target): return result else: self.log_error('acquire lock timeout, failed to set anlt') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to set anlt") return YCable.EEPROM_ERROR @@ -2252,7 +2252,7 @@ def get_anlt(self, target): self.log_error("get anlt: unsupported target") else: self.log_error('acquire lock timeout, failed to get anlt') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get anlt") return YCable.EEPROM_ERROR @@ -2358,7 +2358,7 @@ def get_event_log(self, clear_on_read=False): last_read_id = event_id else: self.log_error('acquire lock timeout, failed to get event log') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get event log") return YCable.EEPROM_ERROR @@ -2414,7 +2414,7 @@ def get_pcs_stats(self, target): pcs_stats['Tx Octets OK'] = self.tcm_read(base + 4 * (Tx + 1)) else: self.log_error('acquire lock timeout, failed to get pcs statisics') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get pcs statisics") return YCable.EEPROM_ERROR @@ -2493,7 +2493,7 @@ def get_fec_stats(self, target): fec_stats['Corrected CW (15 sym err)'] = self.tcm_read(base + (26 << 2)) else: self.log_error('acquire lock timeout, failed to get fec statisics') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get fec statisics") return YCable.EEPROM_ERROR @@ -2524,7 +2524,7 @@ def set_autoswitch_hysteresis_timer(self, time): self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to set autoswitch hysteresis timer') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to set autoswitch hysteresis timer") return YCable.EEPROM_ERROR @@ -2551,7 +2551,7 @@ def get_autoswitch_hysteresis_timer(self): time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error('acquire lock timeout, failed to get autoswitch hysteresis timer') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get autoswitch hysteresis timer") return YCable.EEPROM_ERROR @@ -2592,7 +2592,7 @@ def restart_anlt(self, target): self.fw_cmd_ext(0x7040, 0, lane) else: self.log_error('acquire lock timeout, failed to restart anlt') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to restart anlt") return YCable.EEPROM_ERROR @@ -2641,7 +2641,7 @@ def get_anlt_stats(self, target): anlt_stat['LT_TX_lane%d' % idx] = [(lt_tx1 >> 8) & 0xFF, lt_tx1 & 0xFF, (lt_tx2 >> 8) & 0xFF, lt_tx2 & 0xFF] else: self.log_error('acquire lock timeout, failed to get anlt stat') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get anlt stats") return YCable.EEPROM_ERROR @@ -2756,7 +2756,7 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to enable the PRBS mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to enable the PRBS mode") return YCable.EEPROM_ERROR @@ -2800,7 +2800,7 @@ def disable_prbs_mode(self, target, direction): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to disable the PRBS mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to disable the PRBS mode") return YCable.EEPROM_ERROR @@ -2850,7 +2850,7 @@ def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_ result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to enable the loopback mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to enable the loopback mode") return YCable.EEPROM_ERROR @@ -2889,7 +2889,7 @@ def disable_loopback_mode(self, target): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error('acquire lock timeout, failed to disable loopback mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to disable loopback mode") return YCable.EEPROM_ERROR @@ -2950,7 +2950,7 @@ def get_loopback_mode(self, target): return YCableBase.LOOPBACK_MODE_NEAR_END else: self.log_error('acquire lock timeout, failed to get loopback mode') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get loopback mode") return YCable.EEPROM_ERROR @@ -3011,7 +3011,7 @@ def get_ber_info(self, target): idx += 2 else: self.log_error('acquire lock timeout, failed to get ber info') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get ber info") return YCable.EEPROM_ERROR @@ -3081,7 +3081,7 @@ def debug_dump_registers(self, option=None): result['serde_lane_%d' % ln] = serdes else: self.log_error('acquire lock timeout, failed to dump registers') - return YCableBase.EEPROM_ERROR + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to dump registers") return YCable.EEPROM_ERROR From 356207e2c5cc6015c995530fd43110cee5abda8b Mon Sep 17 00:00:00 2001 From: Xinyu Date: Sat, 20 Aug 2022 01:01:04 +0800 Subject: [PATCH 03/11] [Credo][Ycable] check all side's firmware version and activate it to align the fw version with the input fw file Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 127 +++++++++++++++++++++------ 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 12f8fffc6..d9c4c3c69 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -143,6 +143,12 @@ class YCable(YCableBase): EEPROM_TIMEOUT_ERROR = -1 EEPROM_GENERIC_ERROR = -1 + # side bitamp + SIDE_BMP_NIC = 1 + SIDE_BMP_TOR_A = 2 + SIDE_BMP_TOR_B = 4 + SIDE_BMP_ALL = 7 + # MCU error code MCU_EC_NO_ERROR = 0 MCU_EC_GET_FW_INFO_ERROR = 11 @@ -205,7 +211,7 @@ def __init__(self, port, main_logger): def read_mmap(self, page, byte, len=1): """ - This API converts memory map page and offset to linar address, then returns eeprom values + This API converts memory map page and offset to linear address, then returns eeprom values by calling read_eeprom() Args: @@ -219,7 +225,7 @@ def read_mmap(self, page, byte, len=1): an Integer, length of the reading Returns: - an Integer or bytearray, returns the value of the specified eeprom addres, returns 0xFF if it did not succeed + an Integer or bytearray, returns the value of the specified eeprom address, returns 0xFF if it did not succeed """ if byte < 128: linear_addr = byte @@ -243,7 +249,7 @@ def read_mmap(self, page, byte, len=1): def write_mmap(self, page, byte, value, len=1): """ - This API converts memory map page and offset to linar address for calling write_eeprom() + This API converts memory map page and offset to linear address for calling write_eeprom() Args: page: @@ -1401,9 +1407,14 @@ def download_firmware(self, fwfile): """ if self.platform_chassis is not None: - inFile = open(fwfile, 'rb') - fwImage = bytearray(inFile.read()) - inFile.close() + try: + inFile = open(fwfile, 'rb') + fwImage = bytearray(inFile.read()) + inFile.close() + except Exception: + self.log_error('File Not Found Error: %s' % (fwfile)) + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE bin_pid = struct.unpack_from('>B', fwImage[5 : 6])[0] mcu_pid = self.read_mmap(0xFB, 187) @@ -1425,7 +1436,7 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_START status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error('Firmware binary start transfer error (error code:%04X)' % (status)) self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED return YCableBase.FIRMWARE_DOWNLOAD_FAILURE else: @@ -1434,7 +1445,7 @@ def download_firmware(self, fwfile): return YCableBase.FIRMWARE_DOWNLOAD_FAILURE ''' - Transfer firmwre image to local side MCU + Transfer firmware image to local side MCU ''' total_chunk = len(fwImage) // YCable.VSC_BUFF_SIZE chunk_idx = 0 @@ -1558,7 +1569,7 @@ def activate_firmware(self, fwfile=None, hitless=False): This routine should activate the downloaded firmware on all the components of the Y cable of the port for which this API is called.. This API is meant to be used in conjunction with download_firmware API, and - should be called once download_firmware API is succesful. + should be called once download_firmware API is successful. This means that the firmware which has been downloaded should be activated (start being utilized by the cable) once this API is successfully executed. @@ -1571,12 +1582,12 @@ def activate_firmware(self, fwfile=None, hitless=False): choosing (binary, archive, etc.). But note that it should be one file which contains firmware for all components of the Y-cable. In case the vendor chooses to pass this file in activate_firmware, the API should - have the logic to retreive the firmware version from this file + have the logic to retrieve the firmware version from this file which has to be activated on the components of the Y-Cable this API has been called for. If None is passed for fwfile, the cable should activate whatever firmware is marked to be activated next. - If provided, it should retreive the firmware version(s) from this file, ensure + If provided, it should retrieve the firmware version(s) from this file, ensure they are downloaded on the cable, then activate them. hitless (optional): @@ -1595,27 +1606,27 @@ def activate_firmware(self, fwfile=None, hitless=False): with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: if lock_status: self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS - side = 0x7 + side_bitmap = YCable.SIDE_BMP_ALL vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_COMMIT vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = side + vsc_req_form[YCable.VSC_BYTE_ADDR0] = side_bitmap status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error('Firmware commit error (error code:%04X)' % (status)) self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED return YCableBase.FIRMWARE_ACTIVATE_FAILURE vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_RUN vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = side - vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless + vsc_req_form[YCable.VSC_BYTE_ADDR0] = side_bitmap + vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless status = self.send_vsc(vsc_req_form) time.sleep(5) if status != YCable.MCU_EC_NO_ERROR: - self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error('Firmware run error (error code:%04X)' % (status)) self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED return YCableBase.FIRMWARE_ACTIVATE_FAILURE @@ -1625,9 +1636,13 @@ def activate_firmware(self, fwfile=None, hitless=False): self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED return YCableBase.FIRMWARE_ACTIVATE_FAILURE else: - inFile = open(fwfile, 'rb') - fwImage = bytearray(inFile.read()) - inFile.close() + try: + inFile = open(fwfile, 'rb') + fwImage = bytearray(inFile.read()) + inFile.close() + except Exception as e: + self.log_error('activate_firmware, open fw bin error(%s), fwfile:%s' % (e, fwfile)) + return YCableBase.FIRMWARE_ACTIVATE_FAILURE build_msb = struct.unpack_from(' 150: + break else: self.log_error('acquire lock timeout, failed to get event log') return YCable.EEPROM_ERROR From 9f61bea9007569a5802cd27dedec2156a84b7cff Mon Sep 17 00:00:00 2001 From: Xinyu Date: Sat, 20 Aug 2022 10:53:18 +0800 Subject: [PATCH 04/11] [Credo][Ycable] fix alerts of None should use the 'is' operator Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index d9c4c3c69..eec4f5042 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1653,7 +1653,7 @@ def activate_firmware(self, fwfile=None, hitless=False): side_bitmap = 0 fwVer = self.get_firmware_version(YCableBase.TARGET_NIC) - if fwVer == None: + if fwVer is None: self.log_error("activate_firmware, failed to get NIC firmware version") return YCableBase.FIRMWARE_ACTIVATE_FAILURE else: @@ -1661,7 +1661,7 @@ def activate_firmware(self, fwfile=None, hitless=False): side_bitmap |= YCable.SIDE_BMP_NIC fwVer = self.get_firmware_version(YCableBase.TARGET_TOR_A) - if fwVer == None: + if fwVer is None: self.log_error("activate_firmware, failed to get TOR A firmware version") return YCableBase.FIRMWARE_ACTIVATE_FAILURE else: @@ -1669,7 +1669,7 @@ def activate_firmware(self, fwfile=None, hitless=False): side_bitmap |= YCable.SIDE_BMP_TOR_A fwVer = self.get_firmware_version(YCableBase.TARGET_TOR_B) - if fwVer == None: + if fwVer is None: self.log_error("activate_firmware, failed to get TOR B firmware version") return YCableBase.FIRMWARE_ACTIVATE_FAILURE else: From 2cf7505b5574db6377b76c32b1f6de9c65fbc9be Mon Sep 17 00:00:00 2001 From: Xinyu Date: Fri, 26 Aug 2022 15:47:26 +0800 Subject: [PATCH 05/11] [Credo][Ycable] do not locker whole debug_dump_registers() function to avoid acquire lock timeout error Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 209 ++++++++++++++------------- 1 file changed, 108 insertions(+), 101 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index eec4f5042..62b3e9360 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -3113,53 +3113,48 @@ def debug_dump_registers(self, option=None): which would help diagnose the cable for proper functioning """ if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = {} - result['pn'] = self.get_part_number() - result['sn'] = self.get_serial_number() - result['uart_stat'] = self.get_uart_stat() - result['nic_temp'] = self.get_nic_temperature() - result['nic_voltage'] = self.get_nic_voltage() - result['fw_init_status'] = self.get_dsp_fw_init_stat() - result['serdes_detect'] = self.get_dsp_link_Dect() - - lanes = [0,1,2,3,12,13,14,15,20,21,22,23] - - for ln in list(lanes): - data = self.get_serdes_params(ln) - serdes = {} - serdes['ch_est'] = struct.unpack_from(' Date: Fri, 26 Aug 2022 16:01:39 +0800 Subject: [PATCH 06/11] [Credo][Ycable] add queue_info(), operation_time() and reset_casue() Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 134 +++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 62b3e9360..12275ea09 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -62,6 +62,8 @@ class YCable(YCableBase): OFFSET_EXTEND_SWITCH_COUNT_TYPE = 741 OFFSET_EXTEND_SWITCH_COUNT = 742 OFFSET_CLEAR_SWITCH_COUNT = 746 + OFFSET_OPERATION_TIME = 747 + OFFSET_RESET_CAUSE = 751 OFFSET_CONFIGURE_PRBS_TYPE = 768 OFFSET_ENABLE_PRBS = 769 OFFSET_INITIATE_BER_MEASUREMENT = 770 @@ -119,9 +121,11 @@ class YCable(YCableBase): EVENTLOG_OPTION_CLEAR = 0x02 # VSC opcode + VSC_OPCODE_QUEUE_INFO = 0x18 VSC_OPCODE_UART_STAT = 0x1C VSC_OPCODE_SERDES_INFO = 0x1D VSC_OPCODE_DSP_LOADFW_STAT = 0x1F + VSC_OPCODE_MEM_READ = 0x40 VSC_OPCODE_FWUPD = 0x80 VSC_OPCODE_EVENTLOG = 0x81 VSC_OPCODE_TCM_READ = 0x82 @@ -3121,6 +3125,7 @@ def debug_dump_registers(self, option=None): result['nic_voltage'] = self.get_nic_voltage() result['fw_init_status'] = self.get_dsp_fw_init_stat() result['serdes_detect'] = self.get_dsp_link_detect() + result['queue_info'] = self.queue_info() lanes = [0,1,2,3,12,13,14,15,20,21,22,23] @@ -3154,6 +3159,135 @@ def debug_dump_registers(self, option=None): return result + def queue_info(self): + """ + This API should dump all the meaningful data from the eeprom which can + help vendor debug the queue info for the UART stats in particular + currently relevant to the MCU + using this API the vendor could check how many txns are currently waiting to be processed,proceessed + in the queue etc for debugging purposes + Args: + None + Returns: + a Dictionary: + with all the relevant key-value pairs for all the meaningful fields + for the queue inside the MCU firmware + which would help diagnose the cable for proper functioning + """ + + if self.platform_chassis is not None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + result = {} + for option in range(2): + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_QUEUE_INFO + vsc_req_form[YCable.VSC_BYTE_OPTION] = option + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('Dump Uart statstics error (error code:0x%04X)' % (status)) + return result + + data = self.read_mmap(YCable.MIS_PAGE_FC, 128, 48) + ver = self.read_mmap(YCable.MIS_PAGE_VSC, 130, 1) + + queue = {} + + offset = 0 + cnt = {} + cnt['r_ptr'] = struct.unpack_from(' Date: Mon, 29 Aug 2022 16:15:36 +0800 Subject: [PATCH 07/11] [Credo][Ycable] fix 'unused local variable' alert Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 12275ea09..83391a824 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -3189,7 +3189,6 @@ def queue_info(self): return result data = self.read_mmap(YCable.MIS_PAGE_FC, 128, 48) - ver = self.read_mmap(YCable.MIS_PAGE_VSC, 130, 1) queue = {} From 42c78ce8001ceae93f1aa12e35e035771196bd62 Mon Sep 17 00:00:00 2001 From: Xinyu Date: Mon, 29 Aug 2022 16:24:30 +0800 Subject: [PATCH 08/11] [Credo][Ycable] add activate_target_firmware() Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 163 +++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 83391a824..33aeb56aa 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1755,6 +1755,169 @@ def rollback_firmware(self, fwfile=None): return YCableBase.FIRMWARE_ROLLBACK_SUCCESS + def activate_target_firmware(self, target, fwfile=None, hitless=False): + """ + This routine should activate the downloaded firmware on specific target + of the Y cable of the port for which this API is called.. + This API is meant to be used in conjunction with download_firmware API, and + should be called once download_firmware API is succesful. + This means that the firmware which has been downloaded should be + activated (start being utilized by the cable) once this API is + successfully executed. + The port on which this API is called for can be referred using self.port. + Args: + target: + One of the following predefined constants, the actual target to activate the firmware on: + TARGET_NIC -> NIC, + TARGET_TOR_A -> TORA, + TARGET_TOR_B -> TORB + fwfile (optional): + a string, a path to the file which contains the firmware image. + Note that the firmware file can be in the format of the vendor's + choosing (binary, archive, etc.). But note that it should be one file + which contains firmware for all components of the Y-cable. In case the + vendor chooses to pass this file in activate_firmware, the API should + have the logic to retrieve the firmware version from this file + which has to be activated on the components of the Y-Cable + this API has been called for. + If None is passed for fwfile, the cable should activate whatever + firmware is marked to be activated next. + If provided, it should retrieve the firmware version(s) from this file, ensure + they are downloaded on the cable, then activate them. + hitless (optional): + a boolean, True, Hitless upgrade: it will backup/restore the current state + (ex. variables of link status, API attributes...etc.) before + and after firmware upgrade. + a boolean, False, Non-hitless upgrade: it will update the firmware regardless + the current status, a link flip can be observed during the upgrade. + Returns: + One of the following predefined constants: + FIRMWARE_ACTIVATE_SUCCESS + FIRMWARE_ACTIVATE_FAILURE + """ + if self.platform_chassis is not None: + + if target == YCableBase.TARGET_NIC: + act_bmp = YCable.SIDE_BMP_NIC + elif target == YCableBase.TARGET_TOR_A: + act_bmp = YCable.SIDE_BMP_TOR_A + elif target == YCableBase.TARGET_TOR_B: + act_bmp = YCable.SIDE_BMP_TOR_B + else: + act_bmp = YCable.SIDE_BMP_ALL + + if fwfile is None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS + + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_COMMIT + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD + vsc_req_form[YCable.VSC_BYTE_ADDR0] = act_bmp + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('Firmware commit error (error code:%04X)' % (status)) + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_RUN + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD + vsc_req_form[YCable.VSC_BYTE_ADDR0] = act_bmp + vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless + status = self.send_vsc(vsc_req_form) + time.sleep(5) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('Firmware run error (error code:%04X)' % (status)) + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED + else: + self.log_error('acquire lock timeout, failed to activate target firmware') + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + else: + try: + inFile = open(fwfile, 'rb') + fwImage = bytearray(inFile.read()) + inFile.close() + except Exception as e: + self.log_error('activate_target_firmware, open fw bin error(%s), fwfile:%s' % (e, fwfile)) + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + + build_msb = struct.unpack_from(' Date: Tue, 30 Aug 2022 15:50:26 +0800 Subject: [PATCH 09/11] [Credo][Ycable] add health_check() Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 194 ++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 2 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 33aeb56aa..898704af0 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -47,6 +47,7 @@ class YCable(YCableBase): OFFSET_SWITCH_MUX_DIRECTION = 642 OFFSET_MUX_DIRECTION = 644 OFFSET_ACTIVE_TOR_INDICATOR = 645 + OFFSET_API_VERSION = 650 OFFSET_ENABLE_AUTO_SWITCH = 651 OFFSET_AUTO_SWITCH_HYSTERESIS = 652 OFFSET_MANUAL_SWITCH_COUNT_TOR_A = 653 @@ -153,6 +154,9 @@ class YCable(YCableBase): SIDE_BMP_TOR_B = 4 SIDE_BMP_ALL = 7 + CABLE_HEALTHY = True + CABLE_UNHEALTHY = False + # MCU error code MCU_EC_NO_ERROR = 0 MCU_EC_GET_FW_INFO_ERROR = 11 @@ -456,6 +460,84 @@ def tcm_write(self, addr, data): return True + def tcm_read_atomic(self, addr): + """ + This API sends the tcm read command to the serdes chip via VSC cmd + + Args: + addr: + an Integer, address of tcm space + Returns: + an Integer, return data of tcm address + """ + + if self.platform_chassis is not None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_READ + vsc_req_form[130] = (addr >> 0) & 0xFF + vsc_req_form[131] = (addr >> 8) & 0xFF + vsc_req_form[132] = (addr >> 16) & 0xFF + vsc_req_form[133] = (addr >> 24) & 0xFF + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('tcm read addr[%04X] error[%04X]' % (addr, status)) + return -1 + + data = (self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) | + (self.read_mmap(YCable.MIS_PAGE_VSC, 136) << 16) | (self.read_mmap(YCable.MIS_PAGE_VSC, 137) << 24)) + else: + self.log_error('acquire lock timeout, failed to read serdes tcm register') + return YCable.EEPROM_ERROR + else: + self.log_error("platform_chassis is not loaded, failed to read serdes tcm register") + return YCable.EEPROM_ERROR + + return data + + def tcm_write_atomic(self, addr, data): + """ + This API sends the tcm write command to the serdes chip via VSC cmd + + Args: + addr: + an Integer, address of tcm space + + data: + an Integer, value to be written to the address + + Returns: + a boolean, True if the tcm write succeeded and False if it did not succeed. + """ + + if self.platform_chassis is not None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_WRITE + vsc_req_form[130] = (addr >> 0) & 0xFF + vsc_req_form[131] = (addr >> 8) & 0xFF + vsc_req_form[132] = (addr >> 16) & 0xFF + vsc_req_form[133] = (addr >> 24) & 0xFF + vsc_req_form[134] = (data >> 0) & 0xFF + vsc_req_form[135] = (data >> 8) & 0xFF + vsc_req_form[136] = (data >> 16) & 0xFF + vsc_req_form[137] = (data >> 24) & 0xFF + + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('tcm read addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) + return False + else: + self.log_error('acquire lock timeout, failed to write serdes tcm register') + return YCable.EEPROM_ERROR + else: + self.log_error("platform_chassis is not loaded, failed to write serdes tcm register") + return YCable.EEPROM_ERROR + + return True + def reg_read(self, addr): """ This API reads the serdes register via vsc @@ -509,6 +591,77 @@ def reg_write(self, addr, data): return True + def reg_read_atomic(self, addr): + """ + This API reads the serdes register in atomic method + + Args: + addr: + an Integer, address of the serdes register + Returns: + an Integer, return data of the register + """ + + if self.platform_chassis is not None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_READ + vsc_req_form[130] = (addr >> 0) & 0xFF + vsc_req_form[131] = (addr >> 8) & 0xFF + vsc_req_form[132] = (addr >> 16) & 0xFF + vsc_req_form[133] = (addr >> 24) & 0xFF + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('reg read addr[%04X] error[%04X]' % (addr, status)) + return YCable.EEPROM_ERROR + + return self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) + else: + self.log_error('acquire lock timeout, failed to read serdes register') + return YCable.EEPROM_ERROR + else: + self.log_error("platform_chassis is not loaded, failed to read serdes register") + return YCable.EEPROM_ERROR + + def reg_write_atomic(self, addr, data): + """ + This API writes the serdes register in atomic method + + Args: + addr: + an Integer, address of the serdes register + + data: + an Integer, value to be written to the register address + + Returns: + an Integer, 0 if the register write succeeded. + """ + + if self.platform_chassis is not None: + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_WRITE + vsc_req_form[130] = (addr >> 0) & 0xFF + vsc_req_form[131] = (addr >> 8) & 0xFF + vsc_req_form[134] = (data >> 0) & 0xFF + vsc_req_form[135] = (data >> 8) & 0xFF + + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('reg write addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) + return YCable.EEPROM_ERROR + else: + self.log_error('acquire lock timeout, failed to write serdes register') + return YCable.EEPROM_ERROR + else: + self.log_error("platform_chassis is not loaded, failed to write serdes register") + return YCable.EEPROM_ERROR + + return 0 + def toggle_mux_to_tor_a(self): """ This API does a hard switch toggle of the Y cable's MUX regardless of link state to @@ -3280,7 +3433,10 @@ def debug_dump_registers(self, option=None): which would help diagnose the cable for proper functioning """ if self.platform_chassis is not None: + api_ver = self.platform_chassis.get_sfp(self.port).read_eeprom(YCable.OFFSET_API_VERSION, 1)[0] + result = {} + result['vendor'] = self.get_vendor() result['pn'] = self.get_part_number() result['sn'] = self.get_serial_number() result['uart_stat'] = self.get_uart_stat() @@ -3288,7 +3444,9 @@ def debug_dump_registers(self, option=None): result['nic_voltage'] = self.get_nic_voltage() result['fw_init_status'] = self.get_dsp_fw_init_stat() result['serdes_detect'] = self.get_dsp_link_detect() - result['queue_info'] = self.queue_info() + + if api_ver >= 0x18: + result['queue_info'] = self.queue_info() lanes = [0,1,2,3,12,13,14,15,20,21,22,23] @@ -3450,6 +3608,39 @@ def operation_time(self): return result + def health_check(self): + """ + This API checks the health of the cable, where it is healthy/unhealythy for RMA purposes/diagnostics. + The port on which this API is called for can be referred using self.port. + + Args: + Returns: + a Boolean, True if the cable is healthy and False if it is not healthy. + """ + + if self.platform_chassis is not None: + api_ver = self.platform_chassis.get_sfp(self.port).read_eeprom(YCable.OFFSET_API_VERSION, 1)[0] + + vendor = self.get_vendor() + if vendor != "Credo ": + self.log_error("check cable health fail: unable to get correct vendor name:%s" % (vendor)) + return YCable.CABLE_UNHEALTHY + + uart_stat = self.get_uart_stat() + if api_ver >= 0x18 and uart_stat['Local']['UART2']['RxErrorCnt'] > 100: + self.log_error("check cable health fail: uart rx error count overlimit:%d" % (uart_stat['local']['UART2']['RxErrorCnt'])) + return YCable.CABLE_UNHEALTHY + + serdes_fw_tag = self.reg_read_atomic(0xB71A) + if serdes_fw_tag != 0x6A6A: + self.log_error("check cable health fail: serdes fw is not loaded correctly:%04X" % (serdes_fw_tag)) + return YCable.CABLE_UNHEALTHY + else: + self.log_error("platform_chassis is not loaded, failed to check cable health") + return YCable.EEPROM_ERROR + + return YCable.CABLE_HEALTHY + def get_dsp_link_detect(self): """ This API returns rdy/sd of DSP. @@ -3471,7 +3662,6 @@ def get_dsp_link_detect(self): result['rdyTorA'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 3, 1)[0] result['sdTorB'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 4, 1)[0] result['rdyTorB'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 5, 1)[0] - else: self.log_error("platform_chassis is not loaded, failed to get init. status of DSP firmware") From 9da11441a3bbfb8f10dd5851cd4c2c619e90776a Mon Sep 17 00:00:00 2001 From: Xinyu Date: Wed, 31 Aug 2022 12:07:51 +0800 Subject: [PATCH 10/11] [Credo][Ycable] add mem_read() Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 898704af0..b09563e60 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -3608,6 +3608,64 @@ def operation_time(self): return result + def mem_read(self, target, addr, length): + """ + This API should return the memory contents of the cable which would be useful in debug for the + y-cable + Args: + None + Returns: + a Dictionary: + with all the relevant key-value pairs for all the meaningful fields + for the memory inside the MCU firmware + which would help diagnose the cable for proper functioning + """ + + data = bytearray() + + if self.platform_chassis is not None: + curr = 0 + while curr < length: + if target == 0: + if (length - curr) > 512: size = 512 + else: size = length - curr + else: + size = 4 + + with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: + if lock_status: + vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) + vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_MEM_READ + vsc_req_form[YCable.VSC_BYTE_OPTION] = target + vsc_req_form[130] = (addr >> 0) & 0xFF + vsc_req_form[131] = (addr >> 8) & 0xFF + vsc_req_form[132] = (addr >> 16) & 0xFF + vsc_req_form[133] = (addr >> 24) & 0xFF + vsc_req_form[134] = (size >> 0) & 0xFF + vsc_req_form[135] = (size >> 8) & 0xFF + vsc_req_form[136] = (size >> 16) & 0xFF + vsc_req_form[137] = (size >> 24) & 0xFF + status = self.send_vsc(vsc_req_form) + + idx = 0 + while idx < size: + if (size - idx) > 128: + data.extend(self.read_mmap(YCable.MIS_PAGE_FC + idx // 128, 128 + idx % 128, 128)) + idx += 128 + else: + data.extend(self.read_mmap(YCable.MIS_PAGE_FC + idx // 128, 128 + idx % 128, size - idx)) + idx = size + else: + self.log_error('acquire lock timeout, failed to read memory') + return YCable.EEPROM_ERROR + + curr += size + addr += size + else: + self.log_error("platform_chassis is not loaded, failed to read memory") + + return data + def health_check(self): """ This API checks the health of the cable, where it is healthy/unhealythy for RMA purposes/diagnostics. From 2c691c4b0bfabcc856eaa210ff948c84ed32f539 Mon Sep 17 00:00:00 2001 From: Xinyu Date: Wed, 31 Aug 2022 15:22:40 +0800 Subject: [PATCH 11/11] [Credo][Ycable] fix alert of ' Unused local variable' Signed-off-by: Xinyu --- sonic_y_cable/credo/y_cable_credo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index b09563e60..0c0adfdcc 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -3646,6 +3646,9 @@ def mem_read(self, target, addr, length): vsc_req_form[136] = (size >> 16) & 0xFF vsc_req_form[137] = (size >> 24) & 0xFF status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error('read MCU internal memory error error (error code:0x%04X)' % (status)) + return YCable.EEPROM_ERROR idx = 0 while idx < size: