Skip to content

Commit

Permalink
DellEMC: Fix z9332f low power mode issue (#8693)
Browse files Browse the repository at this point in the history
  • Loading branch information
aravindmani-1 authored and judyjoseph committed Oct 14, 2021
1 parent 733d3a8 commit e3cb49f
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 52 deletions.
175 changes: 134 additions & 41 deletions device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand All @@ -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):
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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)

Expand All @@ -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):
"""
Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit e3cb49f

Please sign in to comment.