diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py index d037fd9273dd..f3108ff12f85 100644 --- a/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py @@ -2,13 +2,12 @@ # # Platform-specific SFP transceiver interface for SONiC # - try: - import struct import sys import getopt import time import select + import io from sonic_sfp.sfputilbase import SfpUtilBase from os import * from mmap import * @@ -19,6 +18,25 @@ # from xcvrd SFP_STATUS_REMOVED = '0' SFP_STATUS_INSERTED = '1' +MEDIA_TYPE_OFFSET = 0 +MEDIA_TYPE_WIDTH = 1 +QSFP_DD_MODULE_ENC_OFFSET = 3 +QSFP_DD_MODULE_ENC_WIDTH = 1 + +SFP_TYPE_LIST = [ + '03' # SFP/SFP+/SFP28 and later +] +QSFP_TYPE_LIST = [ + '0c', # QSFP + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_LIST = [ + '18' #QSFP_DD Type +] +OSFP_TYPE_LIST=[ + '19' # OSFP 8X Type +] class SfpUtil(SfpUtilBase): @@ -87,18 +105,77 @@ def qsfp_ports(self): def port_to_eeprom_mapping(self): return self._port_to_eeprom_mapping + def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): + eeprom_raw = [] + try: + eeprom = io.open(eeprom_path, mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw , str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except (OSError, IOError): + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _write_eeprom_bytes(self, eeprom_path, offset, num_bytes, value): + try: + with io.open(eeprom_path, mode='r+b', buffering=0) as f: + f.seek(offset) + f.write(value[0:num_bytes]) + except (OSError, IOError): + return False + return True + + + def get_media_type(self, port_num): + """ + Reads optic eeprom byte to determine media type inserted + """ + eeprom_raw = [] + eeprom_raw = self._read_eeprom_bytes(self.port_to_eeprom_mapping[port_num], MEDIA_TYPE_OFFSET, + MEDIA_TYPE_WIDTH) + if eeprom_raw is not None: + if eeprom_raw[0] in SFP_TYPE_LIST: + sfp_type = 'SFP' + elif eeprom_raw[0] in QSFP_TYPE_LIST: + sfp_type = 'QSFP' + elif eeprom_raw[0] in QSFP_DD_TYPE_LIST: + sfp_type = 'QSFP_DD' + else: + #Set native port type if EEPROM type is not recognized/readable + sfp_type = 'QSFP_DD' + else: + sfp_type = 'QSFP_DD' + + return sfp_type + def pci_mem_read(self, mm, offset): mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mem_val = str(reg_val)[1:-2] - # print "reg_val read:%x"%reg_val - return mem_val + return mm.read_byte() def pci_mem_write(self, mm, offset, data): mm.seek(offset) - # print "data to write:%x"%data - mm.write(struct.pack('I', data)) + mm.write_byte(data) def pci_set_value(self, resource, val, offset): fd = open(resource, O_RDWR) @@ -181,54 +258,70 @@ def get_low_power_mode(self, port_num): # Check for invalid port_num if port_num < self.port_start or port_num > self.port_end: return False - - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num-1) * 16) - - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) - - # Absence of status throws error - if (reg_value == ""): + if port_num > self.PORTS_IN_BLOCK: + return False + if self.get_media_type(port_num) == 'QSFP_DD': + lpmode = self._read_eeprom_bytes(self.port_to_eeprom_mapping[port_num], QSFP_DD_MODULE_ENC_OFFSET, + QSFP_DD_MODULE_ENC_WIDTH) + if lpmode is not None: + if int(lpmode[0])>>1 == 1: + return True return False + else: + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - # Mask off 4th bit for presence - mask = (1 << 6) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + # Absence of status throws error + if (status == ""): + return False - # LPMode is active high - if reg_value & mask == 0: - return False + reg_value = int(status) - return True + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + return False + return True def set_low_power_mode(self, port_num, lpmode): # Check for invalid port_num if port_num < self.port_start or port_num > self.port_end: return False - - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num-1) * 16) - - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) - - # Absence of status throws error - if (reg_value == ""): + if port_num > self.PORTS_IN_BLOCK: return False - # Mask off 4th bit for presence - mask = (1 << 6) + if self.get_media_type(port_num) == 'QSFP_DD': + if lpmode is True: + write_val = 0x10 + else: + write_val = 0x0 - # LPMode is active high; set or clear the bit accordingly - if lpmode is True: - reg_value = reg_value | mask + self._write_eeprom_bytes(self.port_to_eeprom_mapping[port_num], 26, 1, bytearray([write_val])) else: - reg_value = reg_value & ~mask + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) - # Convert our register value back to a hex string and write back - status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for presence + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) return True def reset(self, port_num): diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py index 1b4327ff342c..a08667a8e71e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py @@ -13,7 +13,6 @@ import re import time import subprocess - import struct import mmap from sonic_platform_base.sfp_base import SfpBase from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId @@ -60,6 +59,8 @@ QSFP_DD_APP1_ADV_WIDTH = 32 QSFP_DD_APP2_ADV_OFFSET = 351 QSFP_DD_APP2_ADV_WIDTH = 28 +QSFP_DD_MODULE_ENC_OFFSET = 3 +QSFP_DD_MODULE_ENC_WIDTH = 1 QSFP_INFO_OFFSET = 128 QSFP_DOM_OFFSET = 0 @@ -311,16 +312,12 @@ def _strip_unit_from_str(self, value_str): def pci_mem_read(self, mm, offset): mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mem_val = str(reg_val)[1:-2] - # print "reg_val read:%x"%reg_val - return mem_val + return mm.read_byte() def pci_mem_write(self, mm, offset, data): mm.seek(offset) # print "data to write:%x"%data - mm.write(struct.pack('I', data)) + mm.write_byte(data) def pci_set_value(self, resource, val, offset): fd = os.open(resource, os.O_RDWR) @@ -338,6 +335,15 @@ def pci_get_value(self, resource, offset): os.close(fd) return val + def _write_eeprom_bytes(self, offset, num_bytes, value): + try: + with open(self.eeprom_path, mode='r+b', buffering=0) as f: + f.seek(offset) + f.write(value[0:num_bytes]) + except (OSError, IOError): + return False + return True + def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): eeprom_raw = [] try: @@ -994,7 +1000,13 @@ def get_lpmode(self): """ lpmode_state = False try: - if self.sfp_type.startswith('QSFP'): + if self.sfp_type == 'QSFP_DD': + lpmode = self._read_eeprom_bytes(self.eeprom_path, QSFP_DD_MODULE_ENC_OFFSET, QSFP_DD_MODULE_ENC_WIDTH) + if lpmode is not None: + if int(lpmode[0])>>1 == 1: + return True + return False + else: # Port offset starts with 0x4000 port_offset = 16384 + ((self.index-1) * 16) @@ -1005,8 +1017,9 @@ def get_lpmode(self): mask = (1 << 6) lpmode_state = (reg_value & mask) - except ValueError: pass - return lpmode_state + except ValueError: + pass + return bool(lpmode_state) def get_power_override(self): """ @@ -1231,7 +1244,14 @@ def set_lpmode(self, lpmode): Sets the lpmode(low power mode) of this SFP """ try: - if self.port_type == 'QSFP_DD': + if self.sfp_type == 'QSFP_DD': + if lpmode is True: + write_val = 0x10 + else: + write_val = 0x0 + + self._write_eeprom_bytes(26, 1, bytearray([write_val])) + else: # Port offset starts with 0x4000 port_offset = 16384 + ((self.index-1) * 16)