[devices]: DellEMC: Platform 2.0 Api(sfp,eeprom,chassis )for z9264f (#4007)
- Sfp,Eeprom,Chassis(transceiver change event) support added for z9264f Platform 2.0 API - Added Interrupt handler to SFP change event in dell_z9264f_fpga_ocores.c - Fixed few indentation and offset issues in sfputil.py for z9264f
This commit is contained in:
parent
c6fee49e76
commit
c2677a5614
@ -10,6 +10,7 @@
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os.path
|
||||
from sonic_eeprom import eeprom_tlvinfo
|
||||
except ImportError, e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
@ -18,5 +19,13 @@ except ImportError, e:
|
||||
class board(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
def __init__(self, name, path, cpld_root, ro):
|
||||
self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0050/eeprom"
|
||||
self.eeprom_path = None
|
||||
for b in (0,1):
|
||||
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
|
||||
if os.path.exists(f):
|
||||
self.eeprom_path = f
|
||||
break
|
||||
if self.eeprom_path is None:
|
||||
return
|
||||
|
||||
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
||||
|
@ -44,6 +44,8 @@ SFP_VOLT_OFFSET = 98
|
||||
SFP_VOLT_WIDTH = 2
|
||||
SFP_MODULE_THRESHOLD_OFFSET = 0
|
||||
SFP_MODULE_THRESHOLD_WIDTH = 56
|
||||
SFP_CHANNL_MON_OFFSET = 100
|
||||
SFP_CHANNL_MON_WIDTH = 6
|
||||
|
||||
XCVR_DOM_CAPABILITY_OFFSET = 92
|
||||
XCVR_DOM_CAPABILITY_WIDTH = 1
|
||||
@ -226,8 +228,8 @@ class SfpUtil(SfpUtilBase):
|
||||
if (reg_value == ""):
|
||||
return False
|
||||
|
||||
# Mask off 4th bit for presence
|
||||
mask = (1 << 6)
|
||||
# Mask off 4th bit for reset
|
||||
mask = (1 << 4)
|
||||
|
||||
# ResetL is active low
|
||||
reg_value = reg_value & ~mask
|
||||
@ -347,7 +349,7 @@ class SfpUtil(SfpUtilBase):
|
||||
]
|
||||
transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
|
||||
|
||||
if port_num in self.qsfp_ports:
|
||||
if port_num in self.qsfp_ports:
|
||||
offset = 0
|
||||
offset_xcvr = 128
|
||||
file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR)
|
||||
@ -379,7 +381,7 @@ class SfpUtil(SfpUtilBase):
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH)
|
||||
if dom_temperature_raw is not None:
|
||||
if dom_temperature_raw is not None:
|
||||
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
@ -411,10 +413,22 @@ class SfpUtil(SfpUtilBase):
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
transceiver_dom_info_dict['tx1power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx1power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx2power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx3power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx4power'] = 'N/A'
|
||||
else:
|
||||
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH)
|
||||
if dom_channel_monitor_raw is not None:
|
||||
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0)
|
||||
else:
|
||||
return None
|
||||
|
||||
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value']
|
||||
transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value']
|
||||
transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value']
|
||||
transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value']
|
||||
|
||||
try:
|
||||
sysfsfile_eeprom.close()
|
||||
except IOError:
|
||||
@ -433,64 +447,66 @@ class SfpUtil(SfpUtilBase):
|
||||
transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value']
|
||||
|
||||
else:
|
||||
offset = 256
|
||||
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
|
||||
if not self._sfp_eeprom_present(file_path, 0):
|
||||
return None
|
||||
offset = 256
|
||||
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
|
||||
if not self._sfp_eeprom_present(file_path, 0):
|
||||
return None
|
||||
|
||||
try:
|
||||
sysfsfile_eeprom = io.open(file_path,"rb",0)
|
||||
except IOError:
|
||||
print("Error: reading sysfs file %s" % file_path)
|
||||
return None
|
||||
|
||||
sfpd_obj = sff8472Dom(None,1)
|
||||
if sfpd_obj is None:
|
||||
return None
|
||||
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET),
|
||||
SFP_TEMPE_WIDTH)
|
||||
if dom_temperature_raw is not None:
|
||||
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
try:
|
||||
sysfsfile_eeprom = io.open(file_path,"rb",0)
|
||||
except IOError:
|
||||
print("Error: reading sysfs file %s" % file_path)
|
||||
return None
|
||||
|
||||
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET),
|
||||
SFP_VOLT_WIDTH)
|
||||
if dom_voltage_raw is not None:
|
||||
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
sfpd_obj = sff8472Dom(None,1)
|
||||
if sfpd_obj is None:
|
||||
return None
|
||||
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET),
|
||||
SFP_TEMPE_WIDTH)
|
||||
|
||||
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET),
|
||||
SFP_MODULE_THRESHOLD_WIDTH)
|
||||
if dom_channel_monitor_raw is not None:
|
||||
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
if dom_temperature_raw is not None:
|
||||
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
try:
|
||||
sysfsfile_eeprom.close()
|
||||
except IOError:
|
||||
print("Error: closing sysfs file %s" % file_path)
|
||||
return None
|
||||
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET),
|
||||
SFP_VOLT_WIDTH)
|
||||
|
||||
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
|
||||
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
|
||||
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value']
|
||||
transceiver_dom_info_dict['rx2power'] = 'N/A'
|
||||
transceiver_dom_info_dict['rx3power'] = 'N/A'
|
||||
transceiver_dom_info_dict['rx4power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value']
|
||||
transceiver_dom_info_dict['tx2bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx3bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx4bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value']
|
||||
transceiver_dom_info_dict['tx2power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx3power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx4power'] = 'N/A'
|
||||
if dom_voltage_raw is not None:
|
||||
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_CHANNL_MON_OFFSET),
|
||||
SFP_CHANNL_MON_WIDTH)
|
||||
if dom_channel_monitor_raw is not None:
|
||||
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
|
||||
else:
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
try:
|
||||
sysfsfile_eeprom.close()
|
||||
except IOError:
|
||||
print("Error: closing sysfs file %s" % file_path)
|
||||
return None
|
||||
|
||||
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
|
||||
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
|
||||
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value']
|
||||
transceiver_dom_info_dict['rx2power'] = 'N/A'
|
||||
transceiver_dom_info_dict['rx3power'] = 'N/A'
|
||||
transceiver_dom_info_dict['rx4power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value']
|
||||
transceiver_dom_info_dict['tx2bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx3bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx4bias'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value']
|
||||
transceiver_dom_info_dict['tx2power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx3power'] = 'N/A'
|
||||
transceiver_dom_info_dict['tx4power'] = 'N/A'
|
||||
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
def get_transceiver_dom_threshold_info_dict(self, port_num):
|
||||
transceiver_dom_threshold_info_dict = {}
|
||||
dom_info_dict_keys = ['temphighalarm', 'temphighwarning',
|
||||
|
@ -6,6 +6,7 @@ z9264f/scripts/pcisysfs.py usr/bin
|
||||
z9264f/scripts/qsfp_irq_enable.py usr/bin
|
||||
z9264f/cfg/z9264f-modules.conf etc/modules-load.d
|
||||
z9264f/systemd/platform-modules-z9264f.service etc/systemd/system
|
||||
z9264f/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0
|
||||
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0
|
||||
common/fw-updater usr/local/bin
|
||||
common/onie_mode_set usr/local/bin
|
||||
|
@ -29,6 +29,10 @@ override_dh_auto_build:
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
cd $(MOD_SRC_DIR); \
|
||||
elif [ $$mod = "z9264f" ]; then \
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
cd $(MOD_SRC_DIR); \
|
||||
fi; \
|
||||
echo "making man page alias $$mod -> $$mod APIs";\
|
||||
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
@ -67,6 +71,10 @@ override_dh_clean:
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
|
||||
elif [ $$mod = "z9264f" ]; then \
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
|
||||
fi; \
|
||||
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \
|
||||
done)
|
||||
|
@ -231,6 +231,7 @@ enum {
|
||||
|
||||
#define IRQ_LTCH_STS 0x20
|
||||
#define PRSNT_LTCH_STS 0x10
|
||||
#define MODABS_STS 0x01
|
||||
|
||||
#define PORT_CTRL_OFFSET 0x4000
|
||||
#define PORT_STS_OFFSET 0x4004
|
||||
@ -296,6 +297,7 @@ enum {
|
||||
|
||||
#define FPGA_MSI_VECTOR_ID_4 4
|
||||
#define FPGA_MSI_VECTOR_ID_5 5
|
||||
#define FPGA_MSI_VECTOR_ID_6 6
|
||||
#define FPGA_MSI_VECTOR_ID_8 8
|
||||
#define FPGA_MSI_VECTOR_ID_9 9
|
||||
#define FPGA_MSI_VECTOR_ID_10 10
|
||||
@ -523,7 +525,7 @@ static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr,
|
||||
int ind = 0, port_status=0, port_irq_status=0;
|
||||
struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev);
|
||||
PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count);
|
||||
for(ind=0;ind<64;ind++)
|
||||
for(ind=0;ind<66;ind++)
|
||||
{
|
||||
port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16));
|
||||
port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
@ -585,6 +587,28 @@ static irqreturn_t fpgaport_33_64_isr(int irq, void *dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t fpgaport_65_66_isr(int irq, void *dev)
|
||||
{
|
||||
struct pci_dev *pdev = dev;
|
||||
struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev);
|
||||
int ind = 0, port_status=0, port_irq_status=0;
|
||||
for(ind=64;ind<66;ind++)
|
||||
{
|
||||
port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
if(port_irq_status| (MODABS_STS))
|
||||
{
|
||||
PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status);
|
||||
//write on clear
|
||||
iowrite32( MODABS_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
}
|
||||
}
|
||||
fpgapci->xcvr_intr_count++;
|
||||
PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count);
|
||||
sysfs_notify(&pdev->dev.kobj, NULL, "port_msi");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void fpgai2c_process(struct fpgalogic_i2c *i2c)
|
||||
{
|
||||
struct i2c_msg *msg = i2c->msg;
|
||||
@ -1122,6 +1146,12 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id)
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_6:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_65_66_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_8:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[0]);
|
||||
@ -1180,6 +1210,12 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id)
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_6:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_65_66_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_8:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[0]);
|
||||
|
@ -27,6 +27,7 @@ def pci_set_value(resource, val, offset):
|
||||
close(fd)
|
||||
return val
|
||||
|
||||
#Enabled interrupt for qsfp and sfp
|
||||
for port_num in range(PORT_START, PORT_END+1):
|
||||
port_offset = 0x400c + ((port_num) * 16)
|
||||
pci_set_value(BASE_RES_PATH, 0x30, port_offset)
|
||||
pci_set_value(BASE_RES_PATH, 0x31, port_offset)
|
||||
|
@ -17,9 +17,9 @@ init_devnum() {
|
||||
# Attach/Detach syseeprom on CPU board
|
||||
sys_eeprom() {
|
||||
case $1 in
|
||||
"new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-0/$1
|
||||
"new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-${devnum}/$1
|
||||
;;
|
||||
"delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-0/$1
|
||||
"delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-${devnum}/$1
|
||||
;;
|
||||
*) echo "z9264f_platform: sys_eeprom : invalid command !"
|
||||
;;
|
||||
@ -125,6 +125,20 @@ init_switch_port_led() {
|
||||
fi
|
||||
}
|
||||
|
||||
install_python_api_package() {
|
||||
device="/usr/share/sonic/device"
|
||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||
|
||||
rv=$(pip install $device/$platform/sonic_platform-1.0-py2-none-any.whl)
|
||||
}
|
||||
|
||||
remove_python_api_package() {
|
||||
rv=$(pip show sonic-platform > /dev/null 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
rv=$(pip uninstall -y sonic-platform > /dev/null 2>/dev/null)
|
||||
fi
|
||||
}
|
||||
|
||||
init_devnum
|
||||
|
||||
if [ "$1" == "init" ]; then
|
||||
@ -140,6 +154,7 @@ if [ "$1" == "init" ]; then
|
||||
switch_board_sfp "new_device"
|
||||
switch_board_modsel
|
||||
init_switch_port_led
|
||||
install_python_api_package
|
||||
python /usr/bin/qsfp_irq_enable.py
|
||||
|
||||
elif [ "$1" == "deinit" ]; then
|
||||
@ -149,6 +164,7 @@ elif [ "$1" == "deinit" ]; then
|
||||
switch_board_sfp "delete_device"
|
||||
modprobe -r i2c-mux-pca954x
|
||||
modprobe -r i2c-dev
|
||||
remove_python_api_package
|
||||
else
|
||||
echo "z9264f_platform : Invalid option !"
|
||||
fi
|
||||
|
1
platform/broadcom/sonic-platform-modules-dell/z9264f/setup.py
Symbolic link
1
platform/broadcom/sonic-platform-modules-dell/z9264f/setup.py
Symbolic link
@ -0,0 +1 @@
|
||||
../s6100/setup.py
|
@ -0,0 +1,3 @@
|
||||
__all__ = ["chassis", "sfp", "eeprom"]
|
||||
from sonic_platform import *
|
||||
|
@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DELLEMC Z9264F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
import select
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from sonic_platform.sfp import Sfp
|
||||
from sonic_platform.eeprom import Eeprom
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""
|
||||
DELLEMC Platform-specific Chassis class
|
||||
"""
|
||||
|
||||
OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi"
|
||||
|
||||
oir_fd = -1
|
||||
epoll = -1
|
||||
|
||||
_global_port_pres_dict = {}
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
# sfp.py will read eeprom contents and retrive the eeprom data.
|
||||
# We pass the eeprom path from chassis.py
|
||||
self.PORT_START = 1
|
||||
self.PORT_END = 66
|
||||
PORTS_IN_BLOCK = (self.PORT_END + 1)
|
||||
_sfp_port = range(65, self.PORT_END + 1)
|
||||
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
|
||||
|
||||
for index in range(self.PORT_START, PORTS_IN_BLOCK):
|
||||
port_num = index + 1
|
||||
eeprom_path = eeprom_base.format(port_num)
|
||||
if index not in _sfp_port:
|
||||
sfp_node = Sfp(index, 'QSFP', eeprom_path)
|
||||
else:
|
||||
sfp_node = Sfp(index, 'SFP', eeprom_path)
|
||||
self._sfp_list.append(sfp_node)
|
||||
|
||||
self._eeprom = Eeprom()
|
||||
|
||||
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
|
||||
presence = self.get_sfp(port_num).get_presence()
|
||||
if presence:
|
||||
self._global_port_pres_dict[port_num] = '1'
|
||||
else:
|
||||
self._global_port_pres_dict[port_num] = '0'
|
||||
|
||||
def __del__(self):
|
||||
if self.oir_fd != -1:
|
||||
self.epoll.unregister(self.oir_fd.fileno())
|
||||
self.epoll.close()
|
||||
self.oir_fd.close()
|
||||
|
||||
def _get_register(self, reg_file):
|
||||
retval = 'ERR'
|
||||
if (not os.path.isfile(reg_file)):
|
||||
print reg_file, 'not found !'
|
||||
return retval
|
||||
|
||||
try:
|
||||
with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd:
|
||||
retval = fd.read()
|
||||
except:
|
||||
pass
|
||||
retval = retval.rstrip('\r\n')
|
||||
retval = retval.lstrip(" ")
|
||||
return retval
|
||||
|
||||
def _check_interrupts(self, port_dict):
|
||||
retval = 0
|
||||
is_port_dict_updated = False
|
||||
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
|
||||
sfp = self.get_sfp(port_num)
|
||||
presence = sfp.get_presence()
|
||||
if(presence and (self._global_port_pres_dict[port_num] == '0')):
|
||||
is_port_dict_updated = True
|
||||
self._global_port_pres_dict[port_num] = '1'
|
||||
port_dict[port_num] = '1'
|
||||
elif(not presence and (self._global_port_pres_dict[port_num] == '1')):
|
||||
is_port_dict_updated = True
|
||||
self._global_port_pres_dict[port_num] = '0'
|
||||
port_dict[port_num] = '0'
|
||||
return retval, is_port_dict_updated
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
"""
|
||||
Returns a nested dictionary containing all devices which have
|
||||
experienced a change at chassis level
|
||||
"""
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
try:
|
||||
# We get notified when there is a MSI interrupt (vector 4/5)CVR
|
||||
# Open the sysfs file and register the epoll object
|
||||
self.oir_fd = os.fdopen(os.open(self.OIR_FD_PATH, os.O_RDONLY))
|
||||
if self.oir_fd != -1:
|
||||
# Do a dummy read before epoll register
|
||||
self.oir_fd.read()
|
||||
self.epoll = select.epoll()
|
||||
self.epoll.register(
|
||||
self.oir_fd.fileno(), select.EPOLLIN & select.EPOLLET)
|
||||
else:
|
||||
print("get_transceiver_change_event : unable to create fd")
|
||||
return False, change_dict
|
||||
# Check for missed interrupts by invoking self._check_interrupts
|
||||
# which will update the port_dict.
|
||||
while True:
|
||||
interrupt_count_start = self._get_register(self.OIR_FD_PATH)
|
||||
retval, is_port_dict_updated = self._check_interrupts(port_dict)
|
||||
if ((retval == 0) and (is_port_dict_updated is True)):
|
||||
return True, change_dict
|
||||
interrupt_count_end = self._get_register(self.OIR_FD_PATH)
|
||||
if (interrupt_count_start == 'ERR' or
|
||||
interrupt_count_end == 'ERR'):
|
||||
print("get_transceiver_change_event : \
|
||||
unable to retrive interrupt count")
|
||||
break
|
||||
# check_interrupts() itself may take upto 100s of msecs.
|
||||
# We detect a missed interrupt based on the count
|
||||
if interrupt_count_start == interrupt_count_end:
|
||||
break
|
||||
# Block until an xcvr is inserted or removed with timeout = -1
|
||||
events = self.epoll.poll(
|
||||
timeout=timeout if timeout != 0 else -1)
|
||||
if events:
|
||||
# check interrupts and return the change_dict
|
||||
retval, is_port_dict_updated = \
|
||||
self._check_interrupts(port_dict)
|
||||
if (retval != 0):
|
||||
return False, change_dict
|
||||
return True, change_dict
|
||||
except:
|
||||
return False, change_dict
|
||||
finally:
|
||||
if self.oir_fd != -1:
|
||||
self.epoll.unregister(self.oir_fd.fileno())
|
||||
self.epoll.close()
|
||||
self.oir_fd.close()
|
||||
self.oir_fd = -1
|
||||
self.epoll = -1
|
||||
return False, change_dict
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (1-based) index <index>
|
||||
|
||||
Args:
|
||||
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 1.
|
||||
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
|
||||
|
||||
Returns:
|
||||
An object dervied from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
|
||||
try:
|
||||
# The index will start from 1
|
||||
sfp = self._sfp_list[index-1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the chassis
|
||||
Returns:
|
||||
string: The name of the chassis
|
||||
"""
|
||||
return self._eeprom.modelstr()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the chassis
|
||||
Returns:
|
||||
bool: True if chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the chassis
|
||||
Returns:
|
||||
string: Model/part number of chassis
|
||||
"""
|
||||
return self._eeprom.part_number_str()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the chassis (Service tag)
|
||||
Returns:
|
||||
string: Serial number of chassis
|
||||
"""
|
||||
return self._eeprom.serial_str()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the chassis
|
||||
Returns:
|
||||
bool: A boolean value, True if chassis is operating properly
|
||||
False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_base_mac(self):
|
||||
"""
|
||||
Retrieves the base MAC address for the chassis
|
||||
Returns:
|
||||
A string containing the MAC address in the format
|
||||
'XX:XX:XX:XX:XX:XX'
|
||||
"""
|
||||
return self._eeprom.base_mac_addr()
|
||||
|
||||
def get_serial_number(self):
|
||||
"""
|
||||
Retrieves the hardware serial number for the chassis
|
||||
Returns:
|
||||
A string containing the hardware serial number for this chassis.
|
||||
"""
|
||||
return self._eeprom.serial_number_str()
|
||||
|
||||
def get_system_eeprom_info(self):
|
||||
"""
|
||||
Retrieves the full content of system EEPROM information for the chassis
|
||||
Returns:
|
||||
A dictionary where keys are the type code defined in
|
||||
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||
values.
|
||||
"""
|
||||
return self._eeprom.system_eeprom_info()
|
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DellEmc Z9264F
|
||||
#
|
||||
# Platform and model specific eeprom subclass, inherits from the base class,
|
||||
# and provides the followings:
|
||||
# - the eeprom format definition
|
||||
# - specific encoder/decoder if there is special need
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os.path
|
||||
from sonic_eeprom import eeprom_tlvinfo
|
||||
import binascii
|
||||
except ImportError, e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
def __init__(self):
|
||||
self.eeprom_path = None
|
||||
for b in (0, 1):
|
||||
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
|
||||
if os.path.exists(f):
|
||||
self.eeprom_path = f
|
||||
break
|
||||
if self.eeprom_path is None:
|
||||
return
|
||||
super(Eeprom, self).__init__(self.eeprom_path, 0, '', True)
|
||||
self.eeprom_tlv_dict = dict()
|
||||
try:
|
||||
self.eeprom_data = self.read_eeprom()
|
||||
except:
|
||||
self.eeprom_data = "N/A"
|
||||
raise RuntimeError("Eeprom is not Programmed")
|
||||
else:
|
||||
eeprom = self.eeprom_data
|
||||
|
||||
if not self.is_valid_tlvinfo_header(eeprom):
|
||||
return
|
||||
|
||||
total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10])
|
||||
tlv_index = self._TLV_INFO_HDR_LEN
|
||||
tlv_end = self._TLV_INFO_HDR_LEN + total_length
|
||||
|
||||
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
|
||||
if not self.is_valid_tlv(eeprom[tlv_index:]):
|
||||
break
|
||||
|
||||
tlv = eeprom[tlv_index:tlv_index + 2
|
||||
+ ord(eeprom[tlv_index + 1])]
|
||||
code = "0x%02X" % (ord(tlv[0]))
|
||||
|
||||
if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT:
|
||||
value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) |
|
||||
(ord(tlv[4]) << 8) | ord(tlv[5]))
|
||||
value += str(tlv[6:6 + ord(tlv[1])])
|
||||
else:
|
||||
name, value = self.decoder(None, tlv)
|
||||
|
||||
self.eeprom_tlv_dict[code] = value
|
||||
if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32:
|
||||
break
|
||||
|
||||
tlv_index += ord(eeprom[tlv_index+1]) + 2
|
||||
|
||||
def serial_number_str(self):
|
||||
"""
|
||||
Returns the serial number
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
return results[2]
|
||||
|
||||
def base_mac_addr(self):
|
||||
"""
|
||||
Returns the base mac address found in the system EEPROM
|
||||
"""
|
||||
(is_valid, t) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_MAC_BASE)
|
||||
if not is_valid or t[1] != 6:
|
||||
return super(TlvInfoDecoder, self).switchaddrstr(e)
|
||||
|
||||
return ":".join([binascii.b2a_hex(T) for T in t[2]])
|
||||
|
||||
def modelstr(self):
|
||||
"""
|
||||
Returns the Model name
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_PRODUCT_NAME)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
|
||||
return results[2]
|
||||
|
||||
def part_number_str(self):
|
||||
"""
|
||||
Returns the part number
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_PART_NUMBER)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
|
||||
return results[2]
|
||||
|
||||
def serial_str(self):
|
||||
"""
|
||||
Returns the servicetag number
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_SERVICE_TAG)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
|
||||
return results[2]
|
||||
|
||||
def revision_str(self):
|
||||
"""
|
||||
Returns the device revision
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_DEVICE_VERSION)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
|
||||
return results[2]
|
||||
|
||||
def system_eeprom_info(self):
|
||||
"""
|
||||
Returns a dictionary, where keys are the type code defined in
|
||||
ONIE EEPROM format and values are their corresponding values
|
||||
found in the system EEPROM.
|
||||
"""
|
||||
return self.eeprom_tlv_dict
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user